From f6b7869adc0b04e022728137fcb512643700f948 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 Bug: 204140533 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 Merged-In: I3024443c21cfb1c7971f3999640039caea10d0d5 Change-Id: I3024443c21cfb1c7971f3999640039caea10d0d5 --- .../com/android/server/wm/DisplayContent.java | 24 ++++++++++------ .../com/android/server/wm/ZOrderingTests.java | 28 +++++++++++++++++++ 2 files changed, 43 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 29b1a80b7b581..51f470444950d 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -121,6 +121,7 @@ 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.DisplayContentProto.SLEEP_TOKENS; +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; @@ -5025,15 +5026,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 72b05c08661b5..be5fd59cf66d2 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java @@ -23,6 +23,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 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; @@ -38,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; @@ -399,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