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

Commit 469cbe90 authored by Ming-Shin Lu's avatar Ming-Shin Lu Committed by Android (Google) Code Review
Browse files

Merge "Fix IME jumpcut when playing user IME animation after IME restarted" into tm-qpr-dev

parents 62b30d3e caeb909e
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -176,7 +176,9 @@ public class InsetsSourceConsumer {

                // If we have a new leash, make sure visibility is up-to-date, even though we
                // didn't want to run an animation above.
                if (mController.getAnimationType(control.getType()) == ANIMATION_TYPE_NONE) {
                    applyRequestedVisibilityToControl();
                }

                // Remove the surface that owned by last control when it lost.
                if (!requestedVisible && lastControl == null) {
+43 −4
Original line number Diff line number Diff line
@@ -18,8 +18,10 @@ package android.view;

import static android.view.InsetsController.ANIMATION_TYPE_NONE;
import static android.view.InsetsController.ANIMATION_TYPE_USER;
import static android.view.InsetsSourceConsumer.ShowResult.SHOW_IMMEDIATELY;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.statusBars;

import static junit.framework.Assert.assertEquals;
@@ -28,6 +30,7 @@ import static junit.framework.TestCase.assertTrue;

import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
@@ -75,6 +78,7 @@ public class InsetsSourceConsumerTest {
    private boolean mRemoveSurfaceCalled = false;
    private InsetsController mController;
    private InsetsState mState;
    private ViewRootImpl mViewRoot;

    @Before
    public void setup() {
@@ -86,10 +90,9 @@ public class InsetsSourceConsumerTest {
        instrumentation.runOnMainSync(() -> {
            final Context context = instrumentation.getTargetContext();
            // cannot mock ViewRootImpl since it's final.
            final ViewRootImpl viewRootImpl = new ViewRootImpl(context,
                    context.getDisplayNoVerify());
            mViewRoot = new ViewRootImpl(context, context.getDisplayNoVerify());
            try {
                viewRootImpl.setView(new TextView(context), new LayoutParams(), null);
                mViewRoot.setView(new TextView(context), new LayoutParams(), null);
            } catch (BadTokenException e) {
                // activity isn't running, lets ignore BadTokenException.
            }
@@ -97,7 +100,7 @@ public class InsetsSourceConsumerTest {
            mSpyInsetsSource = Mockito.spy(new InsetsSource(ITYPE_STATUS_BAR));
            mState.addSource(mSpyInsetsSource);

            mController = new InsetsController(new ViewRootInsetsControllerHost(viewRootImpl));
            mController = new InsetsController(new ViewRootInsetsControllerHost(mViewRoot));
            mConsumer = new InsetsSourceConsumer(ITYPE_STATUS_BAR, mState,
                    () -> mMockTransaction, mController) {
                @Override
@@ -207,4 +210,40 @@ public class InsetsSourceConsumerTest {
        });

    }

    @Test
    public void testWontUpdateImeLeashVisibility_whenAnimation() {
        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
            InsetsState state = new InsetsState();
            ViewRootInsetsControllerHost host = new ViewRootInsetsControllerHost(mViewRoot);
            InsetsController insetsController = new InsetsController(host, (controller, type) -> {
                if (type == ITYPE_IME) {
                    return new InsetsSourceConsumer(ITYPE_IME, state,
                            () -> mMockTransaction, controller) {
                        @Override
                        public int requestShow(boolean fromController) {
                            return SHOW_IMMEDIATELY;
                        }
                    };
                }
                return new InsetsSourceConsumer(type, controller.getState(), Transaction::new,
                        controller);
            }, host.getHandler());
            InsetsSourceConsumer imeConsumer = insetsController.getSourceConsumer(ITYPE_IME);

            // Initial IME insets source control with its leash.
            imeConsumer.setControl(new InsetsSourceControl(ITYPE_IME, mLeash,
                    false /* initialVisible */, new Point(), Insets.NONE), new int[1], new int[1]);
            reset(mMockTransaction);

            // Verify when the app requests controlling show IME animation, the IME leash
            // visibility won't be updated when the consumer received the same leash in setControl.
            insetsController.controlWindowInsetsAnimation(ime(), 0L,
                    null /* interpolator */, null /* cancellationSignal */, null /* listener */);
            assertTrue(insetsController.getAnimationType(ITYPE_IME) == ANIMATION_TYPE_USER);
            imeConsumer.setControl(new InsetsSourceControl(ITYPE_IME, mLeash,
                    true /* initialVisible */, new Point(), Insets.NONE), new int[1], new int[1]);
            verify(mMockTransaction, never()).show(mLeash);
        });
    }
}
+11 −4
Original line number Diff line number Diff line
@@ -4388,13 +4388,20 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
     */
    @VisibleForTesting
    InsetsControlTarget computeImeControlTarget() {
        if (mImeInputTarget == null) {
            // A special case that if there is no IME input target while the IME is being killed,
            // in case seeing unexpected IME surface visibility change when delivering the IME leash
            // to the remote insets target during the IME restarting, but the focus window is not in
            // multi-windowing mode, return null target until the next input target updated.
            return null;
        }

        final WindowState imeInputTarget = mImeInputTarget.getWindowState();
        if (!isImeControlledByApp() && mRemoteInsetsControlTarget != null
                || (mImeInputTarget != null
                        && getImeHostOrFallback(mImeInputTarget.getWindowState())
                               == mRemoteInsetsControlTarget)) {
                || getImeHostOrFallback(imeInputTarget) == mRemoteInsetsControlTarget) {
            return mRemoteInsetsControlTarget;
        } else {
            return mImeInputTarget != null ? mImeInputTarget.getWindowState() : null;
            return imeInputTarget;
        }
    }

+9 −1
Original line number Diff line number Diff line
@@ -1251,7 +1251,15 @@ public class DisplayContentTests extends WindowTestsBase {
    public void testComputeImeControlTarget() throws Exception {
        final DisplayContent dc = createNewDisplay();
        dc.setRemoteInsetsController(createDisplayWindowInsetsController());
        dc.setImeInputTarget(createWindow(null, TYPE_BASE_APPLICATION, "app"));
        dc.mCurrentFocus = createWindow(null, TYPE_BASE_APPLICATION, "app");

        // Expect returning null IME control target when the focus window has not yet been the
        // IME input target (e.g. IME is restarting) in fullscreen windowing mode.
        dc.setImeInputTarget(null);
        assertFalse(dc.mCurrentFocus.inMultiWindowMode());
        assertNull(dc.computeImeControlTarget());

        dc.setImeInputTarget(dc.mCurrentFocus);
        dc.setImeLayeringTarget(dc.getImeInputTarget().getWindowState());
        assertEquals(dc.getImeInputTarget().getWindowState(), dc.computeImeControlTarget());
    }