From 9a1c747208ee0e809b1b26a01b68267500a9c7e0 Mon Sep 17 00:00:00 2001 From: Ming-Shin Lu Date: Mon, 17 May 2021 23:29:36 +0800 Subject: [PATCH] Fix lockscreen can't get IME insets when split-screen activated As CL[1] fixed Keyboard covered input box after leaving split screen with using getDefaultTaskDisplayArea().isSplitScreenModeActivated() to check if needs to let IME window above the window when updating the above insets state of windows, in case the windowing mode configuration change not yet updated correctly during task reparenting. However, this change will let notificationShade won't get IME insets like when password lock shown, even split-screen is activated behind. Since notificationShade is not the task window and shouldn't be affected with splict-screen activivated checking, and we should exclude for non-task window to ensure the shade can get IME insets. [1]: I47bcb1234a49ea35c5e0d7281973fb3237e420eb Fix: 188126678 Test: atest WindowStateTests#\ testNotificationShadeHasImeInsetsWhenSplitscreenActivated Test: manual as issue steps: 1) Set password lock 2) Active split screen with any 2 apps 3) Lock phone then try to unlock 4) Verify if password entry is visible and not covered by IME Change-Id: Iff537bead93c977d19b820d6e64286a46f8e4982 --- .../com/android/server/wm/DisplayContent.java | 7 ++-- .../com/android/server/wm/WindowState.java | 5 +-- .../android/server/wm/WindowStateTests.java | 33 +++++++++++++++++++ 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 1ec07d047e13f..735fae3391a2d 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -4603,13 +4603,14 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return super.forAllWindows(callback, traverseTopToBottom); } - private boolean skipImeWindowsDuringTraversal(DisplayContent dc) { + private static boolean skipImeWindowsDuringTraversal(DisplayContent dc) { // We skip IME windows so they're processed just above their target, except // in split-screen mode where we process the IME containers above the docked divider. // Note that this method check should align with {@link // WindowState#applyImeWindowsIfNeeded} in case of any state mismatch. - return dc.getImeTarget(IME_TARGET_LAYERING) != null - && !dc.getDefaultTaskDisplayArea().isSplitScreenModeActivated(); + return dc.mImeLayeringTarget != null + && (!dc.getDefaultTaskDisplayArea().isSplitScreenModeActivated() + || dc.mImeLayeringTarget.getTask() == null); } /** Like {@link #forAllWindows}, but ignores {@link #skipImeWindowsDuringTraversal} */ diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index b93312acb0558..d09cc46a8cb44 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -4855,8 +4855,9 @@ class WindowState extends WindowContainer implements WindowManagerP // (i.e. Like {@link DisplayContent.ImeContainer#skipImeWindowsDuringTraversal}, the IME // window will be ignored to traverse when the IME target is still in split-screen mode). if (isImeLayeringTarget() - && !getDisplayContent().getDefaultTaskDisplayArea().isSplitScreenModeActivated()) { - if (getDisplayContent().forAllImeWindows(callback, traverseTopToBottom)) { + && (!mDisplayContent.getDefaultTaskDisplayArea().isSplitScreenModeActivated() + || getTask() == null)) { + if (mDisplayContent.forAllImeWindows(callback, traverseTopToBottom)) { return true; } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index e3b0bb263830f..152a575c847dc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; +import static android.view.InsetsState.ITYPE_IME; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_STATUS_BAR; import static android.view.Surface.ROTATION_0; @@ -50,6 +51,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; 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.DisplayContent.IME_TARGET_CONTROL; +import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; import static com.android.server.wm.WindowContainer.SYNC_STATE_WAITING_FOR_DRAW; import static com.google.common.truth.Truth.assertThat; @@ -58,6 +60,7 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; @@ -923,4 +926,34 @@ public class WindowStateTests extends WindowTestsBase { verify(app.getDisplayContent()).updateImeControlTarget(); assertEquals(mAppWindow, mDisplayContent.getImeTarget(IME_TARGET_CONTROL).getWindow()); } + + @UseTestDisplay(addWindows = { W_ACTIVITY, W_INPUT_METHOD, W_NOTIFICATION_SHADE }) + @Test + public void testNotificationShadeHasImeInsetsWhenSplitscreenActivated() { + WindowState app = createWindow(null, TYPE_BASE_APPLICATION, + mAppWindow.mToken, "app"); + + // Simulate entering multi-window mode and verify if the split-screen is activated. + app.mActivityRecord.getRootTask().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); + assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, app.getWindowingMode()); + assertTrue(mDisplayContent.getDefaultTaskDisplayArea().isSplitScreenModeActivated()); + + // Simulate notificationShade is shown and being IME layering target. + mNotificationShadeWindow.setHasSurface(true); + mNotificationShadeWindow.mAttrs.flags &= ~FLAG_NOT_FOCUSABLE; + assertTrue(mNotificationShadeWindow.canBeImeTarget()); + mDisplayContent.getInsetsStateController().getSourceProvider(ITYPE_IME).setWindow( + mImeWindow, null, null); + + mDisplayContent.computeImeTarget(true); + assertEquals(mNotificationShadeWindow, mDisplayContent.getImeTarget(IME_TARGET_LAYERING)); + mDisplayContent.getInsetsStateController().getRawInsetsState() + .setSourceVisible(ITYPE_IME, true); + + // Verify notificationShade can still get IME insets even the split-screen is activated. + InsetsState state = mDisplayContent.getInsetsStateController().getInsetsForWindow( + mNotificationShadeWindow); + assertNotNull(state.peekSource(ITYPE_IME)); + assertTrue(state.getSource(ITYPE_IME).isVisible()); + } }