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

Commit abf87cf3 authored by Peter Kalauskas's avatar Peter Kalauskas
Browse files

Use PropertyAnimator for CUJ_SCREEN_OFF_SHOW_AOD

Previously ViewPropertyAnimator - e.g. View.animate() - and
PropertyAnimator were used at the same time for animations on the same
keyguard view. This made the state less predictable since one might
assume calling View.animate().cancel() would cancel all the
PropertyAnimators too (it does not). Since ViewPropertyAnimator was only
used for animating alpha, simplify things by removing usage of
View.animate() and replacing it with a new PropertyAnimator call for the
View.ALPHA property.

Also,

 - Mark KeyguardUserSwitcherController as deprecated

 - Throw IllegalArgumentException if KeyguardStatusView#animate() is
   called on a debuggable build

Test: capture perfetto trace while turning screen off
Test: turn screen off while on lock screen, observe that the fade
      and translation animations remain unchanged
from home screen
Bug: 262705829

Change-Id: I72d8f3986422e3c71a6f91b94e5692e929867737
parent 857b09eb
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -19,10 +19,12 @@ package com.android.keyguard;
import static java.util.Collections.emptySet;

import android.content.Context;
import android.os.Build;
import android.os.Trace;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.widget.GridLayout;

import com.android.systemui.R;
@@ -117,6 +119,16 @@ public class KeyguardStatusView extends GridLayout {
        }
    }

    @Override
    public ViewPropertyAnimator animate() {
        if (Build.IS_DEBUGGABLE) {
            throw new IllegalArgumentException(
                    "KeyguardStatusView does not support ViewPropertyAnimator. "
                            + "Use PropertyAnimator instead.");
        }
        return super.animate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Trace.beginSection("KeyguardStatusView#onMeasure");
+49 −36
Original line number Diff line number Diff line
@@ -18,8 +18,8 @@ package com.android.keyguard;

import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;

import android.util.Property;
import android.view.View;
import android.view.ViewPropertyAnimator;

import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.log.LogBuffer;
@@ -34,6 +34,8 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;

import com.google.errorprone.annotations.CompileTimeConstant;

import java.util.function.Consumer;

/**
 * Helper class for updating visibility of keyguard views based on keyguard and status bar state.
 * This logic is shared by both the keyguard status view and the keyguard user switcher.
@@ -83,47 +85,49 @@ public class KeyguardVisibilityHelper {
            boolean keyguardFadingAway,
            boolean goingToFullShade,
            int oldStatusBarState) {
        mView.animate().cancel();
        PropertyAnimator.cancelAnimation(mView, AnimatableProperty.ALPHA);
        boolean isOccluded = mKeyguardStateController.isOccluded();
        mKeyguardViewVisibilityAnimating = false;

        if ((!keyguardFadingAway && oldStatusBarState == KEYGUARD
                && statusBarState != KEYGUARD) || goingToFullShade) {
            mKeyguardViewVisibilityAnimating = true;
            mView.animate()
                    .alpha(0f)
                    .setStartDelay(0)
                    .setDuration(160)
                    .setInterpolator(Interpolators.ALPHA_OUT)
                    .withEndAction(
                            mAnimateKeyguardStatusViewGoneEndRunnable);

            AnimationProperties animProps = new AnimationProperties()
                    .setCustomInterpolator(View.ALPHA, Interpolators.ALPHA_OUT)
                    .setAnimationEndAction(mSetGoneEndAction);
            if (keyguardFadingAway) {
                mView.animate()
                        .setStartDelay(mKeyguardStateController.getKeyguardFadingAwayDelay())
                        .setDuration(mKeyguardStateController.getShortenedFadingAwayDuration())
                        .start();
                animProps
                        .setDelay(mKeyguardStateController.getKeyguardFadingAwayDelay())
                        .setDuration(mKeyguardStateController.getShortenedFadingAwayDuration());
                log("goingToFullShade && keyguardFadingAway");
            } else {
                animProps.setDelay(0).setDuration(160);
                log("goingToFullShade && !keyguardFadingAway");
            }
            PropertyAnimator.setProperty(
                    mView, AnimatableProperty.ALPHA, 0f, animProps, true /* animate */);
        } else if (oldStatusBarState == StatusBarState.SHADE_LOCKED && statusBarState == KEYGUARD) {
            mView.setVisibility(View.VISIBLE);
            mKeyguardViewVisibilityAnimating = true;
            mView.setAlpha(0f);
            mView.animate()
                    .alpha(1f)
                    .setStartDelay(0)
            PropertyAnimator.setProperty(
                    mView, AnimatableProperty.ALPHA, 1f,
                    new AnimationProperties()
                            .setDelay(0)
                            .setDuration(320)
                    .setInterpolator(Interpolators.ALPHA_IN)
                    .withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable);
                            .setCustomInterpolator(View.ALPHA, Interpolators.ALPHA_IN)
                            .setAnimationEndAction(
                                    property -> mSetVisibleEndRunnable.run()),
                    true /* animate */);
            log("keyguardFadingAway transition w/ Y Aniamtion");
        } else if (statusBarState == KEYGUARD) {
            if (keyguardFadingAway) {
                mKeyguardViewVisibilityAnimating = true;
                ViewPropertyAnimator animator = mView.animate()
                        .alpha(0)
                        .setInterpolator(Interpolators.FAST_OUT_LINEAR_IN)
                        .withEndAction(mAnimateKeyguardStatusViewInvisibleEndRunnable);
                AnimationProperties animProps = new AnimationProperties()
                        .setDelay(0)
                        .setCustomInterpolator(View.ALPHA, Interpolators.FAST_OUT_LINEAR_IN)
                        .setAnimationEndAction(mSetInvisibleEndAction);
                if (mAnimateYPos) {
                    float target = mView.getY() - mView.getHeight() * 0.05f;
                    int delay = 0;
@@ -135,13 +139,16 @@ public class KeyguardVisibilityHelper {
                    PropertyAnimator.setProperty(mView, AnimatableProperty.Y, target,
                            mAnimationProperties,
                            true /* animate */);
                    animator.setDuration(duration)
                            .setStartDelay(delay);
                    animProps.setDuration(duration)
                            .setDelay(delay);
                    log("keyguardFadingAway transition w/ Y Aniamtion");
                } else {
                    log("keyguardFadingAway transition w/o Y Animation");
                }
                animator.start();
                PropertyAnimator.setProperty(
                        mView, AnimatableProperty.ALPHA, 0f,
                        animProps,
                        true /* animate */);
            } else if (mScreenOffAnimationController.shouldAnimateInKeyguard()) {
                log("ScreenOff transition");
                mKeyguardViewVisibilityAnimating = true;
@@ -149,7 +156,7 @@ public class KeyguardVisibilityHelper {
                // Ask the screen off animation controller to animate the keyguard visibility for us
                // since it may need to be cancelled due to keyguard lifecycle events.
                mScreenOffAnimationController.animateInKeyguard(
                        mView, mAnimateKeyguardStatusViewVisibleEndRunnable);
                        mView, mSetVisibleEndRunnable);
            } else {
                log("Direct set Visibility to VISIBLE");
                mView.setVisibility(View.VISIBLE);
@@ -163,19 +170,25 @@ public class KeyguardVisibilityHelper {
        mLastOccludedState = isOccluded;
    }

    private final Runnable mAnimateKeyguardStatusViewInvisibleEndRunnable = () -> {
    private final Consumer<Property> mSetInvisibleEndAction = new Consumer<>() {
        @Override
        public void accept(Property property) {
            mKeyguardViewVisibilityAnimating = false;
            mView.setVisibility(View.INVISIBLE);
            log("Callback Set Visibility to INVISIBLE");
        }
    };

    private final Runnable mAnimateKeyguardStatusViewGoneEndRunnable = () -> {
    private final Consumer<Property> mSetGoneEndAction = new Consumer<>() {
        @Override
        public void accept(Property property) {
            mKeyguardViewVisibilityAnimating = false;
            mView.setVisibility(View.GONE);
            log("CallbackSet Visibility to GONE");
        }
    };

    private final Runnable mAnimateKeyguardStatusViewVisibleEndRunnable = () -> {
    private final Runnable mSetVisibleEndRunnable = () -> {
        mKeyguardViewVisibilityAnimating = false;
        mView.setVisibility(View.VISIBLE);
        log("Callback Set Visibility to VISIBLE");
+4 −0
Original line number Diff line number Diff line
@@ -48,6 +48,10 @@ public abstract class AnimatableProperty {
            View.SCALE_Y, R.id.scale_y_animator_tag, R.id.scale_y_animator_start_value_tag,
            R.id.scale_y_animator_end_value_tag);

    public static final AnimatableProperty ALPHA = AnimatableProperty.from(
            View.ALPHA, R.id.alpha_animator_tag, R.id.alpha_animator_start_value_tag,
            R.id.alpha_animator_end_value_tag);

    /**
     * Similar to X, however this doesn't allow for any other modifications other than from this
     * property. When using X, it's possible that the view is laid out during the animation,
+20 −3
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ public class AnimationProperties {
    public long duration;
    public long delay;
    private ArrayMap<Property, Interpolator> mInterpolatorMap;
    private Consumer<Property> mAnimationCancelAction;
    private Consumer<Property> mAnimationEndAction;

    /**
@@ -50,9 +51,10 @@ public class AnimationProperties {
     * @return a listener that will be added for a given property during its animation.
     */
    public AnimatorListenerAdapter getAnimationFinishListener(Property property) {
        if (mAnimationEndAction == null) {
        if (mAnimationEndAction == null && mAnimationCancelAction == null) {
            return null;
        }
        Consumer<Property> cancelAction = mAnimationCancelAction;
        Consumer<Property> endAction = mAnimationEndAction;
        return new AnimatorListenerAdapter() {
            private boolean mCancelled;
@@ -60,17 +62,32 @@ public class AnimationProperties {
            @Override
            public void onAnimationCancel(Animator animation) {
                mCancelled = true;
                if (cancelAction != null) {
                    cancelAction.accept(property);
                }
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                if (!mCancelled) {
                if (!mCancelled && endAction != null) {
                    endAction.accept(property);
                }
            }
        };
    }

    /**
     * Add a callback for animation cancellation.
     */
    public AnimationProperties setAnimationCancelAction(Consumer<Property> listener) {
        mAnimationCancelAction = listener;
        return this;
    }

    /**
     * Add a callback for animation ending successfully. The callback will not be called when the
     * animations is cancelled.
     */
    public AnimationProperties setAnimationEndAction(Consumer<Property> listener) {
        mAnimationEndAction = listener;
        return this;
+24 −27
Original line number Diff line number Diff line
@@ -175,15 +175,19 @@ class UnlockedScreenOffAnimationController @Inject constructor(
        // We animate the Y properly separately using the PropertyAnimator, as the panel
        // view also needs to update the end position.
        PropertyAnimator.cancelAnimation(keyguardView, AnimatableProperty.Y)
        PropertyAnimator.setProperty<View>(keyguardView, AnimatableProperty.Y, currentY,
        PropertyAnimator.setProperty(keyguardView, AnimatableProperty.Y, currentY,
                AnimationProperties().setDuration(duration.toLong()),
                true /* animate */)

        keyguardView.animate()
        // Cancel any existing CUJs before starting the animation
        interactionJankMonitor.cancel(CUJ_SCREEN_OFF_SHOW_AOD)

        PropertyAnimator.setProperty(
            keyguardView, AnimatableProperty.ALPHA, 1f,
            AnimationProperties()
                .setDelay(0)
                .setDuration(duration.toLong())
                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
                .alpha(1f)
                .withEndAction {
                .setAnimationEndAction {
                    aodUiAnimationPlaying = false

                    // Lock the keyguard if it was waiting for the screen off animation to end.
@@ -199,30 +203,23 @@ class UnlockedScreenOffAnimationController @Inject constructor(
                    // Done going to sleep, reset this flag.
                    decidedToAnimateGoingToSleep = null

                    // We need to unset the listener. These are persistent for future animators
                    keyguardView.animate().setListener(null)
                    interactionJankMonitor.end(CUJ_SCREEN_OFF_SHOW_AOD)
                }
                .setListener(object : AnimatorListenerAdapter() {
                    override fun onAnimationCancel(animation: Animator?) {
                .setAnimationCancelAction {
                    // If we're cancelled, reset state flags/listeners. The end action above
                    // will not be called, which is what we want since that will finish the
                    // screen off animation and show the lockscreen, which we don't want if we
                    // were cancelled.
                    aodUiAnimationPlaying = false
                    decidedToAnimateGoingToSleep = null
                        keyguardView.animate().setListener(null)

                    interactionJankMonitor.cancel(CUJ_SCREEN_OFF_SHOW_AOD)
                }

                    override fun onAnimationStart(animation: Animator?) {
                .setCustomInterpolator(View.ALPHA, Interpolators.FAST_OUT_SLOW_IN),
            true /* animate */)
        interactionJankMonitor.begin(
            mCentralSurfaces.notificationShadeWindowView,
                                CUJ_SCREEN_OFF_SHOW_AOD)
                    }
                })
                .start()
            CUJ_SCREEN_OFF_SHOW_AOD
        )
    }

    override fun onStartedWakingUp() {
Loading