Merge "[DO NOT MERGE] Support native shared libs" into oc-dev
diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java
index 8eefd25..4966b43 100644
--- a/cmds/am/src/com/android/commands/am/Instrument.java
+++ b/cmds/am/src/com/android/commands/am/Instrument.java
@@ -382,6 +382,7 @@
                 oldAnims = mWm.getAnimationScales();
                 mWm.setAnimationScale(0, 0.0f);
                 mWm.setAnimationScale(1, 0.0f);
+                mWm.setAnimationScale(2, 0.0f);
             }
 
             // Figure out which component we are tring to do.
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 5fedc9e..c4f17fa 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -214,5 +214,7 @@
     if (mapbase != MAP_FAILED) {
         munmap((void *)mapbase, mapsize);
     }
-    return 0;
+
+    // b/36066697: Avoid running static destructors.
+    _exit(1);
 }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 3574f8d..bc6e9cd 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -16,17 +16,9 @@
 
 package android.app;
 
-import android.graphics.Rect;
-import android.view.ViewRootImpl.ActivityConfigCallback;
-import android.view.autofill.AutofillManager;
-import android.view.autofill.AutofillPopupWindow;
-import android.view.autofill.IAutofillWindowPresenter;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.app.ToolbarActionBar;
-import com.android.internal.app.WindowDecorActionBar;
-import com.android.internal.policy.DecorView;
-import com.android.internal.policy.PhoneWindow;
+import static android.os.Build.VERSION_CODES.O;
+
+import static java.lang.Character.MIN_VALUE;
 
 import android.annotation.CallSuper;
 import android.annotation.DrawableRes;
@@ -62,6 +54,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
 import android.media.session.MediaController;
@@ -114,15 +107,26 @@
 import android.view.ViewGroup.LayoutParams;
 import android.view.ViewManager;
 import android.view.ViewRootImpl;
+import android.view.ViewRootImpl.ActivityConfigCallback;
 import android.view.Window;
 import android.view.Window.WindowControllerCallback;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.autofill.AutofillManager;
+import android.view.autofill.AutofillPopupWindow;
+import android.view.autofill.IAutofillWindowPresenter;
 import android.widget.AdapterView;
 import android.widget.Toast;
 import android.widget.Toolbar;
 
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.app.ToolbarActionBar;
+import com.android.internal.app.WindowDecorActionBar;
+import com.android.internal.policy.DecorView;
+import com.android.internal.policy.PhoneWindow;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -131,9 +135,6 @@
 import java.util.HashMap;
 import java.util.List;
 
-import static android.os.Build.VERSION_CODES.O;
-import static java.lang.Character.MIN_VALUE;
-
 /**
  * An activity is a single, focused thing that the user can do.  Almost all
  * activities interact with the user, so the Activity class takes care of
@@ -719,7 +720,7 @@
     public static final int FINISH_TASK_WITH_ACTIVITY = 2;
 
     static final String FRAGMENTS_TAG = "android:fragments";
-    private static final String LAST_ACCESSIBILITY_ID = "android:lastAccessibilityId";
+    private static final String LAST_AUTOFILL_ID = "android:lastAutofillId";
 
     private static final String AUTOFILL_RESET_NEEDED = "@android:autofillResetNeeded";
     private static final String WINDOW_HIERARCHY_TAG = "android:viewHierarchyState";
@@ -853,8 +854,8 @@
 
     private boolean mAutoFillResetNeeded;
 
-    /** The last accessibility id that was returned from {@link #getNextAccessibilityId()} */
-    private int mLastAccessibilityId = View.LAST_APP_ACCESSIBILITY_ID;
+    /** The last autofill id that was returned from {@link #getNextAutofillId()} */
+    private int mLastAutofillId = View.LAST_APP_AUTOFILL_ID;
 
     private AutofillPopupWindow mAutofillPopupWindow;
 
@@ -999,7 +1000,8 @@
         }
         if (savedInstanceState != null) {
             mAutoFillResetNeeded = savedInstanceState.getBoolean(AUTOFILL_RESET_NEEDED, false);
-            mLastAccessibilityId = savedInstanceState.getInt(LAST_ACCESSIBILITY_ID, View.NO_ID);
+            mLastAutofillId = savedInstanceState.getInt(LAST_AUTOFILL_ID,
+                    View.LAST_APP_AUTOFILL_ID);
 
             if (mAutoFillResetNeeded) {
                 getAutofillManager().onCreate(savedInstanceState);
@@ -1348,24 +1350,23 @@
     }
 
     /**
-     * Gets the next accessibility ID.
+     * Gets the next autofill ID.
      *
-     * <p>All IDs will be bigger than {@link View#LAST_APP_ACCESSIBILITY_ID}. All IDs returned
+     * <p>All IDs will be bigger than {@link View#LAST_APP_AUTOFILL_ID}. All IDs returned
      * will be unique.
      *
      * @return A ID that is unique in the activity
      *
      * {@hide}
      */
-    @Override
-    public int getNextAccessibilityId() {
-        if (mLastAccessibilityId == Integer.MAX_VALUE - 1) {
-            mLastAccessibilityId = View.LAST_APP_ACCESSIBILITY_ID;
+    public int getNextAutofillId() {
+        if (mLastAutofillId == Integer.MAX_VALUE - 1) {
+            mLastAutofillId = View.LAST_APP_AUTOFILL_ID;
         }
 
-        mLastAccessibilityId++;
+        mLastAutofillId++;
 
-        return mLastAccessibilityId;
+        return mLastAutofillId;
     }
 
     /**
@@ -1563,7 +1564,7 @@
     protected void onSaveInstanceState(Bundle outState) {
         outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
 
-        outState.putInt(LAST_ACCESSIBILITY_ID, mLastAccessibilityId);
+        outState.putInt(LAST_AUTOFILL_ID, mLastAutofillId);
         Parcelable p = mFragments.saveAllState();
         if (p != null) {
             outState.putParcelable(FRAGMENTS_TAG, p);
@@ -7455,7 +7456,7 @@
 
     /** @hide */
     @Override
-    @NonNull public View[] findViewsByAccessibilityIdTraversal(@NonNull int[] viewIds) {
+    @NonNull public View[] findViewsByAutofillIdTraversal(@NonNull int[] viewIds) {
         final View[] views = new View[viewIds.length];
         final ArrayList<ViewRootImpl> roots =
                 WindowManagerGlobal.getInstance().getRootViews(getActivityToken());
@@ -7466,7 +7467,7 @@
             if (rootView != null) {
                 for (int viewNum = 0; viewNum < viewIds.length; viewNum++) {
                     if (views[viewNum] == null) {
-                        views[viewNum] = rootView.findViewByAccessibilityIdTraversal(
+                        views[viewNum] = rootView.findViewByAutofillIdTraversal(
                                 viewIds[viewNum]);
                     }
                 }
@@ -7478,14 +7479,14 @@
 
     /** @hide */
     @Override
-    @Nullable public View findViewByAccessibilityIdTraversal(int viewId) {
+    @Nullable public View findViewByAutofillIdTraversal(int viewId) {
         final ArrayList<ViewRootImpl> roots =
                 WindowManagerGlobal.getInstance().getRootViews(getActivityToken());
         for (int rootNum = 0; rootNum < roots.size(); rootNum++) {
             final View rootView = roots.get(rootNum).getView();
 
             if (rootView != null) {
-                final View view = rootView.findViewByAccessibilityIdTraversal(viewId);
+                final View view = rootView.findViewByAutofillIdTraversal(viewId);
                 if (view != null) {
                     return view;
                 }
@@ -7499,7 +7500,7 @@
     @Override
     @NonNull public boolean[] getViewVisibility(@NonNull int[] viewIds) {
         final boolean[] isVisible = new boolean[viewIds.length];
-        final View views[] = findViewsByAccessibilityIdTraversal(viewIds);
+        final View views[] = findViewsByAutofillIdTraversal(viewIds);
 
         for (int i = 0; i < viewIds.length; i++) {
             View view = views[i];
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index cbb93a0..6dead3e 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -1244,7 +1244,7 @@
                 // Once we parcel the thumbnail for transfering over to the system, create a copy of
                 // the bitmap to a hardware bitmap and pass through the GraphicBuffer
                 if (mThumbnail != null) {
-                    final Bitmap hwBitmap = mThumbnail.copy(Config.HARDWARE, true /* immutable */);
+                    final Bitmap hwBitmap = mThumbnail.copy(Config.HARDWARE, false /* isMutable */);
                     if (hwBitmap != null) {
                         b.putParcelable(KEY_ANIM_THUMBNAIL, hwBitmap.createGraphicBufferHandle());
                     } else {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 268a105b..1b25e65 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -256,28 +256,34 @@
 
     @Override
     public void setTheme(int resId) {
-        if (mThemeResource != resId) {
-            mThemeResource = resId;
-            initializeTheme();
+        synchronized (mSync) {
+            if (mThemeResource != resId) {
+                mThemeResource = resId;
+                initializeTheme();
+            }
         }
     }
 
     @Override
     public int getThemeResId() {
-        return mThemeResource;
+        synchronized (mSync) {
+            return mThemeResource;
+        }
     }
 
     @Override
     public Resources.Theme getTheme() {
-        if (mTheme != null) {
+        synchronized (mSync) {
+            if (mTheme != null) {
+                return mTheme;
+            }
+
+            mThemeResource = Resources.selectDefaultTheme(mThemeResource,
+                    getOuterContext().getApplicationInfo().targetSdkVersion);
+            initializeTheme();
+
             return mTheme;
         }
-
-        mThemeResource = Resources.selectDefaultTheme(mThemeResource,
-                getOuterContext().getApplicationInfo().targetSdkVersion);
-        initializeTheme();
-
-        return mTheme;
     }
 
     private void initializeTheme() {
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 266fa7e..4e8277c 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -1051,6 +1051,9 @@
         public void updateAutofillValue(AutofillValue value) {
             mAutofillValue = value;
             if (value.isText()) {
+                if (mText == null) {
+                    mText = new ViewNodeText();
+                }
                 mText.mText = value.getTextValue();
             }
         }
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index 67d56d5..dfd5996 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -208,6 +208,8 @@
             if (wrapper == null) return;
 
             stopAdvertisingSet(wrapper);
+
+            mLegacyAdvertisers.remove(callback);
         }
     }
 
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index dabe608..86a30cf 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -214,10 +214,12 @@
             return;
         }
         try {
-            mService.requestNotificationAccess(component).send();
+            IntentSender intentSender = mService.requestNotificationAccess(component)
+                    .getIntentSender();
+            mContext.startIntentSender(intentSender, null, 0, 0, 0);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
-        } catch (PendingIntent.CanceledException e) {
+        } catch (IntentSender.SendIntentException e) {
             throw new RuntimeException(e);
         }
     }
@@ -288,6 +290,7 @@
 
         @Override
         public void onActivityDestroyed(Activity activity) {
+            if (activity != getActivity()) return;
             try {
                 mService.stopScan(mRequest, this, getCallingPackage());
             } catch (RemoteException e) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index db80c72..2303a38 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -488,27 +488,27 @@
      */
     public abstract Context getApplicationContext();
 
-    /** Non-activity related accessibility ids are unique in the app */
-    private static int sLastAccessibilityId = View.NO_ID;
+    /** Non-activity related autofill ids are unique in the app */
+    private static int sLastAutofillId = View.NO_ID;
 
     /**
-     * Gets the next accessibility ID.
+     * Gets the next autofill ID.
      *
-     * <p>All IDs will be smaller or the same as {@link View#LAST_APP_ACCESSIBILITY_ID}. All IDs
+     * <p>All IDs will be smaller or the same as {@link View#LAST_APP_AUTOFILL_ID}. All IDs
      * returned will be unique.
      *
      * @return A ID that is unique in the process
      *
      * {@hide}
      */
-    public int getNextAccessibilityId() {
-        if (sLastAccessibilityId == View.LAST_APP_ACCESSIBILITY_ID - 1) {
-            sLastAccessibilityId = View.NO_ID;
+    public int getNextAutofillId() {
+        if (sLastAutofillId == View.LAST_APP_AUTOFILL_ID - 1) {
+            sLastAutofillId = View.NO_ID;
         }
 
-        sLastAccessibilityId++;
+        sLastAutofillId++;
 
-        return sLastAccessibilityId;
+        return sLastAutofillId;
     }
 
     /**
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index e127ca3..3b27905 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -956,8 +956,7 @@
     /**
      * @hide
      */
-    @Override
-    public int getNextAccessibilityId() {
-        return mBase.getNextAccessibilityId();
+    public int getNextAutofillId() {
+        return mBase.getNextAutofillId();
     }
 }
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 0611f17..2b82c77 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -936,6 +936,11 @@
                 return this;
             }
 
+            Builder disable(int bit) {
+                mMask &= ~bit;
+                return this;
+            }
+
             /**
              * Construct the VmPolicy instance.
              *
@@ -1214,7 +1219,13 @@
         if (IS_USER_BUILD) {
             setCloseGuardEnabled(false);
         } else {
-            VmPolicy.Builder policyBuilder = new VmPolicy.Builder().detectAll().penaltyDropBox();
+            VmPolicy.Builder policyBuilder = new VmPolicy.Builder().detectAll();
+            if (!IS_ENG_BUILD) {
+                // Activity leak detection causes too much slowdown for userdebug because of the
+                // GCs.
+                policyBuilder = policyBuilder.disable(DETECT_VM_ACTIVITY_LEAKS);
+            }
+            policyBuilder = policyBuilder.penaltyDropBox();
             if (IS_ENG_BUILD) {
                 policyBuilder.penaltyLog();
             }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 65669ee..9e74c8e 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5188,6 +5188,15 @@
         public static final String USER_SETUP_COMPLETE = "user_setup_complete";
 
         /**
+         * Whether the current user has been set up via setup wizard (0 = false, 1 = true)
+         * This value differs from USER_SETUP_COMPLETE in that it can be reset back to 0
+         * in case SetupWizard has been re-enabled on TV devices.
+         *
+         * @hide
+         */
+        public static final String TV_USER_SETUP_COMPLETE = "tv_user_setup_complete";
+
+        /**
          * Prefix for category name that marks whether a suggested action from that category was
          * completed.
          * @hide
@@ -9821,6 +9830,16 @@
         public static final String ENABLE_EPHEMERAL_FEATURE = "enable_ephemeral_feature";
 
         /**
+         * Toggle to enable/disable dexopt for instant applications. The default is for dexopt
+         * to be disabled.
+         * <p>
+         * Type: int (0 to disable, 1 to enable)
+         *
+         * @hide
+         */
+        public static final String INSTANT_APP_DEXOPT_ENABLED = "instant_app_dexopt_enabled";
+
+        /**
          * The min period for caching installed instant apps in milliseconds.
          * <p>
          * Type: long
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 9df315b..07c3503 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -23,9 +23,7 @@
 import android.annotation.SdkConstant;
 import android.app.Activity;
 import android.app.Service;
-import android.app.assist.AssistStructure;
 import android.content.Intent;
-import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.IBinder;
 import android.os.ICancellationSignal;
@@ -35,9 +33,6 @@
 
 import com.android.internal.os.SomeArgs;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * Top-level service of the current autofill service for a given user.
  *
@@ -192,6 +187,11 @@
      * {@link SaveCallback#onSuccess()} or {@link SaveCallback#onFailure(CharSequence)})
      * to notify the result of the request.
      *
+     * <p><b>NOTE: </b>to retrieve the actual value of the field, the service should call
+     * {@link android.app.assist.AssistStructure.ViewNode#getAutofillValue()}; if it calls
+     * {@link android.app.assist.AssistStructure.ViewNode#getText()} or other methods, there is no
+     * guarantee such method will return the most recent value of the field.
+     *
      * @param request the {@link SaveRequest request} to handle.
      *        See {@link FillResponse} for examples of multiple-sections requests.
      * @param callback object used to notify the result of the request.
@@ -207,12 +207,6 @@
     public void onDisconnected() {
     }
 
-    /** @hide */
-    @Deprecated
-    public final void disableSelf() {
-        getSystemService(AutofillManager.class).disableOwnedAutofillServices();
-    }
-
     /**
      * Returns the {@link FillEventHistory.Event events} since the last {@link FillResponse} was
      * returned.
diff --git a/core/java/android/service/autofill/FillContext.java b/core/java/android/service/autofill/FillContext.java
index 6956c8a..f8a8751 100644
--- a/core/java/android/service/autofill/FillContext.java
+++ b/core/java/android/service/autofill/FillContext.java
@@ -106,15 +106,15 @@
     }
 
     /**
-     * Finds {@link ViewNode}s that have the requested ids.
+     * Finds {@link ViewNode ViewNodes} that have the requested ids.
      *
-     * @param ids The ids of the node to find
+     * @param ids The ids of the node to find.
      *
-     * @return The nodes indexed in the same way as the ids
+     * @return The nodes indexed in the same way as the ids.
      *
      * @hide
      */
-    @NonNull public ViewNode[] findViewNodesByAutofillIds(@NonNull AutofillId... ids) {
+    @NonNull public ViewNode[] findViewNodesByAutofillIds(@NonNull AutofillId[] ids) {
         final LinkedList<ViewNode> nodesToProcess = new LinkedList<>();
         final ViewNode[] foundNodes = new AssistStructure.ViewNode[ids.length];
 
@@ -178,6 +178,30 @@
         return foundNodes;
     }
 
+    /**
+     * Finds the {@link ViewNode} that has the requested {@code id}, if any.
+     *
+     * @hide
+     */
+    @Nullable public ViewNode findViewNodeByAutofillId(@NonNull AutofillId id) {
+        final LinkedList<ViewNode> nodesToProcess = new LinkedList<>();
+        final int numWindowNodes = mStructure.getWindowNodeCount();
+        for (int i = 0; i < numWindowNodes; i++) {
+            nodesToProcess.add(mStructure.getWindowNodeAt(i).getRootViewNode());
+        }
+        while (!nodesToProcess.isEmpty()) {
+            final ViewNode node = nodesToProcess.removeFirst();
+            if (id.equals(node.getAutofillId())) {
+                return node;
+            }
+            for (int i = 0; i < node.getChildCount(); i++) {
+                nodesToProcess.addLast(node.getChildAt(i));
+            }
+        }
+
+        return null;
+    }
+
     public static final Parcelable.Creator<FillContext> CREATOR =
             new Parcelable.Creator<FillContext>() {
         @Override
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index fa3f55b..6ea7d5e 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -273,13 +273,24 @@
          *
          * <p>See {@link SaveInfo} for more info.
          *
-         * @throws IllegalArgumentException if {@code requiredIds} is {@code null} or empty.
+         * @throws IllegalArgumentException if {@code requiredIds} is {@code null} or empty, or if
+         * it contains any {@code null} entry.
          */
         public Builder(@SaveDataType int type, @NonNull AutofillId[] requiredIds) {
-            Preconditions.checkArgument(requiredIds != null && requiredIds.length > 0,
-                    "must have at least one required id: " + Arrays.toString(requiredIds));
+            // TODO: add CTS unit tests (not integration) to assert the null cases
             mType = type;
-            mRequiredIds = requiredIds;
+            mRequiredIds = assertValid(requiredIds);
+        }
+
+        private AutofillId[] assertValid(AutofillId[] ids) {
+            Preconditions.checkArgument(ids != null && ids.length > 0,
+                    "must have at least one id: " + Arrays.toString(ids));
+            for (int i = 0; i < ids.length; i++) {
+                final AutofillId id = ids[i];
+                Preconditions.checkArgument(id != null,
+                        "cannot have null id: " + Arrays.toString(ids));
+            }
+            return ids;
         }
 
         /**
@@ -302,12 +313,14 @@
          *
          * @param ids The ids of the optional views.
          * @return This builder.
+         *
+         * @throws IllegalArgumentException if {@code ids} is {@code null} or empty, or if
+         * it contains any {@code null} entry.
          */
-        public @NonNull Builder setOptionalIds(@Nullable AutofillId[] ids) {
+        public @NonNull Builder setOptionalIds(@NonNull AutofillId[] ids) {
+            // TODO: add CTS unit tests (not integration) to assert the null cases
             throwIfDestroyed();
-            if (ids != null && ids.length != 0) {
-                mOptionalIds = ids;
-            }
+            mOptionalIds = assertValid(ids);
             return this;
         }
 
@@ -421,7 +434,10 @@
             final Builder builder = new Builder(parcel.readInt(),
                     parcel.readParcelableArray(null, AutofillId.class));
             builder.setNegativeAction(parcel.readInt(), parcel.readParcelable(null));
-            builder.setOptionalIds(parcel.readParcelableArray(null, AutofillId.class));
+            final AutofillId[] optionalIds = parcel.readParcelableArray(null, AutofillId.class);
+            if (optionalIds != null) {
+                builder.setOptionalIds(optionalIds);
+            }
             builder.setDescription(parcel.readCharSequence());
             builder.setFlags(parcel.readInt());
             return builder.build();
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index caadc36..cb98c88 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -72,6 +72,15 @@
      * Creates a display event receiver.
      *
      * @param looper The looper to use when invoking callbacks.
+     */
+    public DisplayEventReceiver(Looper looper) {
+        this(looper, VSYNC_SOURCE_APP);
+    }
+
+    /**
+     * Creates a display event receiver.
+     *
+     * @param looper The looper to use when invoking callbacks.
      * @param vsyncSource The source of the vsync tick. Must be on of the VSYNC_SOURCE_* values.
      */
     public DisplayEventReceiver(Looper looper, int vsyncSource) {
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 5f55bdc..04fa637 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -224,6 +224,14 @@
      * Constant for {@link #getActionMasked}: A movement has happened outside of the
      * normal bounds of the UI element.  This does not provide a full gesture,
      * but only the initial location of the movement/touch.
+     * <p>
+     * Note: Because the location of any event will be outside the
+     * bounds of the view hierarchy, it will not get dispatched to
+     * any children of a ViewGroup by default. Therefore,
+     * movements with ACTION_OUTSIDE should be handled in either the
+     * root {@link View} or in the appropriate {@link Window.Callback}
+     * (e.g. {@link android.app.Activity} or {@link android.app.Dialog}).
+     * </p>
      */
     public static final int ACTION_OUTSIDE          = 4;
 
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 8bb3fa9..4f9dbd5 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -52,7 +52,9 @@
 
     private static native long nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture)
             throws OutOfResourcesException;
+
     private static native long nativeCreateFromSurfaceControl(long surfaceControlNativeObject);
+    private static native long nativeGetFromSurfaceControl(long surfaceControlNativeObject);
 
     private static native long nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty)
             throws OutOfResourcesException;
@@ -410,6 +412,9 @@
      * back from a client, converting it from the representation being managed
      * by the window manager to the representation the client uses to draw
      * in to it.
+     *
+     * @param other {@link SurfaceControl} to copy from.
+     *
      * @hide
      */
     public void copyFrom(SurfaceControl other) {
@@ -420,7 +425,39 @@
         long surfaceControlPtr = other.mNativeObject;
         if (surfaceControlPtr == 0) {
             throw new NullPointerException(
-                    "SurfaceControl native object is null. Are you using a released SurfaceControl?");
+                    "null SurfaceControl native object. Are you using a released SurfaceControl?");
+        }
+        long newNativeObject = nativeGetFromSurfaceControl(surfaceControlPtr);
+
+        synchronized (mLock) {
+            if (mNativeObject != 0) {
+                nativeRelease(mNativeObject);
+            }
+            setNativeObjectLocked(newNativeObject);
+        }
+    }
+
+    /**
+     * Gets a reference a surface created from this one.  This surface now holds a reference
+     * to the same data as the original surface, and is -not- the owner.
+     * This is for use by the window manager when returning a window surface
+     * back from a client, converting it from the representation being managed
+     * by the window manager to the representation the client uses to draw
+     * in to it.
+     *
+     * @param other {@link SurfaceControl} to create surface from.
+     *
+     * @hide
+     */
+    public void createFrom(SurfaceControl other) {
+        if (other == null) {
+            throw new IllegalArgumentException("other must not be null");
+        }
+
+        long surfaceControlPtr = other.mNativeObject;
+        if (surfaceControlPtr == 0) {
+            throw new NullPointerException(
+                    "null SurfaceControl native object. Are you using a released SurfaceControl?");
         }
         long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);
 
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 679a9cd..7e0ade4 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -641,6 +641,16 @@
                         mSurface.copyFrom(mSurfaceControl);
                     }
 
+                    if (sizeChanged && getContext().getApplicationInfo().targetSdkVersion
+                            < Build.VERSION_CODES.O) {
+                        // Some legacy applications use the underlying native {@link Surface} object
+                        // as a key to whether anything has changed. In these cases, updates to the
+                        // existing {@link Surface} will be ignored when the size changes.
+                        // Therefore, we must explicitly recreate the {@link Surface} in these
+                        // cases.
+                        mSurface.createFrom(mSurfaceControl);
+                    }
+
                     if (visible && mSurface.isValid()) {
                         if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
                             mSurfaceCreated = true;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index b093284..4882165 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -802,7 +802,7 @@
      *
      * {@hide}
      */
-    public static final int LAST_APP_ACCESSIBILITY_ID = Integer.MAX_VALUE / 2;
+    public static final int LAST_APP_AUTOFILL_ID = Integer.MAX_VALUE / 2;
 
     /**
      * Attribute to find the autofilled highlight
@@ -2045,6 +2045,11 @@
     private SparseArray<Object> mKeyedTags;
 
     /**
+     * The next available accessibility id.
+     */
+    private static int sNextAccessibilityViewId;
+
+    /**
      * The animation currently associated with this view.
      * @hide
      */
@@ -2086,16 +2091,19 @@
     @ViewDebug.ExportedProperty(resolveId = true)
     int mID = NO_ID;
 
-    /** The ID of this view for accessibility and autofill purposes.
+    /** The ID of this view for autofill purposes.
      * <ul>
      *     <li>== {@link #NO_ID}: ID has not been assigned yet
-     *     <li>&le; {@link #LAST_APP_ACCESSIBILITY_ID}: View is not part of a activity. The ID is
+     *     <li>&le; {@link #LAST_APP_AUTOFILL_ID}: View is not part of a activity. The ID is
      *                                                  unique in the process. This might change
      *                                                  over activity lifecycle events.
-     *     <li>&gt; {@link #LAST_APP_ACCESSIBILITY_ID}: View is part of a activity. The ID is
+     *     <li>&gt; {@link #LAST_APP_AUTOFILL_ID}: View is part of a activity. The ID is
      *                                                  unique in the activity. This stays the same
      *                                                  over activity lifecycle events.
      */
+    private int mAutofillViewId = NO_ID;
+
+    // ID for accessibility purposes. This ID must be unique for every window
     private int mAccessibilityViewId = NO_ID;
 
     private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED;
@@ -7723,7 +7731,7 @@
         if (mAutofillId == null) {
             // The autofill id needs to be unique, but its value doesn't matter,
             // so it's better to reuse the accessibility id to save space.
-            mAutofillId = new AutofillId(getAccessibilityViewId());
+            mAutofillId = new AutofillId(getAutofillViewId());
         }
         return mAutofillId;
     }
@@ -7956,7 +7964,7 @@
 
     private boolean isAutofillable() {
         return getAutofillType() != AUTOFILL_TYPE_NONE && isImportantForAutofill()
-                && getAccessibilityViewId() > LAST_APP_ACCESSIBILITY_ID;
+                && getAutofillViewId() > LAST_APP_AUTOFILL_ID;
     }
 
     private void populateVirtualStructure(ViewStructure structure,
@@ -8474,12 +8482,26 @@
      */
     public int getAccessibilityViewId() {
         if (mAccessibilityViewId == NO_ID) {
-            mAccessibilityViewId = mContext.getNextAccessibilityId();
+            mAccessibilityViewId = sNextAccessibilityViewId++;
         }
         return mAccessibilityViewId;
     }
 
     /**
+     * Gets the unique identifier of this view on the screen for autofill purposes.
+     *
+     * @return The view autofill id.
+     *
+     * @hide
+     */
+    public int getAutofillViewId() {
+        if (mAutofillViewId == NO_ID) {
+            mAutofillViewId = mContext.getNextAutofillId();
+        }
+        return mAutofillViewId;
+    }
+
+    /**
      * Gets the unique identifier of the window in which this View reseides.
      *
      * @return The window accessibility id.
@@ -12117,7 +12139,7 @@
         if (isAutofillable()) {
             AutofillManager afm = getAutofillManager();
 
-            if (afm != null && getAccessibilityViewId() > LAST_APP_ACCESSIBILITY_ID) {
+            if (afm != null && getAutofillViewId() > LAST_APP_AUTOFILL_ID) {
                 if (mVisibilityChangeForAutofillHandler != null) {
                     mVisibilityChangeForAutofillHandler.removeMessages(0);
                 }
@@ -17547,16 +17569,16 @@
      *
      * @return Returns a Parcelable object containing the view's current dynamic
      *         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 #onRestoreInstanceState(Parcelable)
+     * @see #saveHierarchyState(SparseArray)
+     * @see #dispatchSaveInstanceState(SparseArray)
      * @see #setSaveEnabled(boolean)
      */
     @CallSuper
     @Nullable protected Parcelable onSaveInstanceState() {
         mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
         if (mStartActivityRequestWho != null || isAutofilled()
-                || mAccessibilityViewId > LAST_APP_ACCESSIBILITY_ID) {
+                || mAutofillViewId > LAST_APP_AUTOFILL_ID) {
             BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE);
 
             if (mStartActivityRequestWho != null) {
@@ -17567,13 +17589,13 @@
                 state.mSavedData |= BaseSavedState.IS_AUTOFILLED;
             }
 
-            if (mAccessibilityViewId > LAST_APP_ACCESSIBILITY_ID) {
-                state.mSavedData |= BaseSavedState.ACCESSIBILITY_ID;
+            if (mAutofillViewId > LAST_APP_AUTOFILL_ID) {
+                state.mSavedData |= BaseSavedState.AUTOFILL_ID;
             }
 
             state.mStartActivityRequestWhoSaved = mStartActivityRequestWho;
             state.mIsAutofilled = isAutofilled();
-            state.mAccessibilityViewId = mAccessibilityViewId;
+            state.mAutofillViewId = mAutofillViewId;
             return state;
         }
         return BaseSavedState.EMPTY_STATE;
@@ -17651,8 +17673,8 @@
             if ((baseState.mSavedData & BaseSavedState.IS_AUTOFILLED) != 0) {
                 setAutofilled(baseState.mIsAutofilled);
             }
-            if ((baseState.mSavedData & BaseSavedState.ACCESSIBILITY_ID) != 0) {
-                mAccessibilityViewId = baseState.mAccessibilityViewId;
+            if ((baseState.mSavedData & BaseSavedState.AUTOFILL_ID) != 0) {
+                mAutofillViewId = baseState.mAutofillViewId;
             }
         }
     }
@@ -21476,7 +21498,7 @@
      * @param accessibilityId The searched accessibility id.
      * @return The found view.
      */
-    final <T extends View> T  findViewByAccessibilityId(int accessibilityId) {
+    final <T extends View> T findViewByAccessibilityId(int accessibilityId) {
         if (accessibilityId < 0) {
             return null;
         }
@@ -21488,11 +21510,11 @@
     }
 
     /**
-     * Performs the traversal to find a view by its unuque and stable accessibility id.
+     * Performs the traversal to find a view by its unique and stable accessibility id.
      *
      * <strong>Note:</strong>This method does not stop at the root namespace
      * boundary since the user can touch the screen at an arbitrary location
-     * potentially crossing the root namespace bounday which will send an
+     * potentially crossing the root namespace boundary which will send an
      * accessibility event to accessibility services and they should be able
      * to obtain the event source. Also accessibility ids are guaranteed to be
      * unique in the window.
@@ -21509,6 +21531,23 @@
     }
 
     /**
+     * Performs the traversal to find a view by its autofill id.
+     *
+     * <strong>Note:</strong>This method does not stop at the root namespace
+     * boundary.
+     *
+     * @param autofillId The autofill id.
+     * @return The found view.
+     * @hide
+     */
+    public <T extends View> T findViewByAutofillIdTraversal(int autofillId) {
+        if (getAutofillViewId() == autofillId) {
+            return (T) this;
+        }
+        return null;
+    }
+
+    /**
      * Look for a child view with the given tag.  If this view has the given
      * tag, return this view.
      *
@@ -24974,13 +25013,13 @@
     public static class BaseSavedState extends AbsSavedState {
         static final int START_ACTIVITY_REQUESTED_WHO_SAVED = 0b1;
         static final int IS_AUTOFILLED = 0b10;
-        static final int ACCESSIBILITY_ID = 0b100;
+        static final int AUTOFILL_ID = 0b100;
 
         // Flags that describe what data in this state is valid
         int mSavedData;
         String mStartActivityRequestWhoSaved;
         boolean mIsAutofilled;
-        int mAccessibilityViewId;
+        int mAutofillViewId;
 
         /**
          * Constructor used when reading from a parcel. Reads the state of the superclass.
@@ -25003,7 +25042,7 @@
             mSavedData = source.readInt();
             mStartActivityRequestWhoSaved = source.readString();
             mIsAutofilled = source.readBoolean();
-            mAccessibilityViewId = source.readInt();
+            mAutofillViewId = source.readInt();
         }
 
         /**
@@ -25022,7 +25061,7 @@
             out.writeInt(mSavedData);
             out.writeString(mStartActivityRequestWhoSaved);
             out.writeBoolean(mIsAutofilled);
-            out.writeInt(mAccessibilityViewId);
+            out.writeInt(mAutofillViewId);
         }
 
         public static final Parcelable.Creator<BaseSavedState> CREATOR
@@ -26273,9 +26312,6 @@
                 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip;
             }
             mTooltipInfo.mTooltipText = tooltipText;
-            if (mTooltipInfo.mTooltipPopup != null && mTooltipInfo.mTooltipPopup.isShowing()) {
-                mTooltipInfo.mTooltipPopup.updateContent(mTooltipInfo.mTooltipText);
-            }
         }
     }
 
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 4b79b8c..66df335 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1361,6 +1361,27 @@
         return null;
     }
 
+    /** @hide */
+    @Override
+    public View findViewByAutofillIdTraversal(int autofillId) {
+        View foundView = super.findViewByAutofillIdTraversal(autofillId);
+        if (foundView != null) {
+            return foundView;
+        }
+
+        final int childrenCount = mChildrenCount;
+        final View[] children = mChildren;
+        for (int i = 0; i < childrenCount; i++) {
+            View child = children[i];
+            foundView = child.findViewByAutofillIdTraversal(autofillId);
+            if (foundView != null) {
+                return foundView;
+            }
+        }
+
+        return null;
+    }
+
     @Override
     public void dispatchWindowFocusChanged(boolean hasFocus) {
         super.dispatchWindowFocusChanged(hasFocus);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 2605b4a..fd950db 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2471,6 +2471,9 @@
         mInLayout = true;
 
         final View host = mView;
+        if (host == null) {
+            return;
+        }
         if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
             Log.v(mTag, "Laying out " + host + " to (" +
                     host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
@@ -2778,6 +2781,8 @@
     private void performDraw() {
         if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
             return;
+        } else if (mView == null) {
+            return;
         }
 
         final boolean fullRedrawNeeded = mFullRedrawNeeded;
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 41a8b8a..bdadcc7 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -912,14 +912,14 @@
     }
 
     /**
-     * Notifies that the availability of the accessibility button in the system's navigation area
+     * Notifies that the visibility of the accessibility button in the system's navigation area
      * has changed.
      *
-     * @param available {@code true} if the accessibility button is available within the system
+     * @param shown {@code true} if the accessibility button is visible within the system
      *                  navigation area, {@code false} otherwise
      * @hide
      */
-    public void notifyAccessibilityButtonAvailabilityChanged(boolean available) {
+    public void notifyAccessibilityButtonVisibilityChanged(boolean shown) {
         final IAccessibilityManager service;
         synchronized (mLock) {
             service = getServiceLocked();
@@ -928,9 +928,9 @@
             }
         }
         try {
-            service.notifyAccessibilityButtonAvailabilityChanged(available);
+            service.notifyAccessibilityButtonVisibilityChanged(shown);
         } catch (RemoteException re) {
-            Log.e(LOG_TAG, "Error while dispatching accessibility button availability change", re);
+            Log.e(LOG_TAG, "Error while dispatching accessibility button visibility change", re);
         }
     }
 
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 06cb5dc..3f499ab 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -64,7 +64,7 @@
 
     void notifyAccessibilityButtonClicked();
 
-    void notifyAccessibilityButtonAvailabilityChanged(boolean available);
+    void notifyAccessibilityButtonVisibilityChanged(boolean available);
 
     // Requires WRITE_SECURE_SETTINGS
     void performAccessibilityShortcut();
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 310ec1c..5b04f41 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -246,20 +246,20 @@
         /**
          * Finds views by traversing the hierarchies of the client.
          *
-         * @param viewIds The accessibility ids of the views to find
+         * @param viewIds The autofill ids of the views to find
          *
          * @return And array containing the views (empty if no views found).
          */
-        @NonNull View[] findViewsByAccessibilityIdTraversal(@NonNull int[] viewIds);
+        @NonNull View[] findViewsByAutofillIdTraversal(@NonNull int[] viewIds);
 
         /**
          * Finds a view by traversing the hierarchies of the client.
          *
-         * @param viewId The accessibility id of the views to find
+         * @param viewId The autofill id of the views to find
          *
          * @return The view, or {@code null} if not found
          */
-        @Nullable View findViewByAccessibilityIdTraversal(int viewId);
+        @Nullable View findViewByAutofillIdTraversal(int viewId);
 
         /**
          * Runs the specified action on the UI thread.
@@ -795,11 +795,11 @@
     }
 
     private static AutofillId getAutofillId(View view) {
-        return new AutofillId(view.getAccessibilityViewId());
+        return new AutofillId(view.getAutofillViewId());
     }
 
     private static AutofillId getAutofillId(View parent, int virtualId) {
-        return new AutofillId(parent.getAccessibilityViewId(), virtualId);
+        return new AutofillId(parent.getAutofillViewId(), virtualId);
     }
 
     private void startSessionLocked(@NonNull AutofillId id, @NonNull Rect bounds,
@@ -1039,7 +1039,7 @@
             final int itemCount = ids.size();
             int numApplied = 0;
             ArrayMap<View, SparseArray<AutofillValue>> virtualValues = null;
-            final View[] views = client.findViewsByAccessibilityIdTraversal(getViewIds(ids));
+            final View[] views = client.findViewsByAutofillIdTraversal(getViewIds(ids));
 
             for (int i = 0; i < itemCount; i++) {
                 final AutofillId id = ids.get(i);
@@ -1232,7 +1232,7 @@
             return null;
         }
 
-        return client.findViewByAccessibilityIdTraversal(autofillId.getViewId());
+        return client.findViewByAutofillIdTraversal(autofillId.getViewId());
     }
 
     /** @hide */
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 0e6e3ae..45e5f8a 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -2584,14 +2584,18 @@
         if (offset == -1) {
             return;
         }
+
         stopTextActionModeWithPreservingSelection();
-        final boolean isOnSelection = mTextView.hasSelection()
-                && offset >= mTextView.getSelectionStart() && offset <= mTextView.getSelectionEnd();
-        if (!isOnSelection) {
-            // Right clicked position is not on the selection. Remove the selection and move the
-            // cursor to the right clicked position.
-            Selection.setSelection((Spannable) mTextView.getText(), offset);
-            stopTextActionMode();
+        if (mTextView.canSelectText()) {
+            final boolean isOnSelection = mTextView.hasSelection()
+                    && offset >= mTextView.getSelectionStart()
+                    && offset <= mTextView.getSelectionEnd();
+            if (!isOnSelection) {
+                // Right clicked position is not on the selection. Remove the selection and move the
+                // cursor to the right clicked position.
+                Selection.setSelection((Spannable) mTextView.getText(), offset);
+                stopTextActionMode();
+            }
         }
 
         if (shouldOfferToShowSuggestions()) {
diff --git a/core/java/com/android/internal/view/TooltipPopup.java b/core/java/com/android/internal/view/TooltipPopup.java
index 52357ac..3930214 100644
--- a/core/java/com/android/internal/view/TooltipPopup.java
+++ b/core/java/com/android/internal/view/TooltipPopup.java
@@ -91,10 +91,6 @@
         return mContentView.getParent() != null;
     }
 
-    public void updateContent(CharSequence tooltipText) {
-        mMessageView.setText(tooltipText);
-    }
-
     private void computePosition(View anchorView, int anchorX, int anchorY, boolean fromTouch,
             WindowManager.LayoutParams outParams) {
         outParams.token = anchorView.getWindowToken();
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 5839fd5..7744e0c 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -394,6 +394,16 @@
 
 static jlong nativeCreateFromSurfaceControl(JNIEnv* env, jclass clazz,
         jlong surfaceControlNativeObj) {
+    sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
+    sp<Surface> surface(ctrl->createSurface());
+    if (surface != NULL) {
+        surface->incStrong(&sRefBaseOwner);
+    }
+    return reinterpret_cast<jlong>(surface.get());
+}
+
+static jlong nativeGetFromSurfaceControl(JNIEnv* env, jclass clazz,
+        jlong surfaceControlNativeObj) {
     /*
      * This is used by the WindowManagerService just after constructing
      * a Surface and is necessary for returning the Surface reference to
@@ -590,6 +600,8 @@
             (void*)nativeAllocateBuffers },
     {"nativeCreateFromSurfaceControl", "(J)J",
             (void*)nativeCreateFromSurfaceControl },
+    {"nativeGetFromSurfaceControl", "(J)J",
+            (void*)nativeGetFromSurfaceControl },
     {"nativeReadFromParcel", "(JLandroid/os/Parcel;)J",
             (void*)nativeReadFromParcel },
     {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V",
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 3251771..8139176 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1288,10 +1288,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN aktiveres af <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="1610714069627824309">"Tryk for at administrere netværket."</string>
     <string name="vpn_text_long" msgid="4907843483284977618">"Forbundet til <xliff:g id="SESSION">%s</xliff:g>. Tryk for at administrere netværket."</string>
-    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Opretter forbindelse til altid aktiveret VPN…"</string>
-    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Altid aktiveret VPN er forbundet"</string>
-    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Forbindelsen til altid aktiveret VPN er afbrudt"</string>
-    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Fejl i altid aktiveret VPN"</string>
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Opretter forbindelse til konstant VPN…"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Konstant VPN er forbundet"</string>
+    <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Forbindelsen til konstant VPN er afbrudt"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Fejl i konstant VPN"</string>
     <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tryk for at konfigurere"</string>
     <string name="upload_file" msgid="2897957172366730416">"Vælg fil"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Ingen fil er valgt"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 778163c..a341a8a 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -447,7 +447,7 @@
     <string name="permlab_changeTetherState" msgid="5952584964373017960">"Tethering-Konnektivität ändern"</string>
     <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Ermöglicht der App, den Status der Tethering-Konnektivität zu ändern"</string>
     <string name="permlab_accessWifiState" msgid="5202012949247040011">"WLAN-Verbindungen abrufen"</string>
-    <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Ermöglicht der App, Informationen zu WLANs abzurufen, etwa ob ein WLAN aktiviert ist, und den Namen verbundener WLAN-Geräte."</string>
+    <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Ermöglicht der App, Informationen zu WLAN-Netzwerken abzurufen, etwa ob ein WLAN aktiviert ist, und den Namen verbundener WLAN-Geräte."</string>
     <string name="permlab_changeWifiState" msgid="6550641188749128035">"WLAN-Verbindungen herstellen und trennen"</string>
     <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Ermöglicht der App, eine Verbindung zu WLAN-Zugangspunkten herzustellen und solche zu trennen und Änderungen an der Gerätekonfiguration für WLAN-Netzwerke vorzunehmen."</string>
     <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"WLAN-Multicast-Empfang zulassen"</string>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
index 6140428..41952df 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
@@ -16,6 +16,8 @@
 
 package com.android.printspooler.model;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -29,21 +31,27 @@
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.print.PageRange;
 import android.print.PrintAttributes;
-import android.print.PrintAttributes.MediaSize;
 import android.print.PrintAttributes.Margins;
+import android.print.PrintAttributes.MediaSize;
 import android.print.PrintDocumentInfo;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.view.View;
+
 import com.android.internal.annotations.GuardedBy;
 import com.android.printspooler.renderer.IPdfRenderer;
 import com.android.printspooler.renderer.PdfManipulationService;
 import com.android.printspooler.util.BitmapSerializeUtils;
+import com.android.printspooler.util.PageRangeUtils;
+
 import dalvik.system.CloseGuard;
+
 import libcore.io.IoUtils;
 
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.Map;
@@ -69,8 +77,9 @@
 
     private RenderSpec mLastRenderSpec;
 
-    private int mScheduledPreloadFirstShownPage = INVALID_PAGE_INDEX;
-    private int mScheduledPreloadLastShownPage = INVALID_PAGE_INDEX;
+    @Nullable private PageRange mScheduledPreloadVisiblePages;
+    @Nullable private PageRange[] mScheduledPreloadSelectedPages;
+    @Nullable private PageRange[] mScheduledPreloadWrittenPages;
 
     private int mState;
 
@@ -129,14 +138,24 @@
         }
     }
 
-    public void startPreload(int firstShownPage, int lastShownPage) {
+    /**
+     * Preload selected, written pages around visiblePages.
+     *
+     * @param visiblePages The pages currently visible
+     * @param selectedPages The pages currently selected (e.g. they might become visible by
+     *                      scrolling)
+     * @param writtenPages The pages currently in the document
+     */
+    public void startPreload(@NonNull PageRange visiblePages, @NonNull PageRange[] selectedPages,
+            @NonNull PageRange[] writtenPages) {
         // If we do not have a render spec we have no clue what size the
         // preloaded bitmaps should be, so just take a note for what to do.
         if (mLastRenderSpec == null) {
-            mScheduledPreloadFirstShownPage = firstShownPage;
-            mScheduledPreloadLastShownPage = lastShownPage;
+            mScheduledPreloadVisiblePages = visiblePages;
+            mScheduledPreloadSelectedPages = selectedPages;
+            mScheduledPreloadWrittenPages = writtenPages;
         } else if (mState == STATE_OPENED) {
-            mRenderer.startPreload(firstShownPage, lastShownPage, mLastRenderSpec);
+            mRenderer.startPreload(visiblePages, selectedPages, writtenPages, mLastRenderSpec);
         }
     }
 
@@ -222,11 +241,12 @@
 
             // We tired to preload but didn't know the bitmap size, now
             // that we know let us do the work.
-            if (mScheduledPreloadFirstShownPage != INVALID_PAGE_INDEX
-                    && mScheduledPreloadLastShownPage != INVALID_PAGE_INDEX) {
-                startPreload(mScheduledPreloadFirstShownPage, mScheduledPreloadLastShownPage);
-                mScheduledPreloadFirstShownPage = INVALID_PAGE_INDEX;
-                mScheduledPreloadLastShownPage = INVALID_PAGE_INDEX;
+            if (mScheduledPreloadVisiblePages != null) {
+                startPreload(mScheduledPreloadVisiblePages, mScheduledPreloadSelectedPages,
+                        mScheduledPreloadWrittenPages);
+                mScheduledPreloadVisiblePages = null;
+                mScheduledPreloadSelectedPages = null;
+                mScheduledPreloadWrittenPages = null;
             }
 
             if (mState == STATE_OPENED) {
@@ -523,10 +543,45 @@
             mDestroyed = true;
         }
 
-        public void startPreload(int firstShownPage, int lastShownPage, RenderSpec renderSpec) {
+        /**
+         * How many pages are {@code pages} before pageNum. E.g. page 5 in [0-1], [4-7] has the
+         * index 4.
+         *
+         * @param pageNum The number of the page to find
+         * @param pages A normalized array of page ranges
+         *
+         * @return The index or {@link #INVALID_PAGE_INDEX} if not found
+         */
+        private int findIndexOfPage(int pageNum, @NonNull PageRange[] pages) {
+            int pagesBefore = 0;
+            for (int i = 0; i < pages.length; i++) {
+                if (pages[i].contains(pageNum)) {
+                    return pagesBefore + pageNum - pages[i].getStart();
+                } else {
+                    pagesBefore += pages[i].getSize();
+                }
+            }
+
+            return INVALID_PAGE_INDEX;
+        }
+
+        void startPreload(@NonNull PageRange visiblePages, @NonNull PageRange[] selectedPages,
+                @NonNull PageRange[] writtenPages, RenderSpec renderSpec) {
+            if (PageRangeUtils.isAllPages(selectedPages)) {
+                selectedPages = new PageRange[]{new PageRange(0, mPageCount - 1)};
+            }
+
             if (DEBUG) {
-                Log.i(LOG_TAG, "Preloading pages around [" + firstShownPage
-                        + "-" + lastShownPage + "]");
+                Log.i(LOG_TAG, "Preloading pages around " + visiblePages + " from "
+                        + Arrays.toString(selectedPages));
+            }
+
+            int firstVisiblePageIndex = findIndexOfPage(visiblePages.getStart(), selectedPages);
+            int lastVisiblePageIndex = findIndexOfPage(visiblePages.getEnd(), selectedPages);
+
+            if (firstVisiblePageIndex == INVALID_PAGE_INDEX
+                    || lastVisiblePageIndex == INVALID_PAGE_INDEX) {
+                return;
             }
 
             final int bitmapSizeInBytes = renderSpec.bitmapWidth * renderSpec.bitmapHeight
@@ -534,28 +589,33 @@
             final int maxCachedPageCount = mPageContentCache.getMaxSizeInBytes()
                     / bitmapSizeInBytes;
             final int halfPreloadCount = (maxCachedPageCount
-                    - (lastShownPage - firstShownPage)) / 2 - 1;
+                    - (lastVisiblePageIndex - firstVisiblePageIndex)) / 2 - 1;
 
-            final int excessFromStart;
-            if (firstShownPage - halfPreloadCount < 0) {
-                excessFromStart = halfPreloadCount - firstShownPage;
-            } else {
-                excessFromStart = 0;
+            final int fromIndex = Math.max(firstVisiblePageIndex - halfPreloadCount, 0);
+            final int toIndex = lastVisiblePageIndex + halfPreloadCount;
+
+            if (DEBUG) {
+                Log.i(LOG_TAG, "fromIndex=" + fromIndex + " toIndex=" + toIndex);
             }
 
-            final int excessFromEnd;
-            if (lastShownPage + halfPreloadCount >= mPageCount) {
-                excessFromEnd = (lastShownPage + halfPreloadCount) - mPageCount;
-            } else {
-                excessFromEnd = 0;
-            }
+            int previousRangeSizes = 0;
+            for (int rangeNum = 0; rangeNum < selectedPages.length; rangeNum++) {
+                PageRange range = selectedPages[rangeNum];
 
-            final int fromIndex = Math.max(firstShownPage - halfPreloadCount - excessFromEnd, 0);
-            final int toIndex = Math.min(lastShownPage + halfPreloadCount + excessFromStart,
-                    mPageCount - 1);
+                int thisRangeStart = Math.max(0, fromIndex - previousRangeSizes);
+                int thisRangeEnd = Math.min(range.getSize(), toIndex - previousRangeSizes + 1);
 
-            for (int i = fromIndex; i <= toIndex; i++) {
-                renderPage(i, renderSpec, null);
+                for (int i = thisRangeStart; i < thisRangeEnd; i++) {
+                    if (PageRangeUtils.contains(writtenPages, range.getStart() + i)) {
+                        if (DEBUG) {
+                            Log.i(LOG_TAG, "Preloading " + (range.getStart() + i));
+                        }
+
+                        renderPage(range.getStart() + i, renderSpec, null);
+                    }
+                }
+
+                previousRangeSizes += range.getSize();
             }
         }
 
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
index 54400b3..1eadb8e 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
@@ -16,6 +16,7 @@
 
 package com.android.printspooler.ui;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -24,8 +25,8 @@
 import android.os.Looper;
 import android.os.ParcelFileDescriptor;
 import android.print.PageRange;
-import android.print.PrintAttributes.MediaSize;
 import android.print.PrintAttributes.Margins;
+import android.print.PrintAttributes.MediaSize;
 import android.print.PrintDocumentInfo;
 import android.support.v7.widget.RecyclerView.Adapter;
 import android.support.v7.widget.RecyclerView.ViewHolder;
@@ -33,11 +34,12 @@
 import android.util.SparseArray;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.View.MeasureSpec;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
-import android.view.View.MeasureSpec;
 import android.widget.TextView;
+
 import com.android.printspooler.R;
 import com.android.printspooler.model.OpenDocumentCallback;
 import com.android.printspooler.model.PageContentRepository;
@@ -45,6 +47,7 @@
 import com.android.printspooler.util.PageRangeUtils;
 import com.android.printspooler.widget.PageContentView;
 import com.android.printspooler.widget.PreviewPageFrame;
+
 import dalvik.system.CloseGuard;
 
 import java.util.ArrayList;
@@ -794,14 +797,16 @@
         page.setTag(null);
     }
 
-    public void startPreloadContent(PageRange pageRangeInAdapter) {
-        final int startPageInDocument = computePageIndexInDocument(pageRangeInAdapter.getStart());
-        final int startPageInFile = computePageIndexInFile(startPageInDocument);
-        final int endPageInDocument = computePageIndexInDocument(pageRangeInAdapter.getEnd());
-        final int endPageInFile = computePageIndexInFile(endPageInDocument);
-        if (startPageInDocument != INVALID_PAGE_INDEX && endPageInDocument != INVALID_PAGE_INDEX) {
-            mPageContentRepository.startPreload(startPageInFile, endPageInFile);
+    void startPreloadContent(@NonNull PageRange visiblePagesInAdapter) {
+        int startVisibleDocument = computePageIndexInDocument(visiblePagesInAdapter.getStart());
+        int endVisibleDocument = computePageIndexInDocument(visiblePagesInAdapter.getEnd());
+        if (startVisibleDocument == INVALID_PAGE_INDEX
+                || endVisibleDocument == INVALID_PAGE_INDEX) {
+            return;
         }
+
+        mPageContentRepository.startPreload(new PageRange(startVisibleDocument, endVisibleDocument),
+                mSelectedPages, mWrittenPages);
     }
 
     public void stopPreloadContent() {
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 48bf180..f5d5140 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -273,7 +273,7 @@
     <string name="show_all_anrs" msgid="28462979638729082">"Tots els errors sense resposta"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Informa que una aplicació en segon pla no respon"</string>
     <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Mostra avisos del canal de notificacions"</string>
-    <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Mostra un avís a la pantalla quan una app publica una notificació sense canal vàlid"</string>
+    <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Mostra un avís a la pantalla quan una aplicació publica una notificació sense un canal vàlid"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Força permís d\'aplicacions a l\'emmagatzem. extern"</string>
     <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Permet que qualsevol aplicació es pugui escriure en un dispositiu d’emmagatzematge extern, independentment dels valors definits"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Força l\'ajust de la mida de les activitats"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 00f0b5e..6889e01 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -272,8 +272,8 @@
     <string name="app_process_limit_title" msgid="4280600650253107163">"Limite proc. em 2º plano"</string>
     <string name="show_all_anrs" msgid="28462979638729082">"Mostrar todos os ANR"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Mostrar erro \"Aplic. não Resp.\" p/ aplic. 2º plano"</string>
-    <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Mostrar avisos do canal de notif."</string>
-    <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Mostra um aviso no ecrã quando uma aplic. publica uma notific. sem um canal válido"</string>
+    <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Mostrar avisos do canal de notificações"</string>
+    <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Mostra um aviso no ecrã quando uma aplicação publica uma notificação sem o canal ser válido"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Forçar perm. de aplicações no armazenamento ext."</string>
     <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Torna qualquer aplicação elegível para ser gravada no armazenamento externo, independentemente dos valores do manifesto"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Forçar as atividades a serem redimensionáveis"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 33b973d..9a0b1bf 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -79,7 +79,7 @@
     <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"取消"</string>
     <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"配對完成後,所配對的裝置即可在連線後存取你的聯絡人和通話紀錄。"</string>
     <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"無法與 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 配對。"</string>
-    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"無法與 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 配對,因為 PIN 或密碼金鑰不正確。"</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"無法與 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 配對,因為 PIN 碼或密碼金鑰不正確。"</string>
     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"無法與 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 通訊。"</string>
     <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」拒絕配對要求。"</string>
     <string name="accessibility_wifi_off" msgid="1166761729660614716">"已關閉 Wi-Fi。"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 623d1a6..0ea9d96 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -511,7 +511,10 @@
             }
         }
 
-        mSeen = seen;
+        // Only replace the previous value if we have a recent scan result to use
+        if (seen != 0) {
+            mSeen = seen;
+        }
     }
 
     /**
@@ -940,8 +943,10 @@
         security = getSecurity(result);
         if (security == SECURITY_PSK)
             pskType = getPskType(result);
-        mRssi = result.level;
-        mSeen = result.timestamp;
+
+        mScanResultCache.put(result.BSSID, result);
+        updateRssi();
+        mSeen = result.timestamp; // even if the timestamp is old it is still valid
     }
 
     public void saveWifiState(Bundle savedState) {
diff --git a/packages/SystemUI/res/layout/navigation_bar_window.xml b/packages/SystemUI/res/layout/navigation_bar_window.xml
index 051bf3a..6fa46d4 100644
--- a/packages/SystemUI/res/layout/navigation_bar_window.xml
+++ b/packages/SystemUI/res/layout/navigation_bar_window.xml
@@ -16,11 +16,11 @@
 ** limitations under the License.
 */
 -->
-<FrameLayout
+<com.android.systemui.statusbar.phone.NavigationBarFrame
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:id="@+id/navigation_bar_frame"
     android:layout_height="match_parent"
     android:layout_width="match_parent">
 
-</FrameLayout>
+</com.android.systemui.statusbar.phone.NavigationBarFrame>
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index cf8747e..96a7112 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -234,6 +234,7 @@
         scaledLayoutParams.setMargins(0, 0, 0, marginBottom);
 
         mBatteryIconView.setLayoutParams(scaledLayoutParams);
+        FontSizeUtils.updateFontSize(mBatteryPercentView, R.dimen.qs_time_expanded_size);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
index 2d0fe6f..4d0e60d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
@@ -32,6 +32,7 @@
 
 import com.android.systemui.R;
 import com.android.systemui.plugins.qs.*;
+import com.android.systemui.plugins.qs.QSTile.BooleanState;
 
 public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView {
 
@@ -44,6 +45,7 @@
     private String mAccessibilityClass;
     private boolean mTileState;
     private boolean mCollapsedView;
+    private boolean mClicked;
 
     public QSTileBaseView(Context context, QSIconView icon) {
         this(context, icon, false);
@@ -153,7 +155,11 @@
         setContentDescription(state.contentDescription);
         mAccessibilityClass = state.expandedAccessibilityClassName;
         if (state instanceof QSTile.BooleanState) {
-            mTileState = ((QSTile.BooleanState) state).value;
+            boolean newState = ((BooleanState) state).value;
+            if (mTileState != newState) {
+                mClicked = false;
+                mTileState = newState;
+            }
         }
     }
 
@@ -173,15 +179,22 @@
     }
 
     @Override
+    public boolean performClick() {
+        mClicked = true;
+        return super.performClick();
+    }
+
+    @Override
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
         super.onInitializeAccessibilityEvent(event);
         if (!TextUtils.isEmpty(mAccessibilityClass)) {
             event.setClassName(mAccessibilityClass);
             if (Switch.class.getName().equals(mAccessibilityClass)) {
+                boolean b = mClicked ? !mTileState : mTileState;
                 String label = getResources()
-                        .getString(!mTileState ? R.string.switch_bar_on : R.string.switch_bar_off);
+                        .getString(b ? R.string.switch_bar_on : R.string.switch_bar_off);
                 event.setContentDescription(label);
-                event.setChecked(!mTileState);
+                event.setChecked(b);
             }
         }
     }
@@ -192,10 +205,11 @@
         if (!TextUtils.isEmpty(mAccessibilityClass)) {
             info.setClassName(mAccessibilityClass);
             if (Switch.class.getName().equals(mAccessibilityClass)) {
+                boolean b = mClicked ? !mTileState : mTileState;
                 String label = getResources()
-                        .getString(mTileState ? R.string.switch_bar_on : R.string.switch_bar_off);
+                        .getString(b ? R.string.switch_bar_on : R.string.switch_bar_off);
                 info.setText(label);
-                info.setChecked(mTileState);
+                info.setChecked(b);
                 info.setCheckable(true);
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 76f6e7d..f26afcc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -32,17 +32,16 @@
 import com.android.settingslib.wifi.AccessPoint;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.R.string;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.DetailAdapter;
-import com.android.systemui.qs.QSDetailItems;
-import com.android.systemui.qs.QSDetailItems.Item;
-import com.android.systemui.qs.QSHost;
 import com.android.systemui.plugins.qs.QSIconView;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTile.SignalState;
-import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.qs.QSDetailItems;
+import com.android.systemui.qs.QSDetailItems.Item;
+import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.SignalTileView;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
@@ -180,7 +179,7 @@
                 minimalContentDescription.append(removeDoubleQuotes(cb.enabledDesc));
             }
         }
-        state.contentDescription = minimalContentDescription;
+        state.contentDescription = minimalContentDescription.toString();
         state.dualLabelContentDescription = r.getString(
                 R.string.accessibility_quick_settings_open_settings, getTileLabel());
         state.expandedAccessibilityClassName = Switch.class.getName();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
index 7eaa290..bf926c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
@@ -48,6 +48,7 @@
  */
 public class NotificationInflater {
 
+    public static final String TAG = "NotificationInflater";
     @VisibleForTesting
     static final int FLAG_REINFLATE_ALL = ~0;
     private static final int FLAG_REINFLATE_CONTENT_VIEW = 1<<0;
@@ -315,7 +316,8 @@
         return cancellationSignal;
     }
 
-    private static void applyRemoteView(final InflationProgress result,
+    @VisibleForTesting
+    static void applyRemoteView(final InflationProgress result,
             final int reInflateFlags, int inflationId,
             final ExpandableNotificationRow row,
             final boolean redactAmbient, boolean isNewView,
@@ -325,6 +327,7 @@
             NotificationViewWrapper existingWrapper,
             final HashMap<Integer, CancellationSignal> runningInflations,
             ApplyCallback applyCallback) {
+        RemoteViews newContentView = applyCallback.getRemoteView();
         RemoteViews.OnViewAppliedListener listener
                 = new RemoteViews.OnViewAppliedListener() {
 
@@ -343,12 +346,31 @@
 
             @Override
             public void onError(Exception e) {
-                runningInflations.remove(inflationId);
-                handleInflationError(runningInflations, e, entry.notification, callback);
+                // Uh oh the async inflation failed. Due to some bugs (see b/38190555), this could
+                // actually also be a system issue, so let's try on the UI thread again to be safe.
+                try {
+                    View newView = existingView;
+                    if (isNewView) {
+                        newView = newContentView.apply(
+                                result.packageContext,
+                                parentLayout,
+                                remoteViewClickHandler);
+                    } else {
+                        newContentView.reapply(
+                                result.packageContext,
+                                existingView,
+                                remoteViewClickHandler);
+                    }
+                    Log.wtf(TAG, "Async Inflation failed but normal inflation finished normally.",
+                            e);
+                    onViewApplied(newView);
+                } catch (Exception anotherException) {
+                    runningInflations.remove(inflationId);
+                    handleInflationError(runningInflations, e, entry.notification, callback);
+                }
             }
         };
         CancellationSignal cancellationSignal;
-        RemoteViews newContentView = applyCallback.getRemoteView();
         if (isNewView) {
             cancellationSignal = newContentView.applyAsync(
                     result.packageContext,
@@ -620,14 +642,16 @@
         }
     }
 
-    private static class InflationProgress {
+    @VisibleForTesting
+    static class InflationProgress {
         private RemoteViews newContentView;
         private RemoteViews newHeadsUpView;
         private RemoteViews newExpandedView;
         private RemoteViews newAmbientView;
         private RemoteViews newPublicView;
 
-        private Context packageContext;
+        @VisibleForTesting
+        Context packageContext;
 
         private View inflatedContentView;
         private View inflatedHeadsUpView;
@@ -636,7 +660,8 @@
         private View inflatedPublicView;
     }
 
-    private abstract static class ApplyCallback {
+    @VisibleForTesting
+    abstract static class ApplyCallback {
         public abstract void setResultView(View v);
         public abstract RemoteViews getRemoteView();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFrame.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFrame.java
new file mode 100644
index 0000000..741f783
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFrame.java
@@ -0,0 +1,59 @@
+/*
+ * 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.phone;
+
+import static android.view.MotionEvent.ACTION_OUTSIDE;
+
+import android.annotation.AttrRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.FrameLayout;
+
+import com.android.systemui.statusbar.policy.DeadZone;
+
+public class NavigationBarFrame extends FrameLayout {
+
+    private DeadZone mDeadZone = null;
+
+    public NavigationBarFrame(@NonNull Context context) {
+        super(context);
+    }
+
+    public NavigationBarFrame(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public NavigationBarFrame(@NonNull Context context, @Nullable AttributeSet attrs,
+            @AttrRes int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public void setDeadZone(@NonNull DeadZone deadZone) {
+        mDeadZone = deadZone;
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent event) {
+        if (event.getAction() == ACTION_OUTSIDE) {
+            if (mDeadZone != null) {
+                return mDeadZone.onTouchEvent(event);
+            }
+        }
+        return super.dispatchTouchEvent(event);
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 8d9d461..0557cb1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -250,9 +250,6 @@
         if (mGestureHelper.onTouchEvent(event)) {
             return true;
         }
-        if (mDeadZone != null && event.getAction() == MotionEvent.ACTION_OUTSIDE) {
-            mDeadZone.poke(event);
-        }
         return super.onTouchEvent(event);
     }
 
@@ -614,9 +611,8 @@
     public void reorient() {
         updateCurrentView();
 
-        getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
-
         mDeadZone = (DeadZone) mCurrentView.findViewById(R.id.deadzone);
+        ((NavigationBarFrame) getRootView()).setDeadZone(mDeadZone);
         mDeadZone.setDisplayRotation(mCurrentRotation);
 
         // force the low profile & disabled states into compliance
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 74a7e51..f58fe82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -5050,6 +5050,12 @@
         mDozing = mDozingRequested && mState == StatusBarState.KEYGUARD
                 || mFingerprintUnlockController.getMode()
                         == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
+        // When in wake-and-unlock we may not have received a change to mState
+        // but we still should not be dozing, manually set to false.
+        if (mFingerprintUnlockController.getMode() ==
+                FingerprintUnlockController.MODE_WAKE_AND_UNLOCK) {
+            mDozing = false;
+        }
         mStatusBarWindowManager.setDozing(mDozing);
         updateDozingState();
         Trace.endSection();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
index 4c879c6..13ee23f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
@@ -127,6 +127,7 @@
         final int action = event.getAction();
         if (action == MotionEvent.ACTION_OUTSIDE) {
             poke(event);
+            return true;
         } else if (action == MotionEvent.ACTION_DOWN) {
             if (DEBUG) {
                 Slog.v(TAG, this + " ACTION_DOWN: " + event.getX() + "," + event.getY());
@@ -158,7 +159,7 @@
         return false;
     }
 
-    public void poke(MotionEvent event) {
+    private void poke(MotionEvent event) {
         mLastPokeTime = event.getEventTime();
         if (DEBUG)
             Slog.v(TAG, "poked! size=" + getSize(mLastPokeTime));
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 ee8db88..3429d5c 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
@@ -24,12 +24,17 @@
 
 import android.app.Notification;
 import android.content.Context;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.Looper;
 import android.service.notification.StatusBarNotification;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.FlakyTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+import android.view.ViewGroup;
 import android.widget.RemoteViews;
 
 import com.android.systemui.R;
@@ -45,7 +50,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.HashMap;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -141,6 +148,41 @@
         Assert.assertNull(mRow.getEntry().getRunningTask());
     }
 
+    @Test
+    public void testInflationIsRetriedIfAsyncFails() throws Exception {
+        NotificationInflater.InflationProgress result =
+                new NotificationInflater.InflationProgress();
+        result.packageContext = mContext;
+        CountDownLatch countDownLatch = new CountDownLatch(1);
+        NotificationInflater.applyRemoteView(result,
+                NotificationInflater.FLAG_REINFLATE_EXPANDED_VIEW, 0, mRow,
+                false /* redactAmbient */, true /* isNewView */, new RemoteViews.OnClickHandler(),
+                new NotificationInflater.InflationCallback() {
+                    @Override
+                    public void handleInflationException(StatusBarNotification notification,
+                            Exception e) {
+                        countDownLatch.countDown();
+                        throw new RuntimeException("No Exception expected");
+                    }
+
+                    @Override
+                    public void onAsyncInflationFinished(NotificationData.Entry entry) {
+                        countDownLatch.countDown();
+                    }
+                }, mRow.getEntry(), mRow.getPrivateLayout(), null, null, new HashMap<>(),
+                new NotificationInflater.ApplyCallback() {
+                    @Override
+                    public void setResultView(View v) {
+                    }
+
+                    @Override
+                    public RemoteViews getRemoteView() {
+                        return new AsyncFailRemoteView(mContext.getPackageName(),
+                                R.layout.custom_view_dark);
+                    }
+                });
+        countDownLatch.await();
+    }
 
     @Test
     public void testSupersedesExistingTask() throws Exception {
@@ -199,4 +241,30 @@
             mException = exception;
         }
     }
+
+    private class AsyncFailRemoteView extends RemoteViews {
+        Handler mHandler = new Handler(Looper.getMainLooper());
+
+        public AsyncFailRemoteView(String packageName, int layoutId) {
+            super(packageName, layoutId);
+        }
+
+        @Override
+        public View apply(Context context, ViewGroup parent) {
+            return super.apply(context, parent);
+        }
+
+        @Override
+        public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor,
+                OnViewAppliedListener listener, OnClickHandler handler) {
+            mHandler.post(() -> listener.onError(new RuntimeException("Failed to inflate async")));
+            return new CancellationSignal();
+        }
+
+        @Override
+        public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor,
+                OnViewAppliedListener listener) {
+            return applyAsync(context, parent, executor, listener, null);
+        }
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
index a120cec..4cc83f6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
@@ -14,7 +14,6 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -33,17 +32,13 @@
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
-import com.android.systemui.utils.leaks.BaseLeakChecker;
 
 import android.testing.TestableLooper.RunWithLooper;
-import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper(setAsMainLooper = true)
@@ -54,6 +49,10 @@
         super(NavigationBarFragment.class);
     }
 
+    protected void createRootView() {
+        mView = new NavigationBarFrame(mContext);
+    }
+
     @Before
     public void setup() {
         mDependency.injectTestDependency(Dependency.BG_LOOPER, Looper.getMainLooper());
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index fa78f10..7ddc1a2 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -243,6 +243,8 @@
 
     private WindowsForAccessibilityCallback mWindowsForAccessibilityCallback;
 
+    private boolean mIsAccessibilityButtonShown;
+
     private UserState getCurrentUserStateLocked() {
         return getUserStateLocked(mCurrentUserId);
     }
@@ -881,21 +883,21 @@
     }
 
     /**
-     * Invoked remotely over AIDL by SysUi when the availability of the accessibility
+     * Invoked remotely over AIDL by SysUi when the visibility of the accessibility
      * button within the system's navigation area has changed.
      *
-     * @param available {@code true} if the accessibility button is available to the
+     * @param shown {@code true} if the accessibility button is shown to the
      *                  user, {@code false} otherwise
      */
     @Override
-    public void notifyAccessibilityButtonAvailabilityChanged(boolean available) {
+    public void notifyAccessibilityButtonVisibilityChanged(boolean shown) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Caller does not hold permission "
                     + android.Manifest.permission.STATUS_BAR_SERVICE);
         }
         synchronized (mLock) {
-            notifyAccessibilityButtonAvailabilityChangedLocked(available);
+            notifyAccessibilityButtonVisibilityChangedLocked(shown);
         }
     }
 
@@ -1200,13 +1202,14 @@
         }
     }
 
-    private void notifyAccessibilityButtonAvailabilityChangedLocked(boolean available) {
+    private void notifyAccessibilityButtonVisibilityChangedLocked(boolean available) {
         final UserState state = getCurrentUserStateLocked();
-        state.mIsAccessibilityButtonAvailable = available;
+        mIsAccessibilityButtonShown = available;
         for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
             final Service service = state.mBoundServices.get(i);
             if (service.mRequestAccessibilityButton) {
-                service.notifyAccessibilityButtonAvailabilityChangedLocked(available);
+                service.notifyAccessibilityButtonAvailabilityChangedLocked(
+                        service.isAccessibilityButtonAvailableLocked(state));
             }
         }
     }
@@ -1733,7 +1736,7 @@
         scheduleUpdateInputFilter(userState);
         scheduleUpdateClientsIfNeededLocked(userState);
         updateRelevantEventsLocked(userState);
-        updateAccessibilityButtonTargets(userState);
+        updateAccessibilityButtonTargetsLocked(userState);
     }
 
     private void updateAccessibilityFocusBehaviorLocked(UserState userState) {
@@ -2183,18 +2186,12 @@
         }
     }
 
-    private void updateAccessibilityButtonTargets(UserState userState) {
-        final List<Service> services;
-        synchronized (mLock) {
-            services = userState.mBoundServices;
-            int numServices = services.size();
-            for (int i = 0; i < numServices; i++) {
-                final Service service = services.get(i);
-                if (service.mRequestAccessibilityButton) {
-                    boolean available = service.mComponentName.equals(
-                            userState.mServiceAssignedToAccessibilityButton);
-                    service.notifyAccessibilityButtonAvailabilityChangedLocked(available);
-                }
+    private void updateAccessibilityButtonTargetsLocked(UserState userState) {
+        for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
+            final Service service = userState.mBoundServices.get(i);
+            if (service.mRequestAccessibilityButton) {
+                service.notifyAccessibilityButtonAvailabilityChangedLocked(
+                        service.isAccessibilityButtonAvailableLocked(userState));
             }
         }
     }
@@ -2501,7 +2498,7 @@
 
                 case MSG_SHOW_ACCESSIBILITY_BUTTON_CHOOSER: {
                     showAccessibilityButtonTargetSelection();
-                }
+                } break;
             }
         }
 
@@ -2656,6 +2653,10 @@
 
         boolean mRequestAccessibilityButton;
 
+        boolean mReceivedAccessibilityButtonCallbackSinceBind;
+
+        boolean mLastAccessibilityButtonCallbackState;
+
         int mFetchFlags;
 
         long mNotificationTimeout;
@@ -3596,9 +3597,8 @@
                     return false;
                 }
                 userState = getCurrentUserStateLocked();
+                return isAccessibilityButtonAvailableLocked(userState);
             }
-
-            return mRequestAccessibilityButton && userState.mIsAccessibilityButtonAvailable;
         }
 
         @Override
@@ -3656,6 +3656,7 @@
                 mService = null;
             }
             mServiceInterface = null;
+            mReceivedAccessibilityButtonCallbackSinceBind = false;
         }
 
         public boolean isConnectedLocked() {
@@ -3728,6 +3729,48 @@
             }
         }
 
+        private boolean isAccessibilityButtonAvailableLocked(UserState userState) {
+            // If the service does not request the accessibility button, it isn't available
+            if (!mRequestAccessibilityButton) {
+                return false;
+            }
+
+            // If the accessibility button isn't currently shown, it cannot be available to services
+            if (!mIsAccessibilityButtonShown) {
+                return false;
+            }
+
+            // If magnification is on and assigned to the accessibility button, services cannot be
+            if (userState.mIsNavBarMagnificationEnabled
+                    && userState.mIsNavBarMagnificationAssignedToAccessibilityButton) {
+                return false;
+            }
+
+            int requestingServices = 0;
+            for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
+                final Service service = userState.mBoundServices.get(i);
+                if (service.mRequestAccessibilityButton) {
+                    requestingServices++;
+                }
+            }
+
+            if (requestingServices == 1) {
+                // If only a single service is requesting, it must be this service, and the
+                // accessibility button is available to it
+                return true;
+            } else {
+                // With more than one active service, we derive the target from the user's settings
+                if (userState.mServiceAssignedToAccessibilityButton == null) {
+                    // If the user has not made an assignment, we treat the button as available to
+                    // all services until the user interacts with the button to make an assignment
+                    return true;
+                } else {
+                    // If an assignment was made, it defines availability
+                    return mComponentName.equals(userState.mServiceAssignedToAccessibilityButton);
+                }
+            }
+        }
+
         /**
          * Notifies an accessibility service client for a scheduled event given the event type.
          *
@@ -3875,6 +3918,13 @@
         }
 
         private void notifyAccessibilityButtonAvailabilityChangedInternal(boolean available) {
+            // Only notify the service if it's not been notified or the state has changed
+            if (mReceivedAccessibilityButtonCallbackSinceBind
+                    && (mLastAccessibilityButtonCallbackState == available)) {
+                return;
+            }
+            mReceivedAccessibilityButtonCallbackSinceBind = true;
+            mLastAccessibilityButtonCallbackState = available;
             final IAccessibilityServiceClient listener;
             synchronized (mLock) {
                 listener = mServiceInterface;
@@ -4874,7 +4924,6 @@
 
         public int mSoftKeyboardShowMode = 0;
 
-        public boolean mIsAccessibilityButtonAvailable;
         public boolean mIsNavBarMagnificationAssignedToAccessibilityButton;
         public ComponentName mServiceAssignedToAccessibilityButton;
 
@@ -4954,9 +5003,6 @@
             mIsNavBarMagnificationAssignedToAccessibilityButton = false;
             mIsAutoclickEnabled = false;
             mSoftKeyboardShowMode = 0;
-
-            // Clear state tracked from system UI
-            mIsAccessibilityButtonAvailable = false;
         }
 
         public void destroyUiAutomationService() {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 073d7b2..3ae0511 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -255,7 +255,9 @@
 
             final ViewNode node = nodes[i];
             if (node == null) {
-                Slog.w(TAG, "fillStructureWithAllowedValues(): no node for " + viewState.id);
+                if (sVerbose) {
+                    Slog.v(TAG, "fillStructureWithAllowedValues(): no node for " + viewState.id);
+                }
                 continue;
             }
 
@@ -862,11 +864,9 @@
         final int numContexts = mContexts.size();
         for (int i = 0; i < numContexts; i++) {
             final FillContext context = mContexts.get(i);
-            // TODO: create a function that gets just one node so it doesn't create an array
-            // unnecessarily
-            final ViewNode[] nodes = context.findViewNodesByAutofillIds(id);
-            if (nodes != null) {
-                AutofillValue candidate = nodes[0].getAutofillValue();
+            final ViewNode node = context.findViewNodeByAutofillId(id);
+            if (node != null) {
+                final AutofillValue candidate = node.getAutofillValue();
                 if (sDebug) {
                     Slog.d(TAG, "getValueFromContexts(" + id + ") at " + i + ": " + candidate);
                 }
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index de144777..756e274 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -626,19 +626,19 @@
                             != ActivityManager.APP_START_MODE_NORMAL) {
                         if (stopping == null) {
                             stopping = new ArrayList<>();
-                            String compName = service.name.flattenToShortString();
-                            EventLogTags.writeAmStopIdleService(service.appInfo.uid, compName);
-                            StringBuilder sb = new StringBuilder(64);
-                            sb.append("Stopping service due to app idle: ");
-                            UserHandle.formatUid(sb, service.appInfo.uid);
-                            sb.append(" ");
-                            TimeUtils.formatDuration(service.createTime
-                                    - SystemClock.elapsedRealtime(), sb);
-                            sb.append(" ");
-                            sb.append(compName);
-                            Slog.w(TAG, sb.toString());
-                            stopping.add(service);
                         }
+                        String compName = service.name.flattenToShortString();
+                        EventLogTags.writeAmStopIdleService(service.appInfo.uid, compName);
+                        StringBuilder sb = new StringBuilder(64);
+                        sb.append("Stopping service due to app idle: ");
+                        UserHandle.formatUid(sb, service.appInfo.uid);
+                        sb.append(" ");
+                        TimeUtils.formatDuration(service.createTime
+                                - SystemClock.elapsedRealtime(), sb);
+                        sb.append(" ");
+                        sb.append(compName);
+                        Slog.w(TAG, sb.toString());
+                        stopping.add(service);
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4d44b63..6c3a8a4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4136,7 +4136,8 @@
                             ri.activityInfo.packageName, ri.activityInfo.name));
                     mActivityStarter.startActivityLocked(null, intent, null /*ephemeralIntent*/,
                             null, ri.activityInfo, null /*rInfo*/, null, null, null, null, 0, 0, 0,
-                            null, 0, 0, 0, null, false, false, null, null, null);
+                            null, 0, 0, 0, null, false, false, null, null, null,
+                            "startSetupActivity");
                 }
             }
         }
@@ -4475,8 +4476,9 @@
         container.checkEmbeddedAllowedInner(userId, intent, mimeType);
 
         intent.addFlags(FORCE_NEW_TASK_FLAGS);
-        return mActivityStarter.startActivityMayWait(null, -1, null, intent, mimeType, null, null, null,
-                null, 0, 0, null, null, null, null, false, userId, container, null);
+        return mActivityStarter.startActivityMayWait(null, -1, null, intent, mimeType, null, null,
+                null, null, 0, 0, null, null, null, null, false, userId, container, null,
+                "startActivity");
     }
 
     @Override
@@ -4489,7 +4491,8 @@
         // TODO: Switch to user app stacks here.
         return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                 resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
-                profilerInfo, null, null, bOptions, false, userId, null, null);
+                profilerInfo, null, null, bOptions, false, userId, null, null,
+                "startActivityAsUser");
     }
 
     @Override
@@ -4552,7 +4555,8 @@
         try {
             int ret = mActivityStarter.startActivityMayWait(null, targetUid, targetPackage, intent,
                     resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, null,
-                    null, null, bOptions, ignoreTargetSecurity, userId, null, null);
+                    null, null, bOptions, ignoreTargetSecurity, userId, null, null,
+                    "startActivityAsCaller");
             return ret;
         } catch (SecurityException e) {
             // XXX need to figure out how to propagate to original app.
@@ -4581,7 +4585,7 @@
         // TODO: Switch to user app stacks here.
         mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
                 null, null, resultTo, resultWho, requestCode, startFlags, profilerInfo, res, null,
-                bOptions, false, userId, null, null);
+                bOptions, false, userId, null, null, "startActivityAndWait");
         return res;
     }
 
@@ -4595,7 +4599,7 @@
         // TODO: Switch to user app stacks here.
         int ret = mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                 resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
-                null, null, config, bOptions, false, userId, null, null);
+                null, null, config, bOptions, false, userId, null, null, "startActivityWithConfig");
         return ret;
     }
 
@@ -4652,7 +4656,7 @@
         // TODO: Switch to user app stacks here.
         return mActivityStarter.startActivityMayWait(null, callingUid, callingPackage, intent,
                 resolvedType, session, interactor, null, null, 0, startFlags, profilerInfo, null,
-                null, bOptions, false, userId, null, null);
+                null, bOptions, false, userId, null, null, "startVoiceActivity");
     }
 
     @Override
@@ -4671,7 +4675,7 @@
                 ALLOW_FULL_ONLY, "startAssistantActivity", null);
         return mActivityStarter.startActivityMayWait(null, callingUid, callingPackage, intent,
                 resolvedType, null, null, null, null, 0, 0, null, null, null, bOptions, false,
-                userId, null, null);
+                userId, null, null, "startAssistantActivity");
     }
 
     @Override
@@ -4844,7 +4848,7 @@
                     null /*ephemeralIntent*/, r.resolvedType, aInfo, null /*rInfo*/, null,
                     null, resultTo != null ? resultTo.appToken : null, resultWho, requestCode, -1,
                     r.launchedFromUid, r.launchedFromPackage, -1, r.launchedFromUid, 0, options,
-                    false, false, null, null, null);
+                    false, false, null, null, null, "startNextMatchingActivity");
             Binder.restoreCallingIdentity(origId);
 
             r.finishing = wasFinishing;
@@ -4876,7 +4880,7 @@
     final int startActivityInPackage(int uid, String callingPackage,
             Intent intent, String resolvedType, IBinder resultTo,
             String resultWho, int requestCode, int startFlags, Bundle bOptions, int userId,
-            IActivityContainer container, TaskRecord inTask) {
+            IActivityContainer container, TaskRecord inTask, String reason) {
 
         userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                 userId, false, ALLOW_FULL_ONLY, "startActivityInPackage", null);
@@ -4884,7 +4888,7 @@
         // TODO: Switch to user app stacks here.
         int ret = mActivityStarter.startActivityMayWait(null, uid, callingPackage, intent,
                 resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
-                null, null, null, bOptions, false, userId, container, inTask);
+                null, null, null, bOptions, false, userId, container, inTask, reason);
         return ret;
     }
 
@@ -4892,12 +4896,13 @@
     public final int startActivities(IApplicationThread caller, String callingPackage,
             Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle bOptions,
             int userId) {
-        enforceNotIsolatedCaller("startActivities");
+        final String reason = "startActivities";
+        enforceNotIsolatedCaller(reason);
         userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
-                userId, false, ALLOW_FULL_ONLY, "startActivity", null);
+                userId, false, ALLOW_FULL_ONLY, reason, null);
         // TODO: Switch to user app stacks here.
         int ret = mActivityStarter.startActivities(caller, -1, callingPackage, intents,
-                resolvedTypes, resultTo, bOptions, userId);
+                resolvedTypes, resultTo, bOptions, userId, reason);
         return ret;
     }
 
@@ -4905,11 +4910,12 @@
             Intent[] intents, String[] resolvedTypes, IBinder resultTo,
             Bundle bOptions, int userId) {
 
+        final String reason = "startActivityInPackage";
         userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
-                userId, false, ALLOW_FULL_ONLY, "startActivityInPackage", null);
+                userId, false, ALLOW_FULL_ONLY, reason, null);
         // TODO: Switch to user app stacks here.
         int ret = mActivityStarter.startActivities(null, uid, callingPackage, intents, resolvedTypes,
-                resultTo, bOptions, userId);
+                resultTo, bOptions, userId, reason);
         return ret;
     }
 
@@ -14941,6 +14947,10 @@
                 synchronized (this) {
                     dumpLastANRLocked(pw);
                 }
+            } else if ("starter".equals(cmd)) {
+                synchronized (this) {
+                    dumpActivityStarterLocked(pw);
+                }
             } else if ("recents".equals(cmd) || "r".equals(cmd)) {
                 synchronized (this) {
                     dumpRecentsLocked(fd, pw, args, opti, true, dumpPackage);
@@ -15174,6 +15184,11 @@
                 if (dumpAll) {
                     pw.println("-------------------------------------------------------------------------------");
                 }
+                dumpActivityStarterLocked(pw);
+                pw.println();
+                if (dumpAll) {
+                    pw.println("-------------------------------------------------------------------------------");
+                }
                 dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
                 if (mAssociations.size() > 0) {
                     pw.println();
@@ -15239,6 +15254,11 @@
                 if (dumpAll) {
                     pw.println("-------------------------------------------------------------------------------");
                 }
+                dumpActivityStarterLocked(pw);
+                pw.println();
+                if (dumpAll) {
+                    pw.println("-------------------------------------------------------------------------------");
+                }
                 dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
                 if (mAssociations.size() > 0) {
                     pw.println();
@@ -15258,14 +15278,19 @@
     }
 
     private void dumpLastANRLocked(PrintWriter pw) {
+        pw.println("ACTIVITY MANAGER ACTIVITIES (dumpsys activity lastanr)");
         if (mLastANRState == null) {
-            pw.println("ACTIVITY MANAGER ACTIVITIES (dumpsys activity lastanr)");
             pw.println("  <no ANR has occurred since boot>");
         } else {
             pw.println(mLastANRState);
         }
     }
 
+    private void dumpActivityStarterLocked(PrintWriter pw) {
+        pw.println("ACTIVITY MANAGER ACTIVITIES (dumpsys activity starter)");
+        mActivityStarter.dump(pw, "");
+    }
+
     void dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, boolean dumpClient, String dumpPackage) {
         dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage,
@@ -15292,7 +15317,6 @@
             if (needSep) {
                 pw.println();
             }
-            needSep = true;
             printedAnything = true;
             mStackSupervisor.dump(pw, "  ");
         }
@@ -24016,9 +24040,12 @@
                     pw.println("  Reason: " + reason);
                 }
                 pw.println();
+                mActivityStarter.dump(pw, "  ");
+                pw.println();
+                pw.println("-------------------------------------------------------------------------------");
                 dumpActivitiesLocked(null /* fd */, pw, null /* args */, 0 /* opti */,
                         true /* dumpAll */, false /* dumpClient */, null /* dumpPackage */,
-                        "ACTIVITY MANAGER ACTIVITIES (dumpsys activity lastanr)");
+                        "" /* header */);
                 pw.println();
                 pw.close();
 
@@ -24260,7 +24287,7 @@
             }
             return mActivityStarter.startActivityMayWait(appThread, -1, callingPackage, intent,
                     resolvedType, null, null, null, null, 0, 0, null, null,
-                    null, bOptions, false, callingUser, null, tr);
+                    null, bOptions, false, callingUser, null, tr, "AppTaskImpl");
         }
 
         @Override
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 9db957c..bde317a 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3920,7 +3920,7 @@
                             destIntent, null /*ephemeralIntent*/, null, aInfo, null /*rInfo*/, null,
                             null, parent.appToken, null, 0, -1, parent.launchedFromUid,
                             parent.launchedFromPackage, -1, parent.launchedFromUid, 0, null,
-                            false, true, null, null, null);
+                            false, true, null, null, null, "navigateUpTo");
                     foundParentInTask = res == ActivityManager.START_SUCCESS;
                 } catch (RemoteException e) {
                     foundParentInTask = false;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 7de56fa..fe0e07e 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2257,6 +2257,31 @@
         return null;
     }
 
+    /**
+     * Get next valid stack for launching provided activity in the system. This will search across
+     * displays and stacks in last-focused order for a focusable and visible stack, except those
+     * that are on a currently focused display.
+     *
+     * @param r The activity that is being launched.
+     * @param currentFocus The display that previously had focus and thus needs to be ignored when
+     *                     searching for the next candidate.
+     * @return Next valid {@link ActivityStack}, null if not found.
+     */
+    ActivityStack getNextValidLaunchStackLocked(@NonNull ActivityRecord r, int currentFocus) {
+        mWindowManager.getDisplaysInFocusOrder(mTmpOrderedDisplayIds);
+        for (int i = mTmpOrderedDisplayIds.size() - 1; i >= 0; --i) {
+            final int displayId = mTmpOrderedDisplayIds.get(i);
+            if (displayId == currentFocus) {
+                continue;
+            }
+            final ActivityStack stack = getValidLaunchStackOnDisplay(displayId, r);
+            if (stack != null) {
+                return stack;
+            }
+        }
+        return null;
+    }
+
     ActivityRecord getHomeActivity() {
         return getHomeActivityForUser(mCurrentUser);
     }
@@ -5155,7 +5180,7 @@
             intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
             userId = task.userId;
             int result = mService.startActivityInPackage(callingUid, callingPackage, intent, null,
-                    null, null, 0, 0, bOptions, userId, null, task);
+                    null, null, 0, 0, bOptions, userId, null, task, "startActivityFromRecents");
             if (launchStackId == DOCKED_STACK_ID) {
                 setResizingDuringAnimation(task);
             }
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 1ed2ac1..be30d5a 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -115,6 +115,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.service.voice.IVoiceInteractionSession;
+import android.text.TextUtils;
 import android.util.EventLog;
 import android.util.Slog;
 
@@ -124,7 +125,10 @@
 import com.android.server.pm.InstantAppResolver;
 import com.android.server.wm.WindowManagerService;
 
+import java.io.PrintWriter;
+import java.text.DateFormat;
 import java.util.ArrayList;
+import java.util.Date;
 
 /**
  * Controller for interpreting how and then launching activities.
@@ -188,6 +192,19 @@
 
     private boolean mUsingVr2dDisplay;
 
+    // Last home activity record we attempted to start
+    private final ActivityRecord[] mLastHomeActivityStartRecord = new ActivityRecord[1];
+    // The result of the last home activity we attempted to start.
+    private int mLastHomeActivityStartResult;
+    // Last activity record we attempted to start
+    private final ActivityRecord[] mLastStartActivityRecord = new ActivityRecord[1];
+    // The result of the last activity we attempted to start.
+    private int mLastStartActivityResult;
+    // Time in milli seconds we attempted to start the last activity.
+    private long mLastStartActivityTimeMs;
+    // The reason we were trying to start the last activity
+    private String mLastStartReason;
+
     private void reset() {
         mStartActivity = null;
         mIntent = null;
@@ -236,7 +253,37 @@
         mUsingVr2dDisplay = false;
     }
 
-    final int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
+    int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
+            String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
+            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+            IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
+            String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
+            ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
+            ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
+            TaskRecord inTask, String reason) {
+
+        if (TextUtils.isEmpty(reason)) {
+            throw new IllegalArgumentException("Need to specify a reason.");
+        }
+        mLastStartReason = reason;
+        mLastStartActivityTimeMs = System.currentTimeMillis();
+        mLastStartActivityRecord[0] = null;
+
+        mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
+                aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
+                callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
+                options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
+                container, inTask);
+
+        if (outActivity != null) {
+            // mLastStartActivityRecord[0] is set in the call to startActivity above.
+            outActivity[0] = mLastStartActivityRecord[0];
+        }
+        return mLastStartActivityResult;
+    }
+
+    /** DO NOT call this method directly. Use {@link #startActivityLocked} instead. */
+    private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
             String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
             IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
@@ -592,13 +639,14 @@
 
     void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {
         mSupervisor.moveHomeStackTaskToTop(reason);
-        startActivityLocked(null /*caller*/, intent, null /*ephemeralIntent*/,
-                null /*resolvedType*/, aInfo, null /*rInfo*/, null /*voiceSession*/,
-                null /*voiceInteractor*/, null /*resultTo*/, null /*resultWho*/,
-                0 /*requestCode*/, 0 /*callingPid*/, 0 /*callingUid*/, null /*callingPackage*/,
-                0 /*realCallingPid*/, 0 /*realCallingUid*/, 0 /*startFlags*/, null /*options*/,
-                false /*ignoreTargetSecurity*/, false /*componentSpecified*/, null /*outActivity*/,
-                null /*container*/, null /*inTask*/);
+        mLastHomeActivityStartResult = startActivityLocked(null /*caller*/, intent,
+                null /*ephemeralIntent*/, null /*resolvedType*/, aInfo, null /*rInfo*/,
+                null /*voiceSession*/, null /*voiceInteractor*/, null /*resultTo*/,
+                null /*resultWho*/, 0 /*requestCode*/, 0 /*callingPid*/, 0 /*callingUid*/,
+                null /*callingPackage*/, 0 /*realCallingPid*/, 0 /*realCallingUid*/,
+                0 /*startFlags*/, null /*options*/, false /*ignoreTargetSecurity*/,
+                false /*componentSpecified*/, mLastHomeActivityStartRecord /*outActivity*/,
+                null /*container*/, null /*inTask*/, "startHomeActivity: " + reason);
         if (mSupervisor.inResumeTopActivity) {
             // If we are in resume section already, home activity will be initialized, but not
             // resumed (to avoid recursive resume) and will stay that way until something pokes it
@@ -623,7 +671,7 @@
             IBinder resultTo, String resultWho, int requestCode, int startFlags,
             ProfilerInfo profilerInfo, WaitResult outResult,
             Configuration globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId,
-            IActivityContainer iContainer, TaskRecord inTask) {
+            IActivityContainer iContainer, TaskRecord inTask, String reason) {
         // Refuse possible leaked file descriptors
         if (intent != null && intent.hasFileDescriptors()) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -778,7 +826,7 @@
                     resultTo, resultWho, requestCode, callingPid,
                     callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                     options, ignoreTargetSecurity, componentSpecified, outRecord, container,
-                    inTask);
+                    inTask, reason);
 
             Binder.restoreCallingIdentity(origId);
 
@@ -841,7 +889,7 @@
 
     final int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
             Intent[] intents, String[] resolvedTypes, IBinder resultTo,
-            Bundle bOptions, int userId) {
+            Bundle bOptions, int userId, String reason) {
         if (intents == null) {
             throw new NullPointerException("intents is null");
         }
@@ -903,7 +951,7 @@
                             resolvedTypes[i], aInfo, null /*rInfo*/, null, null, resultTo, null, -1,
                             callingPid, callingUid, callingPackage,
                             realCallingPid, realCallingUid, 0,
-                            options, false, componentSpecified, outActivity, null, null);
+                            options, false, componentSpecified, outActivity, null, null, reason);
                     if (res < 0) {
                         return res;
                     }
@@ -2021,7 +2069,18 @@
             return mSupervisor.mFocusedStack;
         }
 
-        if (mSourceDisplayId == DEFAULT_DISPLAY) {
+        if (mSourceDisplayId != DEFAULT_DISPLAY) {
+            // Try to put the activity in a stack on a secondary display.
+            stack = mSupervisor.getValidLaunchStackOnDisplay(mSourceDisplayId, r);
+            if (stack == null) {
+                // If source display is not suitable - look for topmost valid stack in the system.
+                if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
+                        "computeStackFocus: Can't launch on mSourceDisplayId=" + mSourceDisplayId
+                                + ", looking on all displays.");
+                stack = mSupervisor.getNextValidLaunchStackLocked(r, mSourceDisplayId);
+            }
+        }
+        if (stack == null) {
             // We first try to put the task in the first dynamic stack on home display.
             final ArrayList<ActivityStack> homeDisplayStacks = mSupervisor.mHomeStack.mStacks;
             for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
@@ -2037,8 +2096,6 @@
                     bounds != null ? FREEFORM_WORKSPACE_STACK_ID :
                             FULLSCREEN_WORKSPACE_STACK_ID;
             stack = mSupervisor.getStack(stackId, CREATE_IF_NEEDED, ON_TOP);
-        } else {
-            stack = mSupervisor.getValidLaunchStackOnDisplay(mSourceDisplayId, r);
         }
         if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
                 + r + " stackId=" + stack.mStackId);
@@ -2246,4 +2303,40 @@
         }
         return didSomething;
     }
+
+    void dump(PrintWriter pw, String prefix) {
+        pw.println(prefix + "ActivityStarter:");
+        prefix = prefix + "  ";
+
+        pw.println(prefix + "mLastStartReason=" + mLastStartReason);
+        pw.println(prefix + "mLastStartActivityTimeMs="
+                + DateFormat.getDateTimeInstance().format(new Date(mLastStartActivityTimeMs)));
+        pw.println(prefix + "mLastStartActivityResult=" + mLastStartActivityResult);
+        ActivityRecord r = mLastStartActivityRecord[0];
+        if (r != null) {
+            pw.println(prefix + "mLastStartActivityRecord:");
+            r.dump(pw, prefix + " ");
+        }
+        pw.println(prefix + "mLastHomeActivityStartResult=" + mLastHomeActivityStartResult);
+        r = mLastHomeActivityStartRecord[0];
+        if (r != null) {
+            pw.println(prefix + "mLastHomeActivityStartRecord:");
+            r.dump(pw, prefix + " ");
+        }
+        if (mStartActivity != null) {
+            pw.println(prefix + "mStartActivity:");
+            mStartActivity.dump(pw, prefix + " ");
+        }
+        if (mIntent != null) {
+            pw.println(prefix + "mIntent=" + mIntent);
+        }
+        if (mOptions != null) {
+            pw.println(prefix + "mOptions=" + mOptions);
+        }
+        pw.println(prefix + "mLaunchSingleTop=" + mLaunchSingleTop
+                + " mLaunchSingleInstance=" + mLaunchSingleInstance
+                + " mLaunchSingleTask=" + mLaunchSingleTask
+                + " mLaunchFlags=0x" + Integer.toHexString(mLaunchFlags)
+                + " mDoResume=" + mDoResume + " mAddingToTask=" + mAddingToTask);
+    }
 }
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index cfb5478..8991537 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -411,7 +411,7 @@
                                     task.mCallingPackage, task.intent,
                                     null, null, null, 0, 0,
                                     ActivityOptions.makeBasic().toBundle(),
-                                    task.userId, null, null);
+                                    task.userId, null, null, "AppErrors");
                         }
                     }
                 }
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 639b7a9..b3a2c29 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -614,9 +614,10 @@
             skip = true;
         }
 
-        if (!skip && (filter.receiverList.app == null || filter.receiverList.app.crashing)) {
+        if (!skip && (filter.receiverList.app == null || filter.receiverList.app.killed
+                || filter.receiverList.app.crashing)) {
             Slog.w(TAG, "Skipping deliver [" + mQueueName + "] " + r
-                    + " to " + filter.receiverList + ": process crashing");
+                    + " to " + filter.receiverList + ": process gone or crashing");
             skip = true;
         }
 
@@ -1317,7 +1318,7 @@
             }
 
             // Is this receiver's application already running?
-            if (app != null && app.thread != null) {
+            if (app != null && app.thread != null && !app.killed) {
                 try {
                     app.addPackage(info.activityInfo.packageName,
                             info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 6eca3fa..cad5dcf 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -346,7 +346,7 @@
                             } else {
                                 owner.startActivityInPackage(uid, key.packageName, finalIntent,
                                         resolvedType, resultTo, resultWho, requestCode, 0,
-                                        options, userId, container, null);
+                                        options, userId, container, null, "PendingIntentRecord");
                             }
                         } catch (RuntimeException e) {
                             Slog.w(TAG, "Unable to send startActivity intent", e);
diff --git a/services/core/java/com/android/server/am/UserState.java b/services/core/java/com/android/server/am/UserState.java
index 9970c82..b89586d 100644
--- a/services/core/java/com/android/server/am/UserState.java
+++ b/services/core/java/com/android/server/am/UserState.java
@@ -69,7 +69,6 @@
     public boolean setState(int oldState, int newState) {
         if (state == oldState) {
             setState(newState);
-            EventLogTags.writeAmUserStateChanged(mHandle.getIdentifier(), newState);
             return true;
         } else {
             Slog.w(TAG, "Expected user " + mHandle.getIdentifier() + " in state "
@@ -84,6 +83,7 @@
         }
         Slog.i(TAG, "User " + mHandle.getIdentifier() + " state changed from "
                 + stateToString(state) + " to " + stateToString(newState));
+        EventLogTags.writeAmUserStateChanged(mHandle.getIdentifier(), newState);
         lastState = state;
         state = newState;
     }
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 5d3f6f7..107475f 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -438,7 +438,21 @@
             switch (message.what) {
                 case MSG_TIMEOUT:
                     synchronized (mLock) {
-                        handleOpTimeoutLocked();
+                        if (message.obj == mRunningCallback) {
+                            handleOpTimeoutLocked();
+                        } else {
+                            JobCallback jc = (JobCallback)message.obj;
+                            StringBuilder sb = new StringBuilder(128);
+                            sb.append("Ignoring timeout of no longer active job");
+                            if (jc.mStoppedReason != null) {
+                                sb.append(", stopped ");
+                                TimeUtils.formatDuration(SystemClock.elapsedRealtime()
+                                        - jc.mStoppedTime, sb);
+                                sb.append(" because: ");
+                                sb.append(jc.mStoppedReason);
+                            }
+                            Slog.w(TAG, sb.toString());
+                        }
                     }
                     break;
                 default:
@@ -621,7 +635,7 @@
     private void handleOpTimeoutLocked() {
         switch (mVerb) {
             case VERB_BINDING:
-                Slog.e(TAG, "Time-out while trying to bind " + mRunningJob.toShortString() +
+                Slog.w(TAG, "Time-out while trying to bind " + mRunningJob.toShortString() +
                         ", dropping.");
                 closeAndCleanupJobLocked(false /* needsReschedule */, "timed out while binding");
                 break;
@@ -629,26 +643,28 @@
                 // Client unresponsive - wedged or failed to respond in time. We don't really
                 // know what happened so let's log it and notify the JobScheduler
                 // FINISHED/NO-RETRY.
-                Slog.e(TAG, "No response from client for onStartJob '" +
-                        mRunningJob.toShortString());
+                Slog.w(TAG, "No response from client for onStartJob " +
+                        mRunningJob != null ? mRunningJob.toShortString() : "<null>");
                 closeAndCleanupJobLocked(false /* needsReschedule */, "timed out while starting");
                 break;
             case VERB_STOPPING:
                 // At least we got somewhere, so fail but ask the JobScheduler to reschedule.
-                Slog.e(TAG, "No response from client for onStopJob, '" +
-                        mRunningJob.toShortString());
+                Slog.w(TAG, "No response from client for onStopJob " +
+                        mRunningJob != null ? mRunningJob.toShortString() : "<null>");
                 closeAndCleanupJobLocked(true /* needsReschedule */, "timed out while stopping");
                 break;
             case VERB_EXECUTING:
                 // Not an error - client ran out of time.
-                Slog.i(TAG, "Client timed out while executing (no jobFinished received)." +
-                        " sending onStop. "  + mRunningJob.toShortString());
+                Slog.i(TAG, "Client timed out while executing (no jobFinished received), " +
+                        "sending onStop: "  +
+                        mRunningJob != null ? mRunningJob.toShortString() : "<null>");
                 mParams.setStopReason(JobParameters.REASON_TIMEOUT);
                 sendStopMessageLocked("timeout while executing");
                 break;
             default:
                 Slog.e(TAG, "Handling timeout for an invalid job state: " +
-                        mRunningJob.toShortString() + ", dropping.");
+                        mRunningJob != null ? mRunningJob.toShortString() : "<null>"
+                        + ", dropping.");
                 closeAndCleanupJobLocked(false /* needsReschedule */, "invalid timeout");
         }
     }
@@ -749,7 +765,7 @@
                     mRunningJob.getServiceComponent().getShortClassName() + "' jId: " +
                     mParams.getJobId() + ", in " + (timeoutMillis / 1000) + " s");
         }
-        Message m = mCallbackHandler.obtainMessage(MSG_TIMEOUT);
+        Message m = mCallbackHandler.obtainMessage(MSG_TIMEOUT, mRunningCallback);
         mCallbackHandler.sendMessageDelayed(m, timeoutMillis);
         mTimeoutElapsed = SystemClock.elapsedRealtime() + timeoutMillis;
     }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 61d69f9..bdea247 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -307,11 +307,15 @@
 
     // used as a mutex for access to all active notifications & listeners
     final Object mNotificationLock = new Object();
+    @GuardedBy("mNotificationLock")
     final ArrayList<NotificationRecord> mNotificationList =
             new ArrayList<NotificationRecord>();
+    @GuardedBy("mNotificationLock")
     final ArrayMap<String, NotificationRecord> mNotificationsByKey =
             new ArrayMap<String, NotificationRecord>();
+    @GuardedBy("mNotificationLock")
     final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
+    @GuardedBy("mNotificationLock")
     final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
     final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
     final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
@@ -2806,7 +2810,8 @@
             // Clear summary.
             final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
             if (removed != null) {
-                cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED);
+                boolean wasPosted = removeFromNotificationListsLocked(removed);
+                cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted);
             }
         }
     }
@@ -3420,7 +3425,8 @@
                     .setType(MetricsEvent.TYPE_CLOSE)
                     .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
                             mSnoozeCriterionId == null ? 0 : 1));
-            cancelNotificationLocked(r, false, REASON_SNOOZED);
+            boolean wasPosted = removeFromNotificationListsLocked(r);
+            cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted);
             updateLightsLocked();
             if (mSnoozeCriterionId != null) {
                 mNotificationAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
@@ -4206,15 +4212,18 @@
         manager.sendAccessibilityEvent(event);
     }
 
+    /**
+     * Removes all NotificationsRecords with the same key as the given notification record
+     * from both lists. Do not call this method while iterating over either list.
+     */
     @GuardedBy("mNotificationLock")
-    private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {
-        final String canceledKey = r.getKey();
-
-        // Remove from both lists, either list could have a separate Record for what is effectively
-        // the same notification.
+    private boolean removeFromNotificationListsLocked(NotificationRecord r) {
+        // Remove from both lists, either list could have a separate Record for what is
+        // effectively the same notification.
         boolean wasPosted = false;
         NotificationRecord recordInList = null;
-        if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey())) != null) {
+        if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
+                != null) {
             mNotificationList.remove(recordInList);
             mNotificationsByKey.remove(recordInList.sbn.getKey());
             wasPosted = true;
@@ -4223,6 +4232,13 @@
                 != null) {
             mEnqueuedNotifications.remove(recordInList);
         }
+        return wasPosted;
+    }
+
+    @GuardedBy("mNotificationLock")
+    private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
+            boolean wasPosted) {
+        final String canceledKey = r.getKey();
 
         // Record caller.
         recordCallerLocked(r);
@@ -4363,7 +4379,8 @@
                         }
 
                         // Cancel the notification.
-                        cancelNotificationLocked(r, sendDelete, reason);
+                        boolean wasPosted = removeFromNotificationListsLocked(r);
+                        cancelNotificationLocked(r, sendDelete, reason, wasPosted);
                         cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
                                 sendDelete);
                         updateLightsLocked();
@@ -4440,11 +4457,11 @@
                     cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
                             pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
                             false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
-                            listenerName);
+                            listenerName, true /* wasPosted */);
                     cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
                             callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
                             flagChecker, false /*includeCurrentProfiles*/, userId,
-                            false /*sendDelete*/, reason, listenerName);
+                            false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
                     mSnoozeHelper.cancel(userId, pkg);
                 }
             }
@@ -4460,7 +4477,7 @@
     private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
             int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
             String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
-            boolean sendDelete, int reason, String listenerName) {
+            boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
         ArrayList<NotificationRecord> canceledNotifications = null;
         for (int i = notificationList.size() - 1; i >= 0; --i) {
             NotificationRecord r = notificationList.get(i);
@@ -4488,8 +4505,9 @@
             if (canceledNotifications == null) {
                 canceledNotifications = new ArrayList<>();
             }
+            notificationList.remove(i);
             canceledNotifications.add(r);
-            cancelNotificationLocked(r, sendDelete, reason);
+            cancelNotificationLocked(r, sendDelete, reason, wasPosted);
         }
         if (canceledNotifications != null) {
             final int M = canceledNotifications.size();
@@ -4548,11 +4566,11 @@
                     cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
                             null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
                             includeCurrentProfiles, userId, true /*sendDelete*/, reason,
-                            listenerName);
+                            listenerName, true);
                     cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
                             callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
                             flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
-                            reason, listenerName);
+                            reason, listenerName, false);
                     mSnoozeHelper.cancel(userId, includeCurrentProfiles);
                 }
             }
@@ -4569,7 +4587,6 @@
         }
 
         String pkg = r.sbn.getPackageName();
-        int userId = r.getUserId();
 
         if (pkg == null) {
             if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
@@ -4577,15 +4594,15 @@
         }
 
         cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
-                sendDelete);
+                sendDelete, true);
         cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
-                listenerName, sendDelete);
+                listenerName, sendDelete, false);
     }
 
     @GuardedBy("mNotificationLock")
     private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
             NotificationRecord parentNotification, int callingUid, int callingPid,
-            String listenerName, boolean sendDelete) {
+            String listenerName, boolean sendDelete, boolean wasPosted) {
         final String pkg = parentNotification.sbn.getPackageName();
         final int userId = parentNotification.getUserId();
         final int reason = REASON_GROUP_SUMMARY_CANCELED;
@@ -4597,7 +4614,8 @@
                     && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0) {
                 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
                         childSbn.getTag(), userId, 0, 0, reason, listenerName);
-                cancelNotificationLocked(childR, sendDelete, reason);
+                notificationList.remove(i);
+                cancelNotificationLocked(childR, sendDelete, reason, wasPosted);
             }
         }
     }
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 8952870..6953ffd 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -25,6 +25,7 @@
 import android.app.NotificationChannel;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -170,6 +171,11 @@
     private Uri calculateSound() {
         final Notification n = sbn.getNotification();
 
+        // No notification sounds on tv
+        if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
+            return null;
+        }
+
         Uri sound = mChannel.getSound();
         if (mPreChannelsNotification && (getChannel().getUserLockedFields()
                 & NotificationChannel.USER_LOCKED_SOUND) == 0) {
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 2c0cc95..d7b36aa 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -53,6 +53,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -524,12 +525,11 @@
         if (r == null) {
             throw new IllegalArgumentException("Invalid package");
         }
-        LogMaker lm = new LogMaker(MetricsProto.MetricsEvent.ACTION_NOTIFICATION_CHANNEL_GROUP)
-                .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
-                .addTaggedData(MetricsProto.MetricsEvent.FIELD_NOTIFICATION_CHANNEL_GROUP_ID,
-                        group.getId())
-                .setPackageName(pkg);
-        MetricsLogger.action(lm);
+        final NotificationChannelGroup oldGroup = r.groups.get(group.getId());
+        if (!group.equals(oldGroup)) {
+            // will log for new entries as well as name changes
+            MetricsLogger.action(getChannelGroupLog(group.getId(), pkg));
+        }
         r.groups.put(group.getId(), group);
         updateConfig();
     }
@@ -557,13 +557,16 @@
         if (existing != null && fromTargetApp) {
             if (existing.isDeleted()) {
                 existing.setDeleted(false);
+
+                // log a resurrected channel as if it's new again
+                MetricsLogger.action(getChannelLog(channel, pkg).setType(
+                        MetricsProto.MetricsEvent.TYPE_OPEN));
             }
 
             existing.setName(channel.getName().toString());
             existing.setDescription(channel.getDescription());
             existing.setBlockableSystem(channel.isBlockableSystem());
 
-            MetricsLogger.action(getChannelLog(channel, pkg));
             updateConfig();
             return;
         }
@@ -621,7 +624,10 @@
             r.showBadge = updatedChannel.canShowBadge();
         }
 
-        MetricsLogger.action(getChannelLog(updatedChannel, pkg));
+        if (!channel.equals(updatedChannel)) {
+            // only log if there are real changes
+            MetricsLogger.action(getChannelLog(updatedChannel, pkg));
+        }
         updateConfig();
     }
 
@@ -1140,6 +1146,14 @@
                         channel.getImportance());
     }
 
+    private LogMaker getChannelGroupLog(String groupId, String pkg) {
+        return new LogMaker(MetricsProto.MetricsEvent.ACTION_NOTIFICATION_CHANNEL_GROUP)
+                .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
+                .addTaggedData(MetricsProto.MetricsEvent.FIELD_NOTIFICATION_CHANNEL_GROUP_ID,
+                        groupId)
+                .setPackageName(pkg);
+    }
+
     public void updateBadgingEnabled() {
         if (mBadgingEnabled == null) {
             mBadgingEnabled = new SparseBooleanArray();
@@ -1186,6 +1200,6 @@
         boolean showBadge = DEFAULT_SHOW_BADGE;
 
         ArrayMap<String, NotificationChannel> channels = new ArrayMap<>();
-        ArrayMap<String, NotificationChannelGroup> groups = new ArrayMap<>();
+        Map<String, NotificationChannelGroup> groups = new ConcurrentHashMap<>();
    }
 }
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index ef3e7bc..2940a6e 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -714,11 +714,17 @@
 
         final Map<String, List<String>> pendingChanges = new ArrayMap<>(targetPackageNames.size());
         synchronized (mLock) {
+            final List<String> frameworkOverlays =
+                mImpl.getEnabledOverlayPackageNames("android", userId);
             final int N = targetPackageNames.size();
             for (int i = 0; i < N; i++) {
                 final String targetPackageName = targetPackageNames.get(i);
-                pendingChanges.put(targetPackageName,
-                        mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
+                List<String> list = new ArrayList<>();
+                if (!"android".equals(targetPackageName)) {
+                    list.addAll(frameworkOverlays);
+                }
+                list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
+                pendingChanges.put(targetPackageName, list);
             }
         }
 
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 261bcc5..db6e974 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -170,6 +170,7 @@
 
         final PackageInfo targetPackage = mPackageManager.getPackageInfo(packageName, userId);
         updateAllOverlaysForTarget(packageName, userId, targetPackage);
+        mListener.onOverlaysChanged(packageName, userId);
     }
 
     void onTargetPackageChanged(@NonNull final String packageName, final int userId) {
@@ -178,7 +179,9 @@
         }
 
         final PackageInfo targetPackage = mPackageManager.getPackageInfo(packageName, userId);
-        updateAllOverlaysForTarget(packageName, userId, targetPackage);
+        if (updateAllOverlaysForTarget(packageName, userId, targetPackage)) {
+            mListener.onOverlaysChanged(packageName, userId);
+        }
     }
 
     void onTargetPackageUpgrading(@NonNull final String packageName, final int userId) {
@@ -186,7 +189,9 @@
             Slog.d(TAG, "onTargetPackageUpgrading packageName=" + packageName + " userId=" + userId);
         }
 
-        updateAllOverlaysForTarget(packageName, userId, null);
+        if (updateAllOverlaysForTarget(packageName, userId, null)) {
+            mListener.onOverlaysChanged(packageName, userId);
+        }
     }
 
     void onTargetPackageUpgraded(@NonNull final String packageName, final int userId) {
@@ -195,7 +200,9 @@
         }
 
         final PackageInfo targetPackage = mPackageManager.getPackageInfo(packageName, userId);
-        updateAllOverlaysForTarget(packageName, userId, targetPackage);
+        if (updateAllOverlaysForTarget(packageName, userId, targetPackage)) {
+            mListener.onOverlaysChanged(packageName, userId);
+        }
     }
 
     void onTargetPackageRemoved(@NonNull final String packageName, final int userId) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 54f2ffd..51f4e2e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -18123,8 +18123,10 @@
             // step during installation. Instead, we'll take extra time the first time the
             // instant app starts. It's preferred to do it this way to provide continuous
             // progress to the user instead of mysteriously blocking somewhere in the
-            // middle of running an instant app.
-            if (!instantApp) {
+            // middle of running an instant app. The default behaviour can be overridden
+            // via gservices.
+            if (!instantApp || Global.getInt(
+                        mContext.getContentResolver(), Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0) {
                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
                 // Do not run PackageDexOptimizer through the local performDexOpt
                 // method because `pkg` may not be in `mPackages` yet.
@@ -21603,8 +21605,7 @@
         public static final int DUMP_FROZEN = 1 << 19;
         public static final int DUMP_DEXOPT = 1 << 20;
         public static final int DUMP_COMPILER_STATS = 1 << 21;
-        public static final int DUMP_ENABLED_OVERLAYS = 1 << 22;
-        public static final int DUMP_CHANGES = 1 << 23;
+        public static final int DUMP_CHANGES = 1 << 22;
 
         public static final int OPTION_SHOW_FILTERS = 1 << 0;
 
@@ -21848,8 +21849,6 @@
                 dumpState.setDump(DumpState.DUMP_DEXOPT);
             } else if ("compiler-stats".equals(cmd)) {
                 dumpState.setDump(DumpState.DUMP_COMPILER_STATS);
-            } else if ("enabled-overlays".equals(cmd)) {
-                dumpState.setDump(DumpState.DUMP_ENABLED_OVERLAYS);
             } else if ("changes".equals(cmd)) {
                 dumpState.setDump(DumpState.DUMP_CHANGES);
             } else if ("write".equals(cmd)) {
@@ -24626,12 +24625,7 @@
                 }
 
                 final PackageSetting ps = mSettings.mPackages.get(targetPackageName);
-                String[] frameworkOverlayPaths = null;
-                if (!"android".equals(targetPackageName)) {
-                    frameworkOverlayPaths =
-                            mSettings.mPackages.get("android").getOverlayPaths(userId);
-                }
-                ps.setOverlayPaths(overlayPaths, frameworkOverlayPaths, userId);
+                ps.setOverlayPaths(overlayPaths, userId);
                 return true;
             }
         }
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index d17267f..f685127 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -330,21 +330,9 @@
         modifyUserState(userId).installReason = installReason;
     }
 
-    void setOverlayPaths(List<String> overlayPaths, String[] frameworkOverlayPaths, int userId) {
-        if (overlayPaths == null && frameworkOverlayPaths == null) {
-            modifyUserState(userId).overlayPaths = null;
-            return;
-        }
-        final List<String> paths;
-        if (frameworkOverlayPaths == null) {
-            paths = overlayPaths;
-        } else {
-            paths = Lists.newArrayList(frameworkOverlayPaths);
-            if (overlayPaths != null) {
-                paths.addAll(overlayPaths);
-            }
-        }
-        modifyUserState(userId).overlayPaths = paths.toArray(new String[paths.size()]);
+    void setOverlayPaths(List<String> overlayPaths, int userId) {
+        modifyUserState(userId).overlayPaths = overlayPaths == null ? null :
+            overlayPaths.toArray(new String[overlayPaths.size()]);
     }
 
     String[] getOverlayPaths(int userId) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index b006c2d..45d0c58 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4861,9 +4861,9 @@
 
             String[] overlayPaths = ps.getOverlayPaths(user.id);
             if (overlayPaths != null && overlayPaths.length > 0) {
-                pw.println("Overlay paths:");
+                pw.print(prefix); pw.println("  overlay paths:");
                 for (String path : overlayPaths) {
-                    pw.println(path);
+                    pw.print(prefix); pw.print("    "); pw.println(path);
                 }
             }
 
diff --git a/services/core/java/com/android/server/policy/BarController.java b/services/core/java/com/android/server/policy/BarController.java
index 7a28081..b179235 100644
--- a/services/core/java/com/android/server/policy/BarController.java
+++ b/services/core/java/com/android/server/policy/BarController.java
@@ -166,8 +166,14 @@
         return change || stateChanged;
     }
 
-    void setOnBarVisibilityChangedListener(OnBarVisibilityChangedListener listener) {
+    void setOnBarVisibilityChangedListener(OnBarVisibilityChangedListener listener,
+            boolean invokeWithState) {
         mVisibilityChangeListener = listener;
+        if (invokeWithState) {
+            // Optionally report the initial window state for initialization purposes
+            mHandler.obtainMessage(MSG_NAV_BAR_VISIBILITY_CHANGED,
+                    (mState == StatusBarManager.WINDOW_STATE_SHOWING) ? 1 : 0, 0).sendToTarget();
+        }
     }
 
     protected boolean skipAnimation() {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 01eabd8..8b28df1 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1045,7 +1045,7 @@
             new BarController.OnBarVisibilityChangedListener() {
         @Override
         public void onBarVisibilityChanged(boolean visible) {
-            mAccessibilityManager.notifyAccessibilityButtonAvailabilityChanged(visible);
+            mAccessibilityManager.notifyAccessibilityButtonVisibilityChanged(visible);
         }
     };
 
@@ -3037,7 +3037,7 @@
                 mNavigationBar = win;
                 mNavigationBarController.setWindow(win);
                 mNavigationBarController.setOnBarVisibilityChangedListener(
-                        mNavBarVisibilityListener);
+                        mNavBarVisibilityListener, true);
                 if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
                 break;
             case TYPE_NAVIGATION_BAR_PANEL:
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index c1c72ca..b1ed358 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -2044,7 +2044,10 @@
         if (forceOverride || isKeyguardTransit(transit) || !isTransitionSet()
                 || mNextAppTransition == TRANSIT_NONE) {
             setAppTransition(transit, flags);
-        } else if (!alwaysKeepCurrent) {
+        }
+        // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
+        // relies on the fact that we always execute a Keyguard transition after preparing one.
+        else if (!alwaysKeepCurrent && !isKeyguardTransit(transit)) {
             if (transit == TRANSIT_TASK_OPEN && isTransitionEqual(TRANSIT_TASK_CLOSE)) {
                 // Opening a new task always supersedes a close for the anim.
                 setAppTransition(transit, flags);
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 9a9e29a..6d33ce2 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -155,6 +155,10 @@
         mSnapAlgorithm = new PipSnapAlgorithm(service.mContext);
         mDisplayInfo.copyFrom(mDisplayContent.getDisplayInfo());
         reloadResources();
+        // Initialize the aspect ratio to the default aspect ratio.  Don't do this in reload
+        // resources as it would clobber mAspectRatio when entering PiP from fullscreen which
+        // triggers a configuration change and the resources to be reloaded.
+        mAspectRatio = mDefaultAspectRatio;
     }
 
     void onConfigurationChanged() {
@@ -171,7 +175,6 @@
         mCurrentMinSize = mDefaultMinSize;
         mDefaultAspectRatio = res.getFloat(
                 com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio);
-        mAspectRatio = mDefaultAspectRatio;
         final String screenEdgeInsetsDpString = res.getString(
                 com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets);
         final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 4442bb8..82c862f 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -25,6 +25,7 @@
 import static com.android.server.wm.AppTransition.TRANSIT_WALLPAPER_INTRA_CLOSE;
 import static com.android.server.wm.AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN;
 import static com.android.server.wm.AppTransition.TRANSIT_WALLPAPER_OPEN;
+import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
@@ -239,7 +240,7 @@
 
         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
         int transit = mService.mAppTransition.getAppTransition();
-        if (mService.mSkipAppTransitionAnimation) {
+        if (mService.mSkipAppTransitionAnimation && !isKeyguardGoingAwayTransit(transit)) {
             transit = AppTransition.TRANSIT_UNSET;
         }
         mService.mSkipAppTransitionAnimation = false;
@@ -598,42 +599,47 @@
                         + ", openingApps=" + openingApps
                         + ", closingApps=" + closingApps);
         mService.mAnimateWallpaperWithTarget = false;
-        if (closingAppHasWallpaper && openingAppHasWallpaper) {
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
-            switch (transit) {
-                case TRANSIT_ACTIVITY_OPEN:
-                case TRANSIT_TASK_OPEN:
-                case TRANSIT_TASK_TO_FRONT:
-                    transit = TRANSIT_WALLPAPER_INTRA_OPEN;
-                    break;
-                case TRANSIT_ACTIVITY_CLOSE:
-                case TRANSIT_TASK_CLOSE:
-                case TRANSIT_TASK_TO_BACK:
-                    transit = TRANSIT_WALLPAPER_INTRA_CLOSE;
-                    break;
-            }
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                    "New transit: " + AppTransition.appTransitionToString(transit));
-        } else if (openingCanBeWallpaperTarget && transit == TRANSIT_KEYGUARD_GOING_AWAY) {
+        if (openingCanBeWallpaperTarget && transit == TRANSIT_KEYGUARD_GOING_AWAY) {
             transit = TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
                     "New transit: " + AppTransition.appTransitionToString(transit));
-        } else if (oldWallpaper != null && !mService.mOpeningApps.isEmpty()
-                && !openingApps.contains(oldWallpaper.mAppToken)
-                && closingApps.contains(oldWallpaper.mAppToken)) {
-            // We are transitioning from an activity with a wallpaper to one without.
-            transit = TRANSIT_WALLPAPER_CLOSE;
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit away from wallpaper: "
-                    + AppTransition.appTransitionToString(transit));
-        } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw() &&
-                openingApps.contains(wallpaperTarget.mAppToken)) {
-            // We are transitioning from an activity without
-            // a wallpaper to now showing the wallpaper
-            transit = TRANSIT_WALLPAPER_OPEN;
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit into wallpaper: "
-                    + AppTransition.appTransitionToString(transit));
-        } else {
-            mService.mAnimateWallpaperWithTarget = true;
+        }
+        // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
+        // relies on the fact that we always execute a Keyguard transition after preparing one.
+        else if (!isKeyguardGoingAwayTransit(transit)) {
+            if (closingAppHasWallpaper && openingAppHasWallpaper) {
+                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
+                switch (transit) {
+                    case TRANSIT_ACTIVITY_OPEN:
+                    case TRANSIT_TASK_OPEN:
+                    case TRANSIT_TASK_TO_FRONT:
+                        transit = TRANSIT_WALLPAPER_INTRA_OPEN;
+                        break;
+                    case TRANSIT_ACTIVITY_CLOSE:
+                    case TRANSIT_TASK_CLOSE:
+                    case TRANSIT_TASK_TO_BACK:
+                        transit = TRANSIT_WALLPAPER_INTRA_CLOSE;
+                        break;
+                }
+                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                        "New transit: " + AppTransition.appTransitionToString(transit));
+            } else if (oldWallpaper != null && !mService.mOpeningApps.isEmpty()
+                    && !openingApps.contains(oldWallpaper.mAppToken)
+                    && closingApps.contains(oldWallpaper.mAppToken)) {
+                // We are transitioning from an activity with a wallpaper to one without.
+                transit = TRANSIT_WALLPAPER_CLOSE;
+                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit away from wallpaper: "
+                        + AppTransition.appTransitionToString(transit));
+            } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw() &&
+                    openingApps.contains(wallpaperTarget.mAppToken)) {
+                // We are transitioning from an activity without
+                // a wallpaper to now showing the wallpaper
+                transit = TRANSIT_WALLPAPER_OPEN;
+                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit into wallpaper: "
+                        + AppTransition.appTransitionToString(transit));
+            } else {
+                mService.mAnimateWallpaperWithTarget = true;
+            }
         }
         return transit;
     }
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index 75df892..5770c50 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -159,10 +159,12 @@
             readInstalledPrintServicesLocked();
             upgradePersistentStateIfNeeded();
             readDisabledPrintServicesLocked();
+        }
 
-            // Some print services might have gotten installed before the User State came up
-            prunePrintServices();
+        // Some print services might have gotten installed before the User State came up
+        prunePrintServices();
 
+        synchronized (mLock) {
             onConfigurationChangedLocked();
         }
     }
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 ec08874..ae98274 100644
--- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -20,40 +20,9 @@
 import static android.app.Notification.GROUP_ALERT_SUMMARY;
 import static android.app.NotificationManager.IMPORTANCE_HIGH;
 
-import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 
-import com.android.server.lights.Light;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import android.app.ActivityManager;
-import android.app.Notification;
-import android.app.Notification.Builder;
-import android.app.NotificationManager;
-import android.app.NotificationChannel;
-import android.graphics.Color;
-import android.media.AudioAttributes;
-import android.media.AudioManager;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.Vibrator;
-import android.os.VibrationEffect;
-import android.provider.Settings;
-import android.service.notification.StatusBarNotification;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import org.mockito.ArgumentMatcher;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyObject;
@@ -61,11 +30,43 @@
 import static org.mockito.Matchers.argThat;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+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.content.pm.PackageManager;
+import android.graphics.Color;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+import android.provider.Settings;
+import android.service.notification.StatusBarNotification;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.server.lights.Light;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class BuzzBeepBlinkTest extends NotificationTestCase {
@@ -163,6 +164,11 @@
                 true /* noisy */, false /* buzzy*/, false /* lights */);
     }
 
+    private NotificationRecord getInsistentBeepyLeanbackNotification() {
+        return getLeanbackNotificationRecord(mId, true /* insistent */, false /* once */,
+                true /* noisy */, false /* buzzy*/, false /* lights */);
+    }
+
     private NotificationRecord getBuzzyNotification() {
         return getNotificationRecord(mId, false /* insistent */, false /* once */,
                 false /* noisy */, true /* buzzy*/, false /* lights */);
@@ -192,23 +198,30 @@
         return getNotificationRecord(mId, false /* insistent */, true /* once */,
                 false /* noisy */, true /* buzzy*/, true /* lights */,
                 true /* defaultVibration */, true /* defaultSound */, false /* defaultLights */,
-                null, Notification.GROUP_ALERT_ALL);
+                null, Notification.GROUP_ALERT_ALL, false);
     }
 
     private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once,
             boolean noisy, boolean buzzy, boolean lights) {
         return getNotificationRecord(id, insistent, once, noisy, buzzy, lights, true, true, true,
-                null, Notification.GROUP_ALERT_ALL);
+                null, Notification.GROUP_ALERT_ALL, false);
+    }
+
+    private NotificationRecord getLeanbackNotificationRecord(int id, boolean insistent, boolean once,
+            boolean noisy, boolean buzzy, boolean lights) {
+        return getNotificationRecord(id, insistent, once, noisy, buzzy, lights, true, true, true,
+                null, Notification.GROUP_ALERT_ALL, true);
     }
 
     private NotificationRecord getBeepyNotificationRecord(String groupKey, int groupAlertBehavior) {
         return getNotificationRecord(mId, false, false, true, false, false, true, true, true,
-                groupKey, groupAlertBehavior);
+                groupKey, groupAlertBehavior, false);
     }
 
     private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once,
             boolean noisy, boolean buzzy, boolean lights, boolean defaultVibration,
-            boolean defaultSound, boolean defaultLights, String groupKey, int groupAlertBehavior) {
+            boolean defaultSound, boolean defaultLights, String groupKey, int groupAlertBehavior,
+            boolean isLeanback) {
         NotificationChannel channel =
                 new NotificationChannel("test", "test", IMPORTANCE_HIGH);
         final Builder builder = new Builder(getContext())
@@ -257,9 +270,15 @@
             n.flags |= Notification.FLAG_INSISTENT;
         }
 
+        Context context = spy(getContext());
+        PackageManager packageManager = spy(context.getPackageManager());
+        when(context.getPackageManager()).thenReturn(packageManager);
+        when(packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK))
+                .thenReturn(isLeanback);
+
         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid,
                 mPid, n, mUser, null, System.currentTimeMillis());
-        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
+        NotificationRecord r = new NotificationRecord(context, sbn, channel);
         mService.addNotification(r);
         return r;
     }
@@ -367,6 +386,15 @@
     }
 
     @Test
+    public void testNoLeanbackBeep() throws Exception {
+        NotificationRecord r = getInsistentBeepyLeanbackNotification();
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyNeverBeep();
+    }
+
+    @Test
     public void testNoInterruptionForMin() throws Exception {
         NotificationRecord r = getBeepyNotification();
         r.setImportance(NotificationManager.IMPORTANCE_MIN, "foo");
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 bd6e379..46c536c 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -357,6 +357,43 @@
     }
 
     @Test
+    public void testCancelAllNotificationsMultipleEnqueuedDoesNotCrash() throws Exception {
+        final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
+        for (int i = 0; i < 10; i++) {
+            mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+                    sbn.getId(), sbn.getNotification(), sbn.getUserId());
+        }
+        mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
+        waitForIdle();
+    }
+
+    @Test
+    public void testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash() throws Exception {
+        final NotificationRecord parent = generateNotificationRecord(
+                mTestNotificationChannel, 1, "group1", true);
+        final NotificationRecord parentAsChild = generateNotificationRecord(
+                mTestNotificationChannel, 1, "group1", false);
+        final NotificationRecord child = generateNotificationRecord(
+                mTestNotificationChannel, 2, "group1", false);
+
+        // fully post parent notification
+        mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+                parent.sbn.getId(), parent.sbn.getNotification(), parent.sbn.getUserId());
+        waitForIdle();
+
+        // enqueue the child several times
+        for (int i = 0; i < 10; i++) {
+            mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+                    child.sbn.getId(), child.sbn.getNotification(), child.sbn.getUserId());
+        }
+        // make the parent a child, which will cancel the child notification
+        mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+                parentAsChild.sbn.getId(), parentAsChild.sbn.getNotification(),
+                parentAsChild.sbn.getUserId());
+        waitForIdle();
+    }
+
+    @Test
     public void testCancelAllNotifications_IgnoreForegroundService() throws Exception {
         final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
         sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
diff --git a/tests/testables/src/android/testing/BaseFragmentTest.java b/tests/testables/src/android/testing/BaseFragmentTest.java
index 32ee091..f1e4d21 100644
--- a/tests/testables/src/android/testing/BaseFragmentTest.java
+++ b/tests/testables/src/android/testing/BaseFragmentTest.java
@@ -50,7 +50,7 @@
     private static final int VIEW_ID = 42;
     private final Class<? extends Fragment> mCls;
     private Handler mHandler;
-    private FrameLayout mView;
+    protected FrameLayout mView;
     protected FragmentController mFragments;
     protected Fragment mFragment;
 
@@ -61,9 +61,13 @@
         mCls = cls;
     }
 
+    protected void createRootView() {
+        mView = new FrameLayout(mContext);
+    }
+
     @Before
     public void setupFragment() throws Exception {
-        mView = new FrameLayout(mContext);
+        createRootView();
         mView.setId(VIEW_ID);
 
         assertNotNull("BaseFragmentTest must be tagged with @RunWithLooper",