Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a308e124 authored by Ming-Shin Lu's avatar Ming-Shin Lu
Browse files

Fix updateAboveInsetsState may not apply IME window in some cases

In case updateAboveInsetsState didn't apply IME window to update
app's above insets state when an edge case happens during unlocking
the device that WindowState#applyImeWindowsIfNeeded returns false
because the input target has not yet being drawn or visible,

we should keep applying the IME window to update the input target's
insets state when the input target is during unlock and in requested
visible state.

Bug: 246402296
Bug: 201987724
Test: atest InsetsStateControllerTest#\
       testUpdateAboveInsetsState_imeTargetOnScreenBehavior
Test: atest RemoteAnimationControllerTest#\
       testLaunchRemoteAnimationWithoutImeBehind
Test: manual as Bug 246402296
      1) Launch a chat app
      2) Start a chat channel to show IME
      3) Press power button to turn the screen off
      4) Press power button to turn the screen on and unlock
      5) Expect the chat activity looks fine without flickers
Test: manual as Bug 201987724
    0-1) Set secure unlock method (e.g. pattern)
    0-2) Install "Google Pay" app
    0-3) Add a payment method instruction
    1) Start Message app
    2) Click search window and wait IME window appears
    3) Hit power button to lock the device
    4) Tap screen to show Lockscreen
    5) Tap GPay icon
    6) See animation and expect there is no IME flickering behind

Change-Id: Ib43f4e2659d3afab63dc327f5f939fbd13afa5f3
parent f9ca7a2f
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -4927,7 +4927,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
        // animation on the keyguard but seeing the IME window that originally on the app
        // which behinds the keyguard.
        final WindowState imeInputTarget = getImeInputTarget();
        if (imeInputTarget != null && !(imeInputTarget.isDrawn() || imeInputTarget.isVisible())) {
        if (imeInputTarget != null
                && !(imeInputTarget.isDrawn() || imeInputTarget.isVisibleRequested())) {
            return false;
        }
        return mDisplayContent.forAllImeWindows(callback, traverseTopToBottom);
+38 −0
Original line number Diff line number Diff line
@@ -442,6 +442,44 @@ public class InsetsStateControllerTest extends WindowTestsBase {
        verify(navBar, atLeastOnce()).notifyInsetsChanged();
    }

    @Test
    public void testUpdateAboveInsetsState_imeTargetOnScreenBehavior() {
        final WindowToken imeToken = createTestWindowToken(TYPE_INPUT_METHOD, mDisplayContent);
        final WindowState ime = createWindow(null,  TYPE_INPUT_METHOD, imeToken, "ime");
        final WindowState app = createTestWindow("app");

        getController().getSourceProvider(ITYPE_IME).setWindowContainer(ime, null, null);
        ime.getControllableInsetProvider().setServerVisible(true);

        app.mActivityRecord.setVisibility(true);
        mDisplayContent.setImeLayeringTarget(app);
        mDisplayContent.updateImeInputAndControlTarget(app);

        app.setRequestedVisibleTypes(ime(), ime());
        getController().onInsetsModified(app);
        assertTrue(ime.getControllableInsetProvider().getSource().isVisible());

        getController().updateAboveInsetsState(true /* notifyInsetsChange */);
        assertNotNull(app.getInsetsState().peekSource(ITYPE_IME));
        verify(app, atLeastOnce()).notifyInsetsChanged();

        // Expect the app will still get IME insets even when the app was invisible.
        // (i.e. app invisible after locking the device)
        app.mActivityRecord.setVisible(false);
        app.setHasSurface(false);
        getController().updateAboveInsetsState(true /* notifyInsetsChange */);
        assertNotNull(app.getInsetsState().peekSource(ITYPE_IME));
        verify(app, atLeastOnce()).notifyInsetsChanged();

        // Expect the app will get IME insets when the app is requesting visible.
        // (i.e. app is going to visible when unlocking the device)
        app.mActivityRecord.setVisibility(true);
        assertTrue(app.isVisibleRequested());
        getController().updateAboveInsetsState(true /* notifyInsetsChange */);
        assertNotNull(app.getInsetsState().peekSource(ITYPE_IME));
        verify(app, atLeastOnce()).notifyInsetsChanged();
    }

    @Test
    public void testDispatchGlobalInsets() {
        final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
+1 −0
Original line number Diff line number Diff line
@@ -772,6 +772,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
            // Simulating now win1 is being covered by the lockscreen which has no surface,
            // and then launching an activity win2 with the remote animation
            win1.mHasSurface = false;
            win1.mActivityRecord.setVisibility(false);
            mDisplayContent.mOpeningApps.add(win2.mActivityRecord);
            final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
                    win2.mActivityRecord, new Point(50, 100), null,