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

Commit a1322dee authored by Josh Tsuji's avatar Josh Tsuji
Browse files

Uses ActivityLaunchAnimator for occlusion animations.

This is used when the lock screen is visible and an activity occludes it,
such as the camera. Currently, the camera launches behind the lock screen
and then the lock screen janks out of the way to show the camera.

There are currently some pretty severe performance issues, but I'm not sure
yet whether that's due to the new launch animator, or the fact that the
old animation is so janky that you can't really tell. I'm investigating
that, but we should get this into the build to start working out any bugs
with the remote occlude animations.

This requires remote occlude animations to be enabled:
adb shell setprop persist.wm.enable_remote_keyguard_animation 2

Test: atest SystemUITests
Bug: 197312643
Change-Id: Id801e44c25c6e2340b4269d215b9a1c056f0ceff
parent 5f73621d
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -301,6 +301,7 @@ class ActivityLaunchAnimator(
         * The intent was started. If [willAnimate] is false, nothing else will happen and the
         * animation will not be started.
         */
        @JvmDefault
        fun onIntentStarted(willAnimate: Boolean) {}

        /**
@@ -308,6 +309,7 @@ class ActivityLaunchAnimator(
         * this if the animation was already started, i.e. if [onLaunchAnimationStart] was called
         * before the cancellation.
         */
        @JvmDefault
        fun onLaunchAnimationCancelled() {}
    }

+3 −0
Original line number Diff line number Diff line
@@ -100,9 +100,11 @@ class LaunchAnimator(
         * needed for the animation. [isExpandingFullyAbove] will be true if the window is expanding
         * fully above the [launchContainer].
         */
        @JvmDefault
        fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {}

        /** The animation made progress and the expandable view [state] should be updated. */
        @JvmDefault
        fun onLaunchAnimationProgress(state: State, progress: Float, linearProgress: Float) {}

        /**
@@ -110,6 +112,7 @@ class LaunchAnimator(
         * called previously. This is typically used to clean up the resources initialized when the
         * animation was started.
         */
        @JvmDefault
        fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {}
    }

+7 −0
Original line number Diff line number Diff line
@@ -679,6 +679,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
    }

    /**
     * Whether the secure camera is currently showing over the keyguard.
     */
    public boolean isSecureCameraLaunchedOverKeyguard() {
        return mSecureCameraLaunched;
    }

    /**
     * @return a cached version of DreamManager.isDreaming()
     */
+13 −40
Original line number Diff line number Diff line
@@ -233,10 +233,13 @@ public class KeyguardService extends Service {
        mKeyguardViewMediator = keyguardViewMediator;
        mKeyguardLifecyclesDispatcher = keyguardLifecyclesDispatcher;
        mShellTransitions = shellTransitions;
    }

        if (shellTransitions != null && Transitions.ENABLE_SHELL_TRANSITIONS) {
            // Nothing here. Initialization for this happens in onCreate.
        } else {
    @Override
    public void onCreate() {
        ((SystemUIApplication) getApplication()).startServicesIfNeeded();

        if (mShellTransitions == null || !Transitions.ENABLE_SHELL_TRANSITIONS) {
            RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
            if (sEnableRemoteKeyguardGoingAwayAnimation) {
                final RemoteAnimationAdapter exitAnimationAdapter =
@@ -248,22 +251,19 @@ public class KeyguardService extends Service {
            }
            if (sEnableRemoteKeyguardOccludeAnimation) {
                final RemoteAnimationAdapter occludeAnimationAdapter =
                        new RemoteAnimationAdapter(mOccludeAnimationRunner, 0, 0);
                        new RemoteAnimationAdapter(
                                mKeyguardViewMediator.getOccludeAnimationRunner(), 0, 0);
                definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_OCCLUDE,
                        occludeAnimationAdapter);

                final RemoteAnimationAdapter unoccludeAnimationAdapter =
                        new RemoteAnimationAdapter(
                                mKeyguardViewMediator.getUnoccludeAnimationRunner(), 0, 0);
                definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_UNOCCLUDE,
                        occludeAnimationAdapter);
                        unoccludeAnimationAdapter);
            }
            ActivityTaskManager.getInstance().registerRemoteAnimationsForDisplay(
                    DEFAULT_DISPLAY, definition);
        }
    }

    @Override
    public void onCreate() {
        ((SystemUIApplication) getApplication()).startServicesIfNeeded();

        if (mShellTransitions == null || !Transitions.ENABLE_SHELL_TRANSITIONS) {
            return;
        }
        if (sEnableRemoteKeyguardGoingAwayAnimation) {
@@ -354,33 +354,6 @@ public class KeyguardService extends Service {
        }
    };

    private final IRemoteAnimationRunner.Stub mOccludeAnimationRunner =
            new IRemoteAnimationRunner.Stub() {
        @Override // Binder interface
        public void onAnimationStart(@WindowManager.TransitionOldType int transit,
                       RemoteAnimationTarget[] apps,
                       RemoteAnimationTarget[] wallpapers,
                        RemoteAnimationTarget[] nonApps,
                        IRemoteAnimationFinishedCallback finishedCallback) {
            Slog.d(TAG, "mOccludeAnimationRunner.onAnimationStart: transit=" + transit);
            try {
                if (transit == TRANSIT_OLD_KEYGUARD_OCCLUDE) {
                    mBinder.setOccluded(true /* isOccluded */, true /* animate */);
                } else if (transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE) {
                    mBinder.setOccluded(false /* isOccluded */, false /* animate */);
                }
                // TODO(bc-unlock): Implement (un)occlude animation.
                finishedCallback.onAnimationFinished();
            } catch (RemoteException e) {
                Slog.e(TAG, "RemoteException");
            }
        }

        @Override // Binder interface
        public void onAnimationCancelled() {
        }
    };

    final IRemoteTransition mOccludeAnimation = new IRemoteTransition.Stub() {
        @Override
        public void startAnimation(IBinder transition, TransitionInfo info,
+162 −1
Original line number Diff line number Diff line
@@ -77,11 +77,13 @@ import android.view.IRemoteAnimationRunner;
import android.view.RemoteAnimationTarget;
import android.view.SyncRtSurfaceTransactionApplier;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.WindowManagerPolicyConstants;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.internal.jank.InteractionJankMonitor;
@@ -89,6 +91,7 @@ import com.android.internal.jank.InteractionJankMonitor.Configuration;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IKeyguardExitCallback;
import com.android.internal.policy.IKeyguardStateCallback;
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardConstants;
@@ -102,7 +105,10 @@ import com.android.keyguard.mediator.ScreenOnCoordinator;
import com.android.systemui.CoreStartable;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.animation.LaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -375,6 +381,9 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
    private int mUnlockSoundId;
    private int mTrustedSoundId;
    private int mLockSoundStreamId;
    private final float mPowerButtonY;
    private final float mWindowCornerRadius;

    /**
     * The animation used for hiding keyguard. This is used to fetch the animation timings if
     * WindowManager is not providing us with them.
@@ -815,6 +824,109 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
        }
    };

    /**
     * Animation launch controller for activities that occlude the keyguard.
     */
    private final ActivityLaunchAnimator.Controller mOccludeAnimationController =
            new ActivityLaunchAnimator.Controller() {
                @Override
                public void onLaunchAnimationStart(boolean isExpandingFullyAbove) {
                    setOccluded(true /* occluded */, false /* animate */);
                }

                @Override
                public void onLaunchAnimationCancelled() {
                    setOccluded(true /* occluded */, false /* animate */);
                }

                @NonNull
                @Override
                public ViewGroup getLaunchContainer() {
                    return ((ViewGroup) mKeyguardViewControllerLazy.get()
                            .getViewRootImpl().getView());
                }

                @Override
                public void setLaunchContainer(@NonNull ViewGroup launchContainer) {
                    // No-op, launch container is always the shade.
                    Log.wtf(TAG, "Someone tried to change the launch container for the "
                            + "ActivityLaunchAnimator, which should never happen.");
                }

                @NonNull
                @Override
                public LaunchAnimator.State createAnimatorState() {
                    final int width = getLaunchContainer().getWidth();
                    final int height = getLaunchContainer().getHeight();

                    final float initialHeight = height / 3f;
                    final float initialWidth = width / 3f;

                    if (mUpdateMonitor.isSecureCameraLaunchedOverKeyguard()) {
                        // Start the animation near the power button, at one-third size, since the
                        // camera was launched from the power button.
                        return new LaunchAnimator.State(
                                (int) (mPowerButtonY - initialHeight / 2f) /* top */,
                                (int) (mPowerButtonY + initialHeight / 2f) /* bottom */,
                                (int) (width - initialWidth) /* left */,
                                width /* right */,
                                mWindowCornerRadius, mWindowCornerRadius);
                    } else {
                        // Start the animation in the center of the screen, scaled down.
                        return new LaunchAnimator.State(
                                height / 2, height / 2, width / 2, width / 2,
                                mWindowCornerRadius, mWindowCornerRadius);
                    }
                }
            };

    /**
     * Animation controller for activities that unocclude the keyguard. This will play the launch
     * animation in reverse.
     */
    private final ActivityLaunchAnimator.Controller mUnoccludeAnimationController =
            new ActivityLaunchAnimator.Controller() {
                @Override
                public void onLaunchAnimationEnd(boolean isExpandingFullyAbove) {
                    setOccluded(false /* isOccluded */, false /* animate */);
                }

                @Override
                public void onLaunchAnimationCancelled() {
                    setOccluded(false /* isOccluded */, false /* animate */);
                }

                @NonNull
                @Override
                public ViewGroup getLaunchContainer() {
                    return ((ViewGroup) mKeyguardViewControllerLazy.get()
                            .getViewRootImpl().getView());
                }

                @Override
                public void setLaunchContainer(@NonNull ViewGroup launchContainer) {
                    // No-op, launch container is always the shade.
                    Log.wtf(TAG, "Someone tried to change the launch container for the "
                            + "ActivityLaunchAnimator, which should never happen.");
                }

                @NonNull
                @Override
                public LaunchAnimator.State createAnimatorState() {
                    final int width = getLaunchContainer().getWidth();
                    final int height = getLaunchContainer().getHeight();

                    // TODO(b/207399883): Unocclude animation. This currently ends instantly.
                    return new LaunchAnimator.State(
                            0, height, 0, width, mWindowCornerRadius, mWindowCornerRadius);
                }
            };

    private IRemoteAnimationRunner mOccludeAnimationRunner =
            new ActivityLaunchRemoteAnimationRunner(mOccludeAnimationController);
    private IRemoteAnimationRunner mUnoccludeAnimationRunner =
            new ActivityLaunchRemoteAnimationRunner(mUnoccludeAnimationController);

    private DeviceConfigProxy mDeviceConfig;
    private DozeParameters mDozeParameters;

@@ -824,6 +936,8 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
    private boolean mWallpaperSupportsAmbientMode;
    private ScreenOnCoordinator mScreenOnCoordinator;

    private Lazy<ActivityLaunchAnimator> mActivityLaunchAnimator;

    /**
     * Injected constructor. See {@link KeyguardModule}.
     */
@@ -850,7 +964,8 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
            ScreenOnCoordinator screenOnCoordinator,
            InteractionJankMonitor interactionJankMonitor,
            DreamOverlayStateController dreamOverlayStateController,
            Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy) {
            Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy,
            Lazy<ActivityLaunchAnimator> activityLaunchAnimator) {
        super(context);
        mFalsingCollector = falsingCollector;
        mLockPatternUtils = lockPatternUtils;
@@ -890,6 +1005,12 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
        mScreenOffAnimationController = screenOffAnimationController;
        mInteractionJankMonitor = interactionJankMonitor;
        mDreamOverlayStateController = dreamOverlayStateController;

        mActivityLaunchAnimator = activityLaunchAnimator;

        mPowerButtonY = context.getResources().getDimensionPixelSize(
                R.dimen.physical_power_button_center_screen_location_y);
        mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
    }

    public void userActivity() {
@@ -1440,6 +1561,14 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
        Trace.endSection();
    }

    public IRemoteAnimationRunner getOccludeAnimationRunner() {
        return mOccludeAnimationRunner;
    }

    public IRemoteAnimationRunner getUnoccludeAnimationRunner() {
        return mUnoccludeAnimationRunner;
    }

    public boolean isHiding() {
        return mHiding;
    }
@@ -2868,4 +2997,36 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
            return mMessage;
        }
    }

    /**
     * Implementation of RemoteAnimationRunner that creates a new
     * {@link ActivityLaunchAnimator.Runner} whenever onAnimationStart is called, delegating the
     * remote animation methods to that runner.
     */
    private class ActivityLaunchRemoteAnimationRunner extends IRemoteAnimationRunner.Stub {

        private final ActivityLaunchAnimator.Controller mActivityLaunchController;
        @Nullable private ActivityLaunchAnimator.Runner mRunner;

        ActivityLaunchRemoteAnimationRunner(ActivityLaunchAnimator.Controller controller) {
            mActivityLaunchController = controller;
        }

        @Override
        public void onAnimationCancelled() throws RemoteException {
            if (mRunner != null) {
                mRunner.onAnimationCancelled();
            }
        }

        @Override
        public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
                RemoteAnimationTarget[] wallpapers,
                RemoteAnimationTarget[] nonApps,
                IRemoteAnimationFinishedCallback finishedCallback)
                throws RemoteException {
            mRunner = mActivityLaunchAnimator.get().createRunner(mActivityLaunchController);
            mRunner.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback);
        }
    }
}
Loading