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

Commit a0e471c1 authored by Johannes Gallmann's avatar Johannes Gallmann
Browse files

Prevent IME predictive back control during hide anim

Insets control should not be granted to ImeBackAnimationController when
there is already a hide animation in progress.

Bug: 362436187
Test: InsetsControllerTest
Flag: android.view.inputmethod.predictive_back_ime
Change-Id: I6284441bc91502c74f03aa6880d0fbb0614e7781
parent 0bda5605
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -1307,7 +1307,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            WindowInsetsAnimationControlListener listener,
            boolean fromIme, long durationMs, @Nullable Interpolator interpolator,
            @AnimationType int animationType, boolean fromPredictiveBack) {
        if ((mState.calculateUncontrollableInsetsFromFrame(mFrame) & types) != 0) {
        if ((mState.calculateUncontrollableInsetsFromFrame(mFrame) & types) != 0
                || (fromPredictiveBack && ((mRequestedVisibleTypes & ime()) == 0))) {
            // abort if insets are uncontrollable or if control request is from predictive back but
            // there is already a hide anim in progress
            listener.onCancelled(null);
            return;
        }
+31 −0
Original line number Diff line number Diff line
@@ -1131,6 +1131,37 @@ public class InsetsControllerTest {
        });
    }

    @Test
    public void testPredictiveBackControlRequestCancelledDuringImeHideAnim() {
        prepareControls();
        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
            // show ime as initial state
            if (!Flags.refactorInsetsController()) {
                mController.show(ime(), true /* fromIme */, ImeTracker.Token.empty());
            } else {
                mController.show(ime(), false /* fromIme */, ImeTracker.Token.empty());
            }
            mController.cancelExistingAnimations(); // fast forward show animation
            mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();
            assertTrue(mController.getState().peekSource(ID_IME).isVisible());

            // start IME hide animation
            mController.hide(ime(), true /* fromIme */, null /* statsToken */);
            assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ime()));

            // start control request (for predictive back animation)
            WindowInsetsAnimationControlListener listener =
                    mock(WindowInsetsAnimationControlListener.class);
            mController.controlWindowInsetsAnimation(ime(), /*cancellationSignal*/ null,
                    listener, /*fromIme*/ false, /*duration*/ -1, /*interpolator*/ null,
                    ANIMATION_TYPE_USER, /*fromPredictiveBack*/ true);

            // verify that control request is cancelled and animation type remains HIDE
            verify(listener).onCancelled(any());
            assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ime()));
        });
    }

    private void waitUntilNextFrame() throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);
        Choreographer.getMainThreadInstance().postCallback(Choreographer.CALLBACK_COMMIT,