From 40c599f4016d4141e83d776134d35308615e3da0 Mon Sep 17 00:00:00 2001 From: Ming-Shin Lu Date: Mon, 4 Oct 2021 22:11:41 +0800 Subject: [PATCH] Consolidate DisplayContent#assignRelativeLayerForIme When the window focus or the ime target changes, DC#assignRelativeLayerForIme will be called to set the relative layering with IME when the imeTarget is the non-child application window without in animating state. Howerver, the animating state checking includes all types of animation. And that makes when taping an editor dialog fragment to show IME, then swiping up to recents will see the IME will behind the dimming because system thought the ime target is animated by recents animation so the relative layering didn't be set. As task switching by recents animation that we would like to keep the current task window hierarchy and IME relative layer during switching, modify the animating check with excluding recents animation. Bug: 201139555 Test: atest ZOrderingTests#\ testAssignWindowLayers_ForImeOnAppWithRecentsAnimating Test: manual as steps: 1) Launch Settings with editor dialogs fragment (E.g. Network & Internet > Private DNS) 2) Tap focus on Editor to show IME 3) Tap and hold on navigation bar 4) Expect IME layer isn't below dimming layer Change-Id: I3024443c21cfb1c7971f3999640039caea10d0d5 --- .../com/android/server/wm/DisplayContent.java | 24 ++++++++++------- .../com/android/server/wm/ZOrderingTests.java | 27 +++++++++++++++++++ 2 files changed, 42 insertions(+), 9 deletions(-) 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