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

Commit ab9fa4d2 authored by Ming-Shin Lu's avatar Ming-Shin Lu Committed by Automerger Merge Worker
Browse files

Merge "Fix IME flicker by dispatching unrelated insets after unset IME frozen"...

Merge "Fix IME flicker by dispatching unrelated insets after unset IME frozen" into sc-v2-dev am: 02a181f7 am: 3f52d48d

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16663837

Change-Id: Iaf1036d48d82527121b530c6bc159365f86bcbb1
parents ccbd71c7 3f52d48d
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -4146,9 +4146,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
     * which controls the visibility and animation of the input method window.
     */
    void updateImeInputAndControlTarget(WindowState target) {
        if (target != null && target.mActivityRecord != null) {
            target.mActivityRecord.mImeInsetsFrozenUntilStartInput = false;
        }
        if (mImeInputTarget != target) {
            ProtoLog.i(WM_DEBUG_IME, "setInputMethodInputTarget %s", target);
            setImeInputTarget(target);
@@ -4156,6 +4153,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
                    .getRawInsetsState().getSourceOrDefaultVisibility(ITYPE_IME));
            updateImeControlTarget();
        }
        // Unfreeze IME insets after the new target updated, in case updateAboveInsetsState may
        // deliver unrelated IME insets change to the non-IME requester.
        if (target != null && target.mActivityRecord != null) {
            target.mActivityRecord.mImeInsetsFrozenUntilStartInput = false;
        }
    }

    void updateImeControlTarget() {
+47 −0
Original line number Diff line number Diff line
@@ -103,6 +103,7 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;

@@ -136,6 +137,7 @@ import android.view.IWindowManager;
import android.view.IWindowSession;
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.InsetsVisibilities;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
import android.view.Surface;
@@ -152,6 +154,7 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.invocation.InvocationOnMock;

import java.util.ArrayList;
@@ -3065,6 +3068,50 @@ public class ActivityRecordTests extends WindowTestsBase {
        assertEquals(state.getSource(ITYPE_IME).getFrame(), imeSource.getFrame());
    }

    @UseTestDisplay(addWindows = {W_ACTIVITY, W_INPUT_METHOD})
    @Test
    public void testImeInsetsFrozenFlag_noDispatchVisibleInsetsWhenAppNotRequest()
            throws RemoteException {
        final WindowState app1 = createWindow(null, TYPE_APPLICATION, "app1");
        final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2");

        mDisplayContent.getInsetsStateController().getSourceProvider(ITYPE_IME).setWindow(
                mImeWindow, null, null);
        mImeWindow.getControllableInsetProvider().setServerVisible(true);

        // Simulate app2 is closing and let app1 is visible to be IME targets.
        makeWindowVisibleAndDrawn(app1, mImeWindow);
        mDisplayContent.setImeLayeringTarget(app1);
        mDisplayContent.updateImeInputAndControlTarget(app1);
        app2.mActivityRecord.commitVisibility(false, false);

        // app1 requests IME visible.
        final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
        requestedVisibilities.setVisibility(ITYPE_IME, true);
        app1.setRequestedVisibilities(requestedVisibilities);
        mDisplayContent.getInsetsStateController().onInsetsModified(app1);

        // Verify app1's IME insets is visible and app2's IME insets frozen flag set.
        assertTrue(app1.getInsetsState().peekSource(ITYPE_IME).isVisible());
        assertTrue(app2.mActivityRecord.mImeInsetsFrozenUntilStartInput);

        // Simulate switching to app2 to make it visible to be IME targets.
        makeWindowVisibleAndDrawn(app2);
        spyOn(app2);
        spyOn(app2.mClient);
        ArgumentCaptor<InsetsState> insetsStateCaptor = ArgumentCaptor.forClass(InsetsState.class);
        doReturn(true).when(app2).isReadyToDispatchInsetsState();
        mDisplayContent.setImeLayeringTarget(app2);
        mDisplayContent.updateImeInputAndControlTarget(app2);

        // Verify after unfreezing app2's IME insets state, we won't dispatch visible IME insets
        // to client if the app didn't request IME visible.
        assertFalse(app2.mActivityRecord.mImeInsetsFrozenUntilStartInput);
        verify(app2.mClient, atLeastOnce()).insetsChanged(insetsStateCaptor.capture(), anyBoolean(),
                anyBoolean());
        assertFalse(insetsStateCaptor.getAllValues().get(0).peekSource(ITYPE_IME).isVisible());
    }

    @Test
    public void testInClosingAnimation_doNotHideSurface() {
        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");