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

Commit 637cc7dc authored by Tiger Huang's avatar Tiger Huang Committed by Automerger Merge Worker
Browse files

Merge "Invoke insets animation callbacks when resizing system bars" into...

Merge "Invoke insets animation callbacks when resizing system bars" into sc-v2-dev am: a42a8d6b am: c5c07300

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

Change-Id: I855558a2b85c58d7e2cd31bc5a429083d4de6d0f
parents 3d755056 c5c07300
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -20,7 +20,8 @@ import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimation.Bounds;

/**
 * Provide an interface to let InsetsAnimationControlImpl call back into its owner.
 * Provide an interface to let InsetsAnimationControlImpl and InsetsResizeAnimationRunner call back
 * into its owner.
 * @hide
 */
public interface InsetsAnimationControlCallbacks {
@@ -34,10 +35,9 @@ public interface InsetsAnimationControlCallbacks {
     *     <li>Dispatch {@link WindowInsetsAnimationControlListener#onReady}</li>
     * </ul>
     */
    void startAnimation(InsetsAnimationControlImpl controller,
            WindowInsetsAnimationControlListener listener, int types,
            WindowInsetsAnimation animation,
            Bounds bounds);
    <T extends InsetsAnimationControlRunner & WindowInsetsAnimationController>
    void startAnimation(T runner, WindowInsetsAnimationControlListener listener, int types,
            WindowInsetsAnimation animation, Bounds bounds);

    /**
     * Schedule the apply by posting the animation callback.
+6 −1
Original line number Diff line number Diff line
@@ -105,7 +105,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
    private float mCurrentAlpha = 1.0f;
    private float mPendingAlpha = 1.0f;
    @VisibleForTesting(visibility = PACKAGE)
    public boolean mReadyDispatched;
    private boolean mReadyDispatched;
    private Boolean mPerceptible;

    @VisibleForTesting
@@ -169,6 +169,11 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
        return mHasZeroInsetsIme;
    }

    @Override
    public void setReadyDispatched(boolean dispatched) {
        mReadyDispatched = dispatched;
    }

    @Override
    public Insets getHiddenStateInsets() {
        return mHiddenInsets;
+2 −2
Original line number Diff line number Diff line
@@ -54,8 +54,8 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro

        @Override
        @UiThread
        public void startAnimation(InsetsAnimationControlImpl controller,
                WindowInsetsAnimationControlListener listener, int types,
        public <T extends InsetsAnimationControlRunner & WindowInsetsAnimationController>
        void startAnimation(T runner, WindowInsetsAnimationControlListener listener, int types,
                WindowInsetsAnimation animation, Bounds bounds) {
            // Animation will be started in constructor already.
        }
+64 −25
Original line number Diff line number Diff line
@@ -205,6 +205,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
    private static final int ANIMATION_DURATION_FADE_IN_MS = 500;
    private static final int ANIMATION_DURATION_FADE_OUT_MS = 1500;

    /** Visible for WindowManagerWrapper */
    public static final int ANIMATION_DURATION_RESIZE = 300;

    private static final int ANIMATION_DELAY_DIM_MS = 500;

    private static final int ANIMATION_DURATION_SYNC_IME_MS = 285;
@@ -235,6 +238,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
    private static final Interpolator FAST_OUT_LINEAR_IN_INTERPOLATOR =
            new PathInterpolator(0.4f, 0f, 1f, 1f);

    /** Visible for WindowManagerWrapper */
    public static final Interpolator RESIZE_INTERPOLATOR = new LinearInterpolator();

    /** The amount IME will move up/down when animating in floating mode. */
    private static final int FLOATING_IME_BOTTOM_INSET_DP = -80;

@@ -288,9 +294,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
    @VisibleForTesting
    public static final int ANIMATION_TYPE_USER = 2;

    /** Running animation will resize insets */
    @VisibleForTesting
    public static final int ANIMATION_TYPE_RESIZE = 3;

    @Retention(RetentionPolicy.SOURCE)
    @IntDef(value = {ANIMATION_TYPE_NONE, ANIMATION_TYPE_SHOW, ANIMATION_TYPE_HIDE,
            ANIMATION_TYPE_USER})
            ANIMATION_TYPE_USER, ANIMATION_TYPE_RESIZE})
    @interface AnimationType {
    }

@@ -320,7 +330,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        private final boolean mDisable;
        private final int mFloatingImeBottomInset;

        private ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
        private final ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
                new ThreadLocal<AnimationHandler>() {
            @Override
            protected AnimationHandler initialValue() {
@@ -550,7 +560,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation

    private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>();
    private final ArrayList<RunningAnimation> mRunningAnimations = new ArrayList<>();
    private final ArrayList<InsetsAnimationControlImpl> mTmpFinishedControls = new ArrayList<>();
    private final ArraySet<InsetsSourceConsumer> mRequestedVisibilityChanged = new ArraySet<>();
    private WindowInsets mLastInsets;

@@ -570,7 +579,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
    private int mCaptionInsetsHeight = 0;
    private boolean mAnimationsDisabled;

    private Runnable mPendingControlTimeout = this::abortPendingImeControlRequest;
    private final Runnable mPendingControlTimeout = this::abortPendingImeControlRequest;
    private final ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners
            = new ArrayList<>();

@@ -580,7 +589,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
    /** Set of inset types which cannot be controlled by the user animation */
    private @InsetsType int mDisabledUserAnimationInsetsTypes;

    private Runnable mInvokeControllableInsetsChangedListeners =
    private final Runnable mInvokeControllableInsetsChangedListeners =
            this::invokeControllableInsetsChangedListeners;

    public InsetsController(Host host) {
@@ -608,23 +617,23 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            }

            final List<WindowInsetsAnimation> runningAnimations = new ArrayList<>();
            final List<WindowInsetsAnimation> finishedAnimations = new ArrayList<>();
            final InsetsState state = new InsetsState(mState, true /* copySources */);
            for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
                RunningAnimation runningAnimation = mRunningAnimations.get(i);
                if (DEBUG) Log.d(TAG, "Running animation type: " + runningAnimation.type);
                InsetsAnimationControlRunner runner = runningAnimation.runner;
                if (runner instanceof InsetsAnimationControlImpl) {
                    InsetsAnimationControlImpl control = (InsetsAnimationControlImpl) runner;
                final InsetsAnimationControlRunner runner = runningAnimation.runner;
                if (runner instanceof WindowInsetsAnimationController) {

                    // Keep track of running animation to be dispatched. Aggregate it here such that
                    // if it gets finished within applyChangeInsets we still dispatch it to
                    // onProgress.
                    if (runningAnimation.startDispatched) {
                        runningAnimations.add(control.getAnimation());
                        runningAnimations.add(runner.getAnimation());
                    }

                    if (control.applyChangeInsets(state)) {
                        mTmpFinishedControls.add(control);
                    if (((WindowInsetsAnimationController) runner).applyChangeInsets(state)) {
                        finishedAnimations.add(runner.getAnimation());
                    }
                }
            }
@@ -642,10 +651,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                }
            }

            for (int i = mTmpFinishedControls.size() - 1; i >= 0; i--) {
                dispatchAnimationEnd(mTmpFinishedControls.get(i).getAnimation());
            for (int i = finishedAnimations.size() - 1; i >= 0; i--) {
                dispatchAnimationEnd(finishedAnimations.get(i));
            }
            mTmpFinishedControls.clear();
        };
    }

@@ -691,15 +699,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                true /* excludeInvisibleIme */)) {
            if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged");
            mHost.notifyInsetsChanged();
            startResizingAnimationIfNeeded(lastState);
        }
        return true;
    }

    private void updateState(InsetsState newState) {
        mState.setDisplayFrame(newState.getDisplayFrame());
        mState.setDisplayCutout(newState.getDisplayCutout());
        mState.setRoundedCorners(newState.getRoundedCorners());
        mState.setPrivacyIndicatorBounds(newState.getPrivacyIndicatorBounds());
        mState.set(newState, 0 /* types */);
        @InsetsType int disabledUserAnimationTypes = 0;
        @InsetsType int[] cancelledUserAnimationTypes = {0};
        for (@InternalInsetsType int type = 0; type < InsetsState.SIZE; type++) {
@@ -764,6 +770,39 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        return false;
    }

    private void startResizingAnimationIfNeeded(InsetsState fromState) {
        if (!fromState.getDisplayFrame().equals(mState.getDisplayFrame())) {
            return;
        }
        @InsetsType int types = 0;
        InsetsState toState = null;
        final ArraySet<Integer> internalTypes = InsetsState.toInternalType(Type.systemBars());
        for (int i = internalTypes.size() - 1; i >= 0; i--) {
            final @InternalInsetsType int type = internalTypes.valueAt(i);
            final InsetsSource fromSource = fromState.peekSource(type);
            final InsetsSource toSource = mState.peekSource(type);
            if (fromSource != null && toSource != null
                    && fromSource.isVisible() && toSource.isVisible()
                    && !fromSource.getFrame().equals(toSource.getFrame())
                    && (Rect.intersects(mFrame, fromSource.getFrame())
                            || Rect.intersects(mFrame, toSource.getFrame()))) {
                types |= InsetsState.toPublicType(toSource.getType());
                if (toState == null) {
                    toState = new InsetsState();
                }
                toState.addSource(new InsetsSource(toSource));
            }
        }
        if (types == 0) {
            return;
        }
        cancelExistingControllers(types);
        final InsetsAnimationControlRunner runner = new InsetsResizeAnimationRunner(
                mFrame, fromState, toState, RESIZE_INTERPOLATOR, ANIMATION_DURATION_RESIZE, types,
                this);
        mRunningAnimations.add(new RunningAnimation(runner, runner.getAnimationType()));
    }

    /**
     * @see InsetsState#calculateInsets
     */
@@ -785,7 +824,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
    /**
     * @see InsetsState#calculateVisibleInsets(Rect, int)
     */
    public Rect calculateVisibleInsets(@SoftInputModeFlags int softInputMode) {
    public Insets calculateVisibleInsets(@SoftInputModeFlags int softInputMode) {
        return mState.calculateVisibleInsets(mFrame, softInputMode);
    }

@@ -1474,12 +1513,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation

    @VisibleForTesting
    @Override
    public void startAnimation(InsetsAnimationControlImpl controller,
            WindowInsetsAnimationControlListener listener, int types,
    public <T extends InsetsAnimationControlRunner & WindowInsetsAnimationController>
    void startAnimation(T runner, WindowInsetsAnimationControlListener listener, int types,
            WindowInsetsAnimation animation, Bounds bounds) {
        mHost.dispatchWindowInsetsAnimationPrepare(animation);
        mHost.addOnPreDrawRunnable(() -> {
            if (controller.isCancelled()) {
            if (runner.isCancelled()) {
                if (WARN) Log.w(TAG, "startAnimation canceled before preDraw");
                return;
            }
@@ -1487,15 +1526,15 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
                    "InsetsAnimation: " + WindowInsets.Type.toString(types), types);
            for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
                RunningAnimation runningAnimation = mRunningAnimations.get(i);
                if (runningAnimation.runner == controller) {
                if (runningAnimation.runner == runner) {
                    runningAnimation.startDispatched = true;
                }
            }
            Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.pendingAnim", 0);
            mHost.dispatchWindowInsetsAnimationStart(animation, bounds);
            mStartingAnimation = true;
            controller.mReadyDispatched = true;
            listener.onReady(controller, types);
            runner.setReadyDispatched(true);
            listener.onReady(runner, types);
            mStartingAnimation = false;
        });
    }
+235 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view;

import static android.view.InsetsAnimationControlImplProto.CURRENT_ALPHA;
import static android.view.InsetsAnimationControlImplProto.IS_CANCELLED;
import static android.view.InsetsAnimationControlImplProto.IS_FINISHED;
import static android.view.InsetsAnimationControlImplProto.PENDING_ALPHA;
import static android.view.InsetsAnimationControlImplProto.PENDING_FRACTION;
import static android.view.InsetsAnimationControlImplProto.PENDING_INSETS;
import static android.view.InsetsAnimationControlImplProto.SHOWN_ON_FINISH;
import static android.view.InsetsAnimationControlImplProto.TMP_MATRIX;
import static android.view.InsetsController.ANIMATION_TYPE_RESIZE;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.graphics.Insets;
import android.graphics.Rect;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.InsetsState.InternalInsetsType;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimation.Bounds;
import android.view.animation.Interpolator;

/**
 * Runs a fake animation of resizing insets to produce insets animation callbacks.
 * @hide
 */
public class InsetsResizeAnimationRunner implements InsetsAnimationControlRunner,
        WindowInsetsAnimationController, WindowInsetsAnimationControlListener {

    private final InsetsState mFromState;
    private final InsetsState mToState;
    private final @InsetsType int mTypes;
    private final WindowInsetsAnimation mAnimation;
    private final InsetsAnimationControlCallbacks mController;
    private ValueAnimator mAnimator;
    private boolean mCancelled;
    private boolean mFinished;

    public InsetsResizeAnimationRunner(Rect frame, InsetsState fromState, InsetsState toState,
            Interpolator interpolator, long duration, @InsetsType int types,
            InsetsAnimationControlCallbacks controller) {
        mFromState = fromState;
        mToState = toState;
        mTypes = types;
        mController = controller;
        mAnimation = new WindowInsetsAnimation(types, interpolator, duration);
        mAnimation.setAlpha(1f);
        final Insets fromInsets = fromState.calculateInsets(
                frame, types, false /* ignoreVisibility */);
        final Insets toInsets = toState.calculateInsets(
                frame, types, false /* ignoreVisibility */);
        controller.startAnimation(this, this, types, mAnimation,
                new Bounds(Insets.min(fromInsets, toInsets), Insets.max(fromInsets, toInsets)));
    }

    @Override
    public int getTypes() {
        return mTypes;
    }

    @Override
    public int getControllingTypes() {
        return mTypes;
    }

    @Override
    public WindowInsetsAnimation getAnimation() {
        return mAnimation;
    }

    @Override
    public int getAnimationType() {
        return ANIMATION_TYPE_RESIZE;
    }

    @Override
    public void cancel() {
        if (mCancelled || mFinished) {
            return;
        }
        mCancelled = true;
        if (mAnimator != null) {
            mAnimator.cancel();
        }
    }

    @Override
    public boolean isCancelled() {
        return mCancelled;
    }

    @Override
    public void onReady(WindowInsetsAnimationController controller, int types) {
        if (mCancelled) {
            return;
        }
        mAnimator = ValueAnimator.ofFloat(0f, 1f);
        mAnimator.setDuration(mAnimation.getDurationMillis());
        mAnimator.addUpdateListener(animation -> {
            mAnimation.setFraction(animation.getAnimatedFraction());
            mController.scheduleApplyChangeInsets(InsetsResizeAnimationRunner.this);
        });
        mAnimator.addListener(new AnimatorListenerAdapter() {

            @Override
            public void onAnimationEnd(Animator animation) {
                mFinished = true;
                mController.scheduleApplyChangeInsets(InsetsResizeAnimationRunner.this);
            }
        });
        mAnimator.start();
    }

    @Override
    public boolean applyChangeInsets(InsetsState outState) {
        final float fraction = mAnimation.getInterpolatedFraction();
        for (@InternalInsetsType int type = 0; type < InsetsState.SIZE; type++) {
            final InsetsSource fromSource = mFromState.peekSource(type);
            final InsetsSource toSource = mToState.peekSource(type);
            if (fromSource == null || toSource == null) {
                continue;
            }
            final Rect fromFrame = fromSource.getFrame();
            final Rect toFrame = toSource.getFrame();
            final Rect frame = new Rect(
                    (int) (fromFrame.left + fraction * (toFrame.left - fromFrame.left)),
                    (int) (fromFrame.top + fraction * (toFrame.top - fromFrame.top)),
                    (int) (fromFrame.right + fraction * (toFrame.right - fromFrame.right)),
                    (int) (fromFrame.bottom + fraction * (toFrame.bottom - fromFrame.bottom)));
            final InsetsSource source = new InsetsSource(type);
            source.setFrame(frame);
            source.setVisible(toSource.isVisible());
            outState.addSource(source);
        }
        if (mFinished) {
            mController.notifyFinished(this, true /* shown */);
        }
        return mFinished;
    }

    @Override
    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
        final long token = proto.start(fieldId);
        proto.write(IS_CANCELLED, mCancelled);
        proto.write(IS_FINISHED, mFinished);
        proto.write(TMP_MATRIX, "null");
        proto.write(PENDING_INSETS, "null");
        proto.write(PENDING_FRACTION, mAnimation.getInterpolatedFraction());
        proto.write(SHOWN_ON_FINISH, true);
        proto.write(CURRENT_ALPHA, 1f);
        proto.write(PENDING_ALPHA, 1f);
        proto.end(token);
    }

    @Override
    public Insets getHiddenStateInsets() {
        return Insets.NONE;
    }

    @Override
    public Insets getShownStateInsets() {
        return Insets.NONE;
    }

    @Override
    public Insets getCurrentInsets() {
        return Insets.NONE;
    }

    @Override
    public float getCurrentFraction() {
        return 0;
    }

    @Override
    public float getCurrentAlpha() {
        return 0;
    }

    @Override
    public void setInsetsAndAlpha(Insets insets, float alpha, float fraction) {
    }

    @Override
    public void finish(boolean shown) {
    }

    @Override
    public boolean isFinished() {
        return false;
    }

    @Override
    public void notifyControlRevoked(int types) {
    }

    @Override
    public void updateSurfacePosition(SparseArray<InsetsSourceControl> controls) {
    }

    @Override
    public boolean hasZeroInsetsIme() {
        return false;
    }

    @Override
    public void setReadyDispatched(boolean dispatched) {
    }

    @Override
    public void onFinished(WindowInsetsAnimationController controller) {
    }

    @Override
    public void onCancelled(WindowInsetsAnimationController controller) {
    }
}
Loading