From 08579765ecf31c676852ca05640a16365cadf168 Mon Sep 17 00:00:00 2001 From: Ming-Shin Lu Date: Fri, 19 Mar 2021 00:31:03 +0800 Subject: [PATCH] Fix NavigationBar overlapping with the IME window As WindowToken#setInsetsFrozen that introduced by CL[1], [2] that used for freezing dispathcing insets state when the app transitioning or becoming invisible. To prevent unnecessary app UI glitch during dispatching insets changes while animating, the method call ends up setting frozen insets state for all children windows. Since forAllWindows will call forAllImeWindows to also set frozen insets state for IME window when the window is IME layering targets and not in split-screen windowing mode, which is not expected because the IME window is controlled by IME insets provider and should not have frozen insets state to make IME UI been overlapped with navbar because of wrong insets state. Make sure to set frozen state only for the window belongs to the same window token. [1]: Iae5025beaed7d70a4623b446a1bb73574d420663 [2]: I56418733c1abbd73e88a8918a5d55ecc15344c5e Fix: 181840663 Test: manual as issue steps: 1) Factory reset device. 2) Skip Setup Wizard. 3) Select a WIFI hotspot which require a password to show up keyboard 4) Verify if IME layout correctly without overlapping with navbar. Test: atest WindowTokenTests#testSetInsetsFrozen_notAffectImeWindowState Change-Id: I9442095e833bf430f49cd824af2ab430da5d662c --- .../com/android/server/wm/WindowToken.java | 14 ++++++---- .../android/server/wm/WindowTokenTests.java | 26 +++++++++++++++++++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 8867aa747379b..193c74f7ec503 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -758,10 +758,14 @@ class WindowToken extends WindowContainer { /** @see WindowState#freezeInsetsState() */ void setInsetsFrozen(boolean freeze) { - if (freeze) { - forAllWindows(WindowState::freezeInsetsState, true /* traverseTopToBottom */); - } else { - forAllWindows(WindowState::clearFrozenInsetsState, true /* traverseTopToBottom */); - } + forAllWindows(w -> { + if (w.mToken == this) { + if (freeze) { + w.freezeInsetsState(); + } else { + w.clearFrozenInsetsState(); + } + } + }, true /* traverseTopToBottom */); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java index e2585e5ebfbaf..16e0d90ac2d3c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.view.InsetsState.ITYPE_IME; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; @@ -250,4 +251,29 @@ public class WindowTokenTests extends WindowTestsBase { verify(selectFunc).apply(token2.windowType, options); } + + /** + * Test that {@link WindowToken#setInsetsFrozen(boolean)} will set the frozen insets + * states for its children windows and by default it shouldn't let IME window setting + * the frozen insets state even the window of the window token is the IME layering target. + */ + @UseTestDisplay(addWindows = W_INPUT_METHOD) + @Test + public void testSetInsetsFrozen_notAffectImeWindowState() { + // Pre-condition: make the IME window be controlled by IME insets provider. + mDisplayContent.getInsetsStateController().getSourceProvider(ITYPE_IME).setWindow( + mDisplayContent.mInputMethodWindow, null, null); + + // Simulate an app window to be the IME layering target, assume the app window has no + // frozen insets state by default. + final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + mDisplayContent.setImeLayeringTarget(app); + assertNull(app.getFrozenInsetsState()); + assertTrue(app.isImeLayeringTarget()); + + // Verify invoking setInsetsFrozen shouldn't let IME window setting the frozen insets state. + app.mToken.setInsetsFrozen(true); + assertNotNull(app.getFrozenInsetsState()); + assertNull(mDisplayContent.mInputMethodWindow.getFrozenInsetsState()); + } }