Merge "Batterystats BLE results counter takes in count" into oc-dev
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index ca4b4d5..3fd0f50 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -28,6 +28,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.List;
 
 /**
@@ -1341,15 +1342,16 @@
         // One problem is that the old node dependencies point to nodes in the old AnimatorSet.
         // We need to track the old/new nodes in order to reconstruct the dependencies in the clone.
 
+        HashMap<Node, Node> clonesMap = new HashMap<>(nodeCount);
         for (int n = 0; n < nodeCount; n++) {
             final Node node = mNodes.get(n);
             Node nodeClone = node.clone();
-            node.mTmpClone = nodeClone;
+            clonesMap.put(node, nodeClone);
             anim.mNodes.add(nodeClone);
             anim.mNodeMap.put(nodeClone.mAnimation, nodeClone);
         }
 
-        anim.mRootNode = mRootNode.mTmpClone;
+        anim.mRootNode = clonesMap.get(mRootNode);
         anim.mDelayAnim = (ValueAnimator) anim.mRootNode.mAnimation;
 
         // Now that we've cloned all of the nodes, we're ready to walk through their
@@ -1357,25 +1359,22 @@
         for (int i = 0; i < nodeCount; i++) {
             Node node = mNodes.get(i);
             // Update dependencies for node's clone
-            node.mTmpClone.mLatestParent = node.mLatestParent == null ?
-                    null : node.mLatestParent.mTmpClone;
+            Node nodeClone = clonesMap.get(node);
+            nodeClone.mLatestParent = node.mLatestParent == null
+                    ? null : clonesMap.get(node.mLatestParent);
             int size = node.mChildNodes == null ? 0 : node.mChildNodes.size();
             for (int j = 0; j < size; j++) {
-                node.mTmpClone.mChildNodes.set(j, node.mChildNodes.get(j).mTmpClone);
+                nodeClone.mChildNodes.set(j, clonesMap.get(node.mChildNodes.get(j)));
             }
             size = node.mSiblings == null ? 0 : node.mSiblings.size();
             for (int j = 0; j < size; j++) {
-                node.mTmpClone.mSiblings.set(j, node.mSiblings.get(j).mTmpClone);
+                nodeClone.mSiblings.set(j, clonesMap.get(node.mSiblings.get(j)));
             }
             size = node.mParents == null ? 0 : node.mParents.size();
             for (int j = 0; j < size; j++) {
-                node.mTmpClone.mParents.set(j, node.mParents.get(j).mTmpClone);
+                nodeClone.mParents.set(j, clonesMap.get(node.mParents.get(j)));
             }
         }
-
-        for (int n = 0; n < nodeCount; n++) {
-            mNodes.get(n).mTmpClone = null;
-        }
         return anim;
     }
 
@@ -1748,11 +1747,6 @@
         ArrayList<Node> mChildNodes = null;
 
         /**
-         * Temporary field to hold the clone in AnimatorSet#clone. Cleaned after clone is complete
-         */
-        private Node mTmpClone = null;
-
-        /**
          * Flag indicating whether the animation in this node is finished. This flag
          * is used by AnimatorSet to check, as each animation ends, whether all child animations
          * are mEnded and it's time to send out an end event for the entire AnimatorSet.
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index e50c307..51c2246 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1696,15 +1696,27 @@
 
     @Override
     public int installExistingPackage(String packageName) throws NameNotFoundException {
-        return installExistingPackageAsUser(packageName, mContext.getUserId());
+        return installExistingPackage(packageName, PackageManager.INSTALL_REASON_UNKNOWN);
+    }
+
+    @Override
+    public int installExistingPackage(String packageName, int installReason)
+            throws NameNotFoundException {
+        return installExistingPackageAsUser(packageName, installReason, mContext.getUserId());
     }
 
     @Override
     public int installExistingPackageAsUser(String packageName, int userId)
             throws NameNotFoundException {
+        return installExistingPackageAsUser(packageName, PackageManager.INSTALL_REASON_UNKNOWN,
+                userId);
+    }
+
+    private int installExistingPackageAsUser(String packageName, int installReason, int userId)
+            throws NameNotFoundException {
         try {
             int res = mPM.installExistingPackageAsUser(packageName, userId, 0 /*installFlags*/,
-                    PackageManager.INSTALL_REASON_UNKNOWN);
+                    installReason);
             if (res == INSTALL_FAILED_INVALID_URI) {
                 throw new NameNotFoundException("Package " + packageName + " doesn't exist");
             }
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index cc7e0fd..1c1883b 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -71,6 +71,7 @@
     int getDeletedChannelCount(String pkg, int uid);
     void deleteNotificationChannelGroup(String pkg, String channelGroupId);
     ParceledListSlice getNotificationChannelGroups(String pkg);
+    boolean onlyHasDefaultChannel(String pkg, int uid);
 
     // TODO: Remove this when callers have been migrated to the equivalent
     // INotificationListener method.
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 4294eab..ccbd5b4 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2703,6 +2703,7 @@
         private int mBackgroundColor = COLOR_INVALID;
         private int mForegroundColor = COLOR_INVALID;
         private int mBackgroundColorHint = COLOR_INVALID;
+        private boolean mRebuildStyledRemoteViews;
 
         /**
          * Constructs a new Builder with the defaults:
@@ -4251,7 +4252,7 @@
          *   @hide
          */
         public RemoteViews createContentView(boolean increasedHeight) {
-            if (mN.contentView != null && (mStyle == null || !mStyle.displayCustomViewInline())) {
+            if (mN.contentView != null && useExistingRemoteView()) {
                 return mN.contentView;
             } else if (mStyle != null) {
                 final RemoteViews styleView = mStyle.makeContentView(increasedHeight);
@@ -4262,13 +4263,17 @@
             return applyStandardTemplate(getBaseLayoutResource());
         }
 
+        private boolean useExistingRemoteView() {
+            return mStyle == null || (!mStyle.displayCustomViewInline()
+                    && !mRebuildStyledRemoteViews);
+        }
+
         /**
          * Construct a RemoteViews for the final big notification layout.
          */
         public RemoteViews createBigContentView() {
             RemoteViews result = null;
-            if (mN.bigContentView != null
-                    && (mStyle == null || !mStyle.displayCustomViewInline())) {
+            if (mN.bigContentView != null && useExistingRemoteView()) {
                 return mN.bigContentView;
             } else if (mStyle != null) {
                 result = mStyle.makeBigContentView();
@@ -4343,8 +4348,7 @@
          * @hide
          */
         public RemoteViews createHeadsUpContentView(boolean increasedHeight) {
-            if (mN.headsUpContentView != null
-                    && (mStyle == null ||  !mStyle.displayCustomViewInline())) {
+            if (mN.headsUpContentView != null && useExistingRemoteView()) {
                 return mN.headsUpContentView;
             } else if (mStyle != null) {
                 final RemoteViews styleView = mStyle.makeHeadsUpContentView(increasedHeight);
@@ -4806,7 +4810,7 @@
             }
 
             if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N
-                    && (mStyle == null || !mStyle.displayCustomViewInline())) {
+                    && (useExistingRemoteView())) {
                 if (mN.contentView == null) {
                     mN.contentView = createContentView();
                     mN.extras.putInt(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT,
@@ -4978,6 +4982,19 @@
         public void setBackgroundColorHint(int backgroundColor) {
             mBackgroundColorHint = backgroundColor;
         }
+
+
+        /**
+         * Forces all styled remoteViews to be built from scratch and not use any cached
+         * RemoteViews.
+         * This is needed for legacy apps that are baking in their remoteviews into the
+         * notification.
+         *
+         * @hide
+         */
+        public void setRebuildStyledRemoteViews(boolean rebuild) {
+            mRebuildStyledRemoteViews = rebuild;
+        }
     }
 
     /**
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 40fe6af..fcf1931 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -95,7 +95,6 @@
 import android.os.BatteryManager;
 import android.os.BatteryStats;
 import android.os.Build;
-import android.os.Debug;
 import android.os.DropBoxManager;
 import android.os.HardwarePropertiesManager;
 import android.os.IBatteryPropertiesRegistrar;
@@ -118,8 +117,6 @@
 import android.os.storage.StorageManager;
 import android.print.IPrintManager;
 import android.print.PrintManager;
-import android.view.autofill.AutofillManager;
-import android.view.autofill.IAutoFillManager;
 import android.service.oemlock.IOemLockService;
 import android.service.oemlock.OemLockManager;
 import android.service.persistentdata.IPersistentDataBlockService;
@@ -136,6 +133,8 @@
 import android.view.WindowManagerImpl;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.CaptioningManager;
+import android.view.autofill.AutofillManager;
+import android.view.autofill.IAutoFillManager;
 import android.view.inputmethod.InputMethodManager;
 import android.view.textclassifier.TextClassificationManager;
 import android.view.textservice.TextServicesManager;
@@ -660,7 +659,7 @@
                                 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE);
                         ICompanionDeviceManager service =
                                 ICompanionDeviceManager.Stub.asInterface(iBinder);
-                        return new CompanionDeviceManager(service, ctx);
+                        return new CompanionDeviceManager(service, ctx.getOuterContext());
                     }});
 
         registerService(Context.CONSUMER_IR_SERVICE, ConsumerIrManager.class,
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 1994206..eae9e1e 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -19,6 +19,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.service.autofill.FillContext;
+import android.service.autofill.FillRequest;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
@@ -494,7 +495,7 @@
             ViewNodeBuilder builder = new ViewNodeBuilder(assist, mRoot, false);
             if ((root.getWindowFlags() & WindowManager.LayoutParams.FLAG_SECURE) != 0) {
                 if (forAutoFill) {
-                    final int autofillFlags = (flags & AutofillManager.FLAG_MANUAL_REQUEST) != 0
+                    final int autofillFlags = (flags & FillRequest.FLAG_MANUAL_REQUEST) != 0
                             ? View.AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS : 0;
                     view.onProvideAutofillStructure(builder, autofillFlags);
                 } else {
@@ -506,7 +507,7 @@
                 }
             }
             if (forAutoFill) {
-                final int autofillFlags = (flags & AutofillManager.FLAG_MANUAL_REQUEST) != 0
+                final int autofillFlags = (flags & FillRequest.FLAG_MANUAL_REQUEST) != 0
                         ? View.AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS : 0;
                 view.dispatchProvideAutofillStructure(builder, autofillFlags);
             } else {
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index fac9e13..4e70e3f 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -21,11 +21,14 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.Activity;
+import android.app.Application;
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.IntentSender;
 import android.content.pm.PackageManager;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.service.notification.NotificationListenerService;
@@ -137,26 +140,11 @@
         }
         checkNotNull(request, "Request cannot be null");
         checkNotNull(callback, "Callback cannot be null");
-        final Handler finalHandler = Handler.mainIfNull(handler);
         try {
             mService.associate(
                     request,
-                    //TODO implicit pointer to outer class -> =null onDestroy
-                    //TODO onStop if isFinishing -> stopScan
-                    new IFindDeviceCallback.Stub() {
-                        @Override
-                        public void onSuccess(PendingIntent launcher) {
-                            finalHandler.post(() -> {
-                                callback.onDeviceFound(launcher.getIntentSender());
-                            });
-                        }
-
-                        @Override
-                        public void onFailure(CharSequence reason) {
-                            finalHandler.post(() -> callback.onFailure(reason));
-                        }
-                    },
-                    mContext.getPackageName());
+                    new CallbackProxy(request, callback, Handler.mainIfNull(handler)),
+                    getCallingPackage());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -175,7 +163,7 @@
             return Collections.emptyList();
         }
         try {
-            return mService.getAssociations(mContext.getPackageName(), mContext.getUserId());
+            return mService.getAssociations(getCallingPackage(), mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -200,7 +188,7 @@
             return;
         }
         try {
-            mService.disassociate(deviceMacAddress, mContext.getPackageName());
+            mService.disassociate(deviceMacAddress, getCallingPackage());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -263,4 +251,57 @@
         }
         return featurePresent;
     }
+
+    private Activity getActivity() {
+        return (Activity) mContext;
+    }
+
+    private String getCallingPackage() {
+        return mContext.getPackageName();
+    }
+
+    private class CallbackProxy extends IFindDeviceCallback.Stub
+            implements Application.ActivityLifecycleCallbacks {
+
+        private Callback mCallback;
+        private Handler mHandler;
+        private AssociationRequest mRequest;
+
+        private CallbackProxy(AssociationRequest request, Callback callback, Handler handler) {
+            mCallback = callback;
+            mHandler = handler;
+            mRequest = request;
+            getActivity().getApplication().registerActivityLifecycleCallbacks(this);
+        }
+
+        @Override
+        public void onSuccess(PendingIntent launcher) {
+            mHandler.post(() -> mCallback.onDeviceFound(launcher.getIntentSender()));
+        }
+
+        @Override
+        public void onFailure(CharSequence reason) {
+            mHandler.post(() -> mCallback.onFailure(reason));
+        }
+
+        @Override
+        public void onActivityDestroyed(Activity activity) {
+            try {
+                mService.stopScan(mRequest, this, getCallingPackage());
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+            getActivity().getApplication().unregisterActivityLifecycleCallbacks(this);
+            mCallback = null;
+            mHandler = null;
+            mRequest = null;
+        }
+
+        @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) {}
+        @Override public void onActivityStarted(Activity activity) {}
+        @Override public void onActivityResumed(Activity activity) {}
+        @Override public void onActivityPaused(Activity activity) {}
+        @Override public void onActivityStopped(Activity activity) {}
+        @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}
+    }
 }
diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl
index d395208..561342e 100644
--- a/core/java/android/companion/ICompanionDeviceManager.aidl
+++ b/core/java/android/companion/ICompanionDeviceManager.aidl
@@ -30,6 +30,9 @@
     void associate(in AssociationRequest request,
         in IFindDeviceCallback callback,
         in String callingPackage);
+    void stopScan(in AssociationRequest request,
+        in IFindDeviceCallback callback,
+        in String callingPackage);
 
     List<String> getAssociations(String callingPackage, int userId);
     void disassociate(String deviceMacAddress, String callingPackage);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index d2468d9..a68c097 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -157,6 +157,7 @@
             MATCH_DISABLED_COMPONENTS,
             MATCH_DISABLED_UNTIL_USED_COMPONENTS,
             MATCH_INSTANT,
+            MATCH_STATIC_SHARED_LIBRARIES,
             GET_DISABLED_UNTIL_USED_COMPONENTS,
             GET_UNINSTALLED_PACKAGES,
     })
@@ -177,6 +178,7 @@
             MATCH_SYSTEM_ONLY,
             MATCH_UNINSTALLED_PACKAGES,
             MATCH_INSTANT,
+            MATCH_STATIC_SHARED_LIBRARIES,
             GET_DISABLED_COMPONENTS,
             GET_DISABLED_UNTIL_USED_COMPONENTS,
             GET_UNINSTALLED_PACKAGES,
@@ -475,6 +477,16 @@
     public static final int MATCH_EXPLICITLY_VISIBLE_ONLY = 0x02000000;
 
     /**
+     * Internal {@link PackageInfo} flag: include static shared libraries.
+     * Apps that depend on static shared libs can always access the version
+     * of the lib they depend on. System/shell/root can access all shared
+     * libs regardless of dependency but need to explicitly ask for them
+     * via this flag.
+     * @hide
+     */
+    public static final int MATCH_STATIC_SHARED_LIBRARIES = 0x04000000;
+
+    /**
      * Internal flag used to indicate that a system component has done their
      * homework and verified that they correctly handle packages and components
      * that come and go over time. In particular:
@@ -4618,6 +4630,14 @@
 
     /**
      * If there is already an application with the given package name installed
+     * on the system for other users, also install it for the calling user.
+     * @hide
+     */
+    public abstract int installExistingPackage(String packageName, @InstallReason int installReason)
+            throws NameNotFoundException;
+
+    /**
+     * If there is already an application with the given package name installed
      * on the system for other users, also install it for the specified user.
      * @hide
      */
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index b5fd116..3eea72d 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -203,6 +203,8 @@
     private static final String APK_DATA = "apk";
     private static final String PROCESS_DATA = "pr";
     private static final String CPU_DATA = "cpu";
+    private static final String GLOBAL_CPU_FREQ_DATA = "gcf";
+    private static final String CPU_TIMES_AT_FREQ_DATA = "ctf";
     private static final String SENSOR_DATA = "sr";
     private static final String VIBRATOR_DATA = "vib";
     private static final String FOREGROUND_DATA = "fg";
@@ -265,6 +267,13 @@
     private final Formatter mFormatter = new Formatter(mFormatBuilder);
 
     /**
+     * Indicates times spent by the uid at each cpu frequency in all process states.
+     *
+     * Other types might include times spent in foreground, background etc.
+     */
+    private final String UID_TIMES_TYPE_ALL = "A";
+
+    /**
      * State for keeping track of counting information.
      */
     public static abstract class Counter {
@@ -303,6 +312,24 @@
     }
 
     /**
+     * State for keeping track of array of long counting information.
+     */
+    public static abstract class LongCounterArray {
+        /**
+         * Returns the counts associated with this Counter for the
+         * selected type of statistics.
+         *
+         * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT
+         */
+        public abstract long[] getCountsLocked(int which);
+
+        /**
+         * Temporary for debugging.
+         */
+        public abstract void logState(Printer pw, String prefix);
+    }
+
+    /**
      * Container class that aggregates counters for transmit, receive, and idle state of a
      * radio controller.
      */
@@ -523,6 +550,9 @@
         public abstract Timer getBluetoothScanBackgroundTimer();
         public abstract Counter getBluetoothScanResultCounter();
 
+        public abstract long[] getCpuFreqTimes(int which);
+        public abstract long[] getScreenOffCpuFreqTimes(int which);
+
         // Note: the following times are disjoint.  They can be added together to find the
         // total time a uid has had any processes running at all.
 
@@ -1077,6 +1107,8 @@
 
     public abstract long getNextMaxDailyDeadline();
 
+    public abstract long[] getCpuFreqs();
+
     public final static class HistoryTag {
         public String string;
         public int uid;
@@ -3274,6 +3306,15 @@
             }
         }
 
+        final long[] cpuFreqs = getCpuFreqs();
+        if (cpuFreqs != null) {
+            sb.setLength(0);
+            for (int i = 0; i < cpuFreqs.length; ++i) {
+                sb.append((i == 0 ? "" : ",") + cpuFreqs[i]);
+            }
+            dumpLine(pw, 0 /* uid */, category, GLOBAL_CPU_FREQ_DATA, sb.toString());
+        }
+
         for (int iu = 0; iu < NU; iu++) {
             final int uid = uidStats.keyAt(iu);
             if (reqUid >= 0 && uid != reqUid) {
@@ -3506,6 +3547,27 @@
                         0 /* old cpu power, keep for compatibility */);
             }
 
+            final long[] cpuFreqTimeMs = u.getCpuFreqTimes(which);
+            // If total cpuFreqTimes is null, then we don't need to check for screenOffCpuFreqTimes.
+            if (cpuFreqTimeMs != null) {
+                sb.setLength(0);
+                for (int i = 0; i < cpuFreqTimeMs.length; ++i) {
+                    sb.append((i == 0 ? "" : ",") + cpuFreqTimeMs[i]);
+                }
+                final long[] screenOffCpuFreqTimeMs = u.getScreenOffCpuFreqTimes(which);
+                if (screenOffCpuFreqTimeMs != null) {
+                    for (int i = 0; i < screenOffCpuFreqTimeMs.length; ++i) {
+                        sb.append("," + screenOffCpuFreqTimeMs[i]);
+                    }
+                } else {
+                    for (int i = 0; i < cpuFreqTimeMs.length; ++i) {
+                        sb.append(",0");
+                    }
+                }
+                dumpLine(pw, uid, category, CPU_TIMES_AT_FREQ_DATA, UID_TIMES_TYPE_ALL,
+                        cpuFreqTimeMs.length, sb.toString());
+            }
+
             final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats
                     = u.getProcessStats();
             for (int ipr=processStats.size()-1; ipr>=0; ipr--) {
@@ -4373,6 +4435,16 @@
             pw.println(sb.toString());
         }
 
+        final long[] cpuFreqs = getCpuFreqs();
+        if (cpuFreqs != null) {
+            sb.setLength(0);
+            sb.append("CPU freqs:");
+            for (int i = 0; i < cpuFreqs.length; ++i) {
+                sb.append(" " + cpuFreqs[i]);
+            }
+            pw.println(sb.toString());
+        }
+
         for (int iu=0; iu<NU; iu++) {
             final int uid = uidStats.keyAt(iu);
             if (reqUid >= 0 && uid != reqUid && uid != Process.SYSTEM_UID) {
@@ -4835,6 +4907,25 @@
                 pw.println(sb.toString());
             }
 
+            final long[] cpuFreqTimes = u.getCpuFreqTimes(which);
+            if (cpuFreqTimes != null) {
+                sb.setLength(0);
+                sb.append("    Total cpu time per freq:");
+                for (int i = 0; i < cpuFreqTimes.length; ++i) {
+                    sb.append(" " + cpuFreqTimes[i]);
+                }
+                pw.println(sb.toString());
+            }
+            final long[] screenOffCpuFreqTimes = u.getScreenOffCpuFreqTimes(which);
+            if (screenOffCpuFreqTimes != null) {
+                sb.setLength(0);
+                sb.append("    Total screen-off cpu time per freq:");
+                for (int i = 0; i < screenOffCpuFreqTimes.length; ++i) {
+                    sb.append(" " + screenOffCpuFreqTimes[i]);
+                }
+                pw.println(sb.toString());
+            }
+
             final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats
                     = u.getProcessStats();
             for (int ipr=processStats.size()-1; ipr>=0; ipr--) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cf44c7d..3cd54b8 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6946,6 +6946,13 @@
         public static final String CMAS_ADDITIONAL_BROADCAST_PKG = "cmas_additional_broadcast_pkg";
 
         /**
+         * Whether the launcher should show any notification badges.
+         * The value is boolean (1 or 0).
+         * @hide
+         */
+        public static final String NOTIFICATION_BADGING = "notification_badging";
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
@@ -7040,7 +7047,8 @@
             AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
             ASSIST_GESTURE_ENABLED,
             ASSIST_GESTURE_SENSITIVITY,
-            VR_DISPLAY_MODE
+            VR_DISPLAY_MODE,
+            NOTIFICATION_BADGING
         };
 
         /**
@@ -9947,7 +9955,8 @@
             CALL_AUTO_RETRY,
             DOCK_AUDIO_MEDIA_ENABLED,
             ENCODED_SURROUND_OUTPUT,
-            LOW_POWER_MODE_TRIGGER_LEVEL
+            LOW_POWER_MODE_TRIGGER_LEVEL,
+            BLUETOOTH_ON
         };
 
         private static final ContentProviderHolder sProviderHolder =
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 5fd9458..9df315b 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -116,15 +116,7 @@
                 final IFillCallback callback = (IFillCallback) args.arg3;
                 final FillCallback fillCallback = new FillCallback(callback, request.getId());
                 args.recycle();
-                // TODO(b/37563972): temporary try-catch hack to support old method
-                try {
-                    onFillRequest(request, cancellation, fillCallback);
-                } catch (AbstractMethodError e) {
-                    final List<FillContext> contexts = request.getFillContexts();
-                    onFillRequest(contexts.get(contexts.size() - 1).getStructure(),
-                            request.getClientState(), request.getFlags(), cancellation,
-                            fillCallback);
-                }
+                onFillRequest(request, cancellation, fillCallback);
                 break;
             } case MSG_ON_SAVE_REQUEST: {
                 final SomeArgs args = (SomeArgs) msg.obj;
@@ -132,14 +124,7 @@
                 final ISaveCallback callback = (ISaveCallback) args.arg2;
                 final SaveCallback saveCallback = new SaveCallback(callback);
                 args.recycle();
-                // TODO(b/37563972): temporary try-catch hack to support old method
-                try {
-                    onSaveRequest(request, saveCallback);
-                } catch (AbstractMethodError e) {
-                    final List<FillContext> contexts = request.getFillContexts();
-                    onSaveRequest(contexts.get(contexts.size() - 1).getStructure(),
-                            request.getClientState(), saveCallback);
-                }
+                onSaveRequest(request, saveCallback);
                 break;
             } case MSG_DISCONNECT: {
                 onDisconnected();
@@ -201,37 +186,6 @@
             @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback);
 
     /**
-     * Called by the Android system do decide if an {@link Activity} can be autofilled by the
-     * service.
-     *
-     * <p>Service must call one of the {@link FillCallback} methods (like
-     * {@link FillCallback#onSuccess(FillResponse)}
-     * or {@link FillCallback#onFailure(CharSequence)})
-     * to notify the result of the request.
-     *
-     * @param structure {@link Activity}'s view structure.
-     * @param data bundle containing data passed by the service in a last call to
-     *        {@link FillResponse.Builder#setExtras(Bundle)}, if any. This bundle allows your
-     *        service to keep state between fill and save requests as well as when filling different
-     *        sections of the UI as the system will try to aggressively unbind from the service to
-     *        conserve resources.
-     *        See {@link FillResponse} for examples of multiple-sections requests.
-     * @param flags either {@code 0} or {@link AutofillManager#FLAG_MANUAL_REQUEST}.
-     * @param cancellationSignal signal for observing cancellation requests. The system will use
-     *     this to notify you that the fill result is no longer needed and you should stop
-     *     handling this fill request in order to save resources.
-     * @param callback object used to notify the result of the request.
-     *
-     * @hide
-     */
-    @Deprecated
-    public void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
-            int flags, @NonNull CancellationSignal cancellationSignal,
-            @NonNull FillCallback callback) {
-
-    }
-
-    /**
      * Called when user requests service to save the fields of an {@link Activity}.
      *
      * <p>Service must call one of the {@link SaveCallback} methods (like
@@ -246,30 +200,6 @@
             @NonNull SaveCallback callback);
 
     /**
-     * Called when user requests service to save the fields of an {@link Activity}.
-     *
-     * <p>Service must call one of the {@link SaveCallback} methods (like
-     * {@link SaveCallback#onSuccess()} or {@link SaveCallback#onFailure(CharSequence)})
-     * to notify the result of the request.
-     *
-     * @param structure {@link Activity}'s view structure.
-     * @param data bundle containing data passed by the service in a last call to
-     *        {@link FillResponse.Builder#setExtras(Bundle)}, if any. This bundle allows your
-     *        service to keep state between fill and save requests as well as when filling different
-     *        sections of the UI as the system will try to aggressively unbind from the service to
-     *        conserve resources.
-     *        See {@link FillResponse} for examples of multiple-sections requests.
-     * @param callback object used to notify the result of the request.
-     *
-     * @hide
-     */
-    @Deprecated
-    public void onSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
-            @NonNull SaveCallback callback) {
-
-    }
-
-    /**
      * Called when the Android system disconnects from the service.
      *
      * <p> At this point this service may no longer be an active {@link AutofillService}.
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 9487760..fa3f55b 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -326,15 +326,6 @@
             return this;
         }
 
-        /** @hide */
-        // TODO (b/37563972): Remove when callers migrate
-        public @NonNull Builder setNegativeAction(@Nullable CharSequence title,
-                @Nullable IntentSender listener) {
-            throwIfDestroyed();
-            setNegativeAction(NEGATIVE_BUTTON_STYLE_CANCEL, listener);
-            return this;
-        }
-
         /**
          * Sets the style and listener for the negative save action.
          *
diff --git a/core/java/android/util/MemoryIntArray.java b/core/java/android/util/MemoryIntArray.java
index 749cf08..589edbc 100644
--- a/core/java/android/util/MemoryIntArray.java
+++ b/core/java/android/util/MemoryIntArray.java
@@ -56,7 +56,7 @@
 
     private final boolean mIsOwner;
     private final long mMemoryAddr;
-    private int mFd;
+    private int mFd = -1;
 
     /**
      * Creates a new instance.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 07258fc..02ac9bd 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -17306,15 +17306,14 @@
      * item in a list view.
      *
      * @return Returns a Parcelable object containing the view's current dynamic
-     *         state, or null if there is nothing interesting to save. The
-     *         default implementation returns null.
+     *         state, or null if there is nothing interesting to save.
      * @see #onRestoreInstanceState(android.os.Parcelable)
      * @see #saveHierarchyState(android.util.SparseArray)
      * @see #dispatchSaveInstanceState(android.util.SparseArray)
      * @see #setSaveEnabled(boolean)
      */
     @CallSuper
-    protected Parcelable onSaveInstanceState() {
+    @Nullable protected Parcelable onSaveInstanceState() {
         mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
         if (mStartActivityRequestWho != null || isAutofilled()
                 || mAccessibilityViewId > LAST_APP_ACCESSIBILITY_ID) {
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 75a9965..68c74da 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -16,6 +16,7 @@
 
 package android.view.autofill;
 
+import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
 import static android.view.autofill.Helper.sDebug;
 import static android.view.autofill.Helper.sVerbose;
 
@@ -99,14 +100,6 @@
     static final String SESSION_ID_TAG = "android:sessionId";
     static final String LAST_AUTOFILLED_DATA_TAG = "android:lastAutoFilledData";
 
-    /**
-     * @deprecated Use {@link android.service.autofill.FillRequest#FLAG_MANUAL_REQUEST}
-     * @hide
-     */
-    // TODO(b/37563972): remove (and change value of private flags)
-    @Deprecated
-    public static final int FLAG_MANUAL_REQUEST = 0x1;
-
     /** @hide */ public static final int ACTION_START_SESSION = 1;
     /** @hide */ public static final int ACTION_VIEW_ENTERED =  2;
     /** @hide */ public static final int ACTION_VIEW_EXITED = 3;
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index 1f3be84..32fae73 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -140,4 +140,14 @@
     @WorkerThread
     LinksInfo getLinks(
             @NonNull CharSequence text, int linkMask, @Nullable LocaleList defaultLocales);
+
+    /**
+     * Logs a TextClassifier event.
+     *
+     * @param source the text classifier used to generate this event
+     * @param event the text classifier related event
+     * @hide
+     */
+    @WorkerThread
+    default void logEvent(String source, String event) {}
 }
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 7362c70..5f72fc7 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -40,6 +40,7 @@
 import android.widget.TextViewMetrics;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.util.Preconditions;
 
 import java.io.File;
@@ -77,6 +78,8 @@
 
     private final Context mContext;
 
+    private final MetricsLogger mMetricsLogger = new MetricsLogger();
+
     private final Object mSmartSelectionLock = new Object();
     @GuardedBy("mSmartSelectionLock") // Do not access outside this lock.
     private Map<Locale, String> mModelFilePaths;
@@ -105,7 +108,8 @@
                 if (start <= end
                         && start >= 0 && end <= string.length()
                         && start <= selectionStartIndex && end >= selectionEndIndex) {
-                    final TextSelection.Builder tsBuilder = new TextSelection.Builder(start, end);
+                    final TextSelection.Builder tsBuilder = new TextSelection.Builder(start, end)
+                            .setLogSource(LOG_TAG);
                     final SmartSelection.ClassificationResult[] results =
                             smartSelection.classifyText(
                                     string, start, end,
@@ -173,6 +177,13 @@
         return TextClassifier.NO_OP.getLinks(text, linkMask, defaultLocales);
     }
 
+    @Override
+    public void logEvent(String source, String event) {
+        if (LOG_TAG.equals(source)) {
+            mMetricsLogger.count(event, 1);
+        }
+    }
+
     private SmartSelection getSmartSelection(LocaleList localeList) throws FileNotFoundException {
         synchronized (mSmartSelectionLock) {
             localeList = localeList == null ? LocaleList.getEmptyLocaleList() : localeList;
diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
index 3172c13..9a66693 100644
--- a/core/java/android/view/textclassifier/TextSelection.java
+++ b/core/java/android/view/textclassifier/TextSelection.java
@@ -34,13 +34,16 @@
     private final int mEndIndex;
     @NonNull private final EntityConfidence<String> mEntityConfidence;
     @NonNull private final List<String> mEntities;
+    @NonNull private final String mLogSource;
 
     private TextSelection(
-            int startIndex, int endIndex, @NonNull EntityConfidence<String> entityConfidence) {
+            int startIndex, int endIndex, @NonNull EntityConfidence<String> entityConfidence,
+            @NonNull String logSource) {
         mStartIndex = startIndex;
         mEndIndex = endIndex;
         mEntityConfidence = new EntityConfidence<>(entityConfidence);
         mEntities = mEntityConfidence.getEntities();
+        mLogSource = logSource;
     }
 
     /**
@@ -87,6 +90,14 @@
         return mEntityConfidence.getConfidenceScore(entity);
     }
 
+    /**
+     * Returns a tag for the source classifier used to generate this result.
+     * @hide
+     */
+    public String getSourceClassifier() {
+        return mLogSource;
+    }
+
     @Override
     public String toString() {
         return String.format("TextSelection {%d, %d, %s}",
@@ -102,6 +113,7 @@
         private final int mEndIndex;
         @NonNull private final EntityConfidence<String> mEntityConfidence =
                 new EntityConfidence<>();
+        @NonNull private String mLogSource = "";
 
         /**
          * Creates a builder used to build {@link TextSelection} objects.
@@ -131,10 +143,19 @@
         }
 
         /**
+         * Sets a tag for the source classifier used to generate this result.
+         * @hide
+         */
+        Builder setLogSource(@NonNull String logSource) {
+            mLogSource = Preconditions.checkNotNull(logSource);
+            return this;
+        }
+
+        /**
          * Builds and returns {@link TextSelection} object.
          */
         public TextSelection build() {
-            return new TextSelection(mStartIndex, mEndIndex, mEntityConfidence);
+            return new TextSelection(mStartIndex, mEndIndex, mEntityConfidence, mLogSource);
         }
     }
 }
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index b0d6395..bb658c1 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -3925,6 +3925,8 @@
 
         @Override
         public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+            getSelectionActionModeHelper().onSelectionAction();
+
             if (mProcessTextIntentActionsHandler.performMenuItemAction(item)) {
                 return true;
             }
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 16a1087..89182b0 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -56,13 +56,14 @@
     private TextClassification mTextClassification;
     private AsyncTask mTextClassificationAsyncTask;
 
-    private final SelectionInfo mSelectionInfo = new SelectionInfo();
+    private final SelectionTracker mSelectionTracker;
 
     SelectionActionModeHelper(@NonNull Editor editor) {
         mEditor = Preconditions.checkNotNull(editor);
         final TextView textView = mEditor.getTextView();
         mTextClassificationHelper = new TextClassificationHelper(
                 textView.getTextClassifier(), textView.getText(), 0, 1, textView.getTextLocales());
+        mSelectionTracker = new SelectionTracker(textView.getTextClassifier());
     }
 
     public void startActionModeAsync(boolean adjustSelection) {
@@ -99,8 +100,13 @@
         }
     }
 
+    public void onSelectionAction() {
+        mSelectionTracker.onSelectionAction(mTextClassificationHelper.getClassifierTag());
+    }
+
     public boolean resetSelection(int textIndex) {
-        if (mSelectionInfo.resetSelection(textIndex, mEditor)) {
+        if (mSelectionTracker.resetSelection(
+                textIndex, mEditor, mTextClassificationHelper.getClassifierTag())) {
             invalidateActionModeAsync();
             return true;
         }
@@ -113,7 +119,7 @@
     }
 
     public void onDestroyActionMode() {
-        mSelectionInfo.onSelectionDestroyed();
+        mSelectionTracker.onSelectionDestroyed();
         cancelAsyncTask();
     }
 
@@ -137,7 +143,7 @@
     private void startActionMode(@Nullable SelectionResult result) {
         final TextView textView = mEditor.getTextView();
         final CharSequence text = textView.getText();
-        mSelectionInfo.setOriginalSelection(
+        mSelectionTracker.setOriginalSelection(
                 textView.getSelectionStart(), textView.getSelectionEnd());
         if (result != null && text instanceof Spannable) {
             Selection.setSelection((Spannable) text, result.mStart, result.mEnd);
@@ -151,7 +157,8 @@
                 controller.show();
             }
             if (result != null) {
-                mSelectionInfo.onSelectionStarted(result.mStart, result.mEnd);
+                mSelectionTracker.onSelectionStarted(
+                        result.mStart, result.mEnd, mTextClassificationHelper.getClassifierTag());
             }
         }
         mEditor.setRestartActionModeOnNextRefresh(false);
@@ -165,7 +172,9 @@
             actionMode.invalidate();
         }
         final TextView textView = mEditor.getTextView();
-        mSelectionInfo.onSelectionUpdated(textView.getSelectionStart(), textView.getSelectionEnd());
+        mSelectionTracker.onSelectionUpdated(
+                textView.getSelectionStart(), textView.getSelectionEnd(),
+                mTextClassificationHelper.getClassifierTag());
         mTextClassificationAsyncTask = null;
     }
 
@@ -177,49 +186,111 @@
     }
 
     /**
-     * Holds information about the selection and uses it to decide on whether or not to update
-     * the selection when resetSelection is called.
-     * The expected UX here is to allow the user to select a word inside of the "smart selection" on
-     * a single tap.
+     * Tracks and logs smart selection changes.
+     * It is important to trigger this object's methods at the appropriate event so that it tracks
+     * smart selection events appropriately.
      */
-    private static final class SelectionInfo {
+    private static final class SelectionTracker {
+
+        // Log event: Smart selection happened.
+        private static final String LOG_EVENT_MULTI_SELECTION =
+                "textClassifier_multiSelection";
+
+        // Log event: Smart selection acted upon.
+        private static final String LOG_EVENT_MULTI_SELECTION_ACTION =
+                "textClassifier_multiSelection_action";
+
+        // Log event: Smart selection was reset to original selection.
+        private static final String LOG_EVENT_MULTI_SELECTION_RESET =
+                "textClassifier_multiSelection_reset";
+
+        // Log event: Smart selection was user modified.
+        private static final String LOG_EVENT_MULTI_SELECTION_MODIFIED =
+                "textClassifier_multiSelection_modified";
+
+        private final TextClassifier mClassifier;
 
         private int mOriginalStart;
         private int mOriginalEnd;
         private int mSelectionStart;
         private int mSelectionEnd;
 
-        private boolean mResetOriginal;
+        private boolean mSmartSelectionActive;
 
+        SelectionTracker(TextClassifier classifier) {
+            mClassifier = classifier;
+        }
+
+        /**
+         * Called to initialize the original selection before smart selection is triggered.
+         */
         public void setOriginalSelection(int selectionStart, int selectionEnd) {
             mOriginalStart = selectionStart;
             mOriginalEnd = selectionEnd;
-            mResetOriginal = false;
+            mSmartSelectionActive = false;
         }
 
-        public void onSelectionStarted(int selectionStart, int selectionEnd) {
-            // Set the reset flag to true if the selection changed.
+        /**
+         * Called when selection action mode is started.
+         * If the selection indices are different from the original selection indices, we have a
+         * smart selection.
+         */
+        public void onSelectionStarted(int selectionStart, int selectionEnd, String logTag) {
             mSelectionStart = selectionStart;
             mSelectionEnd = selectionEnd;
-            mResetOriginal = mSelectionStart != mOriginalStart || mSelectionEnd != mOriginalEnd;
+            // If the started selection is different from the original selection, we have a
+            // smart selection.
+            mSmartSelectionActive =
+                    mSelectionStart != mOriginalStart || mSelectionEnd != mOriginalEnd;
+            if (mSmartSelectionActive) {
+                mClassifier.logEvent(logTag, LOG_EVENT_MULTI_SELECTION);
+            }
         }
 
-        public void onSelectionUpdated(int selectionStart, int selectionEnd) {
-            // If the selection did not change, maintain the reset state. Otherwise, disable reset.
-            mResetOriginal &= selectionStart == mSelectionStart && selectionEnd == mSelectionEnd;
+        /**
+         * Called when selection bounds change.
+         */
+        public void onSelectionUpdated(int selectionStart, int selectionEnd, String logTag) {
+            final boolean selectionChanged =
+                    selectionStart != mSelectionStart || selectionEnd != mSelectionEnd;
+            if (selectionChanged) {
+                if (mSmartSelectionActive) {
+                    mClassifier.logEvent(logTag, LOG_EVENT_MULTI_SELECTION_MODIFIED);
+                }
+                mSmartSelectionActive = false;
+            }
         }
 
+        /**
+         * Called when the selection action mode is destroyed.
+         */
         public void onSelectionDestroyed() {
-            mResetOriginal = false;
+            mSmartSelectionActive = false;
         }
 
-        public boolean resetSelection(int textIndex, Editor editor) {
+        /**
+         * Logs if the action was taken on a smart selection.
+         */
+        public void onSelectionAction(String logTag) {
+            if (mSmartSelectionActive) {
+                mClassifier.logEvent(logTag, LOG_EVENT_MULTI_SELECTION_ACTION);
+            }
+        }
+
+        /**
+         * Returns true if the current smart selection should be reset to normal selection based on
+         * information that has been recorded about the original selection and the smart selection.
+         * The expected UX here is to allow the user to select a word inside of the smart selection
+         * on a single tap.
+         */
+        public boolean resetSelection(int textIndex, Editor editor, String logTag) {
             final CharSequence text = editor.getTextView().getText();
-            if (mResetOriginal
+            if (mSmartSelectionActive
                     && textIndex >= mSelectionStart && textIndex <= mSelectionEnd
                     && text instanceof Spannable) {
                 // Only allow a reset once.
-                mResetOriginal = false;
+                mSmartSelectionActive = false;
+                mClassifier.logEvent(logTag, LOG_EVENT_MULTI_SELECTION_RESET);
                 return editor.selectCurrentWord();
             }
             return false;
@@ -301,6 +372,7 @@
         /** End index relative to mText. */
         private int mSelectionEnd;
         private LocaleList mLocales;
+        private String mClassifierTag = "";
 
         /** Trimmed text starting from mTrimStart in mText. */
         private CharSequence mTrimmedText;
@@ -364,9 +436,14 @@
                     mTrimmedText, mRelativeStart, mRelativeEnd, mLocales);
             mSelectionStart = Math.max(0, sel.getSelectionStartIndex() + mTrimStart);
             mSelectionEnd = Math.min(mText.length(), sel.getSelectionEndIndex() + mTrimStart);
+            mClassifierTag = sel.getSourceClassifier();
             return classifyText();
         }
 
+        String getClassifierTag() {
+            return mClassifierTag;
+        }
+
         private void trimText() {
             mTrimStart = Math.max(0, mSelectionStart - TRIM_DELTA);
             final int referenceEnd = Math.min(mText.length(), mSelectionEnd + TRIM_DELTA);
diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java
index fef85da..797cf2b 100644
--- a/core/java/com/android/internal/notification/SystemNotificationChannels.java
+++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java
@@ -40,6 +40,7 @@
     public static String UPDATES = "UPDATES";
     public static String NETWORK_STATUS = "NETWORK_STATUS";
     public static String NETWORK_ALERTS = "NETWORK_ALERTS";
+    public static String NETWORK_AVAILABLE = "NETWORK_AVAILABLE";
     public static String VPN = "VPN";
     public static String DEVICE_ADMIN = "DEVICE_ADMIN";
     public static String ALERTS = "ALERTS";
@@ -99,6 +100,11 @@
         channelsList.add(networkAlertsChannel);
 
         channelsList.add(new NotificationChannel(
+                NETWORK_AVAILABLE,
+                context.getString(R.string.notification_channel_network_available),
+                NotificationManager.IMPORTANCE_LOW));
+
+        channelsList.add(new NotificationChannel(
                 VPN,
                 context.getString(R.string.notification_channel_vpn),
                 NotificationManager.IMPORTANCE_LOW));
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index d3eb451..0d0d099 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.os;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.bluetooth.BluetoothActivityEnergyInfo;
@@ -87,6 +88,7 @@
 import java.io.PrintWriter;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Calendar;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -114,7 +116,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 156 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 157 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -149,6 +151,8 @@
 
     private final KernelUidCpuTimeReader mKernelUidCpuTimeReader = new KernelUidCpuTimeReader();
     private KernelCpuSpeedReader[] mKernelCpuSpeedReaders;
+    private final KernelUidCpuFreqTimeReader mKernelUidCpuFreqTimeReader =
+            new KernelUidCpuFreqTimeReader();
 
     private final KernelMemoryBandwidthStats mKernelMemoryBandwidthStats
             = new KernelMemoryBandwidthStats();
@@ -570,6 +574,8 @@
 
     private final NetworkStats.Entry mTmpNetworkStatsEntry = new NetworkStats.Entry();
 
+    private long[] mCpuFreqs;
+
     private PowerProfile mPowerProfile;
 
     /*
@@ -961,6 +967,131 @@
         }
     }
 
+    public static class LongSamplingCounterArray extends LongCounterArray implements TimeBaseObs {
+        final TimeBase mTimeBase;
+        long[] mCounts;
+        long[] mLoadedCounts;
+        long[] mUnpluggedCounts;
+        long[] mPluggedCounts;
+
+        LongSamplingCounterArray(TimeBase timeBase, Parcel in) {
+            mTimeBase = timeBase;
+            mPluggedCounts = in.createLongArray();
+            mCounts = copyArray(mPluggedCounts, mCounts);
+            mLoadedCounts = in.createLongArray();
+            mUnpluggedCounts = in.createLongArray();
+            timeBase.add(this);
+        }
+
+        LongSamplingCounterArray(TimeBase timeBase) {
+            mTimeBase = timeBase;
+            timeBase.add(this);
+        }
+
+        public void writeToParcel(Parcel out) {
+            out.writeLongArray(mCounts);
+            out.writeLongArray(mLoadedCounts);
+            out.writeLongArray(mUnpluggedCounts);
+        }
+
+        @Override
+        public void onTimeStarted(long elapsedRealTime, long baseUptime, long baseRealtime) {
+            mUnpluggedCounts = copyArray(mPluggedCounts, mUnpluggedCounts);
+            mCounts = copyArray(mPluggedCounts, mCounts);
+        }
+
+        @Override
+        public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
+            mPluggedCounts = copyArray(mCounts, mPluggedCounts);
+        }
+
+        @Override
+        public long[] getCountsLocked(int which) {
+            long[] val = copyArray(mTimeBase.isRunning() ? mCounts : mPluggedCounts, null);
+            if (which == STATS_SINCE_UNPLUGGED) {
+                subtract(val, mUnpluggedCounts);
+            } else if (which != STATS_SINCE_CHARGED) {
+                subtract(val, mLoadedCounts);
+            }
+            return val;
+        }
+
+        @Override
+        public void logState(Printer pw, String prefix) {
+            pw.println(prefix + "mCounts=" + Arrays.toString(mCounts)
+                    + " mLoadedCounts=" + Arrays.toString(mLoadedCounts)
+                    + " mUnpluggedCounts=" + Arrays.toString(mUnpluggedCounts)
+                    + " mPluggedCounts=" + Arrays.toString(mPluggedCounts));
+        }
+
+        void addCountLocked(long[] counts) {
+            if (counts == null) {
+                return;
+            }
+            if (mCounts == null) {
+                mCounts = new long[counts.length];
+            }
+            for (int i = 0; i < counts.length; ++i) {
+                mCounts[i] += counts[i];
+            }
+        }
+
+        /**
+         * Clear state of this counter.
+         */
+        void reset(boolean detachIfReset) {
+            fillArray(mCounts, 0);
+            fillArray(mLoadedCounts, 0);
+            fillArray(mPluggedCounts, 0);
+            fillArray(mUnpluggedCounts, 0);
+            if (detachIfReset) {
+                detach();
+            }
+        }
+
+        void detach() {
+            mTimeBase.remove(this);
+        }
+
+        void writeSummaryFromParcelLocked(Parcel out) {
+            out.writeLongArray(mCounts);
+        }
+
+        void readSummaryFromParcelLocked(Parcel in) {
+            mCounts = in.createLongArray();
+            mLoadedCounts = copyArray(mCounts, mLoadedCounts);
+            mUnpluggedCounts = copyArray(mCounts, mUnpluggedCounts);
+            mPluggedCounts = copyArray(mCounts, mPluggedCounts);
+        }
+
+        private void fillArray(long[] a, long val) {
+            if (a != null) {
+                Arrays.fill(a, val);
+            }
+        }
+
+        private void subtract(@NonNull long[] val, long[] toSubtract) {
+            if (toSubtract == null) {
+                return;
+            }
+            for (int i = 0; i < val.length; i++) {
+                val[i] -= toSubtract[i];
+            }
+        }
+
+        private long[] copyArray(long[] src, long[] dest) {
+            if (src == null) {
+                return null;
+            } else {
+                if (dest == null) {
+                    dest = new long[src.length];
+                }
+                System.arraycopy(src, 0, dest, 0, src.length);
+                return dest;
+            }
+        }
+    }
+
     public static class LongSamplingCounter extends LongCounter implements TimeBaseObs {
         final TimeBase mTimeBase;
         long mCount;
@@ -5487,6 +5618,9 @@
         LongSamplingCounter mSystemCpuTime;
         LongSamplingCounter[][] mCpuClusterSpeed;
 
+        LongSamplingCounterArray mCpuFreqTimeMs;
+        LongSamplingCounterArray mScreenOffCpuFreqTimeMs;
+
         /**
          * The statistics we have collected for this uid's wake locks.
          */
@@ -5564,6 +5698,42 @@
         }
 
         @Override
+        public long[] getCpuFreqTimes(int which) {
+            if (mCpuFreqTimeMs == null) {
+                return null;
+            }
+            final long[] cpuFreqTimes = mCpuFreqTimeMs.getCountsLocked(which);
+            if (cpuFreqTimes == null) {
+                return null;
+            }
+            // Return cpuFreqTimes only if atleast one of the elements in non-zero.
+            for (int i = 0; i < cpuFreqTimes.length; ++i) {
+                if (cpuFreqTimes[i] != 0) {
+                    return cpuFreqTimes;
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public long[] getScreenOffCpuFreqTimes(int which) {
+            if (mScreenOffCpuFreqTimeMs == null) {
+                return null;
+            }
+            final long[] cpuFreqTimes = mScreenOffCpuFreqTimeMs.getCountsLocked(which);
+            if (cpuFreqTimes == null) {
+                return null;
+            }
+            // Return cpuFreqTimes only if atleast one of the elements in non-zero.
+            for (int i = 0; i < cpuFreqTimes.length; ++i) {
+                if (cpuFreqTimes[i] != 0) {
+                    return cpuFreqTimes;
+                }
+            }
+            return null;
+        }
+
+        @Override
         public ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
             return mWakelockStats.getMap();
         }
@@ -6358,6 +6528,13 @@
                 }
             }
 
+            if (mCpuFreqTimeMs != null) {
+                mCpuFreqTimeMs.reset(false);
+            }
+            if (mScreenOffCpuFreqTimeMs != null) {
+                mScreenOffCpuFreqTimeMs.reset(false);
+            }
+
             resetLongCounterIfNotNull(mMobileRadioApWakeupCount, false);
             resetLongCounterIfNotNull(mWifiRadioApWakeupCount, false);
 
@@ -6527,6 +6704,13 @@
                     }
                 }
 
+                if (mCpuFreqTimeMs != null) {
+                    mCpuFreqTimeMs.detach();
+                }
+                if (mScreenOffCpuFreqTimeMs != null) {
+                    mScreenOffCpuFreqTimeMs.detach();
+                }
+
                 detachLongCounterIfNotNull(mMobileRadioApWakeupCount);
                 detachLongCounterIfNotNull(mWifiRadioApWakeupCount);
             }
@@ -6743,6 +6927,19 @@
                 out.writeInt(0);
             }
 
+            if (mCpuFreqTimeMs != null) {
+                out.writeInt(1);
+                mCpuFreqTimeMs.writeToParcel(out);
+            } else {
+                out.writeInt(0);
+            }
+            if (mScreenOffCpuFreqTimeMs != null) {
+                out.writeInt(1);
+                mScreenOffCpuFreqTimeMs.writeToParcel(out);
+            } else {
+                out.writeInt(0);
+            }
+
             if (mMobileRadioApWakeupCount != null) {
                 out.writeInt(1);
                 mMobileRadioApWakeupCount.writeToParcel(out);
@@ -6991,6 +7188,18 @@
             }
 
             if (in.readInt() != 0) {
+                mCpuFreqTimeMs = new LongSamplingCounterArray(mBsi.mOnBatteryTimeBase, in);
+            } else {
+                mCpuFreqTimeMs = null;
+            }
+            if (in.readInt() != 0) {
+                mScreenOffCpuFreqTimeMs = new LongSamplingCounterArray(
+                        mBsi.mOnBatteryScreenOffTimeBase, in);
+            } else {
+                mScreenOffCpuFreqTimeMs = null;
+            }
+
+            if (in.readInt() != 0) {
                 mMobileRadioApWakeupCount = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
             } else {
                 mMobileRadioApWakeupCount = null;
@@ -8196,6 +8405,10 @@
         }
     }
 
+    public long[] getCpuFreqs() {
+        return mCpuFreqs;
+    }
+
     public BatteryStatsImpl(File systemDir, Handler handler, ExternalStatsSync externalSync) {
         this(new SystemClocks(), systemDir, handler, externalSync, null);
     }
@@ -9816,6 +10029,8 @@
                     }
                 });
 
+        readKernelUidCpuFreqTimesLocked();
+
         final long elapse = (mClocks.elapsedRealtime() - startTimeMs);
         if (DEBUG_ENERGY_CPU || (elapse >= 100)) {
             Slog.d(TAG, "Reading cpu stats took " + elapse + " ms");
@@ -9904,6 +10119,30 @@
         }
     }
 
+    void readKernelUidCpuFreqTimesLocked() {
+        mKernelUidCpuFreqTimeReader.readDelta(!mOnBatteryInternal ? null :
+                new KernelUidCpuFreqTimeReader.Callback() {
+                    @Override
+                    public void onCpuFreqs(long[] cpuFreqs) {
+                        mCpuFreqs = cpuFreqs;
+                    }
+
+                    @Override
+                    public void onUidCpuFreqTime(int uid, long[] cpuFreqTimeMs) {
+                        final Uid u = getUidStatsLocked(uid);
+                        if (u.mCpuFreqTimeMs == null) {
+                            u.mCpuFreqTimeMs = new LongSamplingCounterArray(mOnBatteryTimeBase);
+                        }
+                        u.mCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs);
+                        if (u.mScreenOffCpuFreqTimeMs == null) {
+                            u.mScreenOffCpuFreqTimeMs = new LongSamplingCounterArray(
+                                    mOnBatteryScreenOffTimeBase);
+                        }
+                        u.mScreenOffCpuFreqTimeMs.addCountLocked(cpuFreqTimeMs);
+                    }
+                });
+    }
+
     boolean setChargingLocked(boolean charging) {
         if (mCharging != charging) {
             mCharging = charging;
@@ -10992,6 +11231,8 @@
             }
         }
 
+        mCpuFreqs = in.createLongArray();
+
         final int NU = in.readInt();
         if (NU > 10000) {
             throw new ParcelFormatException("File corrupt: too many uids " + NU);
@@ -11115,6 +11356,20 @@
             }
 
             if (in.readInt() != 0) {
+                u.mCpuFreqTimeMs = new LongSamplingCounterArray(mOnBatteryTimeBase);
+                u.mCpuFreqTimeMs.readSummaryFromParcelLocked(in);
+            } else {
+                u.mCpuFreqTimeMs = null;
+            }
+            if (in.readInt() != 0) {
+                u.mScreenOffCpuFreqTimeMs = new LongSamplingCounterArray(
+                        mOnBatteryScreenOffTimeBase);
+                u.mScreenOffCpuFreqTimeMs.readSummaryFromParcelLocked(in);
+            } else {
+                u.mScreenOffCpuFreqTimeMs = null;
+            }
+
+            if (in.readInt() != 0) {
                 u.mMobileRadioApWakeupCount = new LongSamplingCounter(mOnBatteryTimeBase);
                 u.mMobileRadioApWakeupCount.readSummaryFromParcelLocked(in);
             } else {
@@ -11364,6 +11619,8 @@
             }
         }
 
+        out.writeLongArray(mCpuFreqs);
+
         final int NU = mUidStats.size();
         out.writeInt(NU);
         for (int iu = 0; iu < NU; iu++) {
@@ -11508,6 +11765,19 @@
                 out.writeInt(0);
             }
 
+            if (u.mCpuFreqTimeMs != null) {
+                out.writeInt(1);
+                u.mCpuFreqTimeMs.writeSummaryFromParcelLocked(out);
+            } else {
+                out.writeInt(0);
+            }
+            if (u.mScreenOffCpuFreqTimeMs != null) {
+                out.writeInt(1);
+                u.mScreenOffCpuFreqTimeMs.writeSummaryFromParcelLocked(out);
+            } else {
+                out.writeInt(0);
+            }
+
             if (u.mMobileRadioApWakeupCount != null) {
                 out.writeInt(1);
                 u.mMobileRadioApWakeupCount.writeSummaryFromParcelLocked(out);
@@ -11798,6 +12068,8 @@
         mFlashlightTurnedOnTimers.clear();
         mCameraTurnedOnTimers.clear();
 
+        mCpuFreqs = in.createLongArray();
+
         int numUids = in.readInt();
         mUidStats.clear();
         for (int i = 0; i < numUids; i++) {
@@ -11957,6 +12229,8 @@
             }
         }
 
+        out.writeLongArray(mCpuFreqs);
+
         if (inclUids) {
             int size = mUidStats.size();
             out.writeInt(size);
diff --git a/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
new file mode 100644
index 0000000..568c883
--- /dev/null
+++ b/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import android.annotation.Nullable;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+
+/**
+ * Reads /proc/uid_time_in_state which has the format:
+ *
+ * uid: [freq1] [freq2] [freq3] ...
+ * [uid1]: [time in freq1] [time in freq2] [time in freq3] ...
+ * [uid2]: [time in freq1] [time in freq2] [time in freq3] ...
+ * ...
+ *
+ * This provides the times a UID's processes spent executing at each different cpu frequency.
+ * The file contains a monotonically increasing count of time for a single boot. This class
+ * maintains the previous results of a call to {@link #readDelta} in order to provide a proper
+ * delta.
+ */
+public class KernelUidCpuFreqTimeReader {
+    private static final String TAG = "KernelUidCpuFreqTimeReader";
+    private static final String UID_TIMES_PROC_FILE = "/proc/uid_time_in_state";
+
+    public interface Callback {
+        void onCpuFreqs(long[] cpuFreqs);
+        void onUidCpuFreqTime(int uid, long[] cpuFreqTimeMs);
+    }
+
+    private long[] mCpuFreqs;
+    private int mCpuFreqsCount;
+
+    private SparseArray<long[]> mLastUidCpuFreqTimeMs = new SparseArray<>();
+
+    public void readDelta(@Nullable Callback callback) {
+        try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) {
+            readDelta(reader, callback);
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e);
+        }
+    }
+
+    @VisibleForTesting
+    public void readDelta(BufferedReader reader, @Nullable Callback callback) throws IOException {
+        String line = reader.readLine();
+        if (line == null) {
+            return;
+        }
+        readCpuFreqs(line, callback);
+        while ((line = reader.readLine()) != null) {
+            final int index = line.indexOf(' ');
+            final int uid = Integer.parseInt(line.substring(0, index - 1), 10);
+            readTimesForUid(uid, line.substring(index + 1, line.length()), callback);
+        }
+    }
+
+    private void readTimesForUid(int uid, String line, Callback callback) {
+        long[] uidTimeMs = mLastUidCpuFreqTimeMs.get(uid);
+        if (uidTimeMs == null) {
+            uidTimeMs = new long[mCpuFreqsCount];
+            mLastUidCpuFreqTimeMs.put(uid, uidTimeMs);
+        }
+        final String[] timesStr = line.split(" ");
+        final int size = timesStr.length;
+        if (size != uidTimeMs.length) {
+            Slog.e(TAG, "No. of readings don't match cpu freqs, readings: " + size
+                    + " cpuFreqsCount: " + uidTimeMs.length);
+            return;
+        }
+        final long[] deltaUidTimeMs = new long[size];
+        for (int i = 0; i < size; ++i) {
+            // Times read will be in units of 10ms
+            final long totalTimeMs = Long.parseLong(timesStr[i], 10) * 10;
+            deltaUidTimeMs[i] = totalTimeMs - uidTimeMs[i];
+            uidTimeMs[i] = totalTimeMs;
+        }
+        if (callback != null) {
+            callback.onUidCpuFreqTime(uid, deltaUidTimeMs);
+        }
+    }
+
+    private void readCpuFreqs(String line, Callback callback) {
+        if (mCpuFreqs == null) {
+            final String[] freqStr = line.split(" ");
+            // First item would be "uid:" which needs to be ignored
+            mCpuFreqsCount = freqStr.length - 1;
+            mCpuFreqs = new long[mCpuFreqsCount];
+            for (int i = 0; i < mCpuFreqsCount; ++i) {
+                mCpuFreqs[i] = Long.parseLong(freqStr[i + 1], 10);
+            }
+        }
+        if (callback != null) {
+            callback.onCpuFreqs(mCpuFreqs);
+        }
+    }
+}
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index ea40fd5..8b73daf 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -503,6 +503,7 @@
     SettingProto demo_user_setup_complete = 165;
     SettingProto instant_apps_enabled = 166;
     SettingProto device_paired = 167;
+    SettingProto notification_badging = 168;
 }
 
 message SystemSettingsProto {
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b7e8467..6640102 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1013,6 +1013,9 @@
     <!-- Is the notification LED intrusive? Used to decide if there should be a disable option -->
     <bool name="config_intrusiveNotificationLed">false</bool>
 
+    <!-- De we do icon badges? Used to decide if there should be a disable option-->
+    <bool name="config_notificationBadging">true</bool>
+
     <!-- Default value for LED off time when the battery is low on charge in miliseconds -->
     <integer name="config_notificationsBatteryLedOff">2875</integer>
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index cb1851b..98356a2 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -629,6 +629,9 @@
     <!-- Text shown when viewing channel settings for notifications related to network alerts -->
     <string name="notification_channel_network_alerts">Network alerts</string>
 
+    <!-- Text shown when viewing the channel settings for notification about open nearby wireless networks. -->
+    <string name="notification_channel_network_available">Network available</string>
+
     <!-- Text shown when viewing channel settings for notifications related to vpn status -->
     <string name="notification_channel_vpn">VPN status</string>
 
@@ -2993,6 +2996,17 @@
     <!-- If there is ever a ringtone set for some setting, but that ringtone can no longer be resolved, t his is shown instead.  For example, if the ringtone was on a SD card and it had been removed, this woudl be shown for ringtones on that SD card. -->
     <string name="ringtone_unknown">Unknown</string>
 
+    <!-- A notification is shown when there are open wireless networks nearby.  This is the notification's title. -->
+    <plurals name="wifi_available">
+        <item quantity="one">Wi-Fi network available</item>
+        <item quantity="other">Wi-Fi networks available</item>
+    </plurals>
+    <!-- A notification is shown when there are open wireless networks nearby.  This is the notification's message. -->
+    <plurals name="wifi_available_detailed">
+        <item quantity="one">Open Wi-Fi network available</item>
+        <item quantity="other">Open Wi-Fi networks available</item>
+    </plurals>
+
     <!-- A notification is shown when a wifi captive portal network is detected.  This is the notification's title. -->
     <string name="wifi_available_sign_in">Sign in to Wi-Fi network</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 31d13c9..74779f3 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1861,6 +1861,8 @@
   <java-symbol type="layout" name="safe_mode" />
   <java-symbol type="layout" name="simple_list_item_2_single_choice" />
   <java-symbol type="layout" name="app_error_dialog" />
+  <java-symbol type="plurals" name="wifi_available" />
+  <java-symbol type="plurals" name="wifi_available_detailed" />
   <java-symbol type="string" name="accessibility_binding_label" />
   <java-symbol type="string" name="adb_active_notification_message" />
   <java-symbol type="string" name="adb_active_notification_title" />
@@ -2087,6 +2089,7 @@
   <java-symbol type="string" name="config_wifi_tether_enable" />
   <java-symbol type="integer" name="config_wifi_wakeup_available" />
   <java-symbol type="bool" name="config_intrusiveNotificationLed" />
+  <java-symbol type="bool" name="config_notificationBadging" />
   <java-symbol type="dimen" name="preference_fragment_padding_bottom" />
   <java-symbol type="dimen" name="preference_fragment_padding_side" />
   <java-symbol type="drawable" name="expander_ic_maximized" />
@@ -2969,6 +2972,7 @@
   <java-symbol type="string" name="notification_channel_updates" />
   <java-symbol type="string" name="notification_channel_network_status" />
   <java-symbol type="string" name="notification_channel_network_alerts" />
+  <java-symbol type="string" name="notification_channel_network_available" />
   <java-symbol type="string" name="notification_channel_vpn" />
   <java-symbol type="string" name="notification_channel_device_admin" />
   <java-symbol type="string" name="notification_channel_alerts" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index ee2f1ca..54d5285 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -37,8 +37,6 @@
 
 /** Tests that ensure appropriate settings are backed up. */
 @RunWith(AndroidJUnit4.class)
-// TODO(b/37684646): Can re-enable pre-submit once test is fixed.
-//@Presubmit
 @SmallTest
 public class SettingsBackupTest {
 
@@ -167,6 +165,7 @@
                     Settings.Global.DEVICE_IDLE_CONSTANTS_WATCH,
                     Settings.Global.BATTERY_SAVER_CONSTANTS,
                     Settings.Global.DEVICE_NAME,
+                    Settings.Global.DEVICE_POLICY_CONSTANTS,
                     Settings.Global.DEVICE_PROVISIONED,
                     Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED,
                     Settings.Global.DISK_FREE_CHANGE_REPORTING_THRESHOLD,
@@ -379,6 +378,7 @@
                     Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
                     Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED,
                     Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED,
+                    Settings.Global.WIFI_WAKEUP_AVAILABLE,
                     Settings.Global.WIFI_WATCHDOG_ON,
                     Settings.Global.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON,
                     Settings.Global.WINDOW_ANIMATION_SCALE,
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java
new file mode 100644
index 0000000..ad8221b
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.BufferedReader;
+
+/**
+ * Test class for {@link KernelUidCpuFreqTimeReader}.
+ *
+ * To run the tests, use
+ *
+ * runtest -c com.android.internal.os.KernelUidCpuFreqTimeReaderTest frameworks-core
+ *
+ * or the following steps:
+ *
+ * Build: m FrameworksCoreTests
+ * Install: adb install -r \
+ *     ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
+ * Run: adb shell am instrument -e class com.android.internal.os.KernelUidCpuFreqTimeReaderTest -w \
+ *     com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KernelUidCpuFreqTimeReaderTest {
+    @Mock private BufferedReader mBufferedReader;
+    @Mock private KernelUidCpuFreqTimeReader.Callback mCallback;
+
+    private KernelUidCpuFreqTimeReader mKernelUidCpuFreqTimeReader;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mKernelUidCpuFreqTimeReader = new KernelUidCpuFreqTimeReader();
+    }
+
+    @Test
+    public void testReadDelta() throws Exception {
+        final long[] freqs = {1, 12, 123, 1234, 12345, 123456};
+        final int[] uids = {1, 22, 333, 4444, 5555};
+        final long[][] times = new long[uids.length][freqs.length];
+        for (int i = 0; i < uids.length; ++i) {
+            for (int j = 0; j < freqs.length; ++j) {
+                times[i][j] = uids[i] * freqs[j] * 10;
+            }
+        }
+        final String[] uidsTimesLines = getUidTimesLines(uids, times);
+        final String[] lines = new String[uidsTimesLines.length + 1];
+        System.arraycopy(uidsTimesLines, 0, lines, 0, uidsTimesLines.length);
+        lines[uidsTimesLines.length] = null;
+        when(mBufferedReader.readLine())
+                .thenReturn(getFreqsLine(freqs), lines);
+        mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback);
+        verify(mCallback).onCpuFreqs(freqs);
+        for (int i = 0; i < uids.length; ++i) {
+            verify(mCallback).onUidCpuFreqTime(uids[i], times[i]);
+        }
+        verifyNoMoreInteractions(mCallback);
+    }
+
+    private String getFreqsLine(long[] freqs) {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("uid:");
+        for (int i = 0; i < freqs.length; ++i) {
+            sb.append(" " + freqs[i]);
+        }
+        return sb.toString();
+    }
+
+    private String[] getUidTimesLines(int[] uids, long[][] times) {
+        final String[] lines = new String[uids.length];
+        final StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < uids.length; ++i) {
+            sb.setLength(0);
+            sb.append(uids[i] + ":");
+            for (int j = 0; j < times[i].length; ++j) {
+                sb.append(" " + times[i][j] / 10);
+            }
+            lines[i] = sb.toString();
+        }
+        return lines;
+    }
+}
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 40d36aa..d586db4 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -1879,15 +1879,22 @@
     }
 
     /**
-     * Rebuilds any caches associated with the bitmap that are used for
-     * drawing it. In the case of purgeable bitmaps, this call will attempt to
-     * ensure that the pixels have been decoded.
-     * If this is called on more than one bitmap in sequence, the priority is
-     * given in LRU order (i.e. the last bitmap called will be given highest
-     * priority).
+     * Builds caches associated with the bitmap that are used for drawing it.
      *
-     * For bitmaps with no associated caches, this call is effectively a no-op,
-     * and therefore is harmless.
+     * <p>Starting in {@link android.os.Build.VERSION_CODES#N}, this call initiates an asynchronous
+     * upload to the GPU on RenderThread, if the Bitmap is not already uploaded. With Hardware
+     * Acceleration, Bitmaps must be uploaded to the GPU in order to be rendered. This is done by
+     * default the first time a Bitmap is drawn, but the process can take several milliseconds,
+     * depending on the size of the Bitmap. Each time a Bitmap is modified and drawn again, it must
+     * be re-uploaded.</p>
+     *
+     * <p>Calling this method in advance can save time in the first frame it's used. For example, it
+     * is recommended to call this on an image decoding worker thread when a decoded Bitmap is about
+     * to be displayed. It is recommended to make any pre-draw modifications to the Bitmap before
+     * calling this method, so the cached, uploaded copy may be reused without re-uploading.</p>
+     *
+     * In {@link android.os.Build.VERSION_CODES#KITKAT} and below, for purgeable bitmaps, this call
+     * would attempt to ensure that the pixels have been decoded.
      */
     public void prepareToDraw() {
         checkRecycled("Can't prepareToDraw on a recycled bitmap!");
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index d1d59b2..1e171d3 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -62,11 +62,12 @@
      */
     private static final ArraySet<String> sBroadcastOnRestore;
     static {
-        sBroadcastOnRestore = new ArraySet<String>(4);
+        sBroadcastOnRestore = new ArraySet<String>(5);
         sBroadcastOnRestore.add(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
         sBroadcastOnRestore.add(Settings.Secure.ENABLED_VR_LISTENERS);
         sBroadcastOnRestore.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
         sBroadcastOnRestore.add(Settings.Secure.ENABLED_INPUT_METHODS);
+        sBroadcastOnRestore.add(Settings.Global.BLUETOOTH_ON);
     }
 
     private interface SettingsLookup {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index f475361..9309359 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1434,6 +1434,9 @@
         dumpSetting(s, p,
                 Settings.Secure.DEVICE_PAIRED,
                 SecureSettingsProto.DEVICE_PAIRED);
+        dumpSetting(s, p,
+                Settings.Secure.NOTIFICATION_BADGING,
+                SecureSettingsProto.NOTIFICATION_BADGING);
     }
 
     private static void dumpProtoSystemSettingsLocked(
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 290ce1f..5460304 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -58,6 +58,7 @@
     <uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG" />
     <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
     <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+    <uses-permission android:name="android.permission.NETWORK_SETTINGS" />
     <uses-permission android:name="android.permission.TETHER_PRIVILEGED" />
     <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
     <uses-permission android:name="android.permission.REQUEST_NETWORK_SCORES" />
@@ -300,7 +301,6 @@
                   android:excludeFromRecents="true"
                   android:stateNotNeeded="true"
                   android:resumeWhilePausing="true"
-                  android:screenOrientation="behind"
                   android:resizeableActivity="true"
                   android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden"
                   android:theme="@style/RecentsTheme.Wallpaper">
diff --git a/packages/SystemUI/res/drawable/qs_background_primary.xml b/packages/SystemUI/res/drawable/qs_background_primary.xml
index 0bdbc5f..8ea9e06 100644
--- a/packages/SystemUI/res/drawable/qs_background_primary.xml
+++ b/packages/SystemUI/res/drawable/qs_background_primary.xml
@@ -15,6 +15,6 @@
 -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android">
     <shape>
-        <solid android:color="?android:attr/colorPrimaryDark"/>
+        <solid android:color="?android:attr/colorPrimary"/>
     </shape>
 </inset>
diff --git a/packages/SystemUI/res/layout/qs_customize_panel.xml b/packages/SystemUI/res/layout/qs_customize_panel.xml
index 9ab8ac6..cbc2575 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel.xml
@@ -21,6 +21,7 @@
     android:layout_width="match_parent"
     android:layout_height="0dp"
     android:orientation="vertical"
+    android:elevation="4dp"
     android:background="@drawable/qs_customizer_background"
     android:gravity="center_horizontal">
 
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
index 1c087b3..f41c494 100644
--- a/packages/SystemUI/res/layout/qs_detail.xml
+++ b/packages/SystemUI/res/layout/qs_detail.xml
@@ -20,6 +20,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="@drawable/qs_detail_background"
+    android:elevation="4dp"
     android:clickable="true"
     android:orientation="vertical"
     android:paddingBottom="8dp"
diff --git a/packages/SystemUI/res/layout/qs_footer.xml b/packages/SystemUI/res/layout/qs_footer.xml
index 047f7aa..c92c811 100644
--- a/packages/SystemUI/res/layout/qs_footer.xml
+++ b/packages/SystemUI/res/layout/qs_footer.xml
@@ -21,6 +21,7 @@
     android:id="@+id/header"
     android:layout_width="match_parent"
     android:layout_height="48dp"
+    android:elevation="4dp"
     android:baselineAligned="false"
     android:clickable="false"
     android:clipChildren="false"
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 3658313..fb47bbc 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -14,22 +14,28 @@
      limitations under the License.
 -->
 <com.android.systemui.qs.QSContainerImpl
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:id="@+id/quick_settings_container"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/quick_settings_container"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="?android:attr/colorPrimaryDark"
+    android:clipToPadding="false"
+    android:clipChildren="false">
+
+    <View
+        android:id="@+id/qs_background"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
+        android:layout_height="match_parent"
         android:background="@drawable/qs_background_primary"
-        android:clipToPadding="false"
-        android:clipChildren="false"
-        android:elevation="4dp">
+        android:elevation="4dp" />
 
     <com.android.systemui.qs.QSPanel
-            android:id="@+id/quick_settings_panel"
-            android:background="#0000"
-            android:layout_marginTop="28dp"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginBottom="48dp" />
+        android:id="@+id/quick_settings_panel"
+        android:layout_marginTop="28dp"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:elevation="4dp"
+        android:layout_marginBottom="48dp" />
 
     <include layout="@layout/quick_status_bar_expanded_header" />
 
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index 520dab4..65344b7 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -24,6 +24,7 @@
     android:layout_height="@dimen/status_bar_header_height"
     android:layout_gravity="@integer/notification_panel_layout_gravity"
     android:baselineAligned="false"
+    android:elevation="4dp"
     android:clickable="false"
     android:clipChildren="false"
     android:clipToPadding="false"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 63abee7..c00b562 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -775,4 +775,6 @@
 
     <dimen name="signal_icon_size">17dp</dimen>
 
+    <dimen name="qs_gutter_height">6dp</dimen>
+
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 88e8b39..2504e36 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -675,9 +675,14 @@
         mLockPatternUtils = new LockPatternUtils(mContext);
         KeyguardUpdateMonitor.setCurrentUser(ActivityManager.getCurrentUser());
 
-        // Assume keyguard is showing (unless it's disabled) until we know for sure...
-        setShowingLocked(!shouldWaitForProvisioning() && !mLockPatternUtils.isLockScreenDisabled(
-                KeyguardUpdateMonitor.getCurrentUser()), true /* forceCallbacks */);
+        // Assume keyguard is showing (unless it's disabled) until we know for sure, unless Keyguard
+        // is disabled.
+        if (mContext.getResources().getBoolean(
+                com.android.keyguard.R.bool.config_enableKeyguardService)) {
+            setShowingLocked(!shouldWaitForProvisioning()
+                    && !mLockPatternUtils.isLockScreenDisabled(
+                            KeyguardUpdateMonitor.getCurrentUser()), true /* forceCallbacks */);
+        }
 
         mStatusBarKeyguardViewManager =
                 SystemUIFactory.getInstance().createStatusBarKeyguardViewManager(mContext,
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index bdc0871..da2d38f 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -73,7 +73,8 @@
             mTouchHandler.onActivityPinned();
             mMediaController.onActivityPinned();
             mMenuController.onActivityPinned();
-            mNotificationController.onActivityPinned(packageName);
+            mNotificationController.onActivityPinned(packageName,
+                    true /* deferUntilAnimationEnds */);
 
             SystemServicesProxy.getInstance(mContext).setPipVisibility(true);
         }
@@ -104,6 +105,7 @@
             mTouchHandler.setTouchEnabled(true);
             mTouchHandler.onPinnedStackAnimationEnded();
             mMenuController.onPinnedStackAnimationEnded();
+            mNotificationController.onPinnedStackAnimationEnded();
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java
index 53746e2..696fdbc 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java
@@ -60,6 +60,9 @@
 
     private PipMotionHelper mMotionHelper;
 
+    // Used when building a deferred notification
+    private String mDeferredNotificationPackageName;
+
     private AppOpsManager.OnOpChangedListener mAppOpsChangedListener = new OnOpChangedListener() {
         @Override
         public void onOpChanged(String op, String packageName) {
@@ -87,10 +90,47 @@
         mMotionHelper = motionHelper;
     }
 
-    public void onActivityPinned(String packageName) {
+    public void onActivityPinned(String packageName, boolean deferUntilAnimationEnds) {
         // Clear any existing notification
         mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID);
 
+        if (deferUntilAnimationEnds) {
+            mDeferredNotificationPackageName = packageName;
+        } else {
+            showNotificationForApp(mDeferredNotificationPackageName);
+        }
+
+        // Register for changes to the app ops setting for this package while it is in PiP
+        registerAppOpsListener(packageName);
+    }
+
+    public void onPinnedStackAnimationEnded() {
+        if (mDeferredNotificationPackageName != null) {
+            showNotificationForApp(mDeferredNotificationPackageName);
+            mDeferredNotificationPackageName = null;
+        }
+    }
+
+    public void onActivityUnpinned(ComponentName topPipActivity) {
+        // Unregister for changes to the previously PiP'ed package
+        unregisterAppOpsListener();
+
+        // Reset the deferred notification package
+        mDeferredNotificationPackageName = null;
+
+        if (topPipActivity != null) {
+            // onActivityUnpinned() is only called after the transition is complete, so we don't
+            // need to defer until the animation ends to update the notification
+            onActivityPinned(topPipActivity.getPackageName(), false /* deferUntilAnimationEnds */);
+        } else {
+            mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID);
+        }
+    }
+
+    /**
+     * Builds and shows the notification for the given app.
+     */
+    private void showNotificationForApp(String packageName) {
         // Build a new notification
         final Notification.Builder builder =
                 new Notification.Builder(mContext, NotificationChannels.GENERAL)
@@ -105,20 +145,6 @@
             // Show the new notification
             mNotificationManager.notify(NOTIFICATION_TAG, NOTIFICATION_ID, builder.build());
         }
-
-        // Register for changes to the app ops setting for this package while it is in PiP
-        registerAppOpsListener(packageName);
-    }
-
-    public void onActivityUnpinned(ComponentName topPipActivity) {
-        // Unregister for changes to the previously PiP'ed package
-        unregisterAppOpsListener();
-
-        if (topPipActivity != null) {
-            onActivityPinned(topPipActivity.getPackageName());
-        } else {
-            mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID);
-        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
index 727eb5a..5b54d85 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
@@ -44,6 +44,7 @@
  */
 public class PipNotification {
     private static final String TAG = "PipNotification";
+    private static final String NOTIFICATION_TAG = PipNotification.class.getName();
     private static final boolean DEBUG = PipManager.DEBUG;
 
     private static final String ACTION_MENU = "PipNotification.menu";
@@ -56,7 +57,7 @@
 
     private MediaController mMediaController;
     private String mDefaultTitle;
-    private Icon mDefaultIcon;
+    private int mDefaultIconResId;
 
     private boolean mNotified;
     private String mTitle;
@@ -167,9 +168,8 @@
     void onConfigurationChanged(Context context) {
         Resources res = context.getResources();
         mDefaultTitle = res.getString(R.string.pip_notification_unknown_title);
-        mDefaultIcon = Icon.createWithResource(context,
-                res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_LTR
-                        ? R.drawable.pip_expand_ll : R.drawable.pip_expand_lr);
+        mDefaultIconResId = res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_LTR
+                        ? R.drawable.pip_expand_ll : R.drawable.pip_expand_lr;
         if (mNotified) {
             // update notification
             notifyPipNotification();
@@ -181,12 +181,16 @@
         mNotificationBuilder
                 .setShowWhen(true)
                 .setWhen(System.currentTimeMillis())
-                // TODO: Sending bitmap doesn't work in launcher side. Once launcher supports it,
-                // we can set icon.
-                //.setSmallIcon(mArt != null ? Icon.createWithBitmap(mArt) : mDefaultIcon)
-                .setSmallIcon(mDefaultIcon.getResId())
+                .setSmallIcon(mDefaultIconResId)
                 .setContentTitle(!TextUtils.isEmpty(mTitle) ? mTitle : mDefaultTitle);
-        mNotificationManager.notify(SystemMessage.NOTE_TV_PIP, mNotificationBuilder.build());
+        if (mArt != null) {
+            mNotificationBuilder.setStyle(new Notification.BigPictureStyle()
+                    .bigPicture(mArt));
+        } else {
+            mNotificationBuilder.setStyle(null);
+        }
+        mNotificationManager.notify(NOTIFICATION_TAG, SystemMessage.NOTE_TV_PIP,
+                mNotificationBuilder.build());
     }
 
     private void dismissPipNotification() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 06264ba..189c04c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -17,11 +17,14 @@
 package com.android.systemui.qs;
 
 import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
 import android.graphics.Point;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.FrameLayout;
 
+import com.android.settingslib.Utils;
 import com.android.systemui.R;
 import com.android.systemui.qs.customize.QSCustomizer;
 
@@ -39,6 +42,8 @@
     protected float mQsExpansion;
     private QSCustomizer mQSCustomizer;
     private QSFooter mQSFooter;
+    private int mGutterHeight;
+    private View mBackground;
 
     public QSContainerImpl(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -52,6 +57,8 @@
         mHeader = findViewById(R.id.header);
         mQSCustomizer = findViewById(R.id.qs_customize);
         mQSFooter = findViewById(R.id.qs_footer);
+        mBackground = findViewById(R.id.qs_background);
+        mGutterHeight = getContext().getResources().getDimensionPixelSize(R.dimen.qs_gutter_height);
     }
 
     @Override
@@ -94,8 +101,9 @@
 
     public void updateBottom() {
         int height = calculateContainerHeight();
-        setBottom(getTop() + height);
+        setBottom(getTop() + height + mGutterHeight);
         mQSDetail.setBottom(getTop() + height);
+        mBackground.setBottom(mQSDetail.getBottom());
         // Pin QS Footer to the bottom of the panel.
         mQSFooter.setTranslationY(height - mQSFooter.getHeight());
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 406f107..5cf049a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -32,6 +32,7 @@
 
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.R.id;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.qs.customize.QSCustomizer;
 import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
@@ -61,6 +62,7 @@
     private QSContainerImpl mContainer;
     private int mLayoutDirection;
     private QSFooter mFooter;
+    private int mGutterHeight;
 
     @Override
     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@@ -75,7 +77,8 @@
         mQSDetail = view.findViewById(R.id.qs_detail);
         mHeader = view.findViewById(R.id.header);
         mFooter = view.findViewById(R.id.qs_footer);
-        mContainer = (QSContainerImpl) view;
+        mContainer = view.findViewById(id.quick_settings_container);
+        mGutterHeight = getContext().getResources().getDimensionPixelSize(R.dimen.qs_gutter_height);
 
         mQSDetail.setQsPanel(mQSPanel, mHeader);
 
@@ -239,7 +242,8 @@
         mContainer.setExpansion(expansion);
         final float translationScaleY = expansion - 1;
         if (!mHeaderAnimating) {
-            getView().setTranslationY(mKeyguardShowing ? (translationScaleY * mHeader.getHeight())
+            int height = mHeader.getHeight() + mGutterHeight;
+            getView().setTranslationY(mKeyguardShowing ? (translationScaleY * height)
                     : headerTranslation);
         }
         mHeader.setExpansion(mKeyguardShowing ? 1 : expansion);
@@ -321,19 +325,19 @@
             LayoutParams layoutParams = (LayoutParams) mQSPanel.getLayoutParams();
             int panelHeight = layoutParams.topMargin + layoutParams.bottomMargin +
                     + mQSPanel.getMeasuredHeight();
-            return panelHeight + getView().getPaddingBottom();
+            return panelHeight + getView().getPaddingBottom() + mGutterHeight;
         } else {
-            return getView().getMeasuredHeight();
+            return getView().getMeasuredHeight() + mGutterHeight;
         }
     }
 
     @Override
     public void setHeightOverride(int desiredHeight) {
-        mContainer.setHeightOverride(desiredHeight);
+        mContainer.setHeightOverride(desiredHeight - mGutterHeight);
     }
 
     public int getQsMinExpansionHeight() {
-        return mHeader.getHeight();
+        return mHeader.getHeight() + mGutterHeight;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 32af230..d12b16b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -340,10 +340,9 @@
         switch (state) {
             case Tile.STATE_UNAVAILABLE:
                 return Utils.getDisabled(context,
-                        Utils.getColorAttr(context, android.R.attr.textColorPrimary));
-            case Tile.STATE_INACTIVE:
-                return Utils.getDisabled(context,
                         Utils.getColorAttr(context, android.R.attr.colorForeground));
+            case Tile.STATE_INACTIVE:
+                return Utils.getColorAttr(context, android.R.attr.textColorHint);
             case Tile.STATE_ACTIVE:
                 return Utils.getColorAttr(context, android.R.attr.textColorPrimary);
             default:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index f5718d9..bae6a27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -23,6 +23,7 @@
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.RectF;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
@@ -177,6 +178,7 @@
      * Similar to mDimmed but is also true if it's not dimmable but should be
      */
     private boolean mNeedsDimming;
+    private int mDimmedAlpha;
 
     public ActivatableNotificationView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -214,6 +216,8 @@
         mBackgroundDimmed = findViewById(R.id.backgroundDimmed);
         mBackgroundNormal.setCustomBackground(R.drawable.notification_material_bg);
         mBackgroundDimmed.setCustomBackground(R.drawable.notification_material_bg_dim);
+        mDimmedAlpha = Color.alpha(mContext.getColor(
+                R.color.notification_material_background_dimmed_color));
         updateBackground();
         updateBackgroundTint();
         updateOutlineAlpha();
@@ -492,10 +496,21 @@
      *                       used and the background color not at all.
      */
     public void setOverrideTintColor(int color, float overrideAmount) {
+        if (mDark) {
+            color = NO_COLOR;
+            overrideAmount = 0;
+        }
         mOverrideTint = color;
         mOverrideAmount = overrideAmount;
         int newColor = calculateBgColor();
         setBackgroundTintColor(newColor);
+        if (!isDimmable() && mNeedsDimming) {
+           mBackgroundNormal.setDrawableAlpha((int) NotificationUtils.interpolate(255,
+                   mDimmedAlpha,
+                   overrideAmount));
+        } else {
+            mBackgroundNormal.setDrawableAlpha(255);
+        }
     }
 
     protected void updateBackgroundTint() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 30ff30f..be221bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -341,14 +341,12 @@
 
     public void appTransitionPending(boolean forced) {
         synchronized (mLock) {
-            mHandler.removeMessages(MSG_APP_TRANSITION_PENDING);
             mHandler.obtainMessage(MSG_APP_TRANSITION_PENDING, forced ? 1 : 0, 0).sendToTarget();
         }
     }
 
     public void appTransitionCancelled() {
         synchronized (mLock) {
-            mHandler.removeMessages(MSG_APP_TRANSITION_CANCELLED);
             mHandler.sendEmptyMessage(MSG_APP_TRANSITION_CANCELLED);
         }
     }
@@ -359,7 +357,6 @@
 
     public void appTransitionStarting(long startTime, long duration, boolean forced) {
         synchronized (mLock) {
-            mHandler.removeMessages(MSG_APP_TRANSITION_STARTING);
             mHandler.obtainMessage(MSG_APP_TRANSITION_STARTING, forced ? 1 : 0, 0,
                     Pair.create(startTime, duration)).sendToTarget();
         }
@@ -368,7 +365,6 @@
     @Override
     public void appTransitionFinished() {
         synchronized (mLock) {
-            mHandler.removeMessages(MSG_APP_TRANSITION_FINISHED);
             mHandler.sendEmptyMessage(MSG_APP_TRANSITION_FINISHED);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
index dea9e31f..194cdc7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
@@ -144,4 +144,8 @@
             ripple.setColor(ColorStateList.valueOf(color));
         }
     }
+
+    public void setDrawableAlpha(int drawableAlpha) {
+        mBackground.setAlpha(drawableAlpha);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index f2595e9..78a5194 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -202,7 +202,7 @@
         //  find the first view that doesn't overlap with the shelf
         int notificationIndex = 0;
         int notGoneIndex = 0;
-        int colorOfViewBeforeLast = 0;
+        int colorOfViewBeforeLast = NO_COLOR;
         boolean backgroundForceHidden = false;
         if (mHideBackground && !mShelfState.hasItemsInStableShelf) {
             backgroundForceHidden = true;
@@ -256,7 +256,10 @@
                 colorTwoBefore = previousColor;
                 transitionAmount = inShelfAmount;
             }
-            if (isLastChild && colorOfViewBeforeLast != NO_COLOR) {
+            if (isLastChild) {
+                if (colorOfViewBeforeLast == NO_COLOR) {
+                    colorOfViewBeforeLast = ownColorUntinted;
+                }
                 row.setOverrideTintColor(colorOfViewBeforeLast, inShelfAmount);
             } else {
                 colorOfViewBeforeLast = ownColorUntinted;
@@ -310,8 +313,9 @@
         float fullTransitionAmount;
         float iconTransitionAmount;
         float shelfStart = getTranslationY();
-        if (viewEnd >= shelfStart && (mAmbientState.isShadeExpanded()
-                || (!row.isPinned() && !row.isHeadsUpAnimatingAway()))) {
+        if (viewEnd >= shelfStart && (!mAmbientState.isUnlockHintRunning() || row.isInShelf())
+                && (mAmbientState.isShadeExpanded()
+                        || (!row.isPinned() && !row.isHeadsUpAnimatingAway()))) {
             if (viewStart < shelfStart) {
 
                 float fullAmount = (shelfStart - viewStart) / fullHeight;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
index 52c053f..f6bd14c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
@@ -23,6 +23,7 @@
 import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
+import android.support.annotation.VisibleForTesting;
 import android.support.v4.graphics.ColorUtils;
 import android.support.v7.graphics.Palette;
 import android.util.LayoutDirection;
@@ -57,9 +58,15 @@
     private boolean mIsLowPriority;
 
     public MediaNotificationProcessor(Context context, Context packageContext) {
+        this(context, packageContext, new ImageGradientColorizer());
+    }
+
+    @VisibleForTesting
+    MediaNotificationProcessor(Context context, Context packageContext,
+            ImageGradientColorizer colorizer) {
         mContext = context;
         mPackageContext = packageContext;
-        mColorizer = new ImageGradientColorizer();
+        mColorizer = colorizer;
     }
 
     /**
@@ -74,6 +81,9 @@
         Bitmap bitmap = null;
         Drawable drawable = null;
         if (largeIcon != null) {
+            // We're transforming the builder, let's make sure all baked in RemoteViews are
+            // rebuilt!
+            builder.setRebuildStyledRemoteViews(true);
             drawable = largeIcon.loadDrawable(mPackageContext);
             int backgroundColor = 0;
             if (notification.isColorizedMedia()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 6a9bfae..0fa8afa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -1985,6 +1985,18 @@
     }
 
     @Override
+    protected void onUnlockHintFinished() {
+        super.onUnlockHintFinished();
+        mNotificationStackScroller.setUnlockHintRunning(false);
+    }
+
+    @Override
+    protected void onUnlockHintStarted() {
+        super.onUnlockHintStarted();
+        mNotificationStackScroller.setUnlockHintRunning(true);
+    }
+
+    @Override
     public KeyguardAffordanceView getLeftIcon() {
         return getLayoutDirection() == LAYOUT_DIRECTION_RTL
                 ? mKeyguardBottomArea.getRightView()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index d342635..e378e871 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -35,7 +35,6 @@
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.DejankUtils;
-import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.Interpolators;
 import com.android.keyguard.LatencyTracker;
@@ -1020,14 +1019,22 @@
             @Override
             public void run() {
                 notifyExpandingFinished();
-                mStatusBar.onHintFinished();
+                onUnlockHintFinished();
                 mHintAnimationRunning = false;
             }
         });
-        mStatusBar.onUnlockHintStarted();
+        onUnlockHintStarted();
         mHintAnimationRunning = true;
     }
 
+    protected void onUnlockHintFinished() {
+        mStatusBar.onHintFinished();
+    }
+
+    protected void onUnlockHintStarted() {
+        mStatusBar.onUnlockHintStarted();
+    }
+
     /**
      * Phase 1: Move everything upwards.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index b2b23a55..e409b9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -60,6 +60,7 @@
     private boolean mExpansionChanging;
     private boolean mPanelFullWidth;
     private boolean mPulsing;
+    private boolean mUnlockHintRunning;
 
     public AmbientState(Context context) {
         reload(context);
@@ -305,4 +306,12 @@
     public void setPanelFullWidth(boolean panelFullWidth) {
         mPanelFullWidth = panelFullWidth;
     }
+
+    public void setUnlockHintRunning(boolean unlockHintRunning) {
+        mUnlockHintRunning = unlockHintRunning;
+    }
+
+    public boolean isUnlockHintRunning() {
+        return mUnlockHintRunning;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 2f7a4ed..61fed2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -4230,6 +4230,10 @@
         mAmbientState.setPanelFullWidth(isFullWidth);
     }
 
+    public void setUnlockHintRunning(boolean running) {
+        mAmbientState.setUnlockHintRunning(running);
+    }
+
     /**
      * A listener that is notified when some child locations might have changed.
      */
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/MediaNotificationProcessorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/MediaNotificationProcessorTest.java
new file mode 100644
index 0000000..5d3a86d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/MediaNotificationProcessorTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import static org.junit.Assert.assertNotSame;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.app.Notification;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.widget.RemoteViews;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MediaNotificationProcessorTest extends SysuiTestCase {
+
+    private MediaNotificationProcessor mProcessor;
+    private Bitmap mBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+    private ImageGradientColorizer mColorizer;
+
+    @Before
+    public void setUp() {
+        mColorizer = spy(new TestableColorizer(mBitmap));
+        mProcessor = new MediaNotificationProcessor(getContext(), getContext(), mColorizer);
+    }
+
+    @Test
+    public void testColorizedWithLargeIcon() {
+        Notification.Builder builder = new Notification.Builder(getContext()).setSmallIcon(
+                R.drawable.ic_person)
+                .setContentTitle("Title")
+                .setLargeIcon(mBitmap)
+                .setContentText("Text");
+        Notification notification = builder.build();
+        mProcessor.processNotification(notification, builder);
+        verify(mColorizer).colorize(any(), anyInt(), anyBoolean());
+    }
+
+    @Test
+    public void testNotColorizedWithoutLargeIcon() {
+        Notification.Builder builder = new Notification.Builder(getContext()).setSmallIcon(
+                R.drawable.ic_person)
+                .setContentTitle("Title")
+                .setContentText("Text");
+        Notification notification = builder.build();
+        mProcessor.processNotification(notification, builder);
+        verifyZeroInteractions(mColorizer);
+    }
+
+    @Test
+    public void testRemoteViewsReset() {
+        Notification.Builder builder = new Notification.Builder(getContext()).setSmallIcon(
+                R.drawable.ic_person)
+                .setContentTitle("Title")
+                .setStyle(new Notification.MediaStyle())
+                .setLargeIcon(mBitmap)
+                .setContentText("Text");
+        Notification notification = builder.build();
+        RemoteViews remoteViews = new RemoteViews(getContext().getPackageName(),
+                R.layout.custom_view_dark);
+        notification.contentView = remoteViews;
+        notification.bigContentView = remoteViews;
+        notification.headsUpContentView = remoteViews;
+        mProcessor.processNotification(notification, builder);
+        verify(mColorizer).colorize(any(), anyInt(), anyBoolean());
+        RemoteViews contentView = builder.createContentView();
+        assertNotSame(contentView, remoteViews);
+        contentView = builder.createBigContentView();
+        assertNotSame(contentView, remoteViews);
+        contentView = builder.createHeadsUpContentView();
+        assertNotSame(contentView, remoteViews);
+    }
+
+    public static class TestableColorizer extends ImageGradientColorizer {
+        private final Bitmap mBitmap;
+
+        private TestableColorizer(Bitmap bitmap) {
+            mBitmap = bitmap;
+        }
+
+        @Override
+        public Bitmap colorize(Drawable drawable, int backgroundColor, boolean isRtl) {
+            return mBitmap;
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java
index 15381b7..0c5bdea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java
@@ -162,7 +162,7 @@
             }
         });
         block.run();
-        countDownLatch.await(5, java.util.concurrent.TimeUnit.SECONDS);
+        countDownLatch.await();
         if (exceptionHolder.mException != null) {
             throw exceptionHolder.mException;
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notification/PropertyAnimatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
similarity index 94%
rename from packages/SystemUI/tests/src/com/android/systemui/notification/PropertyAnimatorTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
index 8484bed..eaa073c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notification/PropertyAnimatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
@@ -1,18 +1,20 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
  *      http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
  */
 
-package com.android.systemui.notification;
+package com.android.systemui.statusbar.notification;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notification/VisualStabilityManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
similarity index 93%
rename from packages/SystemUI/tests/src/com/android/systemui/notification/VisualStabilityManagerTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
index 76bb6c0..e4c43735 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notification/VisualStabilityManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
@@ -1,18 +1,20 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
  *      http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
  */
 
-package com.android.systemui.notification;
+package com.android.systemui.statusbar.notification;
 
 import android.service.notification.StatusBarNotification;
 import android.support.test.runner.AndroidJUnit4;
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index b2712ff..aad4431 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -4365,7 +4365,7 @@
                                     }
                                     addWidgetLocked(id);
                                 }
-                                if (id.provider.info != null) {
+                                if (id.provider != null && id.provider.info != null) {
                                     stashProviderRestoreUpdateLocked(id.provider,
                                             restoredId, id.appWidgetId);
                                 } else {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index faa6182..35371a7 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -621,16 +621,17 @@
         @Override
         protected Void doInBackground(Void... ignored) {
             int numSessionsToRemove;
-            ArrayMap<IBinder, Integer> sessionsToRemove;
+
+            SparseArray<IBinder> sessionsToRemove;
 
             synchronized (mLock) {
                 numSessionsToRemove = mSessions.size();
-                sessionsToRemove = new ArrayMap<>(numSessionsToRemove);
+                sessionsToRemove = new SparseArray<>(numSessionsToRemove);
 
                 for (int i = 0; i < numSessionsToRemove; i++) {
                     Session session = mSessions.valueAt(i);
 
-                    sessionsToRemove.put(session.getActivityTokenLocked(), session.id);
+                    sessionsToRemove.put(session.id, session.getActivityTokenLocked());
                 }
             }
 
@@ -640,7 +641,7 @@
             for (int i = 0; i < numSessionsToRemove; i++) {
                 try {
                     // The activity manager cannot resolve activities that have been removed
-                    if (am.getActivityClassForToken(sessionsToRemove.keyAt(i)) != null) {
+                    if (am.getActivityClassForToken(sessionsToRemove.valueAt(i)) != null) {
                         sessionsToRemove.removeAt(i);
                         i--;
                         numSessionsToRemove--;
@@ -652,9 +653,10 @@
 
             synchronized (mLock) {
                 for (int i = 0; i < numSessionsToRemove; i++) {
-                    Session sessionToRemove = mSessions.get(sessionsToRemove.valueAt(i));
+                    Session sessionToRemove = mSessions.get(sessionsToRemove.keyAt(i));
 
-                    if (sessionToRemove != null) {
+                    if (sessionToRemove != null && sessionsToRemove.valueAt(i)
+                            == sessionToRemove.getActivityTokenLocked()) {
                         if (sessionToRemove.isSavingLocked()) {
                             if (sVerbose) {
                                 Slog.v(TAG, "Session " + sessionToRemove.id + " is saving");
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 4746ee9..6d58e72 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -1122,7 +1122,7 @@
 
     private void notifyUnavailableToClient() {
         synchronized (mLock) {
-            if (!mHasCallback) return;
+            if (!mHasCallback || mCurrentViewId == null) return;
             try {
                 mClient.notifyNoFillUi(id, mCurrentViewId);
             } catch (RemoteException e) {
@@ -1371,10 +1371,15 @@
         pw.print(prefix); pw.print("id: "); pw.println(id);
         pw.print(prefix); pw.print("uid: "); pw.println(uid);
         pw.print(prefix); pw.print("mActivityToken: "); pw.println(mActivityToken);
-        pw.print(prefix); pw.print("mResponses: "); pw.println(mResponses.size());
-        for (int i = 0; i < mResponses.size(); i++) {
-            pw.print(prefix2); pw.print('#'); pw.print(i); pw.print(' ');
-                pw.println(mResponses.valueAt(i));
+        pw.print(prefix); pw.print("mResponses: ");
+        if (mResponses == null) {
+            pw.println("null");
+        } else {
+            pw.println(mResponses.size());
+            for (int i = 0; i < mResponses.size(); i++) {
+                pw.print(prefix2); pw.print('#'); pw.print(i);
+                pw.print(' '); pw.println(mResponses.valueAt(i));
+            }
         }
         pw.print(prefix); pw.print("mCurrentViewId: "); pw.println(mCurrentViewId);
         pw.print(prefix); pw.print("mViewStates size: "); pw.println(mViewStates.size());
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 6093241..73f1705 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -110,10 +110,15 @@
     private final CompanionDeviceManagerImpl mImpl;
     private final ConcurrentMap<Integer, AtomicFile> mUidToStorage = new ConcurrentHashMap<>();
     private IDeviceIdleController mIdleController;
-    private IFindDeviceCallback mFindDeviceCallback;
     private ServiceConnection mServiceConnection;
     private IAppOpsService mAppOpsManager;
 
+    private IFindDeviceCallback mFindDeviceCallback;
+    private AssociationRequest mRequest;
+    private String mCallingPackage;
+
+    private final Object mLock = new Object();
+
     public CompanionDeviceManagerService(Context context) {
         super(context);
         mImpl = new CompanionDeviceManagerImpl();
@@ -156,8 +161,12 @@
     }
 
     private void cleanup() {
-        mServiceConnection = unbind(mServiceConnection);
-        mFindDeviceCallback = unlinkToDeath(mFindDeviceCallback, this, 0);
+        synchronized (mLock) {
+            mServiceConnection = unbind(mServiceConnection);
+            mFindDeviceCallback = unlinkToDeath(mFindDeviceCallback, this, 0);
+            mRequest = null;
+            mCallingPackage = null;
+        }
     }
 
     /**
@@ -222,6 +231,17 @@
         }
 
         @Override
+        public void stopScan(AssociationRequest request,
+                IFindDeviceCallback callback,
+                String callingPackage) {
+            if (Objects.equals(request, mRequest)
+                    && Objects.equals(callback, mFindDeviceCallback)
+                    && Objects.equals(callingPackage, mCallingPackage)) {
+                cleanup();
+            }
+        }
+
+        @Override
         public List<String> getAssociations(String callingPackage, int userId)
                 throws RemoteException {
             checkCallerIsSystemOr(callingPackage, userId);
@@ -340,7 +360,11 @@
                             "onServiceConnected(name = " + name + ", service = "
                                     + service + ")");
                 }
+
                 mFindDeviceCallback = findDeviceCallback;
+                mRequest = request;
+                mCallingPackage = callingPackage;
+
                 try {
                     mFindDeviceCallback.asBinder().linkToDeath(
                             CompanionDeviceManagerService.this, 0);
@@ -348,6 +372,7 @@
                     cleanup();
                     return;
                 }
+
                 try {
                     ICompanionDeviceDiscoveryService.Stub
                             .asInterface(service)
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index c785fb9..b65f54e 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -91,6 +91,7 @@
     private static final String REASON_SYSTEM_BOOT = "system boot";
     private static final String REASON_UNEXPECTED = "unexpected crash";
     private static final String REASON_USER_SWITCH = "user switch";
+    private static final String REASON_RESTORE_USER_SETTING = "restore user setting";
 
     private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
     //Maximum msec to wait for service restart
@@ -119,6 +120,10 @@
     private static final int MESSAGE_USER_UNLOCKED = 301;
     private static final int MESSAGE_ADD_PROXY_DELAYED = 400;
     private static final int MESSAGE_BIND_PROFILE_SERVICE = 401;
+    private static final int MESSAGE_RESTORE_USER_SETTING = 500;
+
+    private static final int RESTORE_SETTING_TO_ON = 1;
+    private static final int RESTORE_SETTING_TO_OFF = 0;
 
     private static final int MAX_ERROR_RESTART_RETRIES = 6;
 
@@ -318,6 +323,26 @@
                 } else {
                     if (DBG) Slog.e(TAG, "No Bluetooth Adapter address parameter found");
                 }
+            } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) {
+                final String name = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
+                if (Settings.Global.BLUETOOTH_ON.equals(name)) {
+                    // The Bluetooth On state may be changed during system restore.
+                    final String prevValue = intent.getStringExtra(
+                            Intent.EXTRA_SETTING_PREVIOUS_VALUE);
+                    final String newValue = intent.getStringExtra(
+                            Intent.EXTRA_SETTING_NEW_VALUE);
+
+                    if (DBG) Slog.d(TAG, "ACTION_SETTING_RESTORED with BLUETOOTH_ON, prevValue=" +
+                                    prevValue + ", newValue=" + newValue);
+
+                    if ((newValue != null) && (prevValue != null) && !prevValue.equals(newValue)) {
+                        Message msg = mHandler.obtainMessage(MESSAGE_RESTORE_USER_SETTING,
+                                                             newValue.equals("0") ?
+                                                             RESTORE_SETTING_TO_OFF :
+                                                             RESTORE_SETTING_TO_ON, 0);
+                        mHandler.sendMessage(msg);
+                    }
+                }
             }
         }
     };
@@ -350,12 +375,14 @@
         registerForBleScanModeChange();
         mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
         mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
-        IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
+        filter.addAction(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED);
+        filter.addAction(Intent.ACTION_SETTING_RESTORED);
         filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
         mContext.registerReceiver(mReceiver, filter);
-        filter = new IntentFilter(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED);
-        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
-        mContext.registerReceiver(mReceiver, filter);
+
         loadStoredNameAndAddress();
         if (isBluetoothPersistedStateOn()) {
             if (DBG) Slog.d(TAG, "Startup: Bluetooth persisted state is ON.");
@@ -1421,6 +1448,20 @@
                     }
                     break;
 
+                case MESSAGE_RESTORE_USER_SETTING:
+                    try {
+                        if ((msg.arg1 == RESTORE_SETTING_TO_OFF) && mEnable) {
+                            if (DBG) Slog.d(TAG, "Restore Bluetooth state to disabled");
+                            disable(REASON_RESTORE_USER_SETTING, true);
+                        } else if ((msg.arg1 == RESTORE_SETTING_TO_ON) && !mEnable) {
+                            if (DBG) Slog.d(TAG, "Restore Bluetooth state to enabled");
+                            enable(REASON_RESTORE_USER_SETTING);
+                        }
+                    } catch (RemoteException e) {
+                        Slog.e(TAG,"Unable to change Bluetooth On setting", e);
+                    }
+                    break;
+
                 case MESSAGE_REGISTER_ADAPTER:
                 {
                     IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e76ffb1..214edd0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -13407,8 +13407,12 @@
     public void setRenderThread(int tid) {
         synchronized (this) {
             ProcessRecord proc;
+            int pid = Binder.getCallingPid();
+            if (pid == Process.myPid()) {
+                demoteSystemServerRenderThread(tid);
+                return;
+            }
             synchronized (mPidsSelfLocked) {
-                int pid = Binder.getCallingPid();
                 proc = mPidsSelfLocked.get(pid);
                 if (proc != null && proc.renderThreadTid == 0 && tid > 0) {
                     // ensure the tid belongs to the process
@@ -13441,6 +13445,16 @@
         }
     }
 
+    /**
+     * We only use RenderThread in system_server to store task snapshots to the disk, which should
+     * happen in the background. Thus, demote render thread from system_server to a lower priority.
+     *
+     * @param tid the tid of the RenderThread
+     */
+    private void demoteSystemServerRenderThread(int tid) {
+        setThreadPriority(tid, Process.THREAD_PRIORITY_BACKGROUND);
+    }
+
     @Override
     public int setVrMode(IBinder token, boolean enabled, ComponentName packageName) {
         if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) {
@@ -14499,6 +14513,7 @@
         // concurrently during execution of this method)
         synchronized (this) {
             sb.append("Process: ").append(processName).append("\n");
+            sb.append("PID: ").append(process.pid).append("\n");
             int flags = process.info.flags;
             IPackageManager pm = AppGlobals.getPackageManager();
             sb.append("Flags: 0x").append(Integer.toHexString(flags)).append("\n");
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index f13dad7..4e00f2d 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -283,6 +283,7 @@
     boolean visible;        // does this activity's window need to be shown?
     boolean visibleIgnoringKeyguard; // is this activity visible, ignoring the fact that Keyguard
                                      // might hide this activity?
+    private boolean mLastSetWindowVisibility; // The last window visibility state that was set.
     private boolean mDeferHidingClient; // If true we told WM to defer reporting to the client
                                         // process that it is hidden.
     boolean sleeping;       // have we told the activity to sleep?
@@ -1581,6 +1582,10 @@
     }
 
     void setVisibility(boolean visible) {
+        if (mLastSetWindowVisibility == visible) {
+            return;
+        }
+        mLastSetWindowVisibility = visible;
         mWindowContainerController.setVisibility(visible, mDeferHidingClient);
         mStackSupervisor.mActivityMetricsLogger.notifyVisibilityChanged(this, visible);
     }
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index c5d5867..c56e4ea 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1933,7 +1933,7 @@
      *
      * @return true if {@param r} is visible taken Keyguard state into account, false otherwise
      */
-    private boolean checkKeyguardVisibility(ActivityRecord r, boolean shouldBeVisible,
+    boolean checkKeyguardVisibility(ActivityRecord r, boolean shouldBeVisible,
             boolean isTop) {
         final boolean isInPinnedStack = r.getStack().getStackId() == PINNED_STACK_ID;
         final boolean keyguardShowing = mStackSupervisor.mKeyguardController.isKeyguardShowing();
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 4049500..8210c07 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1333,7 +1333,13 @@
         }
 
         r.startFreezingScreenLocked(app, 0);
-        r.setVisibility(true);
+        if (r.getStack().checkKeyguardVisibility(r, true /* shouldBeVisible */, true /* isTop */)) {
+            // We only set the visibility to true if the activity is allowed to be visible based on
+            // keyguard state. This avoids setting this into motion in window manager that is later
+            // cancelled due to later calls to ensure visible activities that set visibility back to
+            // false.
+            r.setVisibility(true);
+        }
 
         // schedule launch ticks to collect information about slow apps.
         r.startLaunchTickingLocked();
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index 2e6cd3f..57b1ccc 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -807,7 +807,7 @@
             ArrayList<JobStatus> result = new ArrayList<JobStatus>();
             for (int i = mJobs.size() - 1; i >= 0; i--) {
                 if (UserHandle.getUserId(mJobs.keyAt(i)) == userId) {
-                    ArraySet<JobStatus> jobs = mJobs.get(i);
+                    ArraySet<JobStatus> jobs = mJobs.valueAt(i);
                     if (jobs != null) {
                         result.addAll(jobs);
                     }
diff --git a/services/core/java/com/android/server/notification/BadgeExtractor.java b/services/core/java/com/android/server/notification/BadgeExtractor.java
index e6edaf1..1bd2085 100644
--- a/services/core/java/com/android/server/notification/BadgeExtractor.java
+++ b/services/core/java/com/android/server/notification/BadgeExtractor.java
@@ -41,9 +41,10 @@
             if (DBG) Slog.d(TAG, "missing config");
             return null;
         }
+        boolean userWantsBadges = mConfig.badgingEnabled(record.sbn.getUser());
         boolean appCanShowBadge =
                 mConfig.canShowBadge(record.sbn.getPackageName(), record.sbn.getUid());
-        if (!appCanShowBadge) {
+        if (!userWantsBadges || !appCanShowBadge) {
             record.setShowBadge(false);
         } else {
             record.setShowBadge(mConfig.getNotificationChannel(record.sbn.getPackageName(),
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index da919ec..9cd0dff 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -927,6 +927,8 @@
     };
 
     private final class SettingsObserver extends ContentObserver {
+        private final Uri NOTIFICATION_BADGING_URI
+                = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
         private final Uri NOTIFICATION_LIGHT_PULSE_URI
                 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
         private final Uri NOTIFICATION_RATE_LIMIT_URI
@@ -938,6 +940,8 @@
 
         void observe() {
             ContentResolver resolver = getContext().getContentResolver();
+            resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
+                    false, this, UserHandle.USER_ALL);
             resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
                     false, this, UserHandle.USER_ALL);
             resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
@@ -963,6 +967,9 @@
                 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
                             Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
             }
+            if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
+                mRankingHelper.updateBadgingEnabled();
+            }
         }
     }
 
@@ -1820,6 +1827,12 @@
         }
 
         @Override
+        public boolean onlyHasDefaultChannel(String pkg, int uid) {
+            enforceSystemOrSystemUI("onlyHasDefaultChannel");
+            return mRankingHelper.onlyHasDefaultChannel(pkg, uid);
+        }
+
+        @Override
         public int getDeletedChannelCount(String pkg, int uid) {
             enforceSystemOrSystemUI("getDeletedChannelCount");
             return mRankingHelper.getDeletedChannelCount(pkg, uid);
@@ -4022,6 +4035,7 @@
 
     private void handleRankingSort(Message msg) {
         if (!(msg.obj instanceof Boolean)) return;
+        if (mRankingHelper == null) return;
         boolean forceUpdate = ((Boolean) msg.obj == null) ? false : (boolean) msg.obj;
         synchronized (mNotificationLock) {
             final int N = mNotificationList.size();
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 4d19b52..36da04d 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -18,6 +18,7 @@
 import android.app.NotificationChannel;
 import android.app.NotificationChannelGroup;
 import android.content.pm.ParceledListSlice;
+import android.os.UserHandle;
 
 import java.util.Collection;
 
@@ -27,6 +28,7 @@
     int getImportance(String packageName, int uid);
     void setShowBadge(String packageName, int uid, boolean showBadge);
     boolean canShowBadge(String packageName, int uid);
+    boolean badgingEnabled(UserHandle userHandle);
 
     Collection<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
             int uid);
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 788f21d..e83d453 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -21,6 +21,8 @@
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.internal.util.Preconditions;
 
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationChannelGroup;
@@ -33,10 +35,14 @@
 import android.metrics.LogMaker;
 import android.os.Build;
 import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
 import android.service.notification.NotificationListenerService.Ranking;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Slog;
+import android.util.SparseBooleanArray;
 
 import org.json.JSONArray;
 import org.json.JSONException;
@@ -91,6 +97,7 @@
     private final Context mContext;
     private final RankingHandler mRankingHandler;
     private final PackageManager mPm;
+    private SparseBooleanArray mBadgingEnabled;
 
     public RankingHelper(Context context, PackageManager pm, RankingHandler rankingHandler,
             NotificationUsageStats usageStats, String[] extractorNames) {
@@ -100,6 +107,8 @@
 
         mPreliminaryComparator = new NotificationComparator(mContext);
 
+        updateBadgingEnabled();
+
         final int N = extractorNames.length;
         mSignalExtractors = new NotificationSignalExtractor[N];
         for (int i = 0; i < N; i++) {
@@ -303,7 +312,8 @@
 
     private void createDefaultChannelIfNeeded(Record r) throws NameNotFoundException {
         if (r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
-            // Already exists
+            r.channels.get(NotificationChannel.DEFAULT_CHANNEL_ID).setName(
+                    mContext.getString(R.string.default_notification_channel_label));
             return;
         }
 
@@ -769,6 +779,21 @@
         return new ParceledListSlice<>(channels);
     }
 
+    /**
+     * True for pre-O apps that only have the default channel, or pre O apps that have no
+     * channels yet. This method will create the default channel for pre-O apps that don't have it.
+     * Should never be true for O+ targeting apps, but that's enforced on boot/when an app
+     * upgrades.
+     */
+    public boolean onlyHasDefaultChannel(String pkg, int uid) {
+        Record r = getOrCreateRecord(pkg, uid);
+        if (r.channels.size() == 1
+                && r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
+            return true;
+        }
+        return false;
+    }
+
     public int getDeletedChannelCount(String pkg, int uid) {
         Preconditions.checkNotNull(pkg);
         int deletedCount = 0;
@@ -1111,6 +1136,38 @@
                         channel.getImportance());
     }
 
+    public void updateBadgingEnabled() {
+        if (mBadgingEnabled == null) {
+            mBadgingEnabled = new SparseBooleanArray();
+        }
+        boolean changed = false;
+        // update the cached values
+        for (int index = 0; index < mBadgingEnabled.size(); index++) {
+            int userId = mBadgingEnabled.keyAt(index);
+            final boolean oldValue = mBadgingEnabled.get(userId);
+            final boolean newValue = Secure.getIntForUser(mContext.getContentResolver(),
+                    Secure.NOTIFICATION_BADGING,
+                    DEFAULT_SHOW_BADGE ? 1 : 0, userId) != 0;
+            mBadgingEnabled.put(userId, newValue);
+            changed |= oldValue != newValue;
+        }
+        if (changed) {
+            mRankingHandler.requestSort(false);
+        }
+    }
+
+    public boolean badgingEnabled(UserHandle userHandle) {
+        int userId = userHandle.getIdentifier();
+        if (mBadgingEnabled.indexOfKey(userId) < 0) {
+            mBadgingEnabled.put(userId,
+                    Secure.getIntForUser(mContext.getContentResolver(),
+                            Secure.NOTIFICATION_BADGING,
+                            DEFAULT_SHOW_BADGE ? 1 : 0, userId) != 0);
+        }
+        return mBadgingEnabled.get(userId, DEFAULT_SHOW_BADGE);
+    }
+
+
     private static class Record {
         static int UNKNOWN_UID = UserHandle.USER_NULL;
 
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index bb7ffda..6625331 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -724,6 +724,9 @@
             grantRuntimePermissionsLPw(smsPackage, PHONE_PERMISSIONS, userId);
             grantRuntimePermissionsLPw(smsPackage, CONTACTS_PERMISSIONS, userId);
             grantRuntimePermissionsLPw(smsPackage, SMS_PERMISSIONS, userId);
+            grantRuntimePermissionsLPw(smsPackage, STORAGE_PERMISSIONS, userId);
+            grantRuntimePermissionsLPw(smsPackage, MICROPHONE_PERMISSIONS, userId);
+            grantRuntimePermissionsLPw(smsPackage, CAMERA_PERMISSIONS, userId);
         }
     }
 
@@ -737,6 +740,9 @@
             grantRuntimePermissionsLPw(smsPackage, PHONE_PERMISSIONS, false, true, userId);
             grantRuntimePermissionsLPw(smsPackage, CONTACTS_PERMISSIONS, false, true, userId);
             grantRuntimePermissionsLPw(smsPackage, SMS_PERMISSIONS, false, true, userId);
+            grantRuntimePermissionsLPw(smsPackage, STORAGE_PERMISSIONS, false, true, userId);
+            grantRuntimePermissionsLPw(smsPackage, MICROPHONE_PERMISSIONS, false, true, userId);
+            grantRuntimePermissionsLPw(smsPackage, CAMERA_PERMISSIONS, false, true, userId);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/OtaDexoptShellCommand.java b/services/core/java/com/android/server/pm/OtaDexoptShellCommand.java
index bbd4048..575e0f9 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptShellCommand.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptShellCommand.java
@@ -21,6 +21,7 @@
 import android.os.ShellCommand;
 
 import java.io.PrintWriter;
+import java.util.Locale;
 
 class OtaDexoptShellCommand extends ShellCommand {
     final IOtaDexopt mInterface;
@@ -93,7 +94,10 @@
     private int runOtaProgress() throws RemoteException {
         final float progress = mInterface.getProgress();
         final PrintWriter pw = getOutPrintWriter();
-        pw.format("%.2f", progress);
+        // Note: The float output is parsed by update_engine. It does needs to be non-localized,
+        //       as it's always expected to be "0.xy," never "0,xy" or similar. So use the ROOT
+        //       Locale for formatting. (b/37760573)
+        pw.format(Locale.ROOT, "%.2f", progress);
         return 0;
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 1129076..8fcfc8f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -29,7 +29,6 @@
 import static com.android.server.pm.PackageInstallerService.prepareStageDir;
 
 import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
@@ -46,7 +45,6 @@
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
 import android.content.pm.Signature;
-import android.content.pm.UserInfo;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.FileBridge;
@@ -56,7 +54,6 @@
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
-import android.os.ProxyFileDescriptorCallback;
 import android.os.RemoteException;
 import android.os.RevocableFileDescriptor;
 import android.os.UserHandle;
@@ -1168,19 +1165,7 @@
         // Send broadcast to default launcher only if it's a new install
         final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
         if (success && isNewInstall) {
-            UserManagerService ums = UserManagerService.getInstance();
-            if (ums != null) {
-                final UserInfo parent = ums.getProfileParent(userId);
-                final int launcherUid = (parent != null) ? parent.id : userId;
-                final ComponentName launcherComponent = mPm.getDefaultHomeActivity(launcherUid);
-                if (launcherComponent != null) {
-                    Intent launcherIntent = new Intent(PackageInstaller.ACTION_SESSION_COMMITTED)
-                            .putExtra(PackageInstaller.EXTRA_SESSION, generateInfo())
-                            .putExtra(Intent.EXTRA_USER, UserHandle.of(userId))
-                            .setPackage(launcherComponent.getPackageName());
-                    mContext.sendBroadcastAsUser(launcherIntent, UserHandle.of(launcherUid));
-                }
-            }
+            mPm.sendSessionCommitBroadcast(generateInfo(), userId);
         }
 
         mCallback.onSessionFinished(this, success);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e4b5241..0e91d30 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -382,6 +382,8 @@
     private static final boolean DEBUG_PACKAGE_SCANNING = false;
     private static final boolean DEBUG_VERIFY = false;
     private static final boolean DEBUG_FILTERS = false;
+    private static final boolean DEBUG_PERMISSIONS = false;
+    private static final boolean DEBUG_SHARED_LIBRARIES = false;
 
     // Debug output for dexopting. This is shared between PackageManagerService, OtaDexoptService
     // and PackageDexOptimizer. All these classes have their own flag to allow switching a single
@@ -2783,10 +2785,12 @@
                         // skip setup wizard; allow it to keep the high priority filter
                         continue;
                     }
-                    Slog.w(TAG, "Protected action; cap priority to 0;"
-                            + " package: " + filter.activity.info.packageName
-                            + " activity: " + filter.activity.className
-                            + " origPrio: " + filter.getPriority());
+                    if (DEBUG_FILTERS) {
+                        Slog.i(TAG, "Protected action; cap priority to 0;"
+                                + " package: " + filter.activity.info.packageName
+                                + " activity: " + filter.activity.className
+                                + " origPrio: " + filter.getPriority());
+                    }
                     filter.setPriority(0);
                 }
             }
@@ -3615,7 +3619,7 @@
             if (matchFactoryOnly) {
                 final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
                 if (ps != null) {
-                    if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) {
+                    if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) {
                         return null;
                     }
                     return generatePackageInfo(ps, flags, userId);
@@ -3630,14 +3634,14 @@
                 Log.v(TAG, "getPackageInfo " + packageName + ": " + p);
             if (p != null) {
                 if (filterSharedLibPackageLPr((PackageSetting) p.mExtras,
-                        Binder.getCallingUid(), userId)) {
+                        Binder.getCallingUid(), userId, flags)) {
                     return null;
                 }
                 return generatePackageInfo((PackageSetting)p.mExtras, flags, userId);
             }
             if (!matchFactoryOnly && (flags & MATCH_KNOWN_PACKAGES) != 0) {
                 final PackageSetting ps = mSettings.mPackages.get(packageName);
-                if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) {
+                if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) {
                     return null;
                 }
                 return generatePackageInfo(ps, flags, userId);
@@ -3646,13 +3650,17 @@
         return null;
     }
 
-
-    private boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId) {
-        // System/shell/root get to see all static libs
-        final int appId = UserHandle.getAppId(uid);
-        if (appId == Process.SYSTEM_UID || appId == Process.SHELL_UID
-                || appId == Process.ROOT_UID) {
-            return false;
+    private boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId,
+            int flags) {
+        // Callers can access only the libs they depend on, otherwise they need to explicitly
+        // ask for the shared libraries given the caller is allowed to access all static libs.
+        if ((flags & PackageManager.MATCH_STATIC_SHARED_LIBRARIES) != 0) {
+            // System/shell/root get to see all static libs
+            final int appId = UserHandle.getAppId(uid);
+            if (appId == Process.SYSTEM_UID || appId == Process.SHELL_UID
+                    || appId == Process.ROOT_UID) {
+                return false;
+            }
         }
 
         // No package means no static lib as it is always on internal storage
@@ -3847,7 +3855,7 @@
         if (!sUserManager.exists(userId)) return null;
         PackageSetting ps = mSettings.mPackages.get(packageName);
         if (ps != null) {
-            if (filterSharedLibPackageLPr(ps, uid, userId)) {
+            if (filterSharedLibPackageLPr(ps, uid, userId, flags)) {
                 return null;
             }
             if (ps.pkg == null) {
@@ -3888,7 +3896,7 @@
             if (p != null) {
                 PackageSetting ps = mSettings.mPackages.get(packageName);
                 if (ps == null) return null;
-                if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) {
+                if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) {
                     return null;
                 }
                 // Note: isEnabledLP() does not apply here - always return info
@@ -4349,7 +4357,6 @@
                     }
                     final long identity = Binder.clearCallingIdentity();
                     try {
-                        // TODO: We will change version code to long, so in the new API it is long
                         PackageInfo packageInfo = getPackageInfoVersioned(
                                 libInfo.getDeclaringPackage(), flags, userId);
                         if (packageInfo == null) {
@@ -4492,7 +4499,8 @@
                     }
                     PackageSetting ps = mSettings.getPackageLPr(libEntry.apk);
                     if (ps != null && !filterSharedLibPackageLPr(ps, Binder.getCallingUid(),
-                            UserHandle.getUserId(Binder.getCallingUid()))) {
+                            UserHandle.getUserId(Binder.getCallingUid()),
+                            PackageManager.MATCH_STATIC_SHARED_LIBRARIES)) {
                         if (libs == null) {
                             libs = new ArraySet<>();
                         }
@@ -7547,7 +7555,7 @@
             if (listUninstalled) {
                 list = new ArrayList<>(mSettings.mPackages.size());
                 for (PackageSetting ps : mSettings.mPackages.values()) {
-                    if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) {
+                    if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) {
                         continue;
                     }
                     final PackageInfo pi = generatePackageInfo(ps, flags, userId);
@@ -7559,7 +7567,7 @@
                 list = new ArrayList<>(mPackages.size());
                 for (PackageParser.Package p : mPackages.values()) {
                     if (filterSharedLibPackageLPr((PackageSetting) p.mExtras,
-                            Binder.getCallingUid(), userId)) {
+                            Binder.getCallingUid(), userId, flags)) {
                         continue;
                     }
                     final PackageInfo pi = generatePackageInfo((PackageSetting)
@@ -7664,7 +7672,7 @@
                         effectiveFlags |= PackageManager.MATCH_ANY_USER;
                     }
                     if (ps.pkg != null) {
-                        if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) {
+                        if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) {
                             continue;
                         }
                         ai = PackageParser.generateApplicationInfo(ps.pkg, effectiveFlags,
@@ -7688,7 +7696,7 @@
                 for (PackageParser.Package p : mPackages.values()) {
                     if (p.mExtras != null) {
                         PackageSetting ps = (PackageSetting) p.mExtras;
-                        if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) {
+                        if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) {
                             continue;
                         }
                         ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
@@ -9294,8 +9302,8 @@
                     throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
                             "Package " + packageName + " requires unavailable shared library "
                                     + libName + "; failing!");
-                } else {
-                    Slog.w(TAG, "Package " + packageName
+                } else if (DEBUG_SHARED_LIBRARIES) {
+                    Slog.i(TAG, "Package " + packageName
                             + " desires unavailable shared library "
                             + libName + "; ignoring!");
                 }
@@ -10658,13 +10666,13 @@
 
                 // Now that permission groups have a special meaning, we ignore permission
                 // groups for legacy apps to prevent unexpected behavior. In particular,
-                // permissions for one app being granted to someone just becase they happen
+                // permissions for one app being granted to someone just because they happen
                 // to be in a group defined by another app (before this had no implications).
                 if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
                     p.group = mPermissionGroups.get(p.info.group);
                     // Warn for a permission in an unknown group.
-                    if (p.info.group != null && p.group == null) {
-                        Slog.w(TAG, "Permission " + p.info.name + " from package "
+                    if (DEBUG_PERMISSIONS && p.info.group != null && p.group == null) {
+                        Slog.i(TAG, "Permission " + p.info.name + " from package "
                                 + p.info.packageName + " in an unknown group " + p.info.group);
                     }
                 }
@@ -11017,12 +11025,14 @@
                     if (ps.pkg != null && ps.pkg.applicationInfo != null &&
                             !TextUtils.equals(adjustedAbi, ps.pkg.applicationInfo.primaryCpuAbi)) {
                         ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
-                        Slog.i(TAG, "Adjusting ABI for " + ps.name + " to " + adjustedAbi
-                                + " (requirer="
-                                + (requirer != null ? requirer.pkg : "null")
-                                + ", scannedPackage="
-                                + (scannedPackage != null ? scannedPackage : "null")
-                                + ")");
+                        if (DEBUG_ABI_SELECTION) {
+                            Slog.i(TAG, "Adjusting ABI for " + ps.name + " to " + adjustedAbi
+                                    + " (requirer="
+                                    + (requirer != null ? requirer.pkg : "null")
+                                    + ", scannedPackage="
+                                    + (scannedPackage != null ? scannedPackage : "null")
+                                    + ")");
+                        }
                         try {
                             mInstaller.rmdex(ps.codePathString,
                                     getDexCodeInstructionSet(getPreferredInstructionSet()));
@@ -11743,8 +11753,10 @@
 
             if (bp == null || bp.packageSetting == null) {
                 if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
-                    Slog.w(TAG, "Unknown permission " + name
-                            + " in package " + pkg.packageName);
+                    if (DEBUG_PERMISSIONS) {
+                        Slog.i(TAG, "Unknown permission " + name
+                                + " in package " + pkg.packageName);
+                    }
                 }
                 continue;
             }
@@ -11752,14 +11764,18 @@
 
             // Limit ephemeral apps to ephemeral allowed permissions.
             if (pkg.applicationInfo.isInstantApp() && !bp.isInstant()) {
-                Log.i(TAG, "Denying non-ephemeral permission " + bp.name + " for package "
-                        + pkg.packageName);
+                if (DEBUG_PERMISSIONS) {
+                    Log.i(TAG, "Denying non-ephemeral permission " + bp.name + " for package "
+                            + pkg.packageName);
+                }
                 continue;
             }
 
             if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) {
-                Log.i(TAG, "Denying runtime-only permission " + bp.name + " for package "
-                        + pkg.packageName);
+                if (DEBUG_PERMISSIONS) {
+                    Log.i(TAG, "Denying runtime-only permission " + bp.name + " for package "
+                            + pkg.packageName);
+                }
                 continue;
             }
 
@@ -11817,8 +11833,8 @@
                 } break;
             }
 
-            if (DEBUG_INSTALL) {
-                Log.i(TAG, "Package " + pkg.packageName + " granting " + perm);
+            if (DEBUG_PERMISSIONS) {
+                Slog.i(TAG, "Granting permission " + perm + " to package " + pkg.packageName);
             }
 
             if (grant != GRANT_DENIED) {
@@ -11964,9 +11980,11 @@
                     default: {
                         if (packageOfInterest == null
                                 || packageOfInterest.equals(pkg.packageName)) {
-                            Slog.w(TAG, "Not granting permission " + perm
-                                    + " to package " + pkg.packageName
-                                    + " because it was previously installed without");
+                            if (DEBUG_PERMISSIONS) {
+                                Slog.i(TAG, "Not granting permission " + perm
+                                        + " to package " + pkg.packageName
+                                        + " because it was previously installed without");
+                            }
                         }
                     } break;
                 }
@@ -11985,8 +12003,10 @@
                 } else if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) == 0) {
                     // Don't print warning for app op permissions, since it is fine for them
                     // not to be granted, there is a UI for the user to decide.
-                    if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
-                        Slog.w(TAG, "Not granting permission " + perm
+                    if (DEBUG_PERMISSIONS
+                            && (packageOfInterest == null
+                                    || packageOfInterest.equals(pkg.packageName))) {
+                        Slog.i(TAG, "Not granting permission " + perm
                                 + " to package " + pkg.packageName
                                 + " (protectionLevel=" + bp.protectionLevel
                                 + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
@@ -12355,10 +12375,12 @@
                     ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0);
             if (!privilegedApp) {
                 // non-privileged applications can never define a priority >0
-                Slog.w(TAG, "Non-privileged app; cap priority to 0;"
-                        + " package: " + applicationInfo.packageName
-                        + " activity: " + intent.activity.className
-                        + " origPrio: " + intent.getPriority());
+                if (DEBUG_FILTERS) {
+                    Slog.i(TAG, "Non-privileged app; cap priority to 0;"
+                            + " package: " + applicationInfo.packageName
+                            + " activity: " + intent.activity.className
+                            + " origPrio: " + intent.getPriority());
+                }
                 intent.setPriority(0);
                 return;
             }
@@ -12398,10 +12420,12 @@
                             // setup wizard gets whatever it wants
                             return;
                         }
-                        Slog.w(TAG, "Protected action; cap priority to 0;"
-                                + " package: " + intent.activity.info.packageName
-                                + " activity: " + intent.activity.className
-                                + " origPrio: " + intent.getPriority());
+                        if (DEBUG_FILTERS) {
+                            Slog.i(TAG, "Protected action; cap priority to 0;"
+                                    + " package: " + intent.activity.info.packageName
+                                    + " activity: " + intent.activity.className
+                                    + " origPrio: " + intent.getPriority());
+                        }
                         intent.setPriority(0);
                         return;
                     }
@@ -13603,6 +13627,12 @@
             int userId) {
         final boolean isSystem = isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting);
         sendPackageAddedForNewUsers(packageName, isSystem, pkgSetting.appId, userId);
+
+        // Send a session commit broadcast
+        final PackageInstaller.SessionInfo info = new PackageInstaller.SessionInfo();
+        info.installReason = pkgSetting.getInstallReason(userId);
+        info.appPackageName = packageName;
+        sendSessionCommitBroadcast(info, userId);
     }
 
     public void sendPackageAddedForNewUsers(String packageName, boolean isSystem, int appId, int... userIds) {
@@ -20118,11 +20148,27 @@
         return getHomeActivitiesAsUser(allHomeCandidates, UserHandle.getCallingUserId());
     }
 
+    public void sendSessionCommitBroadcast(PackageInstaller.SessionInfo sessionInfo, int userId) {
+        UserManagerService ums = UserManagerService.getInstance();
+        if (ums != null) {
+            final UserInfo parent = ums.getProfileParent(userId);
+            final int launcherUid = (parent != null) ? parent.id : userId;
+            final ComponentName launcherComponent = getDefaultHomeActivity(launcherUid);
+            if (launcherComponent != null) {
+                Intent launcherIntent = new Intent(PackageInstaller.ACTION_SESSION_COMMITTED)
+                        .putExtra(PackageInstaller.EXTRA_SESSION, sessionInfo)
+                        .putExtra(Intent.EXTRA_USER, UserHandle.of(userId))
+                        .setPackage(launcherComponent.getPackageName());
+                mContext.sendBroadcastAsUser(launcherIntent, UserHandle.of(launcherUid));
+            }
+        }
+    }
+
     /**
      * Report the 'Home' activity which is currently set as "always use this one". If non is set
      * then reports the most likely home activity or null if there are more than one.
      */
-    public ComponentName getDefaultHomeActivity(int userId) {
+    private ComponentName getDefaultHomeActivity(int userId) {
         List<ResolveInfo> allHomeCandidates = new ArrayList<>();
         ComponentName cn = getHomeActivitiesAsUser(allHomeCandidates, userId);
         if (cn != null) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 6aff600..8e058ad 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -5325,7 +5325,7 @@
     @Override
     public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
             WindowState attached, WindowState imeTarget) {
-        final boolean visible = !win.isGoneForLayoutLw() && win.getAttrs().alpha > 0f;
+        final boolean visible = win.isVisibleLw() && win.getAttrs().alpha > 0f;
         if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisible=" + visible);
         applyKeyguardPolicyLw(win, imeTarget);
         final int fl = PolicyControl.getWindowFlags(win, attrs);
@@ -5960,15 +5960,23 @@
                             result &= ~ACTION_PASS_TO_USER;
                             break;
                         }
-                        if (telecomManager.isInCall()
-                                && (result & ACTION_PASS_TO_USER) == 0) {
-                            // If we are in call but we decided not to pass the key to
-                            // the application, just pass it to the session service.
-                            MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(
-                                    event, AudioManager.USE_DEFAULT_STREAM_TYPE, false);
-                            break;
-                        }
                     }
+                    int audioMode = AudioManager.MODE_NORMAL;
+                    try {
+                        audioMode = getAudioService().getMode();
+                    } catch (Exception e) {
+                        Log.e(TAG, "Error getting AudioService in interceptKeyBeforeQueueing.", e);
+                    }
+                    boolean isInCall = (telecomManager != null && telecomManager.isInCall()) ||
+                            audioMode == AudioManager.MODE_IN_COMMUNICATION;
+                    if (isInCall && (result & ACTION_PASS_TO_USER) == 0) {
+                        // If we are in call but we decided not to pass the key to
+                        // the application, just pass it to the session service.
+                        MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(
+                                event, AudioManager.USE_DEFAULT_STREAM_TYPE, false);
+                        break;
+                    }
+
                 }
                 if (mUseTvRouting || mHandleVolumeKeysInWM) {
                     // Defer special key handlings to
@@ -6313,7 +6321,7 @@
                 try {
                     getAudioService().adjustSuggestedStreamVolume(AudioManager.ADJUST_RAISE,
                             AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName, TAG);
-                } catch (RemoteException e) {
+                } catch (Exception e) {
                     Log.e(TAG, "Error dispatching volume up in dispatchTvAudioEvent.", e);
                 }
                 break;
@@ -6321,7 +6329,7 @@
                 try {
                     getAudioService().adjustSuggestedStreamVolume(AudioManager.ADJUST_LOWER,
                             AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName, TAG);
-                } catch (RemoteException e) {
+                } catch (Exception e) {
                     Log.e(TAG, "Error dispatching volume down in dispatchTvAudioEvent.", e);
                 }
                 break;
@@ -6332,7 +6340,7 @@
                                 AudioManager.ADJUST_TOGGLE_MUTE,
                                 AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName, TAG);
                     }
-                } catch (RemoteException e) {
+                } catch (Exception e) {
                     Log.e(TAG, "Error dispatching mute in dispatchTvAudioEvent.", e);
                 }
                 break;
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 6a18beb..39b902e 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -59,6 +59,7 @@
 import android.os.Environment;
 import android.os.FileObserver;
 import android.os.FileUtils;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
 import android.os.Process;
@@ -663,13 +664,35 @@
         @Override
         public void onServiceDisconnected(ComponentName name) {
             synchronized (mLock) {
+                Slog.w(TAG, "Wallpaper service gone: " + name);
+                if (!Objects.equals(name, mWallpaper.wallpaperComponent)) {
+                    Slog.e(TAG, "Does not match expected wallpaper component "
+                            + mWallpaper.wallpaperComponent);
+                }
                 mService = null;
                 mEngine = null;
                 if (mWallpaper.connection == this) {
-                    // The wallpaper disappeared.  If this isn't a system-default one, track
-                    // crashes and fall back to default if it continues to misbehave.
+                    // There is an inherent ordering race between this callback and the
+                    // package monitor that receives notice that a package is being updated,
+                    // so we cannot quite trust at this moment that we know for sure that
+                    // this is not an update.  If we think this is a genuine non-update
+                    // wallpaper outage, we do our "wait for reset" work as a continuation,
+                    // a short time in the future, specifically to allow any pending package
+                    // update message on this same looper thread to be processed.
+                    if (!mWallpaper.wallpaperUpdating) {
+                        mContext.getMainThreadHandler().postDelayed(() -> processDisconnect(this),
+                                1000);
+                    }
+                }
+            }
+        }
+
+        private void processDisconnect(final ServiceConnection connection) {
+            synchronized (mLock) {
+                // The wallpaper disappeared.  If this isn't a system-default one, track
+                // crashes and fall back to default if it continues to misbehave.
+                if (connection == mWallpaper.connection) {
                     final ComponentName wpService = mWallpaper.wallpaperComponent;
-                    Slog.w(TAG, "Wallpaper service gone: " + wpService);
                     if (!mWallpaper.wallpaperUpdating
                             && mWallpaper.userId == mCurrentUserId
                             && !Objects.equals(mDefaultWallpaperComponent, wpService)
@@ -682,7 +705,7 @@
                         // during {@link #MIN_WALLPAPER_CRASH_TIME} millis.
                         if (mWallpaper.lastDiedTime != 0
                                 && mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME
-                                    > SystemClock.uptimeMillis()) {
+                                > SystemClock.uptimeMillis()) {
                             Slog.w(TAG, "Reverting to built-in wallpaper!");
                             clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null);
                         } else {
@@ -690,18 +713,22 @@
 
                             // If we didn't reset it right away, do so after we couldn't connect to
                             // it for an extended amount of time to avoid having a black wallpaper.
-                            FgThread.getHandler().removeCallbacks(mResetRunnable);
-                            FgThread.getHandler().postDelayed(mResetRunnable,
-                                    WALLPAPER_RECONNECT_TIMEOUT_MS);
+                            final Handler fgHandler = FgThread.getHandler();
+                            fgHandler.removeCallbacks(mResetRunnable);
+                            fgHandler.postDelayed(mResetRunnable, WALLPAPER_RECONNECT_TIMEOUT_MS);
                             if (DEBUG_LIVE) {
                                 Slog.i(TAG, "Started wallpaper reconnect timeout for " + wpService);
                             }
                         }
-                        final String flattened = name.flattenToString();
+                        final String flattened = wpService.flattenToString();
                         EventLog.writeEvent(EventLogTags.WP_WALLPAPER_CRASHED,
                                 flattened.substring(0, Math.min(flattened.length(),
                                         MAX_WALLPAPER_COMPONENT_LOG_LENGTH)));
                     }
+                } else {
+                    if (DEBUG_LIVE) {
+                        Slog.i(TAG, "Wallpaper changed during disconnect tracking; ignoring");
+                    }
                 }
             }
         }
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 82416ec..fc4ec28 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -158,19 +158,23 @@
     /**
      * Reloads all the resources for the current configuration.
      */
-    void reloadResources() {
+    private void reloadResources() {
         final Resources res = mService.mContext.getResources();
         mMinSize = res.getDimensionPixelSize(
                 com.android.internal.R.dimen.default_minimal_size_pip_resizable_task);
         mDefaultAspectRatio = res.getFloat(
                 com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio);
-        final Size screenEdgeInsetsDp = Size.parseSize(res.getString(
-                com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets));
+        final String screenEdgeInsetsDpString = res.getString(
+                com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets);
+        final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
+                ? Size.parseSize(screenEdgeInsetsDpString)
+                : null;
         mDefaultStackGravity = res.getInteger(
                 com.android.internal.R.integer.config_defaultPictureInPictureGravity);
         mDisplayContent.getDisplay().getRealMetrics(mTmpMetrics);
-        mScreenEdgeInsets = new Point(dpToPx(screenEdgeInsetsDp.getWidth(), mTmpMetrics),
-                dpToPx(screenEdgeInsetsDp.getHeight(), mTmpMetrics));
+        mScreenEdgeInsets = screenEdgeInsetsDp == null ? new Point()
+                : new Point(dpToPx(screenEdgeInsetsDp.getWidth(), mTmpMetrics),
+                        dpToPx(screenEdgeInsetsDp.getHeight(), mTmpMetrics));
         mMinAspectRatio = res.getFloat(
                 com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
         mMaxAspectRatio = res.getFloat(
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index b79173c..1bbe1d0 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -275,6 +275,15 @@
         mPersister.removeObsoleteFiles(persistentTaskIds, runningUserIds);
     }
 
+    /**
+     * Temporarily pauses/unpauses persisting of task snapshots.
+     *
+     * @param paused Whether task snapshot persisting should be paused.
+     */
+    void setPersisterPaused(boolean paused) {
+        mPersister.setPaused(paused);
+    }
+
     void dump(PrintWriter pw, String prefix) {
         mCache.dump(pw, prefix);
     }
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index e5c7a72..0287070 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -60,6 +60,8 @@
     private final ArrayDeque<WriteQueueItem> mWriteQueue = new ArrayDeque<>();
     @GuardedBy("mLock")
     private boolean mQueueIdling;
+    @GuardedBy("mLock")
+    private boolean mPaused;
     private boolean mStarted;
     private final Object mLock = new Object();
     private final DirectoryResolver mDirectoryResolver;
@@ -127,6 +129,15 @@
         }
     }
 
+    void setPaused(boolean paused) {
+        synchronized (mLock) {
+            mPaused = paused;
+            if (!paused) {
+                mLock.notifyAll();
+            }
+        }
+    }
+
     @TestApi
     void waitForQueueEmpty() {
         while (true) {
@@ -142,7 +153,9 @@
     @GuardedBy("mLock")
     private void sendToQueueLocked(WriteQueueItem item) {
         mWriteQueue.offer(item);
-        mLock.notifyAll();
+        if (!mPaused) {
+            mLock.notifyAll();
+        }
     }
 
     private File getDirectory(int userId) {
@@ -185,7 +198,11 @@
             while (true) {
                 WriteQueueItem next;
                 synchronized (mLock) {
-                    next = mWriteQueue.poll();
+                    if (mPaused) {
+                        next = null;
+                    } else {
+                        next = mWriteQueue.poll();
+                    }
                 }
                 if (next != null) {
                     next.write();
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 067cc09..d64dc0e 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -115,8 +115,8 @@
         mAnimationTick = () -> {
             synchronized (mService.mWindowMap) {
                 mAnimationTickScheduled = false;
-                animateLocked(mCurrentFrameTime);
             }
+            animate(mCurrentFrameTime);
         };
         mAnimationFrameCallback = frameTimeNs -> {
             synchronized (mService.mWindowMap) {
@@ -126,8 +126,8 @@
                     return;
                 }
                 mAnimationTickScheduled = true;
-                mSfChoreographer.scheduleAtSfVsync(mAnimationTick);
             }
+            mSfChoreographer.scheduleAtSfVsync(mAnimationTick);
         };
     }
 
@@ -151,135 +151,158 @@
         mDisplayContentsAnimators.delete(displayId);
     }
 
-    /** Locked on mService.mWindowMap. */
-    private void animateLocked(long frameTimeNs) {
-        if (!mInitialized) {
-            return;
-        }
-
-        mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
-        mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
-        boolean wasAnimating = mAnimating;
-        setAnimating(false);
-        mAppWindowAnimating = false;
-        if (DEBUG_WINDOW_TRACE) {
-            Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
-        }
-
-        if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION animateLocked");
-        mService.openSurfaceTransaction();
-        SurfaceControl.setAnimationTransaction();
+    /**
+     * DO NOT HOLD THE WINDOW MANAGER LOCK WHILE CALLING THIS METHOD. Reason: the method closes
+     * an animation transaction, that might be blocking until the next sf-vsync, so we want to make
+     * sure other threads can make progress if this happens.
+     */
+    private void animate(long frameTimeNs) {
+        boolean transactionOpen = false;
+        boolean wasAnimating = false;
         try {
-            final AccessibilityController accessibilityController =
-                    mService.mAccessibilityController;
-            final int numDisplays = mDisplayContentsAnimators.size();
-            for (int i = 0; i < numDisplays; i++) {
-                final int displayId = mDisplayContentsAnimators.keyAt(i);
-                final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
-                dc.stepAppWindowsAnimation(mCurrentTime);
-                DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
+            synchronized (mService.mWindowMap) {
+                if (!mInitialized) {
+                    return;
+                }
 
-                final ScreenRotationAnimation screenRotationAnimation =
-                        displayAnimator.mScreenRotationAnimation;
-                if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
-                    if (screenRotationAnimation.stepAnimationLocked(mCurrentTime)) {
-                        setAnimating(true);
-                    } else {
-                        mBulkUpdateParams |= SET_UPDATE_ROTATION;
-                        screenRotationAnimation.kill();
-                        displayAnimator.mScreenRotationAnimation = null;
+                mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
+                mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
+                wasAnimating = mAnimating;
+                setAnimating(false);
+                mAppWindowAnimating = false;
+                if (DEBUG_WINDOW_TRACE) {
+                    Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
+                }
 
-                        //TODO (multidisplay): Accessibility supported only for the default display.
-                        if (accessibilityController != null && dc.isDefaultDisplay) {
-                            // We just finished rotation animation which means we did not announce
-                            // the rotation and waited for it to end, announce now.
-                            accessibilityController.onRotationChangedLocked(
-                                    mService.getDefaultDisplayContentLocked());
+                if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION animate");
+                mService.openSurfaceTransaction();
+                transactionOpen = true;
+                SurfaceControl.setAnimationTransaction();
+
+                final AccessibilityController accessibilityController =
+                        mService.mAccessibilityController;
+                final int numDisplays = mDisplayContentsAnimators.size();
+                for (int i = 0; i < numDisplays; i++) {
+                    final int displayId = mDisplayContentsAnimators.keyAt(i);
+                    final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
+                    dc.stepAppWindowsAnimation(mCurrentTime);
+                    DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
+
+                    final ScreenRotationAnimation screenRotationAnimation =
+                            displayAnimator.mScreenRotationAnimation;
+                    if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
+                        if (screenRotationAnimation.stepAnimationLocked(mCurrentTime)) {
+                            setAnimating(true);
+                        } else {
+                            mBulkUpdateParams |= SET_UPDATE_ROTATION;
+                            screenRotationAnimation.kill();
+                            displayAnimator.mScreenRotationAnimation = null;
+
+                            //TODO (multidisplay): Accessibility supported only for the default
+                            // display.
+                            if (accessibilityController != null && dc.isDefaultDisplay) {
+                                // We just finished rotation animation which means we did not
+                                // announce the rotation and waited for it to end, announce now.
+                                accessibilityController.onRotationChangedLocked(
+                                        mService.getDefaultDisplayContentLocked());
+                            }
                         }
                     }
+
+                    // Update animations of all applications, including those
+                    // associated with exiting/removed apps
+                    ++mAnimTransactionSequence;
+                    dc.updateWindowsForAnimator(this);
+                    dc.updateWallpaperForAnimator(this);
+                    dc.prepareWindowSurfaces();
+                }
+
+                for (int i = 0; i < numDisplays; i++) {
+                    final int displayId = mDisplayContentsAnimators.keyAt(i);
+                    final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
+
+                    dc.checkAppWindowsReadyToShow();
+
+                    final ScreenRotationAnimation screenRotationAnimation =
+                            mDisplayContentsAnimators.valueAt(i).mScreenRotationAnimation;
+                    if (screenRotationAnimation != null) {
+                        screenRotationAnimation.updateSurfacesInTransaction();
+                    }
+
+                    orAnimating(dc.animateDimLayers());
+                    orAnimating(dc.getDockedDividerController().animate(mCurrentTime));
+                    //TODO (multidisplay): Magnification is supported only for the default display.
+                    if (accessibilityController != null && dc.isDefaultDisplay) {
+                        accessibilityController.drawMagnifiedRegionBorderIfNeededLocked();
+                    }
                 }
 
-                // Update animations of all applications, including those
-                // associated with exiting/removed apps
-                ++mAnimTransactionSequence;
-                dc.updateWindowsForAnimator(this);
-                dc.updateWallpaperForAnimator(this);
-                dc.prepareWindowSurfaces();
-            }
-
-            for (int i = 0; i < numDisplays; i++) {
-                final int displayId = mDisplayContentsAnimators.keyAt(i);
-                final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
-
-                dc.checkAppWindowsReadyToShow();
-
-                final ScreenRotationAnimation screenRotationAnimation =
-                        mDisplayContentsAnimators.valueAt(i).mScreenRotationAnimation;
-                if (screenRotationAnimation != null) {
-                    screenRotationAnimation.updateSurfacesInTransaction();
+                if (mService.mDragState != null) {
+                    mAnimating |= mService.mDragState.stepAnimationLocked(mCurrentTime);
                 }
 
-                orAnimating(dc.animateDimLayers());
-                orAnimating(dc.getDockedDividerController().animate(mCurrentTime));
-                //TODO (multidisplay): Magnification is supported only for the default display.
-                if (accessibilityController != null && dc.isDefaultDisplay) {
-                    accessibilityController.drawMagnifiedRegionBorderIfNeededLocked();
+                if (mAnimating) {
+                    mService.scheduleAnimationLocked();
                 }
-            }
 
-            if (mService.mDragState != null) {
-                mAnimating |= mService.mDragState.stepAnimationLocked(mCurrentTime);
-            }
-
-            if (mAnimating) {
-                mService.scheduleAnimationLocked();
-            }
-
-            if (mService.mWatermark != null) {
-                mService.mWatermark.drawIfNeeded();
+                if (mService.mWatermark != null) {
+                    mService.mWatermark.drawIfNeeded();
+                }
             }
         } catch (RuntimeException e) {
             Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
         } finally {
-            mService.closeSurfaceTransaction();
-            if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animateLocked");
-        }
-
-        boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this);
-        boolean doRequest = false;
-        if (mBulkUpdateParams != 0) {
-            doRequest = mService.mRoot.copyAnimToLayoutParams();
-        }
-
-        if (hasPendingLayoutChanges || doRequest) {
-            mWindowPlacerLocked.requestTraversal();
-        }
-
-        if (mAnimating && !wasAnimating && Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
-            Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
-        }
-
-        if (!mAnimating && wasAnimating) {
-            mWindowPlacerLocked.requestTraversal();
-            if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
-                Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
+            if (transactionOpen) {
+                mService.closeSurfaceTransaction();
+                if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animate");
             }
         }
 
-        if (mRemoveReplacedWindows) {
-            mService.mRoot.removeReplacedWindows();
-            mRemoveReplacedWindows = false;
-        }
+        synchronized (mService.mWindowMap) {
+            boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this);
+            boolean doRequest = false;
+            if (mBulkUpdateParams != 0) {
+                doRequest = mService.mRoot.copyAnimToLayoutParams();
+            }
 
-        mService.stopUsingSavedSurfaceLocked();
-        mService.destroyPreservedSurfaceLocked();
-        mService.mWindowPlacerLocked.destroyPendingSurfaces();
+            if (hasPendingLayoutChanges || doRequest) {
+                mWindowPlacerLocked.requestTraversal();
+            }
 
-        if (DEBUG_WINDOW_TRACE) {
-            Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating
-                    + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams)
-                    + " mPendingLayoutChanges(DEFAULT_DISPLAY)="
-                    + Integer.toHexString(getPendingLayoutChanges(DEFAULT_DISPLAY)));
+            if (mAnimating && !wasAnimating) {
+
+                // Usually app transitions but quite a load onto the system already (with all the
+                // things happening in app), so pause task snapshot persisting to not increase the
+                // load.
+                mService.mTaskSnapshotController.setPersisterPaused(true);
+                if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
+                    Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
+                }
+            }
+
+            if (!mAnimating && wasAnimating) {
+                mWindowPlacerLocked.requestTraversal();
+                mService.mTaskSnapshotController.setPersisterPaused(false);
+                if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
+                    Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
+                }
+            }
+
+            if (mRemoveReplacedWindows) {
+                mService.mRoot.removeReplacedWindows();
+                mRemoveReplacedWindows = false;
+            }
+
+            mService.stopUsingSavedSurfaceLocked();
+            mService.destroyPreservedSurfaceLocked();
+            mService.mWindowPlacerLocked.destroyPendingSurfaces();
+
+            if (DEBUG_WINDOW_TRACE) {
+                Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating
+                        + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams)
+                        + " mPendingLayoutChanges(DEFAULT_DISPLAY)="
+                        + Integer.toHexString(getPendingLayoutChanges(DEFAULT_DISPLAY)));
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index a6b95d6..6cb4ddc 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1310,6 +1310,10 @@
     }
 
     void setSurfaceBoundariesLocked(final boolean recoveringMemory) {
+        if (mSurfaceController == null) {
+            return;
+        }
+
         final WindowState w = mWin;
         final LayoutParams attrs = mWin.getAttrs();
         final Task task = w.getTask();
diff --git a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java b/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
index 0cf4994..262516d 100644
--- a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
@@ -18,20 +18,19 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.when;
 
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+
 import android.app.ActivityManager;
 import android.app.Notification;
 import android.app.Notification.Builder;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
-import android.content.Context;
 import android.os.UserHandle;
+import android.provider.Settings.Secure;
 import android.service.notification.StatusBarNotification;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -43,7 +42,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class BadgeExtractorTest {
+public class BadgeExtractorTest extends NotificationTestCase {
 
     @Mock RankingConfig mConfig;
 
@@ -59,7 +58,11 @@
         MockitoAnnotations.initMocks(this);
     }
 
-    private NotificationRecord getNotificationRecord(NotificationChannel channel) {
+    private NotificationRecord getNotificationRecord(boolean showBadge, int importanceHigh) {
+        NotificationChannel channel = new NotificationChannel("a", "a", importanceHigh);
+        channel.setShowBadge(showBadge);
+        when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
+
         final Builder builder = new Builder(getContext())
                 .setContentTitle("foo")
                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
@@ -73,10 +76,6 @@
         return r;
     }
 
-    private Context getContext() {
-        return InstrumentationRegistry.getTargetContext();
-    }
-
     //
     // Tests
     //
@@ -86,13 +85,9 @@
         BadgeExtractor extractor = new BadgeExtractor();
         extractor.setConfig(mConfig);
 
+        when(mConfig.badgingEnabled(mUser)).thenReturn(true);
         when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(true);
-        NotificationChannel channel =
-                new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_UNSPECIFIED);
-        when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
-        channel.setShowBadge(false);
-
-        NotificationRecord r = getNotificationRecord(channel);
+        NotificationRecord r = getNotificationRecord(false, IMPORTANCE_UNSPECIFIED);
 
         extractor.process(r);
 
@@ -104,13 +99,9 @@
         BadgeExtractor extractor = new BadgeExtractor();
         extractor.setConfig(mConfig);
 
+        when(mConfig.badgingEnabled(mUser)).thenReturn(true);
         when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(false);
-        NotificationChannel channel =
-                new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_HIGH);
-        channel.setShowBadge(true);
-        when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
-
-        NotificationRecord r = getNotificationRecord(channel);
+        NotificationRecord r = getNotificationRecord(true, IMPORTANCE_HIGH);
 
         extractor.process(r);
 
@@ -122,13 +113,9 @@
         BadgeExtractor extractor = new BadgeExtractor();
         extractor.setConfig(mConfig);
 
+        when(mConfig.badgingEnabled(mUser)).thenReturn(true);
         when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(true);
-        NotificationChannel channel =
-                new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_UNSPECIFIED);
-        channel.setShowBadge(true);
-        when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
-
-        NotificationRecord r = getNotificationRecord(channel);
+        NotificationRecord r = getNotificationRecord(true, IMPORTANCE_UNSPECIFIED);
 
         extractor.process(r);
 
@@ -140,13 +127,23 @@
         BadgeExtractor extractor = new BadgeExtractor();
         extractor.setConfig(mConfig);
 
+        when(mConfig.badgingEnabled(mUser)).thenReturn(true);
         when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(false);
-        NotificationChannel channel =
-                new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_UNSPECIFIED);
-        channel.setShowBadge(false);
-        when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
+        NotificationRecord r = getNotificationRecord(false, IMPORTANCE_UNSPECIFIED);
 
-        NotificationRecord r = getNotificationRecord(channel);
+        extractor.process(r);
+
+        assertFalse(r.canShowBadge());
+    }
+
+    @Test
+    public void testAppYesChannelYesUserNo() throws Exception {
+        BadgeExtractor extractor = new BadgeExtractor();
+        extractor.setConfig(mConfig);
+
+        when(mConfig.badgingEnabled(mUser)).thenReturn(false);
+        when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(true);
+        NotificationRecord r = getNotificationRecord(true, IMPORTANCE_HIGH);
 
         extractor.process(r);
 
diff --git a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
index d4904f5..39caa3c 100644
--- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -34,7 +34,6 @@
 import android.app.Notification;
 import android.app.Notification.Builder;
 import android.app.NotificationManager;
-import android.content.Context;
 import android.app.NotificationChannel;
 import android.graphics.Color;
 import android.media.AudioAttributes;
@@ -47,7 +46,6 @@
 import android.os.VibrationEffect;
 import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -69,7 +67,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class BuzzBeepBlinkTest {
+public class BuzzBeepBlinkTest extends NotificationTestCase {
 
     @Mock AudioManager mAudioManager;
     @Mock Vibrator mVibrator;
@@ -328,10 +326,6 @@
                 eq(CUSTOM_LIGHT_COLOR), anyInt(), eq(CUSTOM_LIGHT_ON), eq(CUSTOM_LIGHT_OFF));
     }
 
-    private Context getContext() {
-        return InstrumentationRegistry.getTargetContext();
-    }
-
     //
     // Tests
     //
diff --git a/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java b/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
index 24cb72e..f92bd84 100644
--- a/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
@@ -25,7 +25,6 @@
 import android.app.NotificationManager;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -38,7 +37,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class GlobalSortKeyComparatorTest {
+public class GlobalSortKeyComparatorTest extends NotificationTestCase {
 
     private final String PKG = "PKG";
     private final int UID = 1111111;
@@ -46,24 +45,23 @@
 
     @Test
     public void testComparator() throws Exception {
-        Notification n = new Notification.Builder(
-                InstrumentationRegistry.getContext(), TEST_CHANNEL_ID)
+        Notification n = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
                 .build();
-        NotificationRecord left = new NotificationRecord(InstrumentationRegistry.getContext(),
+        NotificationRecord left = new NotificationRecord(getContext(),
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
                         "", 1499), getDefaultChannel());
         left.setGlobalSortKey("first");
 
-        NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(),
+        NotificationRecord right = new NotificationRecord(getContext(),
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
                         "", 1499), getDefaultChannel());
         right.setGlobalSortKey("second");
 
-        NotificationRecord last = new NotificationRecord(InstrumentationRegistry.getContext(),
+        NotificationRecord last = new NotificationRecord(getContext(),
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
@@ -86,16 +84,15 @@
 
     @Test
     public void testNoCrash_leftNull() throws Exception {
-        Notification n = new Notification.Builder(
-                InstrumentationRegistry.getContext(), TEST_CHANNEL_ID)
+        Notification n = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
                 .build();
-        NotificationRecord left = new NotificationRecord(InstrumentationRegistry.getContext(),
+        NotificationRecord left = new NotificationRecord(getContext(),
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
                         "", 1499), getDefaultChannel());
 
-        NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(),
+        NotificationRecord right = new NotificationRecord(getContext(),
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
@@ -117,17 +114,16 @@
 
     @Test
     public void testNoCrash_rightNull() throws Exception {
-        Notification n = new Notification.Builder(
-                InstrumentationRegistry.getContext(), TEST_CHANNEL_ID)
+        Notification n = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
                 .build();
-        NotificationRecord left = new NotificationRecord(InstrumentationRegistry.getContext(),
+        NotificationRecord left = new NotificationRecord(getContext(),
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
                         "", 1499), getDefaultChannel());
         left.setGlobalSortKey("not null");
 
-        NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(),
+        NotificationRecord right = new NotificationRecord(getContext(),
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
diff --git a/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java b/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
index 05c33a4..8dd1779 100644
--- a/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
@@ -34,10 +34,8 @@
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
-import android.content.Context;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -46,15 +44,11 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class GroupHelperTest {
+public class GroupHelperTest extends NotificationTestCase {
     private @Mock GroupHelper.Callback mCallback;
 
     private GroupHelper mGroupHelper;
 
-    private Context getContext() {
-        return InstrumentationRegistry.getTargetContext();
-    }
-
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
diff --git a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java b/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
index 3dbd803..d325e10 100644
--- a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
@@ -24,10 +24,8 @@
 import android.app.Notification.Builder;
 import android.app.NotificationManager;
 import android.app.NotificationChannel;
-import android.content.Context;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -43,7 +41,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class ImportanceExtractorTest {
+public class ImportanceExtractorTest extends NotificationTestCase {
 
     @Mock RankingConfig mConfig;
 
@@ -75,10 +73,6 @@
         return r;
     }
 
-    private Context getContext() {
-        return InstrumentationRegistry.getTargetContext();
-    }
-
     //
     // Tests
     //
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
index dde08fc..1e5f96f 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
@@ -35,7 +35,6 @@
 import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
 import android.telecom.TelecomManager;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -51,7 +50,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class NotificationComparatorTest {
+public class NotificationComparatorTest extends NotificationTestCase {
     @Mock Context mContext;
     @Mock TelecomManager mTm;
     @Mock RankingHandler handler;
@@ -83,10 +82,8 @@
         MockitoAnnotations.initMocks(this);
         int userId = UserHandle.myUserId();
 
-        when(mContext.getResources()).thenReturn(
-                InstrumentationRegistry.getTargetContext().getResources());
-        when(mContext.getContentResolver()).thenReturn(
-                InstrumentationRegistry.getTargetContext().getContentResolver());
+        when(mContext.getResources()).thenReturn(getContext().getResources());
+        when(mContext.getContentResolver()).thenReturn(getContext().getContentResolver());
         when(mContext.getPackageManager()).thenReturn(mPm);
         when(mContext.getSystemService(eq(Context.TELECOM_SERVICE))).thenReturn(mTm);
         when(mTm.getDefaultDialerPackage()).thenReturn(callPkg);
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationListenerServiceTest.java
index f0f4c4d..725e8f2 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationListenerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationListenerServiceTest.java
@@ -38,7 +38,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class NotificationListenerServiceTest {
+public class NotificationListenerServiceTest extends NotificationTestCase {
 
     private String[] mKeys = new String[] { "key", "key1", "key2", "key3"};
 
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index 177c02d..9afb2d2 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -52,9 +52,9 @@
 import android.os.Binder;
 import android.os.Process;
 import android.os.UserHandle;
+import android.provider.Settings.Secure;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
-import android.support.test.InstrumentationRegistry;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
@@ -75,7 +75,7 @@
 
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
-public class NotificationManagerServiceTest {
+public class NotificationManagerServiceTest extends NotificationTestCase {
     private static final long WAIT_FOR_IDLE_TIMEOUT = 2;
     private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
     private final int uid = Binder.getCallingUid();
@@ -86,7 +86,7 @@
     private IPackageManager mPackageManager;
     @Mock
     private PackageManager mPackageManagerClient;
-    private Context mContext = InstrumentationRegistry.getTargetContext();
+    private Context mContext = getContext();
     private final String PKG = mContext.getPackageName();
     private TestableLooper mTestableLooper;
     @Mock
@@ -122,6 +122,12 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+
+        // most tests assume badging is enabled
+        Secure.putIntForUser(getContext().getContentResolver(),
+                Secure.NOTIFICATION_BADGING, 1,
+                UserHandle.getUserHandleForUid(uid).getIdentifier());
+
         mNotificationManagerService = new TestableNotificationManagerService(mContext);
 
         // MockPackageManager - default returns ApplicationInfo with matching calling UID
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
index 1c8ca84..267d2a6 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
@@ -40,7 +40,6 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -56,7 +55,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class NotificationRecordTest {
+public class NotificationRecordTest extends NotificationTestCase {
 
     private final Context mMockContext = Mockito.mock(Context.class);
     @Mock PackageManager mPm;
@@ -96,8 +95,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        when(mMockContext.getResources()).thenReturn(
-                InstrumentationRegistry.getContext().getResources());
+        when(mMockContext.getResources()).thenReturn(getContext().getResources());
         when(mMockContext.getPackageManager()).thenReturn(mPm);
 
         legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationTestCase.java b/services/tests/notification/src/com/android/server/notification/NotificationTestCase.java
new file mode 100644
index 0000000..cc30aab
--- /dev/null
+++ b/services/tests/notification/src/com/android/server/notification/NotificationTestCase.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.notification;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.testing.TestableContext;
+
+import org.junit.Rule;
+
+
+public class NotificationTestCase {
+    @Rule
+    public final TestableContext mContext =
+            new TestableContext(InstrumentationRegistry.getContext(), null);
+
+    protected Context getContext() {
+        return mContext;
+    }
+}
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 30d6812..0f8c815 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -49,11 +49,14 @@
 import android.net.Uri;
 import android.os.Build;
 import android.os.UserHandle;
+import android.provider.Settings.Secure;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.TestableContext;
+import android.testing.TestableSettingsProvider;
 import android.util.ArrayMap;
 import android.util.Slog;
 import android.util.Xml;
@@ -81,11 +84,13 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class RankingHelperTest {
+public class RankingHelperTest extends NotificationTestCase {
     private static final String PKG = "com.android.server.notification";
     private static final int UID = 0;
+    private static final UserHandle USER = UserHandle.getUserHandleForUid(UID);
     private static final String UPDATED_PKG = "updatedPkg";
     private static final int UID2 = 1111111;
+    private static final UserHandle USER2 = UserHandle.getUserHandleForUid(UID2);
     private static final String TEST_CHANNEL_ID = "test_channel_id";
 
     @Mock NotificationUsageStats mUsageStats;
@@ -106,10 +111,6 @@
     private RankingHelper mHelper;
     private AudioAttributes mAudioAttributes;
 
-    private Context getContext() {
-        return InstrumentationRegistry.getTargetContext();
-    }
-
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
@@ -126,6 +127,9 @@
                 InstrumentationRegistry.getContext().getResources());
         when(mContext.getPackageManager()).thenReturn(mPm);
         when(mContext.getApplicationInfo()).thenReturn(legacy);
+        // most tests assume badging is enabled
+        Secure.putIntForUser(getContext().getContentResolver(),
+                Secure.NOTIFICATION_BADGING, 1, UserHandle.getUserId(UID));
 
         mHelper = new RankingHelper(getContext(), mPm, mHandler, mUsageStats,
                 new String[] {ImportanceExtractor.class.getName()});
@@ -869,6 +873,15 @@
     }
 
     @Test
+    public void testOnlyHasDefaultChannel() throws Exception {
+        assertTrue(mHelper.onlyHasDefaultChannel(PKG, UID));
+        assertFalse(mHelper.onlyHasDefaultChannel(UPDATED_PKG, UID2));
+
+        mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
+        assertFalse(mHelper.onlyHasDefaultChannel(PKG, UID));
+    }
+
+    @Test
     public void testCreateChannel_defaultChannelId() throws Exception {
         try {
             mHelper.createNotificationChannel(PKG, UID, new NotificationChannel(
@@ -1199,4 +1212,36 @@
                     object.getInt("channelCount"));
         }
     }
+
+    @Test
+    public void testBadgingOverrideTrue() throws Exception {
+        Secure.putIntForUser(getContext().getContentResolver(),
+                Secure.NOTIFICATION_BADGING, 1,
+                USER.getIdentifier());
+        mHelper.updateBadgingEnabled(); // would be called by settings observer
+        assertTrue(mHelper.badgingEnabled(USER));
+    }
+
+    @Test
+    public void testBadgingOverrideFalse() throws Exception {
+        Secure.putIntForUser(getContext().getContentResolver(),
+                Secure.NOTIFICATION_BADGING, 0,
+                USER.getIdentifier());
+        mHelper.updateBadgingEnabled(); // would be called by settings observer
+        assertFalse(mHelper.badgingEnabled(USER));
+    }
+
+    @Test
+    public void testBadgingOverrideUserIsolation() throws Exception {
+        Secure.putIntForUser(getContext().getContentResolver(),
+                Secure.NOTIFICATION_BADGING, 0,
+                USER.getIdentifier());
+        Secure.putIntForUser(getContext().getContentResolver(),
+                Secure.NOTIFICATION_BADGING, 1,
+                USER2.getIdentifier());
+        mHelper.updateBadgingEnabled(); // would be called by settings observer
+        assertFalse(mHelper.badgingEnabled(USER));
+        assertTrue(mHelper.badgingEnabled(USER2));
+    }
+
 }
diff --git a/services/tests/notification/src/com/android/server/notification/RateEstimatorTest.java b/services/tests/notification/src/com/android/server/notification/RateEstimatorTest.java
index 07f3162..e354267 100644
--- a/services/tests/notification/src/com/android/server/notification/RateEstimatorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RateEstimatorTest.java
@@ -26,7 +26,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class RateEstimatorTest {
+public class RateEstimatorTest extends NotificationTestCase {
     private long mTestStartTime;
     private RateEstimator mEstimator;
 
diff --git a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
index bc25860..07b21fb 100644
--- a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
@@ -27,11 +27,9 @@
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
-import android.content.Context;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Slog;
@@ -51,7 +49,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class SnoozeHelperTest {
+public class SnoozeHelperTest extends NotificationTestCase {
     private static final String TEST_CHANNEL_ID = "test_channel_id";
 
     @Mock SnoozeHelper.Callback mCallback;
@@ -60,10 +58,6 @@
 
     private SnoozeHelper mSnoozeHelper;
 
-    private Context getContext() {
-        return InstrumentationRegistry.getTargetContext();
-    }
-
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
diff --git a/services/tests/notification/src/com/android/server/notification/ValidateNotificationPeopleTest.java b/services/tests/notification/src/com/android/server/notification/ValidateNotificationPeopleTest.java
index d09b858..4ac0c65 100644
--- a/services/tests/notification/src/com/android/server/notification/ValidateNotificationPeopleTest.java
+++ b/services/tests/notification/src/com/android/server/notification/ValidateNotificationPeopleTest.java
@@ -32,7 +32,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class ValidateNotificationPeopleTest {
+public class ValidateNotificationPeopleTest extends NotificationTestCase {
 
     @Test
     public void testNoExtra() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 0167654..32eee84 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -120,18 +120,21 @@
     @After
     public void tearDown() throws Exception {
         final LinkedList<WindowState> nonCommonWindows = new LinkedList();
-        sWm.mRoot.forAllWindows(w -> {
-            if (!mCommonWindows.contains(w)) {
-                nonCommonWindows.addLast(w);
+
+        synchronized (sWm.mWindowMap) {
+            sWm.mRoot.forAllWindows(w -> {
+                if (!mCommonWindows.contains(w)) {
+                    nonCommonWindows.addLast(w);
+                }
+            }, true /* traverseTopToBottom */);
+
+            while (!nonCommonWindows.isEmpty()) {
+                nonCommonWindows.pollLast().removeImmediately();
             }
-        }, true /* traverseTopToBottom */);
 
-        while (!nonCommonWindows.isEmpty()) {
-            nonCommonWindows.pollLast().removeImmediately();
+            mDisplayContent.removeImmediately();
+            sWm.mInputMethodTarget = null;
         }
-
-        mDisplayContent.removeImmediately();
-        sWm.mInputMethodTarget = null;
     }
 
     private WindowState createCommonWindow(WindowState parent, int type, String name) {
diff --git a/services/usb/Android.mk b/services/usb/Android.mk
index f6d212b..57bf57d 100644
--- a/services/usb/Android.mk
+++ b/services/usb/Android.mk
@@ -7,8 +7,9 @@
 LOCAL_SRC_FILES += \
       $(call all-java-files-under,java)
 
-LOCAL_JAVA_LIBRARIES := services.core
-LOCAL_STATIC_JAVA_LIBRARIES := android.hardware.usb-V1.0-java-static \
-android.hidl.manager-V1.0-java-static
+LOCAL_JAVA_LIBRARIES := services.core \
+android.hidl.manager-V1.0-java
+
+LOCAL_STATIC_JAVA_LIBRARIES := android.hardware.usb-V1.0-java
 
 include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index eddcbda..0a67669 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -855,7 +855,7 @@
                         if (!mConnected) {
                             // restore defaults when USB is disconnected
                             Slog.i(TAG, "Disconnect, setting usb functions to null");
-                            setEnabledFunctions(null, true, false);
+                            setEnabledFunctions(null, !mAdbEnabled, false);
                         }
                         updateUsbFunctions();
                     } else {
diff --git a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
index 5399bb9..840ae22 100644
--- a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
@@ -841,7 +841,7 @@
     // Only one of device and accessory should be non-null.
     private boolean packageMatchesLocked(ResolveInfo info, String metaDataName,
             UsbDevice device, UsbAccessory accessory) {
-        if (info.getComponentInfo().name.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
+        if (isForwardMatch(info)) {
             return true;
         }
 
@@ -902,6 +902,17 @@
     }
 
     /**
+     * If this match used to forward the intent to another profile?
+     *
+     * @param match The match
+     *
+     * @return {@code true} iff this is such a forward match
+     */
+    private boolean isForwardMatch(@NonNull ResolveInfo match) {
+        return match.getComponentInfo().name.equals(FORWARD_INTENT_TO_MANAGED_PROFILE);
+    }
+
+    /**
      * Only return those matches with the highest priority.
      *
      * @param matches All matches, some might have lower priority
@@ -909,16 +920,23 @@
      * @return The matches with the highest priority
      */
     @NonNull
-    private ArrayList<ResolveInfo> preferHighPriority(
-            @NonNull ArrayList<ResolveInfo> matches) {
+    private ArrayList<ResolveInfo> preferHighPriority(@NonNull ArrayList<ResolveInfo> matches) {
         SparseArray<ArrayList<ResolveInfo>> highestPriorityMatchesByUserId = new SparseArray<>();
         SparseIntArray highestPriorityByUserId = new SparseIntArray();
+        ArrayList<ResolveInfo> forwardMatches = new ArrayList<>();
 
         // Create list of highest priority matches per user in highestPriorityMatchesByUserId
         int numMatches = matches.size();
         for (int matchNum = 0; matchNum < numMatches; matchNum++) {
             ResolveInfo match = matches.get(matchNum);
 
+            // Unnecessary forward matches are filtered out later, hence collect them all to add
+            // them below
+            if (isForwardMatch(match)) {
+                forwardMatches.add(match);
+                continue;
+            }
+
             // If this a previously unknown user?
             if (highestPriorityByUserId.indexOfKey(match.targetUserId) < 0) {
                 highestPriorityByUserId.put(match.targetUserId, Integer.MIN_VALUE);
@@ -940,9 +958,10 @@
             }
         }
 
-        // Combine all users back together. This means that all matches have the same priority for a
-        // user. Matches for different users might have different priority.
-        ArrayList<ResolveInfo> combinedMatches = new ArrayList<>();
+        // Combine all users (+ forward matches) back together. This means that all non-forward
+        // matches have the same priority for a user. Matches for different users might have
+        // different priority.
+        ArrayList<ResolveInfo> combinedMatches = new ArrayList<>(forwardMatches);
         int numMatchArrays = highestPriorityMatchesByUserId.size();
         for (int matchArrayNum = 0; matchArrayNum < numMatchArrays; matchArrayNum++) {
             combinedMatches.addAll(highestPriorityMatchesByUserId.valueAt(matchArrayNum));
@@ -951,6 +970,51 @@
         return combinedMatches;
     }
 
+    /**
+     * If there are no matches for a profile, remove the forward intent to this profile.
+     *
+     * @param rawMatches The matches that contain all forward intents
+     *
+     * @return The matches with the unnecessary forward intents removed
+     */
+    @NonNull private ArrayList<ResolveInfo> removeForwardIntentIfNotNeeded(
+            @NonNull ArrayList<ResolveInfo> rawMatches) {
+        final int numRawMatches = rawMatches.size();
+
+        // The raw matches contain the activities that can be started but also the intents to
+        // forward the intent to the other profile
+        int numParentActivityMatches = 0;
+        int numNonParentActivityMatches = 0;
+        for (int i = 0; i < numRawMatches; i++) {
+            final ResolveInfo rawMatch = rawMatches.get(i);
+            if (!isForwardMatch(rawMatch)) {
+                if (UserHandle.getUserHandleForUid(
+                        rawMatch.activityInfo.applicationInfo.uid).equals(mParentUser)) {
+                    numParentActivityMatches++;
+                } else {
+                    numNonParentActivityMatches++;
+                }
+            }
+        }
+
+        // If only one profile has activity matches, we need to remove all switch intents
+        if (numParentActivityMatches == 0 || numNonParentActivityMatches == 0) {
+            ArrayList<ResolveInfo> matches = new ArrayList<>(
+                    numParentActivityMatches + numNonParentActivityMatches);
+
+            for (int i = 0; i < numRawMatches; i++) {
+                ResolveInfo rawMatch = rawMatches.get(i);
+                if (!isForwardMatch(rawMatch)) {
+                    matches.add(rawMatch);
+                }
+            }
+            return matches;
+
+        } else {
+            return rawMatches;
+        }
+    }
+
     private final ArrayList<ResolveInfo> getDeviceMatchesLocked(UsbDevice device, Intent intent) {
         ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>();
         List<ResolveInfo> resolveInfos = queryIntentActivitiesForAllProfiles(intent);
@@ -961,7 +1025,8 @@
                 matches.add(resolveInfo);
             }
         }
-        return preferHighPriority(matches);
+
+        return removeForwardIntentIfNotNeeded(preferHighPriority(matches));
     }
 
     private final ArrayList<ResolveInfo> getAccessoryMatchesLocked(
@@ -975,7 +1040,8 @@
                 matches.add(resolveInfo);
             }
         }
-        return preferHighPriority(matches);
+
+        return removeForwardIntentIfNotNeeded(preferHighPriority(matches));
     }
 
     public void deviceAttached(UsbDevice device) {
@@ -1067,34 +1133,16 @@
      * Start the appropriate package when an device/accessory got attached.
      *
      * @param intent The intent to start the package
-     * @param rawMatches The available resolutions of the intent
+     * @param matches The available resolutions of the intent
      * @param defaultActivity The default activity for the device (if set)
      * @param device The device if a device was attached
      * @param accessory The accessory if a device was attached
      */
-    private void resolveActivity(@NonNull Intent intent, @NonNull ArrayList<ResolveInfo> rawMatches,
+    private void resolveActivity(@NonNull Intent intent, @NonNull ArrayList<ResolveInfo> matches,
             @Nullable ActivityInfo defaultActivity, @Nullable UsbDevice device,
             @Nullable UsbAccessory accessory) {
-        final int numRawMatches = rawMatches.size();
-
-        // The raw matches contain the activities that can be started but also the intents to switch
-        // between the profiles
-        int numParentActivityMatches = 0;
-        int numNonParentActivityMatches = 0;
-        for (int i = 0; i < numRawMatches; i++) {
-            final ResolveInfo rawMatch = rawMatches.get(i);
-            if (!rawMatch.getComponentInfo().name.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
-                if (UserHandle.getUserHandleForUid(
-                        rawMatch.activityInfo.applicationInfo.uid).equals(mParentUser)) {
-                    numParentActivityMatches++;
-                } else {
-                    numNonParentActivityMatches++;
-                }
-            }
-        }
-
         // don't show the resolver activity if there are no choices available
-        if (numParentActivityMatches + numNonParentActivityMatches == 0) {
+        if (matches.size() == 0) {
             if (accessory != null) {
                 String uri = accessory.getUri();
                 if (uri != null && uri.length() > 0) {
@@ -1117,21 +1165,6 @@
             return;
         }
 
-        // If only one profile has activity matches, we need to remove all switch intents
-        ArrayList<ResolveInfo> matches;
-        if (numParentActivityMatches == 0 || numNonParentActivityMatches == 0) {
-            matches = new ArrayList<>(numParentActivityMatches + numNonParentActivityMatches);
-
-            for (int i = 0; i < numRawMatches; i++) {
-                ResolveInfo rawMatch = rawMatches.get(i);
-                if (!rawMatch.getComponentInfo().name.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
-                    matches.add(rawMatch);
-                }
-            }
-        } else {
-            matches = rawMatches;
-        }
-
         if (defaultActivity != null) {
             UsbUserSettingsManager defaultRIUserSettings = mSettingsManager.getSettingsForUser(
                     UserHandle.getUserId(defaultActivity.applicationInfo.uid));
@@ -1216,10 +1249,10 @@
         if (matches.size() == 1) {
             final ActivityInfo activityInfo = matches.get(0).activityInfo;
             if (activityInfo != null) {
-                // bypass dialog and launch the only matching activity
                 if (mDisablePermissionDialogs) {
                     return activityInfo;
                 }
+                // System apps are considered default unless there are other matches
                 if (activityInfo.applicationInfo != null
                         && (activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
                                 != 0) {
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 2d3d79a..bcde519 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -986,6 +986,15 @@
      * @hide
      */
     @Override
+    public int installExistingPackage(String packageName, int installReason)
+            throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
     public int installExistingPackageAsUser(String packageName, int userId)
             throws NameNotFoundException {
         throw new UnsupportedOperationException();
diff --git a/tests/testables/src/android/testing/TestableSettingsProvider.java b/tests/testables/src/android/testing/TestableSettingsProvider.java
index 13056cf..fe97bca1 100644
--- a/tests/testables/src/android/testing/TestableSettingsProvider.java
+++ b/tests/testables/src/android/testing/TestableSettingsProvider.java
@@ -18,6 +18,7 @@
 import android.content.Context;
 import android.os.Bundle;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.test.mock.MockContentProvider;
 import android.util.Log;
@@ -48,9 +49,10 @@
     }
 
     void clearValuesAndCheck(Context context) {
-        mValues.put(key("global", MY_UNIQUE_KEY), MY_UNIQUE_KEY);
-        mValues.put(key("secure", MY_UNIQUE_KEY), MY_UNIQUE_KEY);
-        mValues.put(key("system", MY_UNIQUE_KEY), MY_UNIQUE_KEY);
+        int userId = UserHandle.myUserId();
+        mValues.put(key("global", MY_UNIQUE_KEY, userId), MY_UNIQUE_KEY);
+        mValues.put(key("secure", MY_UNIQUE_KEY, userId), MY_UNIQUE_KEY);
+        mValues.put(key("system", MY_UNIQUE_KEY, userId), MY_UNIQUE_KEY);
 
         // Verify that if any test is using TestableContext, they all have the correct settings
         // provider.
@@ -66,11 +68,12 @@
 
     public Bundle call(String method, String arg, Bundle extras) {
         // Methods are "GET_system", "GET_global", "PUT_secure", etc.
+        final int userId = extras.getInt(Settings.CALL_METHOD_USER_KEY, 0);
         final String[] commands = method.split("_", 2);
         final String op = commands[0];
         final String table = commands[1];
 
-            String k = key(table, arg);
+            String k = key(table, arg, userId);
             String value;
             Bundle out = new Bundle();
             switch (op) {
@@ -103,8 +106,13 @@
             return out;
     }
 
-    private static String key(String table, String key) {
-        return table + "_" + key;
+    private static String key(String table, String key, int userId) {
+        if ("global".equals(table)) {
+            return table + "_" + key;
+        } else {
+            return table + "_" + userId + "_" + key;
+        }
+
     }
 
     /**
diff --git a/tests/testables/tests/src/android/testing/TestableSettingsProviderTest.java b/tests/testables/tests/src/android/testing/TestableSettingsProviderTest.java
index 1f71867..0e2cc57 100644
--- a/tests/testables/tests/src/android/testing/TestableSettingsProviderTest.java
+++ b/tests/testables/tests/src/android/testing/TestableSettingsProviderTest.java
@@ -66,6 +66,16 @@
     }
 
     @Test
+    public void testSeparateUsers() {
+        Secure.putStringForUser(mContentResolver, NONEXISTENT_SETTING, "something", 0);
+        Secure.putStringForUser(mContentResolver, NONEXISTENT_SETTING, "else", 1);
+        assertEquals("something",
+                Secure.getStringForUser(mContentResolver, NONEXISTENT_SETTING, 0));
+        assertEquals("else",
+                Secure.getStringForUser(mContentResolver, NONEXISTENT_SETTING, 1));
+    }
+
+    @Test
     public void testPassThrough() {
         // Grab the value of a setting that is not overridden.
         assertTrue(Secure.getInt(mContentResolver, Secure.USER_SETUP_COMPLETE, 0) != 0);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
index 764eeeb..1b5a54d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
@@ -621,6 +621,12 @@
     }
 
     @Override
+    public int installExistingPackage(String packageName, int installReason)
+            throws NameNotFoundException {
+        return 0;
+    }
+
+    @Override
     public int installExistingPackageAsUser(String packageName, int userId)
             throws NameNotFoundException {
         return 0;
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/font/testfont.ttf b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/font/testfont.ttf
deleted file mode 100644
index 2852302..0000000
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/font/testfont.ttf
+++ /dev/null
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/font/testfont2.ttf b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/font/testfont2.ttf
deleted file mode 100644
index b7bf5b4..0000000
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/font/testfont2.ttf
+++ /dev/null
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
index 2b5e0f9..7b565b1 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
@@ -389,7 +389,8 @@
         assertTrue(sRenderMessages.isEmpty());
     }
 
-    @Test
+    //@Test
+    // Temporarily disabled (b/37725933)
     public void testFonts() throws ClassNotFoundException {
         // TODO: styles seem to be broken in TextView
         renderAndVerify("fonts_test.xml", "font_test.png");