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

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

Freezing IME insets when screen turned-off

An animation flicker case happens when power off/on then unlocking the
device to show an IME activity, sometimes will seeing the app
layout jumps up-and-down after dismissing the snapshot starting window.

The root cause is when turning off the screen, IME window will be hidden
because of keyguard policy change. Then ImeInsetsProvider will
receive onPostLayout to update the insets server frame as invisible and
deliver this invisible insets change to the control target.

Also, showing IME and updating IME insets visibility requires to take
time until the IME starts the input after resuming the IME activity.

As a result, fix this flicker issue with

- Add ImeInsetsSourceProvider#setFrozen(boolean) to freeze the IME state
  when turning off the screen (And unfreeze when the IME is going to
  visible after unlocking the screen).

- Override setServerVisible for ImeInsetsSourceProvider to freeze server
  visiblity when setFrozen(true) gets called.

Bug: 246402296
Test: atest CtsInputMethodTestCases
Test: atest WindowContainerTests ActivityRecordTests
Test: atest ImeInsetsSourceProviderTest
Test: manual with the issue steps:
  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

Change-Id: Icfec9a491681406a382c74b690d8ef303848b32e
parent 46afac61
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -1638,7 +1638,16 @@ public class DisplayPolicy {
     */
    private void applyKeyguardPolicy(WindowState win, WindowState imeTarget) {
        if (win.canBeHiddenByKeyguard()) {
            if (shouldBeHiddenByKeyguard(win, imeTarget)) {
            final boolean shouldBeHiddenByKeyguard = shouldBeHiddenByKeyguard(win, imeTarget);
            if (win.mIsImWindow) {
                // Notify IME insets provider to freeze the IME insets. In case when turning off
                // the screen, the IME insets source window will be hidden because of keyguard
                // policy change and affects the system to freeze the last insets state. (And
                // unfreeze when the IME is going to show)
                mDisplayContent.getInsetsStateController().getImeSourceProvider().setFrozen(
                        shouldBeHiddenByKeyguard);
            }
            if (shouldBeHiddenByKeyguard) {
                win.hide(false /* doAnimation */, true /* requestAnim */);
            } else {
                win.show(false /* doAnimation */, true /* requestAnim */);
+32 −0
Original line number Diff line number Diff line
@@ -55,6 +55,12 @@ final class ImeInsetsSourceProvider extends WindowContainerInsetsSourceProvider
    private boolean mImeShowing;
    private final InsetsSource mLastSource = new InsetsSource(ITYPE_IME);

    /** @see #setFrozen(boolean) */
    private boolean mFrozen;

    /** @see #setServerVisible(boolean) */
    private boolean mServerVisible;

    ImeInsetsSourceProvider(InsetsSource source,
            InsetsStateController stateController, DisplayContent displayContent) {
        super(source, stateController, displayContent);
@@ -80,6 +86,32 @@ final class ImeInsetsSourceProvider extends WindowContainerInsetsSourceProvider
        return control;
    }

    @Override
    void setServerVisible(boolean serverVisible) {
        mServerVisible = serverVisible;
        if (!mFrozen) {
            super.setServerVisible(serverVisible);
        }
    }

    /**
     * Freeze IME insets source state when required.
     *
     * When setting {@param frozen} as {@code true}, the IME insets provider will freeze the
     * current IME insets state and pending the IME insets state update until setting
     * {@param frozen} as {@code false}.
     */
    void setFrozen(boolean frozen) {
        if (mFrozen == frozen) {
            return;
        }
        mFrozen = frozen;
        if (!frozen) {
            // Unfreeze and process the pending IME insets states.
            super.setServerVisible(mServerVisible);
        }
    }

    @Override
    void updateSourceFrame(Rect frame) {
        super.updateSourceFrame(frame);
+22 −0
Original line number Diff line number Diff line
@@ -85,4 +85,26 @@ public class ImeInsetsSourceProviderTest extends WindowTestsBase {
        mImeProvider.setImeShowing(false);
        assertFalse(mImeProvider.isImeShowing());
    }

    @Test
    public void testSetFrozen() {
        WindowState ime = createWindow(null, TYPE_INPUT_METHOD, "ime");
        makeWindowVisibleAndDrawn(ime);
        mImeProvider.setWindowContainer(ime, null, null);
        mImeProvider.setServerVisible(true);
        mImeProvider.setClientVisible(true);
        mImeProvider.updateVisibility();
        assertTrue(mImeProvider.getSource().isVisible());

        // Freezing IME states and set the server visible as false.
        mImeProvider.setFrozen(true);
        mImeProvider.setServerVisible(false);
        // Expect the IME insets visible won't be changed.
        assertTrue(mImeProvider.getSource().isVisible());

        // Unfreeze IME states and expect the IME insets became invisible due to pending IME
        // visible state updated.
        mImeProvider.setFrozen(false);
        assertFalse(mImeProvider.getSource().isVisible());
    }
}