From f6b7869adc0b04e022728137fcb512643700f948 Mon Sep 17 00:00:00 2001 From: Ming-Shin Lu Date: Mon, 4 Oct 2021 22:11:41 +0800 Subject: [PATCH 1/2] 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 From 50c6a4516e5df65db95248882623341b4092f17f Mon Sep 17 00:00:00 2001 From: Ming-Shin Lu Date: Tue, 2 Nov 2021 01:37:05 +0800 Subject: [PATCH 2/2] Fix IME flicker when switching recents tasks CL[1] fixed the IME relative layer issue on editor dialog fragment when swiping up to recents without seeing the IME behinds the dimming layer. However, this introduced another IME flickering when switching tasks with selecting task on the overview screen. The scenerio is: - Focusing an app to show IME - Swiping up to go to the overview screen - Selecting another task The flickering happens to see the "transformed" IME surface that originally belongs to the previous task, but accidentally on top of the selected task during animating the recents task. That's because we removed recents animation animating state in DC#assignRelativeLayerForIme, so that IME can placed on the selected task, but it doesn't make sense to have relative Z of the IME, if the task is not yet to be the IME control target. Consolide "canImeTargetSetRelativeLayer" check in DC#assignRelativeLayerForIme with checking if the current layering target is IME control target. Will not set relative Z if the target is not yet to be IME control target. [1]: I3024443c21cfb1c7971f3999640039caea10d0d5 Bug: 201139555 Bug: 204140533 Test: atest ZOrderingTests Merged-In: Iae65d6047c02dae241f2df21c666a03cca58fd0b Change-Id: Iae65d6047c02dae241f2df21c666a03cca58fd0b --- services/core/java/com/android/server/wm/DisplayContent.java | 1 + .../wmtests/src/com/android/server/wm/ZOrderingTests.java | 3 +++ 2 files changed, 4 insertions(+) diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 51f470444950d..07ab571450509 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -5028,6 +5028,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp if (imeTarget != null && !(imeTarget.mActivityRecord != null && imeTarget.mActivityRecord.hasStartingWindow())) { final boolean canImeTargetSetRelativeLayer = imeTarget.getSurfaceControl() != null + && imeTarget == mImeControlTarget && !imeTarget.inMultiWindowMode() && imeTarget.mToken.getActivity(app -> app.isAnimating(TRANSITION | PARENTS, ANIMATION_TYPE_ALL & ~ANIMATION_TYPE_RECENTS)) == null; 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 be5fd59cf66d2..b3ba217955ea4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java @@ -298,6 +298,7 @@ public class ZOrderingTests extends WindowTestsBase { final WindowState appAboveImeTarget = createWindow("appAboveImeTarget"); mDisplayContent.setImeLayeringTarget(imeAppTarget); + mDisplayContent.setImeControlTarget(imeAppTarget); mDisplayContent.assignChildLayers(mTransaction); // Ime should be above all app windows except for non-fullscreen app window above it and @@ -344,6 +345,7 @@ public class ZOrderingTests extends WindowTestsBase { @Test public void testAssignWindowLayers_ForStatusBarImeTarget() { mDisplayContent.setImeLayeringTarget(mStatusBarWindow); + mDisplayContent.setImeControlTarget(mStatusBarWindow); mDisplayContent.assignChildLayers(mTransaction); assertWindowHigher(mImeWindow, mChildAppWindowAbove); @@ -409,6 +411,7 @@ public class ZOrderingTests extends WindowTestsBase { mAppWindow.mActivityRecord, "imeAppTarget"); mDisplayContent.setImeInputTarget(imeAppTarget); mDisplayContent.setImeLayeringTarget(imeAppTarget); + mDisplayContent.setImeControlTarget(imeAppTarget); mDisplayContent.updateImeParent(); // Simulate the ime layering target task is animating with recents animation.