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

Commit 30383e8f authored by Fabian Kozynski's avatar Fabian Kozynski Committed by Android (Google) Code Review
Browse files

Merge "Properly launch activities that show over lock" into main

parents ef529f28 4cc1f016
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -290,9 +290,10 @@ class ActivityLaunchAnimator(
        controller: Controller?,
        animate: Boolean = true,
        packageName: String? = null,
        showOverLockscreen: Boolean = false,
        intentStarter: PendingIntentStarter
    ) {
        startIntentWithAnimation(controller, animate, packageName) {
        startIntentWithAnimation(controller, animate, packageName, showOverLockscreen) {
            intentStarter.startPendingIntent(it)
        }
    }
+10 −0
Original line number Diff line number Diff line
@@ -56,6 +56,16 @@ public interface ActivityStarter {
            Runnable intentSentUiThreadCallback,
            @Nullable ActivityLaunchAnimator.Controller animationController);

    /**
     * Similar to {@link #startPendingIntentDismissingKeyguard}, except that it supports launching
     * activities on top of the keyguard. If the activity supports {@code showOverLockscreen}, it
     * will show over keyguard without first dimissing it. If it doesn't support it, calling this
     * method is exactly the same as calling {@link #startPendingIntentDismissingKeyguard}.
     */
    void startPendingIntentMaybeDismissingKeyguard(PendingIntent intent,
            @Nullable Runnable intentSentUiThreadCallback,
            @Nullable ActivityLaunchAnimator.Controller animationController);

    /**
     * The intent flag can be specified in startActivity().
     */
+12 −6
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ import android.widget.Switch;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;

import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.animation.ActivityLaunchAnimator;
@@ -538,12 +539,17 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener,
            Log.i(TAG, "Launching activity before click");
        } else {
            Log.i(TAG, "The activity is starting");
            ActivityLaunchAnimator.Controller controller = mViewClicked == null
                    ? null
                    : ActivityLaunchAnimator.Controller.fromView(mViewClicked, 0);
            mUiHandler.post(() ->
                    mActivityStarter.startPendingIntentDismissingKeyguard(
                            pendingIntent, null, controller)

            ActivityLaunchAnimator.Controller controller =
                    mViewClicked == null ? null :
                    ActivityLaunchAnimator.Controller.fromView(
                            mViewClicked,
                            InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE
                    );
            mActivityStarter.startPendingIntentMaybeDismissingKeyguard(
                    pendingIntent,
                    /* intentSentUiThreadCallback= */ null,
                    controller
            );
        }
    }
+177 −127
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@ import android.view.View
import android.view.WindowManager
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.ActivityIntentHelper
import com.android.systemui.res.R
import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.animation.ActivityLaunchAnimator.PendingIntentStarter
import com.android.systemui.animation.DelegateLaunchAnimatorController
@@ -43,6 +42,7 @@ import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.ActivityStarter.OnDismissAction
import com.android.systemui.res.R
import com.android.systemui.settings.UserTracker
import com.android.systemui.shade.ShadeController
import com.android.systemui.shade.ShadeViewController
@@ -134,6 +134,19 @@ constructor(
        )
    }

    override fun startPendingIntentMaybeDismissingKeyguard(
        intent: PendingIntent,
        intentSentUiThreadCallback: Runnable?,
        animationController: ActivityLaunchAnimator.Controller?
    ) {
        activityStarterInternal.startPendingIntentDismissingKeyguard(
            intent = intent,
            intentSentUiThreadCallback = intentSentUiThreadCallback,
            animationController = animationController,
            showOverLockscreen = true,
        )
    }

    /**
     * TODO(b/279084380): Change callers to just call startActivityDismissingKeyguard and deprecate
     *   this.
@@ -454,7 +467,7 @@ constructor(
                    !willLaunchResolverActivity &&
                    shouldAnimateLaunch(isActivityIntent = true)
            val animController =
                wrapAnimationController(
                wrapAnimationControllerForShadeOrStatusBar(
                    animationController = animationController,
                    dismissShade = dismissShade,
                    isLaunchForActivity = true,
@@ -547,12 +560,18 @@ constructor(
            )
        }

        /** Starts a pending intent after dismissing keyguard. */
        /**
         * Starts a pending intent after dismissing keyguard.
         *
         * This can be called in a background thread (to prevent calls in [ActivityIntentHelper] in
         * the main thread).
         */
        fun startPendingIntentDismissingKeyguard(
            intent: PendingIntent,
            intentSentUiThreadCallback: Runnable? = null,
            associatedView: View? = null,
            animationController: ActivityLaunchAnimator.Controller? = null,
            showOverLockscreen: Boolean = false,
        ) {
            val animationController =
                if (associatedView is ExpandableNotificationRow) {
@@ -566,31 +585,46 @@ constructor(
                        lockScreenUserManager.currentUserId,
                    ))

            val actuallyShowOverLockscreen =
                showOverLockscreen &&
                    intent.isActivity &&
                    activityIntentHelper.wouldPendingShowOverLockscreen(
                        intent,
                        lockScreenUserManager.currentUserId
                    )

            val animate =
                !willLaunchResolverActivity &&
                    animationController != null &&
                    shouldAnimateLaunch(intent.isActivity)
                    shouldAnimateLaunch(intent.isActivity, actuallyShowOverLockscreen)

            // If we animate, don't collapse the shade and defer the keyguard dismiss (in case we
            // run the animation on the keyguard). The animation will take care of (instantly)
            // collapsing the shade and hiding the keyguard once it is done.
            val collapse = !animate
            executeRunnableDismissingKeyguard(
                runnable = {
                    try {
            // We wrap animationCallback with a StatusBarLaunchAnimatorController so
            // that the shade is collapsed after the animation (or when it is cancelled,
            // aborted, etc).
                        val controller: ActivityLaunchAnimator.Controller? =
                            wrapAnimationController(
            val statusBarController =
                wrapAnimationControllerForShadeOrStatusBar(
                    animationController = animationController,
                    dismissShade = true,
                    isLaunchForActivity = intent.isActivity,
                )
            val controller =
                if (actuallyShowOverLockscreen) {
                    wrapAnimationControllerForLockscreen(statusBarController)
                } else {
                    statusBarController
                }

            // If we animate, don't collapse the shade and defer the keyguard dismiss (in case we
            // run the animation on the keyguard). The animation will take care of (instantly)
            // collapsing the shade and hiding the keyguard once it is done.
            val collapse = !animate
            val runnable = Runnable {
                try {
                    activityLaunchAnimator.startPendingIntentWithAnimation(
                        controller,
                        animate,
                        intent.creatorPackage,
                        actuallyShowOverLockscreen,
                        object : PendingIntentStarter {
                            override fun startPendingIntent(
                                animationAdapter: RemoteAnimationAdapter?
@@ -634,12 +668,21 @@ constructor(
                    assistManagerLazy.get().hideAssist()
                }
                intentSentUiThreadCallback?.let { postOnUiThread(runnable = it) }
                },
            }

            if (!actuallyShowOverLockscreen) {
                postOnUiThread(delay = 0) {
                    executeRunnableDismissingKeyguard(
                        runnable = runnable,
                        afterKeyguardGone = willLaunchResolverActivity,
                        dismissShade = collapse,
                        willAnimateOnKeyguard = animate,
                    )
                }
            } else {
                postOnUiThread(delay = 0, runnable)
            }
        }

        /** Starts an Activity. */
        fun startActivity(
@@ -678,71 +721,12 @@ constructor(
                // Wrap the animation controller to dismiss the shade and set
                // mIsLaunchingActivityOverLockscreen during the animation.
                val delegate =
                    wrapAnimationController(
                    wrapAnimationControllerForShadeOrStatusBar(
                        animationController = animationController,
                        dismissShade = dismissShade,
                        isLaunchForActivity = true,
                    )
                delegate?.let {
                    controller =
                        object : DelegateLaunchAnimatorController(delegate) {
                            override fun onIntentStarted(willAnimate: Boolean) {
                                delegate?.onIntentStarted(willAnimate)
                                if (willAnimate) {
                                    centralSurfaces?.setIsLaunchingActivityOverLockscreen(true)
                                }
                            }

                            override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
                                super.onLaunchAnimationStart(isExpandingFullyAbove)

                                // Double check that the keyguard is still showing and not going
                                // away, but if so set the keyguard occluded. Typically, WM will let
                                // KeyguardViewMediator know directly, but we're overriding that to
                                // play the custom launch animation, so we need to take care of that
                                // here. The unocclude animation is not overridden, so WM will call
                                // KeyguardViewMediator's unocclude animation runner when the
                                // activity is exited.
                                if (
                                    keyguardStateController.isShowing &&
                                        !keyguardStateController.isKeyguardGoingAway
                                ) {
                                    Log.d(TAG, "Setting occluded = true in #startActivity.")
                                    keyguardViewMediatorLazy
                                        .get()
                                        .setOccluded(true /* isOccluded */, true /* animate */)
                                }
                            }

                            override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
                                // Set mIsLaunchingActivityOverLockscreen to false before actually
                                // finishing the animation so that we can assume that
                                // mIsLaunchingActivityOverLockscreen being true means that we will
                                // collapse the shade (or at least run the post collapse runnables)
                                // later on.
                                centralSurfaces?.setIsLaunchingActivityOverLockscreen(false)
                                delegate?.onLaunchAnimationEnd(isExpandingFullyAbove)
                            }

                            override fun onLaunchAnimationCancelled(
                                newKeyguardOccludedState: Boolean?
                            ) {
                                if (newKeyguardOccludedState != null) {
                                    keyguardViewMediatorLazy
                                        .get()
                                        .setOccluded(newKeyguardOccludedState, false /* animate */)
                                }

                                // Set mIsLaunchingActivityOverLockscreen to false before actually
                                // finishing the animation so that we can assume that
                                // mIsLaunchingActivityOverLockscreen being true means that we will
                                // collapse the shade (or at least run the // post collapse
                                // runnables) later on.
                                centralSurfaces?.setIsLaunchingActivityOverLockscreen(false)
                                delegate.onLaunchAnimationCancelled(newKeyguardOccludedState)
                            }
                        }
                }
                controller = wrapAnimationControllerForLockscreen(delegate)
            } else if (dismissShade) {
                // The animation will take care of dismissing the shade at the end of the animation.
                // If we don't animate, collapse it directly.
@@ -874,7 +858,7 @@ constructor(
         *   window.
         * @param isLaunchForActivity whether the launch is for an activity.
         */
        private fun wrapAnimationController(
        private fun wrapAnimationControllerForShadeOrStatusBar(
            animationController: ActivityLaunchAnimator.Controller?,
            dismissShade: Boolean,
            isLaunchForActivity: Boolean,
@@ -909,6 +893,72 @@ constructor(
            return animationController
        }

        /**
         * Wraps an animation controller so that if an activity would be launched on top of the
         * lockscreen, the correct flags are set for it to be occluded.
         */
        private fun wrapAnimationControllerForLockscreen(
            animationController: ActivityLaunchAnimator.Controller?
        ): ActivityLaunchAnimator.Controller? {
            return animationController?.let {
                object : DelegateLaunchAnimatorController(it) {
                    override fun onIntentStarted(willAnimate: Boolean) {
                        delegate.onIntentStarted(willAnimate)
                        if (willAnimate) {
                            centralSurfaces?.setIsLaunchingActivityOverLockscreen(true)
                        }
                    }

                    override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
                        super.onLaunchAnimationStart(isExpandingFullyAbove)

                        // Double check that the keyguard is still showing and not going
                        // away, but if so set the keyguard occluded. Typically, WM will let
                        // KeyguardViewMediator know directly, but we're overriding that to
                        // play the custom launch animation, so we need to take care of that
                        // here. The unocclude animation is not overridden, so WM will call
                        // KeyguardViewMediator's unocclude animation runner when the
                        // activity is exited.
                        if (
                            keyguardStateController.isShowing &&
                                !keyguardStateController.isKeyguardGoingAway
                        ) {
                            Log.d(TAG, "Setting occluded = true in #startActivity.")
                            keyguardViewMediatorLazy
                                .get()
                                .setOccluded(true /* isOccluded */, true /* animate */)
                        }
                    }

                    override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
                        // Set mIsLaunchingActivityOverLockscreen to false before actually
                        // finishing the animation so that we can assume that
                        // mIsLaunchingActivityOverLockscreen being true means that we will
                        // collapse the shade (or at least run the post collapse runnables)
                        // later on.
                        centralSurfaces?.setIsLaunchingActivityOverLockscreen(false)
                        delegate.onLaunchAnimationEnd(isExpandingFullyAbove)
                    }

                    override fun onLaunchAnimationCancelled(newKeyguardOccludedState: Boolean?) {
                        if (newKeyguardOccludedState != null) {
                            keyguardViewMediatorLazy
                                .get()
                                .setOccluded(newKeyguardOccludedState, false /* animate */)
                        }

                        // Set mIsLaunchingActivityOverLockscreen to false before actually
                        // finishing the animation so that we can assume that
                        // mIsLaunchingActivityOverLockscreen being true means that we will
                        // collapse the shade (or at least run the // post collapse
                        // runnables) later on.
                        centralSurfaces?.setIsLaunchingActivityOverLockscreen(false)
                        delegate.onLaunchAnimationCancelled(newKeyguardOccludedState)
                    }
                }
            }
        }

        /** Retrieves the current user handle to start the Activity. */
        private fun getActivityUserHandle(intent: Intent): UserHandle {
            val packages: Array<String> =
+4 −6
Original line number Diff line number Diff line
@@ -37,7 +37,6 @@ import android.testing.TestableLooper
import android.view.IWindowManager
import android.view.View
import com.android.internal.logging.MetricsLogger
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.animation.view.LaunchableFrameLayout
@@ -48,6 +47,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.QSHost
import com.android.systemui.qs.QsEventLogger
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.res.R
import com.android.systemui.settings.FakeDisplayTracker
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
@@ -343,8 +343,7 @@ class CustomTileTest : SysuiTestCase() {
        testableLooper.processAllMessages()

        verify(activityStarter, never())
            .startPendingIntentDismissingKeyguard(
                any(), any(), any(ActivityLaunchAnimator.Controller::class.java))
            .startPendingIntentMaybeDismissingKeyguard(any(), nullable(), nullable())
    }

    @Test
@@ -357,8 +356,7 @@ class CustomTileTest : SysuiTestCase() {
        testableLooper.processAllMessages()

        verify(activityStarter, never())
            .startPendingIntentDismissingKeyguard(
                any(), any(), any(ActivityLaunchAnimator.Controller::class.java))
            .startPendingIntentMaybeDismissingKeyguard(any(), nullable(), nullable())
    }

    @Test
@@ -373,7 +371,7 @@ class CustomTileTest : SysuiTestCase() {
        testableLooper.processAllMessages()

        verify(activityStarter)
            .startPendingIntentDismissingKeyguard(
            .startPendingIntentMaybeDismissingKeyguard(
                eq(pi), nullable(), nullable<ActivityLaunchAnimator.Controller>())
    }

Loading