Merge "Fix javadoc error in ApplicationExitInfo#getDefiningUid()" into rvc-dev
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index fe270a4..fed9c43 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -68,6 +68,8 @@
     private static final String COMMAND_UNREGISTER_PHONE_ACCOUNT = "unregister-phone-account";
     private static final String COMMAND_SET_DEFAULT_DIALER = "set-default-dialer";
     private static final String COMMAND_GET_DEFAULT_DIALER = "get-default-dialer";
+    private static final String COMMAND_STOP_BLOCK_SUPPRESSION = "stop-block-suppression";
+
     /**
      * Change the system dialer package name if a package name was specified,
      * Example: adb shell telecom set-system-dialer <PACKAGE>
@@ -115,6 +117,8 @@
                 + "usage: telecom set-sim-count <COUNT>\n"
                 + "usage: telecom get-sim-config\n"
                 + "usage: telecom get-max-phones\n"
+                + "usage: telecom stop-block-suppression: Stop suppressing the blocked number"
+                        + " provider after a call to emergency services.\n"
                 + "usage: telecom set-emer-phone-account-filter <PACKAGE>\n"
                 + "\n"
                 + "telecom set-phone-account-enabled: Enables the given phone account, if it has"
@@ -207,6 +211,9 @@
             case COMMAND_UNREGISTER_PHONE_ACCOUNT:
                 runUnregisterPhoneAccount();
                 break;
+            case COMMAND_STOP_BLOCK_SUPPRESSION:
+                runStopBlockSuppression();
+                break;
             case COMMAND_SET_DEFAULT_DIALER:
                 runSetDefaultDialer();
                 break;
@@ -324,8 +331,13 @@
         System.out.println("Success - " + handle + " unregistered.");
     }
 
+    private void runStopBlockSuppression() throws RemoteException {
+        mTelecomService.stopBlockSuppression();
+    }
+
     private void runSetDefaultDialer() throws RemoteException {
-        final String packageName = nextArgRequired();
+        String packageName = nextArg();
+        if ("default".equals(packageName)) packageName = null;
         mTelecomService.setTestDefaultDialer(packageName);
         System.out.println("Success - " + packageName + " set as override default dialer.");
     }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index a828aac..505b498 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1900,26 +1900,31 @@
 
     @Override
     public Object getSystemService(String name) {
-        // We may override this API from outer context.
-        final boolean isUiContext = isUiContext() || getOuterContext().isUiContext();
-        // Check incorrect Context usage.
-        if (isUiComponent(name) && !isUiContext && vmIncorrectContextUseEnabled()) {
-            final String errorMessage = "Tried to access visual service "
-                    + SystemServiceRegistry.getSystemServiceClassName(name)
-                    + " from a non-visual Context:" + getOuterContext();
-            final String message = "Visual services, such as WindowManager, WallpaperService or "
-                    + "LayoutInflater should be accessed from Activity or other visual Context. "
-                    + "Use an Activity or a Context created with "
-                    + "Context#createWindowContext(int, Bundle), which are adjusted to the "
-                    + "configuration and visual bounds of an area on screen.";
-            final Exception exception = new IllegalAccessException(errorMessage);
-            StrictMode.onIncorrectContextUsed(message, exception);
-            Log.e(TAG, errorMessage + message, exception);
+        if (vmIncorrectContextUseEnabled()) {
+            // We may override this API from outer context.
+            final boolean isUiContext = isUiContext() || isOuterUiContext();
+            // Check incorrect Context usage.
+            if (isUiComponent(name) && !isUiContext) {
+                final String errorMessage = "Tried to access visual service "
+                        + SystemServiceRegistry.getSystemServiceClassName(name)
+                        + " from a non-visual Context:" + getOuterContext();
+                final String message = "Visual services, such as WindowManager, WallpaperService "
+                        + "or LayoutInflater should be accessed from Activity or other visual "
+                        + "Context. Use an Activity or a Context created with "
+                        + "Context#createWindowContext(int, Bundle), which are adjusted to "
+                        + "the configuration and visual bounds of an area on screen.";
+                final Exception exception = new IllegalAccessException(errorMessage);
+                StrictMode.onIncorrectContextUsed(message, exception);
+                Log.e(TAG, errorMessage + " " + message, exception);
+            }
         }
-
         return SystemServiceRegistry.getSystemService(this, name);
     }
 
+    private boolean isOuterUiContext() {
+        return getOuterContext() != null && getOuterContext().isUiContext();
+    }
+
     @Override
     public String getSystemServiceName(Class<?> serviceClass) {
         return SystemServiceRegistry.getSystemServiceName(serviceClass);
@@ -2371,7 +2376,7 @@
         context.setResources(createResources(mToken, mPackageInfo, mSplitName, displayId,
                 overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo(),
                 mResources.getLoaders()));
-        context.mIsUiContext = isUiContext() || getOuterContext().isUiContext();
+        context.mIsUiContext = isUiContext() || isOuterUiContext();
         return context;
     }
 
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 5dc41e4..89abfc9 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -1151,6 +1151,9 @@
      */
     @Override
     public boolean isUiContext() {
+        if (mBase == null) {
+            return false;
+        }
         return mBase.isUiContext();
     }
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index c577d0e..53e75d4 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -4666,8 +4666,7 @@
      * Marks an application exempt from having its permissions be automatically revoked when
      * the app is unused for an extended period of time.
      *
-     * Only the installer on record that installed the given package, or a holder of
-     * {@code WHITELIST_AUTO_REVOKE_PERMISSIONS} is allowed to call this.
+     * Only the installer on record that installed the given package is allowed to call this.
      *
      * Packages start in whitelisted state, and it is the installer's responsibility to
      * un-whitelist the packages it installs, unless auto-revoking permissions from that package
diff --git a/core/java/android/inputmethodservice/InlineSuggestionSession.java b/core/java/android/inputmethodservice/InlineSuggestionSession.java
index 509cbe0..90d0ff0a 100644
--- a/core/java/android/inputmethodservice/InlineSuggestionSession.java
+++ b/core/java/android/inputmethodservice/InlineSuggestionSession.java
@@ -149,6 +149,11 @@
      */
     @MainThread
     void invalidate() {
+        try {
+            mCallback.onInlineSuggestionsSessionInvalidated();
+        } catch (RemoteException e) {
+            Log.w(TAG, "onInlineSuggestionsSessionInvalidated() remote exception:" + e);
+        }
         if (mResponseCallback != null) {
             consumeInlineSuggestionsResponse(EMPTY_RESPONSE);
             mResponseCallback.invalidate();
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 5647bf9..c5a11abe 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -605,9 +605,6 @@
             if (DEBUG) Log.v(TAG, "unbindInput(): binding=" + mInputBinding
                     + " ic=" + mInputConnection);
             // Unbind input is per process per display.
-            // TODO(b/150902448): free-up IME surface when target is changing.
-            //  e.g. DisplayContent#setInputMethodTarget()
-            removeImeSurface();
             onUnbindInput();
             mInputBinding = null;
             mInputConnection = null;
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index ef9d990..c1998c6 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -119,11 +119,11 @@
         // If we had a request before to show from IME (tracked with mImeRequestedShow), reaching
         // this code here means that we now got control, so we can start the animation immediately.
         // If client window is trying to control IME and IME is already visible, it is immediate.
-        if (fromIme || mState.getSource(getType()).isVisible()) {
+        if (fromIme || mState.getSource(getType()).isVisible() && getControl() != null) {
             return ShowResult.SHOW_IMMEDIATELY;
         }
 
-        return getImm().requestImeShow(null /* resultReceiver */)
+        return getImm().requestImeShow(mController.getHost().getWindowToken())
                 ? ShowResult.IME_SHOW_DELAYED : ShowResult.IME_SHOW_FAILED;
     }
 
@@ -132,12 +132,15 @@
      */
     @Override
     void notifyHidden() {
-        getImm().notifyImeHidden();
+        getImm().notifyImeHidden(mController.getHost().getWindowToken());
     }
 
     @Override
     public void removeSurface() {
-        getImm().removeImeSurface();
+        final IBinder window = mController.getHost().getWindowToken();
+        if (window != null) {
+            getImm().removeImeSurface(window);
+        }
     }
 
     @Override
@@ -146,6 +149,7 @@
         super.setControl(control, showTypes, hideTypes);
         if (control == null && !mIsRequestedVisibleAwaitingControl) {
             hide();
+            removeSurface();
         }
     }
 
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 40e6f4b..700dc66 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -153,6 +153,9 @@
                 if (oldLeash == null || newLeash == null || !oldLeash.isSameSurface(newLeash)) {
                     applyHiddenToControl();
                 }
+                if (!requestedVisible && !mIsAnimationPending) {
+                    removeSurface();
+                }
             }
         }
         if (lastControl != null) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index a586425..2b7044d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2725,7 +2725,6 @@
                             mAttachInfo.mThreadedRenderer.isEnabled()) {
                         mAttachInfo.mThreadedRenderer.destroy();
                     }
-                    notifySurfaceDestroyed();
                 } else if ((surfaceReplaced
                         || surfaceSizeChanged || windowRelayoutWasForced || colorModeChanged)
                         && mSurfaceHolder == null
@@ -2956,6 +2955,10 @@
             }
         }
 
+        if (surfaceDestroyed) {
+            notifySurfaceDestroyed();
+        }
+
         if (triggerGlobalLayoutListener) {
             mAttachInfo.mRecomputeGlobalAttributes = false;
             mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
@@ -9377,6 +9380,11 @@
         return mInputEventReceiver.getToken();
     }
 
+    @NonNull
+    public IBinder getWindowToken() {
+        return mAttachInfo.mWindowToken;
+    }
+
     /**
      * Class for managing the accessibility interaction connection
      * based on the global accessibility state.
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index aedb59b..3be0a4d 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2109,28 +2109,36 @@
 
     /**
      * Call showSoftInput with currently focused view.
-     * @return {@code true} if IME can be shown.
+     *
+     * @param windowToken the window from which this request originates. If this doesn't match the
+     *                    currently served view, the request is ignored and returns {@code false}.
+     *
+     * @return {@code true} if IME can (eventually) be shown, {@code false} otherwise.
      * @hide
      */
-    public boolean requestImeShow(ResultReceiver resultReceiver) {
+    public boolean requestImeShow(IBinder windowToken) {
         synchronized (mH) {
             final View servedView = getServedViewLocked();
-            if (servedView == null) {
+            if (servedView == null || servedView.getWindowToken() != windowToken) {
                 return false;
             }
-            showSoftInput(servedView, 0 /* flags */, resultReceiver);
+            showSoftInput(servedView, 0 /* flags */, null /* resultReceiver */);
             return true;
         }
     }
 
     /**
      * Notify IME directly that it is no longer visible.
+     *
+     * @param windowToken the window from which this request originates. If this doesn't match the
+     *                    currently served view, the request is ignored.
      * @hide
      */
-    public void notifyImeHidden() {
+    public void notifyImeHidden(IBinder windowToken) {
         synchronized (mH) {
             try {
-                if (mCurMethod != null) {
+                if (mCurMethod != null && mCurRootView != null
+                        && mCurRootView.getWindowToken() == windowToken) {
                     mCurMethod.notifyImeHidden();
                 }
             } catch (RemoteException re) {
@@ -2140,15 +2148,15 @@
 
     /**
      * Notify IME directly to remove surface as it is no longer visible.
+     * @param windowToken The client window token that requests the IME to remove its surface.
      * @hide
      */
-    public void removeImeSurface() {
+    public void removeImeSurface(IBinder windowToken) {
         synchronized (mH) {
             try {
-                if (mCurMethod != null) {
-                    mCurMethod.removeImeSurface();
-                }
-            } catch (RemoteException re) {
+                mService.removeImeSurfaceFromWindow(windowToken);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
             }
         }
     }
diff --git a/core/java/android/widget/EditorTouchState.java b/core/java/android/widget/EditorTouchState.java
index ff3ac073..9eb63087 100644
--- a/core/java/android/widget/EditorTouchState.java
+++ b/core/java/android/widget/EditorTouchState.java
@@ -174,12 +174,9 @@
                 int touchSlop = config.getScaledTouchSlop();
                 mMovedEnoughForDrag = distanceSquared > touchSlop * touchSlop;
                 if (mMovedEnoughForDrag) {
-                    // If the direction of the swipe motion is within 30 degrees of vertical, it is
-                    // considered a vertical drag. We don't actually have to compute the angle to
-                    // implement the check though. When the angle is exactly 30 degrees from
-                    // vertical, 2*deltaX = distance. When the angle is less than 30 degrees from
-                    // vertical, 2*deltaX < distance.
-                    mIsDragCloseToVertical = (4 * deltaXSquared) <= distanceSquared;
+                    // If the direction of the swipe motion is within 45 degrees of vertical, it is
+                    // considered a vertical drag.
+                    mIsDragCloseToVertical = Math.abs(deltaX) <= Math.abs(deltaY);
                 }
             }
         } else if (action == MotionEvent.ACTION_CANCEL) {
diff --git a/core/java/com/android/internal/view/IInlineSuggestionsRequestCallback.aidl b/core/java/com/android/internal/view/IInlineSuggestionsRequestCallback.aidl
index cf1220c..03948a9 100644
--- a/core/java/com/android/internal/view/IInlineSuggestionsRequestCallback.aidl
+++ b/core/java/com/android/internal/view/IInlineSuggestionsRequestCallback.aidl
@@ -58,4 +58,7 @@
     //  #onFinishInput()} is called on the field specified by the earlier
     //  {@link #onInputMethodStartInput(AutofillId)}.
     void onInputMethodFinishInput();
+
+    // Indicates that the current IME changes inline suggestion session.
+    void onInlineSuggestionsSessionInvalidated();
 }
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 8ec51b8..a1cbd3f 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -73,5 +73,8 @@
             in float[] matrixValues);
 
     oneway void reportPerceptible(in IBinder windowToken, boolean perceptible);
+    /** Remove the IME surface. Requires INTERNAL_SYSTEM_WINDOW permission. */
     void removeImeSurface();
+    /** Remove the IME surface. Requires passing the currently focused window. */
+    void removeImeSurfaceFromWindow(in IBinder windowToken);
 }
diff --git a/core/tests/coretests/src/android/content/ContextTest.java b/core/tests/coretests/src/android/content/ContextTest.java
index 17d1389..777f4a3 100644
--- a/core/tests/coretests/src/android/content/ContextTest.java
+++ b/core/tests/coretests/src/android/content/ContextTest.java
@@ -23,6 +23,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import android.app.ActivityThread;
@@ -180,4 +181,26 @@
                 VIRTUAL_DISPLAY_FLAG_PUBLIC | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
         return virtualDisplay.getDisplay();
     }
+
+    @Test
+    public void testIsUiContext_ContextWrapper() {
+        ContextWrapper wrapper = new ContextWrapper(null /* base */);
+
+        assertFalse(wrapper.isUiContext());
+
+        wrapper = new ContextWrapper(new TestUiContext());
+
+        assertTrue(wrapper.isUiContext());
+    }
+
+    private static class TestUiContext extends ContextWrapper {
+        TestUiContext() {
+            super(null /* base */);
+        }
+
+        @Override
+        public boolean isUiContext() {
+            return true;
+        }
+    }
 }
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index 1b32725..7efd616 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -71,6 +71,9 @@
     private SurfaceControl mLeash;
     @Mock Transaction mMockTransaction;
     private InsetsSource mSpyInsetsSource;
+    private boolean mRemoveSurfaceCalled = false;
+    private InsetsController mController;
+    private InsetsState mState;
 
     @Before
     public void setup() {
@@ -89,13 +92,19 @@
             } catch (BadTokenException e) {
                 // activity isn't running, lets ignore BadTokenException.
             }
-            InsetsState state = new InsetsState();
+            mState = new InsetsState();
             mSpyInsetsSource = Mockito.spy(new InsetsSource(ITYPE_STATUS_BAR));
-            state.addSource(mSpyInsetsSource);
+            mState.addSource(mSpyInsetsSource);
 
-            mConsumer = new InsetsSourceConsumer(ITYPE_STATUS_BAR, state,
-                    () -> mMockTransaction,
-                    new InsetsController(new ViewRootInsetsControllerHost(viewRootImpl)));
+            mController = new InsetsController(new ViewRootInsetsControllerHost(viewRootImpl));
+            mConsumer = new InsetsSourceConsumer(ITYPE_STATUS_BAR, mState,
+                    () -> mMockTransaction, mController) {
+                @Override
+                public void removeSurface() {
+                    super.removeSurface();
+                    mRemoveSurfaceCalled = true;
+                }
+            };
         });
         instrumentation.waitForIdleSync();
 
@@ -171,6 +180,25 @@
             mConsumer.setControl(new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point()),
                     new int[1], hideTypes);
             assertEquals(statusBars(), hideTypes[0]);
+            assertFalse(mRemoveSurfaceCalled);
         });
     }
+
+    @Test
+    public void testRestore_noAnimation() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            mConsumer.hide();
+            mController.onStateChanged(mState);
+            mConsumer.setControl(null, new int[1], new int[1]);
+            reset(mMockTransaction);
+            verifyZeroInteractions(mMockTransaction);
+            mRemoveSurfaceCalled = false;
+            int[] hideTypes = new int[1];
+            mConsumer.setControl(new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point()),
+                    new int[1], hideTypes);
+            assertTrue(mRemoveSurfaceCalled);
+            assertEquals(0, hideTypes[0]);
+        });
+
+    }
 }
diff --git a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
index 89cc6e7..838f600 100644
--- a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
+++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
@@ -145,7 +145,7 @@
         // Swipe along a diagonal path. This should drag the cursor. Because we snap the finger to
         // the handle as the touch moves downwards (and because we have some slop to avoid jumping
         // across lines), the cursor position will end up higher than the finger position.
-        onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("3")));
+        onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("2")));
         onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("1")));
 
         // Swipe right-down along a very steep diagonal path. This should not drag the cursor.
@@ -181,7 +181,7 @@
         // Swipe along a diagonal path. This should drag the cursor. Because we snap the finger to
         // the handle as the touch moves downwards (and because we have some slop to avoid jumping
         // across lines), the cursor position will end up higher than the finger position.
-        onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("3")));
+        onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("2")));
         onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("1")));
 
         // Swipe right-down along a very steep diagonal path. This should not drag the cursor.
diff --git a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
index ec75e40..35fd4bd 100644
--- a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
+++ b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
@@ -326,9 +326,9 @@
         mTouchState.update(event1, mConfig);
         assertSingleTap(mTouchState, 0f, 0f, 0, 0);
 
-        // Simulate an ACTION_MOVE event that is > 30 deg from vertical.
+        // Simulate an ACTION_MOVE event that is > 45 deg from vertical.
         long event2Time = 1002;
-        MotionEvent event2 = moveEvent(event1Time, event2Time, 100f, 173f);
+        MotionEvent event2 = moveEvent(event1Time, event2Time, 100f, 90f);
         mTouchState.update(event2, mConfig);
         assertDrag(mTouchState, 0f, 0f, 0, 0, false);
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java b/packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java
index 278b57d..e5ea446 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java
@@ -41,7 +41,7 @@
 
     private final Bitmap mBitmap;
     private final int mSize;
-    private final Paint mPaint;
+    private Paint mIconPaint;
 
     private float mScale;
     private Rect mSrcRect;
@@ -75,18 +75,18 @@
         canvas.drawColor(0, PorterDuff.Mode.CLEAR);
 
         // opaque circle matte
-        mPaint = new Paint();
-        mPaint.setAntiAlias(true);
-        mPaint.setColor(Color.BLACK);
-        mPaint.setStyle(Paint.Style.FILL);
-        canvas.drawPath(fillPath, mPaint);
+        Paint paint = new Paint();
+        paint.setAntiAlias(true);
+        paint.setColor(Color.BLACK);
+        paint.setStyle(Paint.Style.FILL);
+        canvas.drawPath(fillPath, paint);
 
         // mask in the icon where the bitmap is opaque
-        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
-        canvas.drawBitmap(icon, cropRect, circleRect, mPaint);
+        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
+        canvas.drawBitmap(icon, cropRect, circleRect, paint);
 
         // prepare paint for frame drawing
-        mPaint.setXfermode(null);
+        paint.setXfermode(null);
 
         mScale = 1f;
 
@@ -100,7 +100,7 @@
         final float pad = (mSize - inside) / 2f;
 
         mDstRect.set(pad, pad, mSize - pad, mSize - pad);
-        canvas.drawBitmap(mBitmap, mSrcRect, mDstRect, null);
+        canvas.drawBitmap(mBitmap, mSrcRect, mDstRect, mIconPaint);
     }
 
     public void setScale(float scale) {
@@ -122,8 +122,12 @@
 
     @Override
     public void setColorFilter(ColorFilter cf) {
+        if (mIconPaint == null) {
+            mIconPaint = new Paint();
+        }
+        mIconPaint.setColorFilter(cf);
     }
-    
+
     @Override
     public int getIntrinsicWidth() {
         return mSize;
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 597644b..4527c6c 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -53,6 +53,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:elevation="4dp"
+        android:importantForAccessibility="no"
         android:layout_weight="1">
         <com.android.systemui.qs.QSPanel
             android:id="@+id/quick_settings_panel"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
index 279a200..1e50580 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
@@ -26,6 +26,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.GraphicBuffer;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.hardware.HardwareBuffer;
 import android.util.Log;
@@ -63,10 +64,12 @@
 
     public ThumbnailData(TaskSnapshot snapshot) {
         final GraphicBuffer buffer = snapshot.getSnapshot();
-        if (buffer != null && (buffer.getUsage() & HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE) == 0) {
+        if (buffer == null || (buffer.getUsage() & HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE) == 0) {
             // TODO(b/157562905): Workaround for a crash when we get a snapshot without this state
-            Log.e("ThumbnailData", "Unexpected snapshot without USAGE_GPU_SAMPLED_IMAGE");
-            thumbnail = Bitmap.createBitmap(buffer.getWidth(), buffer.getHeight(), ARGB_8888);
+            Log.e("ThumbnailData", "Unexpected snapshot without USAGE_GPU_SAMPLED_IMAGE: "
+                    + buffer);
+            Point taskSize = snapshot.getTaskSize();
+            thumbnail = Bitmap.createBitmap(taskSize.x, taskSize.y, ARGB_8888);
             thumbnail.eraseColor(Color.BLACK);
         } else {
             thumbnail = Bitmap.wrapHardwareBuffer(buffer, snapshot.getColorSpace());
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index 127c5dd..e12b7dd 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -5,6 +5,7 @@
 import android.content.res.Configuration
 import android.graphics.Color
 import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS
+import android.util.Log
 import android.util.MathUtils
 import android.view.LayoutInflater
 import android.view.View
@@ -25,6 +26,7 @@
 import javax.inject.Provider
 import javax.inject.Singleton
 
+private const val TAG = "MediaCarouselController"
 private val settingsIntent = Intent().setAction(ACTION_MEDIA_CONTROLS_SETTINGS)
 
 /**
@@ -236,7 +238,9 @@
         val oldData = mediaPlayers[oldKey]
         if (oldData != null) {
             val oldData = mediaPlayers.remove(oldKey)
-            mediaPlayers.put(key, oldData!!)
+            mediaPlayers.put(key, oldData!!)?.let {
+                Log.wtf(TAG, "new key $key already exists when migrating from $oldKey")
+            }
         }
         var existingPlayer = mediaPlayers[key]
         if (existingPlayer == null) {
@@ -271,6 +275,11 @@
         updatePageIndicator()
         mediaCarouselScrollHandler.onPlayersChanged()
         mediaCarousel.requiresRemeasuring = true
+        // Check postcondition: mediaContent should have the same number of children as there are
+        // elements in mediaPlayers.
+        if (mediaPlayers.size != mediaContent.childCount) {
+            Log.wtf(TAG, "Size of players list and number of views in carousel are out of sync")
+        }
     }
 
     private fun removePlayer(key: String) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 8cb93bf..299ae5b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -517,22 +517,36 @@
 
     fun onNotificationRemoved(key: String) {
         Assert.isMainThread()
-        if (useMediaResumption && mediaEntries.get(key)?.resumeAction != null) {
+        val removed = mediaEntries.remove(key)
+        if (useMediaResumption && removed?.resumeAction != null) {
             Log.d(TAG, "Not removing $key because resumable")
-            // Move to resume key aka package name
-            val data = mediaEntries.remove(key)!!
-            val resumeAction = getResumeMediaAction(data.resumeAction!!)
-            val updated = data.copy(token = null, actions = listOf(resumeAction),
+            // Move to resume key (aka package name) if that key doesn't already exist.
+            val resumeAction = getResumeMediaAction(removed.resumeAction!!)
+            val updated = removed.copy(token = null, actions = listOf(resumeAction),
                     actionsToShowInCompact = listOf(0), active = false, resumption = true)
-            mediaEntries.put(data.packageName, updated)
-            // Notify listeners of "new" controls
+            val pkg = removed?.packageName
+            val migrate = mediaEntries.put(pkg, updated) == null
+            // Notify listeners of "new" controls when migrating or removed and update when not
             val listenersCopy = listeners.toSet()
-            listenersCopy.forEach {
-                it.onMediaDataLoaded(data.packageName, key, updated)
+            if (migrate) {
+                listenersCopy.forEach {
+                    it.onMediaDataLoaded(pkg, key, updated)
+                }
+            } else {
+                // Since packageName is used for the key of the resumption controls, it is
+                // possible that another notification has already been reused for the resumption
+                // controls of this package. In this case, rather than renaming this player as
+                // packageName, just remove it and then send a update to the existing resumption
+                // controls.
+                listenersCopy.forEach {
+                    it.onMediaDataRemoved(key)
+                }
+                listenersCopy.forEach {
+                    it.onMediaDataLoaded(pkg, pkg, updated)
+                }
             }
             return
         }
-        val removed = mediaEntries.remove(key)
         if (removed != null) {
             val listenersCopy = listeners.toSet()
             listenersCopy.forEach {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
index c454048..daf8ca3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
@@ -104,4 +104,13 @@
     public void showBackground() {
         mBackground.showSecondLayer();
     }
+
+    /**
+     * Cancels the animator if it's running.
+     */
+    public void cancelAnimator() {
+        if (mAnimator != null) {
+            mAnimator.cancel();
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 3e2f9de..e5ed88c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -208,6 +208,7 @@
     public void showImmediately() {
         if (!isShown) {
             setVisibility(VISIBLE);
+            mClipper.cancelAnimator();
             mClipper.showBackground();
             isShown = true;
             setTileSpecs();
@@ -230,6 +231,10 @@
             mUiEventLogger.log(QSEditEvent.QS_EDIT_CLOSED);
             isShown = false;
             mToolbar.dismissPopupMenus();
+            mClipper.cancelAnimator();
+            // Make sure we're not opening (because we're closing). Nobody can think we are
+            // customizing after the next two lines.
+            mOpening = false;
             setCustomizing(false);
             save();
             if (animate) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index fba7a22..2ef6934 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -21,7 +21,6 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
 import android.util.AttributeSet;
@@ -33,6 +32,7 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.drawable.CircleFramedDrawable;
 import com.android.systemui.R;
 import com.android.systemui.qs.PseudoGridView;
 import com.android.systemui.qs.QSUserSwitcherEvent;
@@ -100,7 +100,8 @@
             if (item.picture == null) {
                 v.bind(name, getDrawable(mContext, item).mutate(), item.resolveId());
             } else {
-                Drawable drawable = new BitmapDrawable(v.getResources(), item.picture);
+                int avatarSize = (int) v.getResources().getDimension(R.dimen.qs_framed_avatar_size);
+                Drawable drawable = new CircleFramedDrawable(item.picture, avatarSize);
                 drawable.setColorFilter(
                         item.isSwitchToEnabled ? null : getDisabledUserAvatarColorFilter());
                 v.bind(name, drawable, item.info.id);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 732f25f..e942d85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -371,12 +371,26 @@
             float vectorVel = (float) Math.hypot(
                     mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
 
-            boolean expand = flingExpands(vel, vectorVel, x, y)
-                    || event.getActionMasked() == MotionEvent.ACTION_CANCEL || forceCancel;
+            final boolean onKeyguard =
+                    mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
+
+            final boolean expand;
+            if (event.getActionMasked() == MotionEvent.ACTION_CANCEL || forceCancel) {
+                // If we get a cancel, put the shade back to the state it was in when the gesture
+                // started
+                if (onKeyguard) {
+                    expand = true;
+                } else {
+                    expand = !mPanelClosedOnDown;
+                }
+            } else {
+                expand = flingExpands(vel, vectorVel, x, y);
+            }
+
             mDozeLog.traceFling(expand, mTouchAboveFalsingThreshold,
                     mStatusBar.isFalsingThresholdNeeded(), mStatusBar.isWakeUpComingFromTouch());
             // Log collapse gesture if on lock screen.
-            if (!expand && mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
+            if (!expand && onKeyguard) {
                 float displayDensity = mStatusBar.getDisplayDensity();
                 int heightDp = (int) Math.abs((y - mInitialTouchY) / displayDensity);
                 int velocityDp = (int) Math.abs(vel / displayDensity);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index 512d0f3..5ec5ec6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -24,7 +24,6 @@
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.database.DataSetObserver;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
 import android.util.AttributeSet;
@@ -36,6 +35,7 @@
 import android.widget.FrameLayout;
 
 import com.android.settingslib.animation.AppearAnimationUtils;
+import com.android.settingslib.drawable.CircleFramedDrawable;
 import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
@@ -288,7 +288,8 @@
             if (item.picture == null) {
                 v.bind(name, getDrawable(mContext, item).mutate(), item.resolveId());
             } else {
-                Drawable drawable = new BitmapDrawable(v.getResources(), item.picture);
+                int avatarSize = (int) v.getResources().getDimension(R.dimen.kg_framed_avatar_size);
+                Drawable drawable = new CircleFramedDrawable(item.picture, avatarSize);
                 drawable.setColorFilter(
                         item.isSwitchToEnabled ? null : getDisabledUserAvatarColorFilter());
                 v.bind(name, drawable, item.info.id);
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
index 8ba5b99..c0089e5 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
@@ -226,6 +226,8 @@
                             if (!activeControl.getSurfacePosition().equals(lastSurfacePosition)
                                     && mAnimation != null) {
                                 startAnimation(mImeShowing, true /* forceRestart */);
+                            } else if (!mImeShowing) {
+                                removeImeSurface();
                             }
                         });
                     }
@@ -370,16 +372,7 @@
                     dispatchEndPositioning(mDisplayId, mCancelled, t);
                     if (mAnimationDirection == DIRECTION_HIDE && !mCancelled) {
                         t.hide(mImeSourceControl.getLeash());
-                        final IInputMethodManager imms = getImms();
-                        if (imms != null) {
-                            try {
-                                // Remove the IME surface to make the insets invisible for
-                                // non-client controlled insets.
-                                imms.removeImeSurface();
-                            } catch (RemoteException e) {
-                                Slog.e(TAG, "Failed to remove IME surface.", e);
-                            }
-                        }
+                        removeImeSurface();
                     }
                     t.apply();
                     mTransactionPool.release(t);
@@ -402,6 +395,19 @@
         }
     }
 
+    void removeImeSurface() {
+        final IInputMethodManager imms = getImms();
+        if (imms != null) {
+            try {
+                // Remove the IME surface to make the insets invisible for
+                // non-client controlled insets.
+                imms.removeImeSurface();
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to remove IME surface.", e);
+            }
+        }
+    }
+
     /**
      * Allows other things to synchronize with the ime position
      */
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 6761b28..59c2d0e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -31,6 +31,7 @@
 import org.mockito.Mockito.`when` as whenever
 
 private const val KEY = "KEY"
+private const val KEY_2 = "KEY_2"
 private const val PACKAGE_NAME = "com.android.systemui"
 private const val APP_NAME = "SystemUI"
 private const val SESSION_ARTIST = "artist"
@@ -156,8 +157,43 @@
         mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
         // WHEN the notification is removed
         mediaDataManager.onNotificationRemoved(KEY)
-        // THEN the media data indicates that it is
+        // THEN the media data indicates that it is for resumption
         assertThat(listener.data!!.resumption).isTrue()
+        // AND the new key is the package name
+        assertThat(listener.key!!).isEqualTo(PACKAGE_NAME)
+        assertThat(listener.oldKey!!).isEqualTo(KEY)
+        assertThat(listener.removedKey).isNull()
+    }
+
+    @Test
+    fun testOnNotificationRemoved_twoWithResumption() {
+        // GIVEN that the manager has two notifications with resume actions
+        val listener = TestListener()
+        mediaDataManager.addListener(listener)
+        whenever(controller.metadata).thenReturn(metadataBuilder.build())
+        mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+        mediaDataManager.onNotificationAdded(KEY_2, mediaNotification)
+        assertThat(backgroundExecutor.runAllReady()).isEqualTo(2)
+        assertThat(foregroundExecutor.runAllReady()).isEqualTo(2)
+        val data = listener.data!!
+        assertThat(data.resumption).isFalse()
+        val resumableData = data.copy(resumeAction = Runnable {})
+        mediaDataManager.onMediaDataLoaded(KEY, null, resumableData)
+        mediaDataManager.onMediaDataLoaded(KEY_2, null, resumableData)
+        // WHEN the first is removed
+        mediaDataManager.onNotificationRemoved(KEY)
+        // THEN the data is for resumption and the key is migrated to the package name
+        assertThat(listener.data!!.resumption).isTrue()
+        assertThat(listener.key!!).isEqualTo(PACKAGE_NAME)
+        assertThat(listener.oldKey!!).isEqualTo(KEY)
+        assertThat(listener.removedKey).isNull()
+        // WHEN the second is removed
+        mediaDataManager.onNotificationRemoved(KEY_2)
+        // THEN the data is for resumption and the second key is removed
+        assertThat(listener.data!!.resumption).isTrue()
+        assertThat(listener.key!!).isEqualTo(PACKAGE_NAME)
+        assertThat(listener.oldKey!!).isEqualTo(PACKAGE_NAME)
+        assertThat(listener.removedKey!!).isEqualTo(KEY_2)
     }
 
     @Test
@@ -190,6 +226,7 @@
         var data: MediaData? = null
         var key: String? = null
         var oldKey: String? = null
+        var removedKey: String? = null
 
         override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
             this.key = key
@@ -198,9 +235,7 @@
         }
 
         override fun onMediaDataRemoved(key: String) {
-            this.key = key
-            oldKey = null
-            data = null
+            removedKey = key
         }
     }
 }
diff --git a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index 74df113..e10bab4 100644
--- a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -42,6 +42,7 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.system.Os;
 import android.util.Log;
 
@@ -224,9 +225,19 @@
 
     }
 
+    private boolean isAdbOverNetwork() {
+        // If adb TCP port opened, this test may running by adb over network.
+        return (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1)
+                || (SystemProperties.getInt("service.adb.tcp.port", -1) > -1);
+    }
+
     @Test
     public void testPhysicalEthernet() throws Exception {
         assumeTrue(mEm.isAvailable());
+        // Do not run this test if adb is over network and ethernet is connected.
+        // It is likely the adb run over ethernet, the adb would break when ethernet is switching
+        // from client mode to server mode. See b/160389275.
+        assumeFalse(isAdbOverNetwork());
 
         // Get an interface to use.
         final String iface = mTetheredInterfaceRequester.getInterface();
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
index c8cee10..070626be 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
@@ -322,6 +322,12 @@
         return true;
     }
 
+    void clear() {
+        mLongPressingPointerId = -1;
+        mLongPressingPointerDeltaX = 0;
+        mLongPressingPointerDeltaY = 0;
+    }
+
     public void clickWithTouchEvents(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
         final int pointerIndex = event.getActionIndex();
         final int pointerId = event.getPointerId(pointerIndex);
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index 6f2e626..fbc986b 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -809,6 +809,7 @@
 
                 // Announce the end of a the touch interaction.
                 mAms.onTouchInteractionEnd();
+                mDispatcher.clear();
                 mDispatcher.sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
 
             } break;
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
index 68eeb0a..b2daae4 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
@@ -103,6 +103,8 @@
     private boolean mDestroyed = false;
     @GuardedBy("mLock")
     private boolean mPreviousHasNonPinSuggestionShow;
+    @GuardedBy("mLock")
+    private boolean mImeSessionInvalidated = false;
 
     AutofillInlineSuggestionsRequestSession(
             @NonNull InputMethodManagerInternal inputMethodManagerInternal, int userId,
@@ -157,7 +159,7 @@
             Slog.d(TAG,
                     "onInlineSuggestionsResponseLocked called for:" + inlineFillUi.getAutofillId());
         }
-        if (mImeRequest == null || mResponseCallback == null) {
+        if (mImeRequest == null || mResponseCallback == null || mImeSessionInvalidated) {
             return false;
         }
         // TODO(b/151123764): each session should only correspond to one field.
@@ -191,6 +193,7 @@
         if (mDestroyed) {
             return;
         }
+        mImeSessionInvalidated = false;
         if (sDebug) Slog.d(TAG, "onCreateInlineSuggestionsRequestLocked called: " + mAutofillId);
         mInputMethodManagerInternal.onCreateInlineSuggestionsRequest(mUserId,
                 new InlineSuggestionsRequestInfo(mComponentName, mAutofillId, mUiExtras),
@@ -291,6 +294,7 @@
                 return;
             }
             mImeRequestReceived = true;
+            mImeSessionInvalidated = false;
 
             if (request != null && callback != null) {
                 mImeRequest = request;
@@ -346,6 +350,20 @@
         }
     }
 
+    /**
+     * Handles the IME session status received from the IME.
+     *
+     * <p> Should only be invoked in the {@link #mHandler} thread.
+     */
+    private void handleOnReceiveImeSessionInvalidated() {
+        synchronized (mLock) {
+            if (mDestroyed) {
+                return;
+            }
+            mImeSessionInvalidated = true;
+        }
+    }
+
     private static final class InlineSuggestionsRequestCallbackImpl extends
             IInlineSuggestionsRequestCallback.Stub {
 
@@ -433,6 +451,18 @@
                         session, false, false));
             }
         }
+
+        @BinderThread
+        @Override
+        public void onInlineSuggestionsSessionInvalidated() throws RemoteException {
+            if (sDebug) Slog.d(TAG, "onInlineSuggestionsSessionInvalidated() called.");
+            final AutofillInlineSuggestionsRequestSession session = mSession.get();
+            if (session != null) {
+                session.mHandler.sendMessage(obtainMessage(
+                        AutofillInlineSuggestionsRequestSession
+                                ::handleOnReceiveImeSessionInvalidated, session));
+            }
+        }
     }
 
     private static boolean match(@Nullable AutofillId autofillId,
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index 70f0399..05cf40a 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -120,6 +120,11 @@
     public abstract void reportImeControl(@Nullable IBinder windowToken);
 
     /**
+     * Destroys the IME surface.
+     */
+    public abstract void removeImeSurface();
+
+    /**
      * Fake implementation of {@link InputMethodManagerInternal}.  All the methods do nothing.
      */
     private static final InputMethodManagerInternal NOP =
@@ -166,6 +171,10 @@
                 @Override
                 public void reportImeControl(@Nullable IBinder windowToken) {
                 }
+
+                @Override
+                public void removeImeSurface() {
+                }
             };
 
     /**
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 15e8a92..d8ee32e 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -211,6 +211,7 @@
     static final int MSG_INITIALIZE_IME = 1040;
     static final int MSG_CREATE_SESSION = 1050;
     static final int MSG_REMOVE_IME_SURFACE = 1060;
+    static final int MSG_REMOVE_IME_SURFACE_FROM_WINDOW = 1061;
 
     static final int MSG_START_INPUT = 2000;
 
@@ -2128,6 +2129,11 @@
         public void onInputMethodFinishInput() throws RemoteException {
             mCallback.onInputMethodFinishInput();
         }
+
+        @Override
+        public void onInlineSuggestionsSessionInvalidated() throws RemoteException {
+            mCallback.onInlineSuggestionsSessionInvalidated();
+        }
     }
 
     /**
@@ -4000,6 +4006,13 @@
         mHandler.sendMessage(mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE));
     }
 
+    @Override
+    public void removeImeSurfaceFromWindow(IBinder windowToken) {
+        // No permission check, because we'll only execute the request if the calling window is
+        // also the current IME client.
+        mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE_FROM_WINDOW, windowToken).sendToTarget();
+    }
+
     @BinderThread
     private void notifyUserAction(@NonNull IBinder token) {
         if (DEBUG) {
@@ -4273,11 +4286,27 @@
                 return true;
             }
             case MSG_REMOVE_IME_SURFACE: {
-                try {
-                    if (mEnabledSession != null && mEnabledSession.session != null) {
-                        mEnabledSession.session.removeImeSurface();
+                synchronized (mMethodMap) {
+                    try {
+                        if (mEnabledSession != null && mEnabledSession.session != null
+                                && !mShowRequested) {
+                            mEnabledSession.session.removeImeSurface();
+                        }
+                    } catch (RemoteException e) {
                     }
-                } catch (RemoteException e) {
+                }
+                return true;
+            }
+            case MSG_REMOVE_IME_SURFACE_FROM_WINDOW: {
+                IBinder windowToken = (IBinder) msg.obj;
+                synchronized (mMethodMap) {
+                    try {
+                        if (windowToken == mCurFocusedWindow
+                                && mEnabledSession != null && mEnabledSession.session != null) {
+                            mEnabledSession.session.removeImeSurface();
+                        }
+                    } catch (RemoteException e) {
+                    }
                 }
                 return true;
             }
@@ -5111,6 +5140,11 @@
         public void reportImeControl(@Nullable IBinder windowToken) {
             mService.reportImeControl(windowToken);
         }
+
+        @Override
+        public void removeImeSurface() {
+            mService.mHandler.sendMessage(mService.mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE));
+        }
     }
 
     @BinderThread
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 2e3d396..19dff98 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -225,6 +225,11 @@
                         @Override
                         public void reportImeControl(@Nullable IBinder windowToken) {
                         }
+
+                        @Override
+                        public void removeImeSurface() {
+                            reportNotSupported();
+                        }
                     });
         }
 
@@ -1473,6 +1478,12 @@
 
         @BinderThread
         @Override
+        public void removeImeSurfaceFromWindow(IBinder windowToken) {
+            reportNotSupported();
+        }
+
+        @BinderThread
+        @Override
         public boolean showSoftInput(
                 IInputMethodClient client, IBinder token, int flags,
                 ResultReceiver resultReceiver) {
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 3a203d5..c3c2e5e 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -708,12 +708,15 @@
         return ret;
     }
 
+    /**
+     * This method recomputes all component / intent-based visibility and is intended to match the
+     * relevant logic of {@link #addPackageInternal(PackageSetting, ArrayMap)}
+     */
     private void recomputeComponentVisibility(ArrayMap<String, PackageSetting> existingSettings) {
         mQueriesViaComponent.clear();
         for (int i = existingSettings.size() - 1; i >= 0; i--) {
             PackageSetting setting = existingSettings.valueAt(i);
-            if (setting.pkg == null
-                    || mForceQueryable.contains(setting.appId)) {
+            if (setting.pkg == null || requestsQueryAllPackages(setting.pkg)) {
                 continue;
             }
             for (int j = existingSettings.size() - 1; j >= 0; j--) {
@@ -721,7 +724,7 @@
                     continue;
                 }
                 final PackageSetting otherSetting = existingSettings.valueAt(j);
-                if (otherSetting.pkg == null) {
+                if (otherSetting.pkg == null || mForceQueryable.contains(otherSetting.appId)) {
                     continue;
                 }
                 if (canQueryViaComponents(setting.pkg, otherSetting.pkg, mProtectedBroadcasts)) {
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 2df4a92..eddab76 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -18,6 +18,7 @@
 
 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 
 import android.annotation.Nullable;
 import android.content.Context;
@@ -42,10 +43,9 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
 
 /**
  * A service for A/B OTA dexopting.
@@ -123,15 +123,20 @@
         }
         final List<PackageSetting> important;
         final List<PackageSetting> others;
+        Predicate<PackageSetting> isPlatformPackage = pkgSetting ->
+                PLATFORM_PACKAGE_NAME.equals(pkgSetting.pkg.getPackageName());
         synchronized (mPackageManagerService.mLock) {
             // Important: the packages we need to run with ab-ota compiler-reason.
             important = PackageManagerServiceUtils.getPackagesForDexopt(
                     mPackageManagerService.mSettings.mPackages.values(), mPackageManagerService,
                     DEBUG_DEXOPT);
+            // Remove Platform Package from A/B OTA b/160735835.
+            important.removeIf(isPlatformPackage);
             // Others: we should optimize this with the (first-)boot compiler-reason.
             others = new ArrayList<>(mPackageManagerService.mSettings.mPackages.values());
             others.removeAll(important);
             others.removeIf(PackageManagerServiceUtils.REMOVE_IF_NULL_PKG);
+            others.removeIf(isPlatformPackage);
 
             // Pre-size the array list by over-allocating by a factor of 1.5.
             mDexoptCommands = new ArrayList<>(3 * mPackageManagerService.mPackages.size() / 2);
@@ -147,7 +152,7 @@
                 throw new IllegalStateException("Found a core app that's not important");
             }
             mDexoptCommands.addAll(generatePackageDexopts(pkgSetting.pkg, pkgSetting,
-                            PackageManagerService.REASON_FIRST_BOOT));
+                    PackageManagerService.REASON_FIRST_BOOT));
         }
         completeSize = mDexoptCommands.size();
 
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 91b2ea1..08cdd8f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -589,12 +589,12 @@
             }
         }
 
-        if (mBypassNextStagedInstallerCheck) {
-            mBypassNextStagedInstallerCheck = false;
-        } else if (params.isStaged
-                && !isCalledBySystemOrShell(callingUid)
-                && !isWhitelistedStagedInstaller(requestedInstallerPackageName)) {
-            throw new SecurityException("Installer not allowed to commit staged install");
+        if (params.isStaged && !isCalledBySystemOrShell(callingUid)) {
+            if (mBypassNextStagedInstallerCheck) {
+                mBypassNextStagedInstallerCheck = false;
+            } else if (!isStagedInstallerAllowed(requestedInstallerPackageName)) {
+                throw new SecurityException("Installer not allowed to commit staged install");
+            }
         }
 
         if (!params.isMultiPackage) {
@@ -725,7 +725,7 @@
                 || callingUid == Process.SHELL_UID;
     }
 
-    private boolean isWhitelistedStagedInstaller(String installerName) {
+    private boolean isStagedInstallerAllowed(String installerName) {
         return SystemConfig.getInstance().getWhitelistedStagedInstallers().contains(installerName);
     }
 
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index c38d649..4b3ddd8 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -114,7 +114,7 @@
     private static final boolean DEBUG = false;
     private static final String TAG = "UriGrantsManagerService";
     // Maximum number of persisted Uri grants a package is allowed
-    private static final int MAX_PERSISTED_URI_GRANTS = 128;
+    private static final int MAX_PERSISTED_URI_GRANTS = 512;
     private static final boolean ENABLE_DYNAMIC_PERMISSIONS = false;
 
     private final Object mLock = new Object();
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index db4c3ea..e9768a2 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -2443,7 +2443,7 @@
         forAllActivities(ActivityRecord::removeLaunchTickRunnable);
     }
 
-    private void updateTransitLocked(int transit, ActivityOptions options) {
+    private void updateTransitLocked(int transit, ActivityOptions options, boolean forceOverride) {
         if (options != null) {
             ActivityRecord r = topRunningActivity();
             if (r != null && !r.isState(RESUMED)) {
@@ -2452,7 +2452,8 @@
                 ActivityOptions.abort(options);
             }
         }
-        getDisplay().mDisplayContent.prepareAppTransition(transit, false);
+        getDisplay().mDisplayContent.prepareAppTransition(transit, false,
+                0 /* flags */, forceOverride);
     }
 
     final void moveTaskToFront(Task tr, boolean noAnimation, ActivityOptions options,
@@ -2472,8 +2473,17 @@
             // nothing to do!
             if (noAnimation) {
                 ActivityOptions.abort(options);
+            } else if (isSingleTaskInstance()) {
+                // When a task is moved front on the display which can only contain one task, start
+                // a special transition.
+                // {@link AppTransitionController#handleAppTransitionReady} later picks up the
+                // transition, and schedules
+                // {@link ITaskStackListener#onSingleTaskDisplayDrawn} callback which is triggered
+                // after contents are drawn on the display.
+                updateTransitLocked(TRANSIT_SHOW_SINGLE_TASK_DISPLAY, options,
+                        true /* forceOverride */);
             } else {
-                updateTransitLocked(TRANSIT_TASK_TO_FRONT, options);
+                updateTransitLocked(TRANSIT_TASK_TO_FRONT, options, false /* forceOverride */);
             }
             return;
         }
@@ -2519,9 +2529,13 @@
                     mStackSupervisor.mNoAnimActivities.add(r);
                 }
                 ActivityOptions.abort(options);
+            } else if (isSingleTaskInstance()) {
+                updateTransitLocked(TRANSIT_SHOW_SINGLE_TASK_DISPLAY, options,
+                        true /* forceOverride */);
             } else {
-                updateTransitLocked(TRANSIT_TASK_TO_FRONT, options);
+                updateTransitLocked(TRANSIT_TASK_TO_FRONT, options, false /* forceOverride */);
             }
+
             // If a new task is moved to the front, then mark the existing top activity as
             // supporting
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e8a4234..b94fb04 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3574,12 +3574,11 @@
         }
     }
 
-    private void updateImeControlTarget() {
+    void updateImeControlTarget() {
         mInputMethodControlTarget = computeImeControlTarget();
         mInsetsStateController.onImeControlTargetChanged(mInputMethodControlTarget);
 
-        final WindowState win = mInputMethodControlTarget != null
-                ? mInputMethodControlTarget.getWindow() : null;
+        final WindowState win = InsetsControlTarget.asWindowOrNull(mInputMethodControlTarget);
         final IBinder token = win != null ? win.mClient.asBinder() : null;
         // Note: not allowed to call into IMMS with the WM lock held, hence the post.
         mWmService.mH.post(() ->
@@ -3603,6 +3602,17 @@
         if (!isImeControlledByApp() && mRemoteInsetsControlTarget != null) {
             return mRemoteInsetsControlTarget;
         } else {
+            // Now, a special case -- if the last target's window is in the process of exiting, but
+            // not removed, keep on the last target to avoid IME flicker.
+            final WindowState cur = InsetsControlTarget.asWindowOrNull(mInputMethodControlTarget);
+            if (cur != null && !cur.mRemoved && cur.isDisplayedLw() && cur.isClosing()
+                    && !cur.isActivityTypeHome()) {
+                if (DEBUG_INPUT_METHOD) {
+                    Slog.v(TAG_WM, "Not changing control while current window"
+                            + " is closing and not removed");
+                }
+                return cur;
+            }
             // Otherwise, we just use the ime target as received from IME.
             return mInputMethodInputTarget;
         }
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 8298763..99ee5e1 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -18,13 +18,14 @@
 
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME;
 
-import android.graphics.PixelFormat;
 import android.view.InsetsSource;
 import android.view.WindowInsets;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.protolog.common.ProtoLog;
 
+import java.io.PrintWriter;
+
 /**
  * Controller for IME inset source on the server. It's called provider as it provides the
  * {@link InsetsSource} to the client that uses it in {@link InsetsSourceConsumer}.
@@ -132,8 +133,17 @@
                 || (mImeTargetFromIme != null && dcTarget.getParentWindow() == mImeTargetFromIme
                         && dcTarget.mSubLayer > mImeTargetFromIme.mSubLayer)
                 || mImeTargetFromIme == mDisplayContent.getImeFallback()
-                // If IME target is transparent but control target matches requesting window.
-                || (controlTarget == mImeTargetFromIme
-                        && PixelFormat.formatHasAlpha(dcTarget.mAttrs.format));
+                || (!mImeTargetFromIme.isClosing() && controlTarget == mImeTargetFromIme);
+    }
+
+    @Override
+    public void dump(PrintWriter pw, String prefix) {
+        super.dump(pw, prefix);
+        if (mImeTargetFromIme != null) {
+            pw.print(prefix);
+            pw.print("showImePostLayout pending for mImeTargetFromIme=");
+            pw.print(mImeTargetFromIme);
+            pw.println();
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 8734b5e..0216db4 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -16,13 +16,14 @@
 
 package com.android.server.wm;
 
-import static android.os.Process.myPid;
-import static android.os.Process.myUid;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static android.view.Display.INVALID_DISPLAY;
 import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
 import static android.view.WindowManager.INPUT_CONSUMER_PIP;
 import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
 import static android.view.WindowManager.INPUT_CONSUMER_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
 import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS;
@@ -477,12 +478,18 @@
                     mService.getRecentsAnimationController();
             final boolean shouldApplyRecentsInputConsumer = recentsAnimationController != null
                     && recentsAnimationController.shouldApplyInputConsumer(w.mActivityRecord);
+            final int type = w.mAttrs.type;
+            final boolean isVisible = w.isVisibleLw();
             if (inputChannel == null || inputWindowHandle == null || w.mRemoved
                     || (w.cantReceiveTouchInput() && !shouldApplyRecentsInputConsumer)) {
                 if (w.mWinAnimator.hasSurface()) {
+                    // Assign an InputInfo with type to the overlay window which can't receive input
+                    // event. This is used to omit Surfaces from occlusion detection.
+                    populateOverlayInputInfo(mInvalidInputWindow, w.getName(), type, isVisible);
                     mInputTransaction.setInputWindowInfo(
-                        w.mWinAnimator.mSurfaceController.getClientViewRootSurface(),
-                        mInvalidInputWindow);
+                            w.mWinAnimator.mSurfaceController.getClientViewRootSurface(),
+                            mInvalidInputWindow);
+                    return;
                 }
                 // Skip this window because it cannot possibly receive input.
                 return;
@@ -490,9 +497,7 @@
 
             final int flags = w.mAttrs.flags;
             final int privateFlags = w.mAttrs.privateFlags;
-            final int type = w.mAttrs.type;
             final boolean hasFocus = w.isFocused();
-            final boolean isVisible = w.isVisibleLw();
 
             if (mAddRecentsAnimationInputConsumerHandle && shouldApplyRecentsInputConsumer) {
                 if (recentsAnimationController.updateInputConsumerForApp(
@@ -555,6 +560,26 @@
         }
     }
 
+    // This would reset InputWindowHandle fields to prevent it could be found by input event.
+    // We need to check if any new field of InputWindowHandle could impact the result.
+    private static void populateOverlayInputInfo(final InputWindowHandle inputWindowHandle,
+            final String name, final int type, final boolean isVisible) {
+        inputWindowHandle.name = name;
+        inputWindowHandle.layoutParamsType = type;
+        inputWindowHandle.dispatchingTimeoutNanos =
+                WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+        inputWindowHandle.visible = isVisible;
+        inputWindowHandle.canReceiveKeys = false;
+        inputWindowHandle.hasFocus = false;
+        inputWindowHandle.inputFeatures = INPUT_FEATURE_NO_INPUT_CHANNEL;
+        inputWindowHandle.scaleFactor = 1;
+        inputWindowHandle.layoutParamsFlags =
+                FLAG_NOT_TOUCH_MODAL | FLAG_NOT_TOUCHABLE | FLAG_NOT_FOCUSABLE;
+        inputWindowHandle.portalToDisplayId = INVALID_DISPLAY;
+        inputWindowHandle.touchableRegion.setEmpty();
+        inputWindowHandle.setTouchableRegionCrop(null);
+    }
+
     /**
      * Helper function to generate an InputInfo with type SECURE_SYSTEM_OVERLAY. This input
      * info will not have an input channel or be touchable, but is used to omit Surfaces
@@ -564,16 +589,7 @@
     static void setTrustedOverlayInputInfo(SurfaceControl sc, SurfaceControl.Transaction t,
             int displayId, String name) {
         InputWindowHandle inputWindowHandle = new InputWindowHandle(null, displayId);
-        inputWindowHandle.name = name;
-        inputWindowHandle.layoutParamsType = TYPE_SECURE_SYSTEM_OVERLAY;
-        inputWindowHandle.dispatchingTimeoutNanos = -1;
-        inputWindowHandle.visible = true;
-        inputWindowHandle.canReceiveKeys = false;
-        inputWindowHandle.hasFocus = false;
-        inputWindowHandle.ownerPid = myPid();
-        inputWindowHandle.ownerUid = myUid();
-        inputWindowHandle.inputFeatures = INPUT_FEATURE_NO_INPUT_CHANNEL;
-        inputWindowHandle.scaleFactor = 1;
+        populateOverlayInputInfo(inputWindowHandle, name, TYPE_SECURE_SYSTEM_OVERLAY, true);
         t.setInputWindowInfo(sc, inputWindowHandle);
     }
 }
diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java
index c50f296..3ffc26a 100644
--- a/services/core/java/com/android/server/wm/InsetsControlTarget.java
+++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java
@@ -62,4 +62,8 @@
         return false;
     }
 
+    /** Returns {@code target.getWindow()}, or null if {@code target} is {@code null}. */
+    static WindowState asWindowOrNull(InsetsControlTarget target) {
+        return target != null ? target.getWindow() : null;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 63083fa..77bd4a4 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -44,6 +44,7 @@
 import android.view.InsetsState.InternalInsetsType;
 import android.view.WindowManager;
 
+import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.protolog.common.ProtoLog;
 
 import java.io.PrintWriter;
@@ -74,7 +75,21 @@
             w.notifyInsetsChanged();
         }
     };
-    private final InsetsControlTarget mEmptyImeControlTarget = new InsetsControlTarget() { };
+    private final InsetsControlTarget mEmptyImeControlTarget = new InsetsControlTarget() {
+        @Override
+        public void notifyInsetsControlChanged() {
+            InsetsSourceControl[] controls = getControlsForDispatch(this);
+            if (controls == null) {
+                return;
+            }
+            for (InsetsSourceControl control : controls) {
+                if (control.getType() == ITYPE_IME) {
+                    mDisplayContent.mWmService.mH.post(() ->
+                            InputMethodManagerInternal.get().removeImeSurface());
+                }
+            }
+        }
+    };
 
     InsetsStateController(DisplayContent displayContent) {
         mDisplayContent = displayContent;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index c7ffc06..4700864 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2375,7 +2375,8 @@
                         // triggered after contents are drawn on the display.
                         if (display.isSingleTaskInstance()) {
                             display.mDisplayContent.prepareAppTransition(
-                                    TRANSIT_SHOW_SINGLE_TASK_DISPLAY, false);
+                                    TRANSIT_SHOW_SINGLE_TASK_DISPLAY, false,
+                                    0 /* flags */, true /* forceOverride*/);
                         }
                         stack.awakeFromSleepingLocked();
                         if (display.isSingleTaskInstance()) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 837fafe..00be75f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2170,6 +2170,9 @@
         if (isInputMethodTarget()) {
             dc.computeImeTarget(true /* updateImeTarget */);
         }
+        if (dc.mInputMethodControlTarget == this) {
+            dc.updateImeControlTarget();
+        }
 
         final int type = mAttrs.type;
         if (WindowManagerService.excludeWindowTypeFromTapOutTask(type)) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 77e3c59..d64fdb8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -898,6 +898,26 @@
     }
 
     @Test
+    public void testComputeImeControlTarget_exitingApp() throws Exception {
+        final DisplayContent dc = createNewDisplay();
+
+        WindowState exitingWin = createWindow(null, TYPE_BASE_APPLICATION, "exiting app");
+        makeWindowVisible(exitingWin);
+        exitingWin.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
+        exitingWin.mAnimatingExit = true;
+
+        dc.mInputMethodControlTarget = exitingWin;
+        dc.mInputMethodTarget = dc.mInputMethodInputTarget =
+                createWindow(null, TYPE_BASE_APPLICATION, "starting app");
+
+        assertEquals(exitingWin, dc.computeImeControlTarget());
+
+        exitingWin.removeImmediately();
+
+        assertEquals(dc.mInputMethodInputTarget, dc.computeImeControlTarget());
+    }
+
+    @Test
     public void testComputeImeControlTarget_splitscreen() throws Exception {
         final DisplayContent dc = createNewDisplay();
         dc.mInputMethodInputTarget = createWindow(null, TYPE_BASE_APPLICATION, "app");
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 285cf43..dee5a98 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -277,6 +277,11 @@
     boolean setDefaultDialer(in String packageName);
 
     /**
+     * Stop suppressing blocked numbers after a call to emergency services. Shell only.
+     */
+    void stopBlockSuppression();
+
+    /**
     * @see TelecomServiceImpl#createManageBlockedNumbersIntent
     **/
     Intent createManageBlockedNumbersIntent();