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

Commit 42452428 authored by Johannes Gallmann's avatar Johannes Gallmann Committed by Android (Google) Code Review
Browse files

Merge "Prevent insets switch during IME predictive back animation..." into main

parents f14a72ed bf9d8106
Loading
Loading
Loading
Loading
+14 −21
Original line number Diff line number Diff line
@@ -149,15 +149,17 @@ public class ImeBackAnimationController implements OnBackAnimationCallback {

    private void setPreCommitProgress(float progress) {
        if (isHideAnimationInProgress()) return;
        setInterpolatedProgress(BACK_GESTURE.getInterpolation(progress) * PEEK_FRACTION);
    }

    private void setInterpolatedProgress(float progress) {
        if (mWindowInsetsAnimationController != null) {
            float hiddenY = mWindowInsetsAnimationController.getHiddenStateInsets().bottom;
            float shownY = mWindowInsetsAnimationController.getShownStateInsets().bottom;
            float imeHeight = shownY - hiddenY;
            float interpolatedProgress = BACK_GESTURE.getInterpolation(progress);
            int newY = (int) (imeHeight - interpolatedProgress * (imeHeight * PEEK_FRACTION));
            int newY = (int) (imeHeight - progress * imeHeight);
            if (mStartRootScrollY != 0) {
                mViewRoot.setScrollY(
                        (int) (mStartRootScrollY * (1 - interpolatedProgress * PEEK_FRACTION)));
                mViewRoot.setScrollY((int) (mStartRootScrollY * (1 - progress)));
            }
            mWindowInsetsAnimationController.setInsetsAndAlpha(Insets.of(0, 0, 0, newY), 1f,
                    progress);
@@ -171,21 +173,14 @@ public class ImeBackAnimationController implements OnBackAnimationCallback {
            return;
        }
        mTriggerBack = triggerBack;
        int currentBottomInset = mWindowInsetsAnimationController.getCurrentInsets().bottom;
        int targetBottomInset;
        if (triggerBack) {
            targetBottomInset = mWindowInsetsAnimationController.getHiddenStateInsets().bottom;
        } else {
            targetBottomInset = mWindowInsetsAnimationController.getShownStateInsets().bottom;
        }
        mPostCommitAnimator = ValueAnimator.ofFloat(currentBottomInset, targetBottomInset);
        float targetProgress = triggerBack ? 1f : 0f;
        mPostCommitAnimator = ValueAnimator.ofFloat(
                BACK_GESTURE.getInterpolation(mLastProgress) * PEEK_FRACTION, targetProgress);
        mPostCommitAnimator.setInterpolator(
                triggerBack ? STANDARD_ACCELERATE : EMPHASIZED_DECELERATE);
        mPostCommitAnimator.addUpdateListener(animation -> {
            int bottomInset = (int) ((float) animation.getAnimatedValue());
            if (mWindowInsetsAnimationController != null) {
                mWindowInsetsAnimationController.setInsetsAndAlpha(Insets.of(0, 0, 0, bottomInset),
                        1f, animation.getAnimatedFraction());
                setInterpolatedProgress((float) animation.getAnimatedValue());
            } else {
                reset();
            }
@@ -213,14 +208,8 @@ public class ImeBackAnimationController implements OnBackAnimationCallback {
            notifyHideIme();
            // requesting IME as invisible during post-commit
            mInsetsController.setRequestedVisibleTypes(0, ime());
            // Changes the animation state. This also notifies RootView of changed insets, which
            // causes it to reset its scrollY to 0f (animated) if it was panned
            mInsetsController.onAnimationStateChanged(ime(), /*running*/ true);
        }
        if (mStartRootScrollY != 0 && !triggerBack) {
            // This causes RootView to update its scroll back to the panned position
            mInsetsController.getHost().notifyInsetsChanged();
        }
    }

    private void notifyHideIme() {
@@ -282,6 +271,10 @@ public class ImeBackAnimationController implements OnBackAnimationCallback {
        return mPostCommitAnimator != null && mTriggerBack;
    }

    boolean isAnimationInProgress() {
        return mIsPreCommitAnimationInProgress || mWindowInsetsAnimationController != null;
    }

    /**
     * Dump information about this ImeBackAnimationController
     *
+8 −1
Original line number Diff line number Diff line
@@ -70,7 +70,14 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
                        "ImeInsetsSourceConsumer#onAnimationFinished",
                        mController.getHost().getInputMethodManager(), null /* icProto */);
            }
            boolean insetsChanged = super.onAnimationStateChanged(running);
            boolean insetsChanged = false;
            if (Flags.predictiveBackIme() && !running && isShowRequested()
                    && mAnimationState == ANIMATION_STATE_HIDE) {
                // A user controlled hide animation may have ended in the shown state (e.g.
                // cancelled predictive back animation) -> Insets need to be reset to shown.
                insetsChanged |= applyLocalVisibilityOverride();
            }
            insetsChanged |= super.onAnimationStateChanged(running);
            if (running && !isShowRequested()
                    && mController.isPredictiveBackImeHideAnimInProgress()) {
                // IME predictive back animation switched from pre-commit to post-commit.
+20 −13
Original line number Diff line number Diff line
@@ -1197,7 +1197,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                pendingRequest.listener, null /* frame */, true /* fromIme */,
                pendingRequest.mInsetsAnimationSpec,
                pendingRequest.animationType, pendingRequest.layoutInsetsDuringAnimation,
                pendingRequest.useInsetsAnimationThread, statsToken);
                pendingRequest.useInsetsAnimationThread, statsToken,
                false /* fromPredictiveBack */);
    }

    @Override
@@ -1333,7 +1334,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        // TODO(b/342111149): Create statsToken here once ImeTracker#onStart becomes async.
        controlAnimationUnchecked(types, cancellationSignal, listener, mFrame, fromIme, spec,
                animationType, getLayoutInsetsDuringAnimationMode(types, fromPredictiveBack),
                false /* useInsetsAnimationThread */, null);
                false /* useInsetsAnimationThread */, null, fromPredictiveBack);
    }

    private void controlAnimationUnchecked(@InsetsType int types,
@@ -1341,7 +1342,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            WindowInsetsAnimationControlListener listener, @Nullable Rect frame, boolean fromIme,
            InsetsAnimationSpec insetsAnimationSpec, @AnimationType int animationType,
            @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
            boolean useInsetsAnimationThread, @Nullable ImeTracker.Token statsToken) {
            boolean useInsetsAnimationThread, @Nullable ImeTracker.Token statsToken,
            boolean fromPredictiveBack) {
        final boolean visible = layoutInsetsDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN;

        // Basically, we accept the requested visibilities from the upstream callers...
@@ -1351,7 +1353,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        // rejecting showing IME.
        controlAnimationUncheckedInner(types, cancellationSignal, listener, frame, fromIme,
                insetsAnimationSpec, animationType, layoutInsetsDuringAnimation,
                useInsetsAnimationThread, statsToken);
                useInsetsAnimationThread, statsToken, fromPredictiveBack);

        // We are finishing setting the requested visible types. Report them to the server
        // and/or the app.
@@ -1363,7 +1365,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            WindowInsetsAnimationControlListener listener, @Nullable Rect frame, boolean fromIme,
            InsetsAnimationSpec insetsAnimationSpec, @AnimationType int animationType,
            @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
            boolean useInsetsAnimationThread, @Nullable ImeTracker.Token statsToken) {
            boolean useInsetsAnimationThread, @Nullable ImeTracker.Token statsToken,
            boolean fromPredictiveBack) {
        if ((types & mTypesBeingCancelled) != 0) {
            final boolean monitoredAnimation =
                    animationType == ANIMATION_TYPE_SHOW || animationType == ANIMATION_TYPE_HIDE;
@@ -1449,7 +1452,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            }
        } else {
            Pair<Integer, Boolean> typesReadyPair = collectSourceControls(
                    fromIme, types, controls, animationType, statsToken);
                    fromIme, types, controls, animationType, statsToken, fromPredictiveBack);
            typesReady = typesReadyPair.first;
            boolean imeReady = typesReadyPair.second;
            if (DEBUG) {
@@ -1585,7 +1588,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
     */
    private Pair<Integer, Boolean> collectSourceControls(boolean fromIme, @InsetsType int types,
            SparseArray<InsetsSourceControl> controls, @AnimationType int animationType,
            @Nullable ImeTracker.Token statsToken) {
            @Nullable ImeTracker.Token statsToken, boolean fromPredictiveBack) {
        ImeTracker.forLogging().onProgress(statsToken,
                ImeTracker.PHASE_CLIENT_COLLECT_SOURCE_CONTROLS);

@@ -1597,7 +1600,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                continue;
            }
            boolean show = animationType == ANIMATION_TYPE_SHOW
                    || animationType == ANIMATION_TYPE_USER;
                    || (animationType == ANIMATION_TYPE_USER
                            && (!fromPredictiveBack || !mHost.hasAnimationCallbacks()));
            boolean canRun = true;
            if (show) {
                // Show request
@@ -1620,7 +1624,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                        break;
                }
            } else {
                consumer.requestHide(fromIme, statsToken);
                consumer.requestHide(fromIme
                        || (fromPredictiveBack && mHost.hasAnimationCallbacks()), statsToken);
            }
            if (!canRun) {
                if (WARN) Log.w(TAG, String.format(
@@ -1675,9 +1680,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation

    private @LayoutInsetsDuringAnimation int getLayoutInsetsDuringAnimationMode(
            @InsetsType int types, boolean fromPredictiveBack) {
        if (fromPredictiveBack) {
            // When insets are animated by predictive back, we want insets to be shown to prevent a
            // jump cut from shown to hidden at the start of the predictive back animation
        if (fromPredictiveBack && !mHost.hasAnimationCallbacks()) {
            // When insets are animated by predictive back and the app does not have an animation
            // callback, we want insets to be shown to prevent a jump cut from shown to hidden at
            // the start of the predictive back animation
            return LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
        }
        // Generally, we want to layout the opposite of the current state. This is to make animation
@@ -2024,7 +2030,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                listener /* insetsAnimationSpec */,
                show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
                show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
                !hasAnimationCallbacks /* useInsetsAnimationThread */, statsToken);
                !hasAnimationCallbacks /* useInsetsAnimationThread */, statsToken,
                false /* fromPredictiveBack */);
    }

    /**
+6 −0
Original line number Diff line number Diff line
@@ -6094,6 +6094,12 @@ public final class ViewRootImpl implements ViewParent,
    }
    boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
        if (mImeBackAnimationController.isAnimationInProgress()) {
            // IME predictive back animation is currently in progress which means that scrollY is
            // currently controlled by ImeBackAnimationController.
            return false;
        }
        final Rect ci = mAttachInfo.mContentInsets;
        final Rect vi = mAttachInfo.mVisibleInsets;
        int scrollY = 0;
+10 −7
Original line number Diff line number Diff line
@@ -254,11 +254,8 @@ public class ImeBackAnimationControllerTest {
        float progress = 0.5f;
        mBackAnimationController.onBackProgressed(new BackEvent(100f, 0f, progress, EDGE_LEFT));
        // verify correct ime insets manipulation
        float interpolatedProgress = BACK_GESTURE.getInterpolation(progress);
        int expectedInset =
                (int) (IME_HEIGHT - interpolatedProgress * PEEK_FRACTION * IME_HEIGHT);
        verify(mWindowInsetsAnimationController, times(1)).setInsetsAndAlpha(
                eq(Insets.of(0, 0, 0, expectedInset)), eq(1f), anyFloat());
                eq(Insets.of(0, 0, 0, getImeHeight(progress))), eq(1f), anyFloat());
    }

    @Test
@@ -268,12 +265,13 @@ public class ImeBackAnimationControllerTest {
            WindowInsetsAnimationControlListener animationControlListener = startBackGesture();

            // progress back gesture
            mBackAnimationController.onBackProgressed(new BackEvent(100f, 0f, 0.5f, EDGE_LEFT));
            float progress = 0.5f;
            mBackAnimationController.onBackProgressed(new BackEvent(100f, 0f, progress, EDGE_LEFT));

            // commit back gesture
            mBackAnimationController.onBackInvoked();

            // verify setInsetsAndAlpha never called due onReady delayed
            // verify setInsetsAndAlpha never called due to onReady delayed
            verify(mWindowInsetsAnimationController, never()).setInsetsAndAlpha(any(), anyInt(),
                    anyFloat());
            verify(mInsetsController, never()).setPredictiveBackImeHideAnimInProgress(eq(true));
@@ -283,7 +281,7 @@ public class ImeBackAnimationControllerTest {

            // verify setInsetsAndAlpha immediately called
            verify(mWindowInsetsAnimationController, times(1)).setInsetsAndAlpha(
                    eq(Insets.of(0, 0, 0, IME_HEIGHT)), eq(1f), anyFloat());
                    eq(Insets.of(0, 0, 0, getImeHeight(progress))), eq(1f), anyFloat());
            // verify post-commit hide anim has started
            verify(mInsetsController, times(1)).setPredictiveBackImeHideAnimInProgress(eq(true));
        });
@@ -319,4 +317,9 @@ public class ImeBackAnimationControllerTest {

        return animationControlListener.getValue();
    }

    private int getImeHeight(float gestureProgress) {
        float interpolatedProgress = BACK_GESTURE.getInterpolation(gestureProgress);
        return (int) (IME_HEIGHT - interpolatedProgress * PEEK_FRACTION * IME_HEIGHT);
    }
}
Loading