diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index ce6f2920b5c93..7b3aa0a41ca3e 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -117,6 +117,7 @@ import static com.android.server.wm.DisplayContentProto.OPENING_APPS; import static com.android.server.wm.DisplayContentProto.RESUMED_ACTIVITY; import static com.android.server.wm.DisplayContentProto.ROOT_DISPLAY_AREA; import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; @@ -4935,15 +4936,20 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // Keep IME window in surface parent as long as app's starting window // exists so it get's layered above the starting window. if (imeTarget != null && !(imeTarget.mActivityRecord != null - && imeTarget.mActivityRecord.hasStartingWindow()) && ( - !(imeTarget.inMultiWindowMode() - || imeTarget.mToken.isAppTransitioning()) && ( - imeTarget.getSurfaceControl() != null))) { - mImeWindowsContainer.assignRelativeLayer(t, imeTarget.getSurfaceControl(), - // TODO: We need to use an extra level on the app surface to ensure - // this is always above SurfaceView but always below attached window. - 1, forceUpdate); - } else if (mInputMethodSurfaceParent != null) { + && imeTarget.mActivityRecord.hasStartingWindow())) { + final boolean canImeTargetSetRelativeLayer = imeTarget.getSurfaceControl() != null + && !imeTarget.inMultiWindowMode() + && imeTarget.mToken.getActivity(app -> app.isAnimating(TRANSITION | PARENTS, + ANIMATION_TYPE_ALL & ~ANIMATION_TYPE_RECENTS)) == null; + if (canImeTargetSetRelativeLayer) { + mImeWindowsContainer.assignRelativeLayer(t, imeTarget.getSurfaceControl(), + // TODO: We need to use an extra level on the app surface to ensure + // this is always above SurfaceView but always below attached window. + 1, forceUpdate); + return; + } + } + if (mInputMethodSurfaceParent != null) { // The IME surface parent may not be its window parent's surface // (@see #computeImeParent), so set relative layer here instead of letting the window // parent to assign layer. diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java index 22ea3d5be71b3..6c3a1f6790205 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java @@ -24,6 +24,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; @@ -39,10 +40,12 @@ import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.WindowStateAnimator.PRESERVED_SURFACE_LAYER; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -400,6 +403,30 @@ public class ZOrderingTests extends WindowTestsBase { assertWindowHigher(statusBarSubPanel, statusBarPanel); } + @Test + public void testAssignWindowLayers_ForImeOnAppWithRecentsAnimating() { + final WindowState imeAppTarget = createWindow(null, TYPE_APPLICATION, + mAppWindow.mActivityRecord, "imeAppTarget"); + mDisplayContent.setImeInputTarget(imeAppTarget); + mDisplayContent.setImeLayeringTarget(imeAppTarget); + mDisplayContent.updateImeParent(); + + // Simulate the ime layering target task is animating with recents animation. + final Task imeAppTargetTask = imeAppTarget.getTask(); + final SurfaceAnimator imeTargetTaskAnimator = imeAppTargetTask.mSurfaceAnimator; + spyOn(imeTargetTaskAnimator); + doReturn(ANIMATION_TYPE_RECENTS).when(imeTargetTaskAnimator).getAnimationType(); + doReturn(true).when(imeTargetTaskAnimator).isAnimating(); + + mDisplayContent.assignChildLayers(mTransaction); + + // Ime should on top of the application window when in recents animation and keep + // attached on app. + assertTrue(mDisplayContent.shouldImeAttachedToApp()); + assertWindowHigher(mImeWindow, imeAppTarget); + } + + @Test public void testAssignWindowLayers_ForNegativelyZOrderedSubtype() { // TODO(b/70040778): We should aim to eliminate the last user of TYPE_APPLICATION_MEDIA