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
This commit is contained in:
Ming-Shin Lu
2022-11-24 12:00:39 +08:00
parent f9ca7a2ffd
commit a308e124d1
3 changed files with 41 additions and 1 deletions

View File

@@ -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);

View File

@@ -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");

View File

@@ -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,