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

Commit 622b8810 authored by Jorim Jaggi's avatar Jorim Jaggi Committed by Automerger Merge Worker
Browse files

Merge "Fine tune animation parameters for IME animations" into rvc-dev am:...

Merge "Fine tune animation parameters for IME animations" into rvc-dev am: 08a45d24 am: 2a392ab3

Change-Id: I5fe7a2041b0827061153ff8dcb97fcdfb7f224fd
parents aa79b3a0 2a392ab3
Loading
Loading
Loading
Loading
+1 −5
Original line number Diff line number Diff line
@@ -68,7 +68,6 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
    private final @InsetsType int mTypes;
    private final InsetsAnimationControlCallbacks mController;
    private final WindowInsetsAnimation mAnimation;
    private final boolean mFade;
    private Insets mCurrentInsets;
    private Insets mPendingInsets;
    private float mPendingFraction;
@@ -83,11 +82,10 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
            InsetsState state, WindowInsetsAnimationControlListener listener,
            @InsetsType int types,
            InsetsAnimationControlCallbacks controller, long durationMs, Interpolator interpolator,
            boolean fade, @AnimationType int animationType) {
            @AnimationType int animationType) {
        mControls = controls;
        mListener = listener;
        mTypes = types;
        mFade = fade;
        mController = controller;
        mInitialInsetsState = new InsetsState(state, true /* copySources */);
        mCurrentInsets = getInsetsFromState(mInitialInsetsState, frame, null /* typeSideMap */);
@@ -299,8 +297,6 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll

            // If the system is controlling the insets source, the leash can be null.
            if (leash != null) {
                // TODO: use a better interpolation for fade.
                alpha = mFade ? ((float) inset / maxInset * 0.3f + 0.7f) : alpha;
                SurfaceParams params = new SurfaceParams.Builder(leash)
                        .withAlpha(side == ISIDE_FLOATING ? 1 : alpha)
                        .withMatrix(mTmpMatrix)
+2 −2
Original line number Diff line number Diff line
@@ -88,11 +88,11 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro
            InsetsState state, WindowInsetsAnimationControlListener listener,
            @InsetsType int types,
            InsetsAnimationControlCallbacks controller, long durationMs, Interpolator interpolator,
            boolean fade, @AnimationType int animationType, Handler mainThreadHandler) {
            @AnimationType int animationType, Handler mainThreadHandler) {
        mMainThreadHandler = mainThreadHandler;
        mOuterCallbacks = controller;
        mControl = new InsetsAnimationControlImpl(copyControls(controls), frame, state, listener,
                types, mCallbacks, durationMs, interpolator, fade, animationType);
                types, mCallbacks, durationMs, interpolator, animationType);
        InsetsAnimationThread.getHandler().post(() -> listener.onReady(mControl, types));
    }

+108 −60
Original line number Diff line number Diff line
@@ -27,7 +27,9 @@ import android.animation.AnimationHandler;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -36,6 +38,7 @@ import android.graphics.Rect;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.RemoteException;
import android.renderscript.Sampler.Value;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
@@ -50,6 +53,7 @@ import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimation.Bounds;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.PathInterpolator;

import com.android.internal.annotations.VisibleForTesting;
@@ -72,9 +76,20 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation

    private static final int ANIMATION_DURATION_SHOW_MS = 275;
    private static final int ANIMATION_DURATION_HIDE_MS = 340;

    private static final int ANIMATION_DURATION_SYNC_IME_MS = 285;
    private static final int ANIMATION_DURATION_UNSYNC_IME_MS = 200;

    private static final int PENDING_CONTROL_TIMEOUT_MS = 2000;

    public static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
    public static final Interpolator SYSTEM_BARS_INTERPOLATOR =
            new PathInterpolator(0.4f, 0f, 0.2f, 1f);
    private static final Interpolator SYNC_IME_INTERPOLATOR =
            new PathInterpolator(0.2f, 0f, 0f, 1f);
    private static final Interpolator LINEAR_OUT_SLOW_IN_INTERPOLATOR =
            new PathInterpolator(0, 0, 0.2f, 1f);
    private static final Interpolator FAST_OUT_LINEAR_IN_INTERPOLATOR =
            new PathInterpolator(0.4f, 0f, 1f, 1f);

    /**
     * Layout mode during insets animation: The views should be laid out as if the changing inset
@@ -138,27 +153,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            (int) (startValue.right + fraction * (endValue.right - startValue.right)),
            (int) (startValue.bottom + fraction * (endValue.bottom - startValue.bottom)));

    /**
     * Linear animation property
     */
    private static class InsetsProperty extends Property<WindowInsetsAnimationController, Insets> {
        InsetsProperty() {
            super(Insets.class, "Insets");
        }

        @Override
        public Insets get(WindowInsetsAnimationController object) {
            return object.getCurrentInsets();
        }
        @Override
        public void set(WindowInsetsAnimationController controller, Insets value) {
            controller.setInsetsAndAlpha(
                    value, 1f /* alpha */, (((InternalAnimationControlListener)
                            ((InsetsAnimationControlImpl) controller).getListener())
                                    .getRawFraction()));
        }
    }

    /**
     * The default implementation of listener, to be used by InsetsController and InsetsPolicy to
     * animate insets.
@@ -167,9 +161,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            implements WindowInsetsAnimationControlListener {

        private WindowInsetsAnimationController mController;
        private ObjectAnimator mAnimator;
        private ValueAnimator mAnimator;
        private final boolean mShow;
        private final boolean mUseSfVsync;
        private final boolean mHasAnimationCallbacks;
        private final @InsetsType int mRequestedTypes;
        private final long mDurationMs;

        private ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
                new ThreadLocal<AnimationHandler>() {
@@ -181,24 +177,40 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            }
        };

        public InternalAnimationControlListener(boolean show, boolean useSfVsync) {
        public InternalAnimationControlListener(boolean show, boolean hasAnimationCallbacks,
                int requestedTypes) {
            mShow = show;
            mUseSfVsync = useSfVsync;
            mHasAnimationCallbacks = hasAnimationCallbacks;
            mRequestedTypes = requestedTypes;
            mDurationMs = calculateDurationMs();
        }

        @Override
        public void onReady(WindowInsetsAnimationController controller, int types) {
            mController = controller;

            mAnimator = ObjectAnimator.ofObject(
                    controller,
                    new InsetsProperty(),
                    sEvaluator,
                    mShow ? controller.getHiddenStateInsets() : controller.getShownStateInsets(),
                    mShow ? controller.getShownStateInsets() : controller.getHiddenStateInsets()
            );
            mAnimator.setDuration(getDurationMs());
            mAnimator.setInterpolator(INTERPOLATOR);
            mAnimator = ValueAnimator.ofFloat(0f, 1f);
            mAnimator.setDuration(mDurationMs);
            mAnimator.setInterpolator(new LinearInterpolator());
            Insets start = mShow
                    ? controller.getHiddenStateInsets()
                    : controller.getShownStateInsets();
            Insets end = mShow
                    ? controller.getShownStateInsets()
                    : controller.getHiddenStateInsets();
            Interpolator insetsInterpolator = getInterpolator();
            Interpolator alphaInterpolator = getAlphaInterpolator();
            mAnimator.addUpdateListener(animation -> {
                float rawFraction = animation.getAnimatedFraction();
                float alphaFraction = mShow
                        ? rawFraction
                        : 1 - rawFraction;
                float insetsFraction = insetsInterpolator.getInterpolation(rawFraction);
                controller.setInsetsAndAlpha(
                        sEvaluator.evaluate(insetsFraction, start, end),
                        alphaInterpolator.getInterpolation(alphaFraction),
                        rawFraction);
            });
            mAnimator.addListener(new AnimatorListenerAdapter() {

                @Override
@@ -206,7 +218,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                    onAnimationFinish();
                }
            });
            if (mUseSfVsync) {
            if (!mHasAnimationCallbacks) {
                mAnimator.setAnimationHandler(mSfAnimationHandlerThreadLocal.get());
            }
            mAnimator.start();
@@ -224,24 +236,59 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            }
        }

        protected void onAnimationFinish() {
            mController.finish(mShow);
        Interpolator getInterpolator() {
            if ((mRequestedTypes & ime()) != 0) {
                if (mHasAnimationCallbacks) {
                    return SYNC_IME_INTERPOLATOR;
                } else if (mShow) {
                    return LINEAR_OUT_SLOW_IN_INTERPOLATOR;
                } else {
                    return FAST_OUT_LINEAR_IN_INTERPOLATOR;
                }
            } else {
                return SYSTEM_BARS_INTERPOLATOR;
            }
        }

        protected float getRawFraction() {
            return (float) mAnimator.getCurrentPlayTime() / mAnimator.getDuration();
        Interpolator getAlphaInterpolator() {
            if ((mRequestedTypes & ime()) != 0) {
                if (mHasAnimationCallbacks) {
                    return input -> 1f;
                } else if (mShow) {

                    // Alpha animation takes half the time with linear interpolation;
                    return input -> Math.min(1f, 2 * input);
                } else {
                    return FAST_OUT_LINEAR_IN_INTERPOLATOR;
                }
            } else {
                return input -> 1f;
            }
        }

        protected void onAnimationFinish() {
            mController.finish(mShow);
        }

        /**
         * To get the animation duration in MS.
         */
        public long getDurationMs() {
            if (mAnimator != null) {
                return mAnimator.getDuration();
            return mDurationMs;
        }

        private long calculateDurationMs() {
            if ((mRequestedTypes & ime()) != 0) {
                if (mHasAnimationCallbacks) {
                    return ANIMATION_DURATION_SYNC_IME_MS;
                } else {
                    return ANIMATION_DURATION_UNSYNC_IME_MS;
                }
            } else {
                return mShow ? ANIMATION_DURATION_SHOW_MS : ANIMATION_DURATION_HIDE_MS;
            }
        }
    }

    /**
     * Represents a running animation
@@ -525,7 +572,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                    pendingRequest.types, pendingRequest.cancellationSignal,
                    pendingRequest.listener, mFrame,
                    true /* fromIme */, pendingRequest.durationMs, pendingRequest.interpolator,
                    false /* fade */, pendingRequest.animationType,
                    pendingRequest.animationType,
                    pendingRequest.layoutInsetsDuringAnimation,
                    pendingRequest.useInsetsAnimationThread);
            return;
@@ -590,9 +637,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            listener.onCancelled(null);
            return;
        }

        controlAnimationUnchecked(types, cancellationSignal, listener, mFrame, fromIme, durationMs,
                interpolator, false /* fade */, animationType,
                getLayoutInsetsDuringAnimationMode(types),
                interpolator, animationType, getLayoutInsetsDuringAnimationMode(types),
                false /* useInsetsAnimationThread */);
    }

@@ -606,7 +653,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
    private void controlAnimationUnchecked(@InsetsType int types,
            @Nullable CancellationSignal cancellationSignal,
            WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme,
            long durationMs, Interpolator interpolator, boolean fade,
            long durationMs, Interpolator interpolator,
            @AnimationType int animationType,
            @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
            boolean useInsetsAnimationThread) {
@@ -652,10 +699,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation

        final InsetsAnimationControlRunner runner = useInsetsAnimationThread
                ? new InsetsAnimationThreadControlRunner(controls,
                        frame, mState, listener, typesReady, this, durationMs, interpolator, fade,
                        frame, mState, listener, typesReady, this, durationMs, interpolator,
                        animationType, mViewRoot.mHandler)
                : new InsetsAnimationControlImpl(controls,
                        frame, mState, listener, typesReady, this, durationMs, interpolator, fade,
                        frame, mState, listener, typesReady, this, durationMs, interpolator,
                        animationType);
        mRunningAnimations.add(new RunningAnimation(runner, animationType));
        if (cancellationSignal != null) {
@@ -921,25 +968,26 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            return;
        }

        boolean useInsetsAnimationThread = canUseInsetsAnimationThread();
        boolean hasAnimationCallbacks = hasAnimationCallbacks();
        final InternalAnimationControlListener listener =
                new InternalAnimationControlListener(show, useInsetsAnimationThread);
                new InternalAnimationControlListener(show, hasAnimationCallbacks, types);

        // Show/hide animations always need to be relative to the display frame, in order that shown
        // and hidden state insets are correct.
        controlAnimationUnchecked(
                types, null /* cancellationSignal */, listener, mState.getDisplayFrame(), fromIme,
                listener.getDurationMs(),
                INTERPOLATOR, true /* fade */, show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
                show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN
                        : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
                useInsetsAnimationThread);
                listener.getDurationMs(), listener.getInterpolator(),
                show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
                show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
                !hasAnimationCallbacks /* useInsetsAnimationThread */);

    }

    private boolean canUseInsetsAnimationThread() {
    private boolean hasAnimationCallbacks() {
        if (mViewRoot.mView == null) {
            return true;
            return false;
        }
        return !mViewRoot.mView.hasWindowInsetsAnimationCallback();
        return mViewRoot.mView.hasWindowInsetsAnimationCallback();
    }

    private void hideDirectly(
+3 −4
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
import static android.view.WindowInsets.Type.systemBars;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -44,8 +43,6 @@ import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
import android.view.animation.LinearInterpolator;
import android.view.test.InsetsModeSession;

import androidx.test.runner.AndroidJUnit4;

import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -57,6 +54,8 @@ import org.mockito.MockitoAnnotations;

import java.util.List;

import androidx.test.runner.AndroidJUnit4;

/**
 * Tests for {@link InsetsAnimationControlImpl}.
 *
@@ -124,7 +123,7 @@ public class InsetsAnimationControlImplTest {
        mController = new InsetsAnimationControlImpl(controls,
                new Rect(0, 0, 500, 500), mInsetsState, mMockListener, systemBars(),
                mMockController, 10 /* durationMs */, new LinearInterpolator(),
                false /* fade */, 0 /* animationType */);
                0 /* animationType */);
    }

    @Test
+4 −6
Original line number Diff line number Diff line
@@ -22,8 +22,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.view.InsetsController.ANIMATION_TYPE_HIDE;
import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_HIDDEN;
import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.SyncRtSurfaceTransactionApplier.applyParams;
@@ -299,7 +297,7 @@ class InsetsPolicy {
    private void controlAnimationUnchecked(int typesReady,
            SparseArray<InsetsSourceControl> controls, boolean show, Runnable callback) {
        InsetsPolicyAnimationControlListener listener =
                new InsetsPolicyAnimationControlListener(show, callback);
                new InsetsPolicyAnimationControlListener(show, callback, typesReady);
        listener.mControlCallbacks.controlAnimationUnchecked(typesReady, controls, show);
    }

@@ -328,8 +326,8 @@ class InsetsPolicy {
        Runnable mFinishCallback;
        InsetsPolicyAnimationControlCallbacks mControlCallbacks;

        InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback) {
            super(show, true /* useSfVsync */);
        InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback, int types) {
            super(show, false /* hasCallbacks */, types);
            mFinishCallback = finishCallback;
            mControlCallbacks = new InsetsPolicyAnimationControlCallbacks(this);
        }
@@ -361,7 +359,7 @@ class InsetsPolicy {
                mAnimationControl = new InsetsAnimationControlImpl(controls,
                        mFocusedWin.getDisplayContent().getBounds(), getState(),
                        mListener, typesReady, this, mListener.getDurationMs(),
                        InsetsController.INTERPOLATOR, true,
                        InsetsController.SYSTEM_BARS_INTERPOLATOR,
                        show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE);
                SurfaceAnimationThread.getHandler().post(
                        () -> mListener.onReady(mAnimationControl, typesReady));