Merge "Properly launch activities that show over lock" into main
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 4ea57a8..ab4db45 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -290,9 +290,10 @@
         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)
         }
     }
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
index 9cc87fd..f0e3c99 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
@@ -57,6 +57,16 @@
             @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().
      */
     void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade, int flags);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 051eeb0..bd13d06 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -48,6 +48,7 @@
 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 @@
             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
             );
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
index 07d3a1c..2d125462 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
@@ -30,7 +30,6 @@
 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.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 @@
         )
     }
 
+    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 @@
                     !willLaunchResolverActivity &&
                     shouldAnimateLaunch(isActivityIntent = true)
             val animController =
-                wrapAnimationController(
+                wrapAnimationControllerForShadeOrStatusBar(
                     animationController = animationController,
                     dismissShade = dismissShade,
                     isLaunchForActivity = true,
@@ -547,12 +560,18 @@
             )
         }
 
-        /** 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,79 +585,103 @@
                         lockScreenUserManager.currentUserId,
                     ))
 
+            val actuallyShowOverLockscreen =
+                showOverLockscreen &&
+                    intent.isActivity &&
+                    activityIntentHelper.wouldPendingShowOverLockscreen(
+                        intent,
+                        lockScreenUserManager.currentUserId
+                    )
+
             val animate =
                 !willLaunchResolverActivity &&
                     animationController != null &&
-                    shouldAnimateLaunch(intent.isActivity)
+                    shouldAnimateLaunch(intent.isActivity, actuallyShowOverLockscreen)
+
+            // We wrap animationCallback with a StatusBarLaunchAnimatorController so
+            // that the shade is collapsed after the animation (or when it is cancelled,
+            // aborted, etc).
+            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
-            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(
-                                animationController = animationController,
-                                dismissShade = true,
-                                isLaunchForActivity = intent.isActivity,
-                            )
-                        activityLaunchAnimator.startPendingIntentWithAnimation(
-                            controller,
-                            animate,
-                            intent.creatorPackage,
-                            object : PendingIntentStarter {
-                                override fun startPendingIntent(
-                                    animationAdapter: RemoteAnimationAdapter?
-                                ): Int {
-                                    val options =
-                                        ActivityOptions(
-                                            CentralSurfaces.getActivityOptions(
-                                                displayId,
-                                                animationAdapter
-                                            )
+            val runnable = Runnable {
+                try {
+                    activityLaunchAnimator.startPendingIntentWithAnimation(
+                        controller,
+                        animate,
+                        intent.creatorPackage,
+                        actuallyShowOverLockscreen,
+                        object : PendingIntentStarter {
+                            override fun startPendingIntent(
+                                animationAdapter: RemoteAnimationAdapter?
+                            ): Int {
+                                val options =
+                                    ActivityOptions(
+                                        CentralSurfaces.getActivityOptions(
+                                            displayId,
+                                            animationAdapter
                                         )
-                                    // TODO b/221255671: restrict this to only be set for
-                                    // notifications
-                                    options.isEligibleForLegacyPermissionPrompt = true
-                                    options.setPendingIntentBackgroundActivityStartMode(
-                                        ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
                                     )
-                                    return intent.sendAndReturnResult(
-                                        null,
-                                        0,
-                                        null,
-                                        null,
-                                        null,
-                                        null,
-                                        options.toBundle()
-                                    )
-                                }
-                            },
-                        )
-                    } catch (e: PendingIntent.CanceledException) {
-                        // the stack trace isn't very helpful here.
-                        // Just log the exception message.
-                        Log.w(TAG, "Sending intent failed: $e")
-                        if (!collapse) {
-                            // executeRunnableDismissingKeyguard did not collapse for us already.
-                            shadeControllerLazy.get().collapseOnMainThread()
-                        }
-                        // TODO: Dismiss Keyguard.
+                                // TODO b/221255671: restrict this to only be set for
+                                // notifications
+                                options.isEligibleForLegacyPermissionPrompt = true
+                                options.setPendingIntentBackgroundActivityStartMode(
+                                    ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
+                                )
+                                return intent.sendAndReturnResult(
+                                    null,
+                                    0,
+                                    null,
+                                    null,
+                                    null,
+                                    null,
+                                    options.toBundle()
+                                )
+                            }
+                        },
+                    )
+                } catch (e: PendingIntent.CanceledException) {
+                    // the stack trace isn't very helpful here.
+                    // Just log the exception message.
+                    Log.w(TAG, "Sending intent failed: $e")
+                    if (!collapse) {
+                        // executeRunnableDismissingKeyguard did not collapse for us already.
+                        shadeControllerLazy.get().collapseOnMainThread()
                     }
-                    if (intent.isActivity) {
-                        assistManagerLazy.get().hideAssist()
-                    }
-                    intentSentUiThreadCallback?.let { postOnUiThread(runnable = it) }
-                },
-                afterKeyguardGone = willLaunchResolverActivity,
-                dismissShade = collapse,
-                willAnimateOnKeyguard = animate,
-            )
+                    // TODO: Dismiss Keyguard.
+                }
+                if (intent.isActivity) {
+                    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. */
@@ -678,71 +721,12 @@
                 // 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 @@
          *   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 @@
             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> =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
index 43cf1b5..ae47a7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
@@ -37,7 +37,6 @@
 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.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 @@
         testableLooper.processAllMessages()
 
         verify(activityStarter, never())
-            .startPendingIntentDismissingKeyguard(
-                any(), any(), any(ActivityLaunchAnimator.Controller::class.java))
+            .startPendingIntentMaybeDismissingKeyguard(any(), nullable(), nullable())
     }
 
     @Test
@@ -357,8 +356,7 @@
         testableLooper.processAllMessages()
 
         verify(activityStarter, never())
-            .startPendingIntentDismissingKeyguard(
-                any(), any(), any(ActivityLaunchAnimator.Controller::class.java))
+            .startPendingIntentMaybeDismissingKeyguard(any(), nullable(), nullable())
     }
 
     @Test
@@ -373,7 +371,7 @@
         testableLooper.processAllMessages()
 
         verify(activityStarter)
-            .startPendingIntentDismissingKeyguard(
+            .startPendingIntentMaybeDismissingKeyguard(
                 eq(pi), nullable(), nullable<ActivityLaunchAnimator.Controller>())
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
index 68f2728..7de05ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
@@ -19,11 +19,14 @@
 import android.os.RemoteException
 import android.os.UserHandle
 import android.testing.AndroidTestingRunner
+import android.view.View
+import android.widget.FrameLayout
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.ActivityIntentHelper
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.LaunchableView
 import com.android.systemui.assist.AssistManager
 import com.android.systemui.keyguard.KeyguardViewMediator
 import com.android.systemui.keyguard.WakefulnessLifecycle
@@ -41,6 +44,7 @@
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.nullable
 import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
@@ -49,6 +53,7 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.Mock
 import org.mockito.Mockito.anyBoolean
 import org.mockito.Mockito.mock
@@ -116,16 +121,51 @@
     @Test
     fun startPendingIntentDismissingKeyguard_keyguardShowing_dismissWithAction() {
         val pendingIntent = mock(PendingIntent::class.java)
+        whenever(pendingIntent.isActivity).thenReturn(true)
         whenever(keyguardStateController.isShowing).thenReturn(true)
         whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
 
         underTest.startPendingIntentDismissingKeyguard(pendingIntent)
+        mainExecutor.runAllReady()
 
         verify(statusBarKeyguardViewManager)
             .dismissWithAction(any(OnDismissAction::class.java), eq(null), anyBoolean(), eq(null))
     }
 
     @Test
+    fun startPendingIntentMaybeDismissingKeyguard_keyguardShowing_showOverLockscreen_activityLaunchAnimator() {
+        val pendingIntent = mock(PendingIntent::class.java)
+        val parent = FrameLayout(context)
+        val view =
+            object : View(context), LaunchableView {
+                override fun setShouldBlockVisibilityChanges(block: Boolean) {}
+            }
+        parent.addView(view)
+        val controller = ActivityLaunchAnimator.Controller.fromView(view)
+        whenever(pendingIntent.isActivity).thenReturn(true)
+        whenever(keyguardStateController.isShowing).thenReturn(true)
+        whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+        whenever(activityIntentHelper.wouldPendingShowOverLockscreen(eq(pendingIntent), anyInt()))
+            .thenReturn(true)
+
+        underTest.startPendingIntentMaybeDismissingKeyguard(
+            intent = pendingIntent,
+            animationController = controller,
+            intentSentUiThreadCallback = null,
+        )
+        mainExecutor.runAllReady()
+
+        verify(activityLaunchAnimator)
+            .startPendingIntentWithAnimation(
+                nullable(),
+                eq(true),
+                nullable(),
+                eq(true),
+                any(),
+            )
+    }
+
+    @Test
     fun startPendingIntentDismissingKeyguard_associatedView_getAnimatorController() {
         val pendingIntent = mock(PendingIntent::class.java)
         val associatedView = mock(ExpandableNotificationRow::class.java)