• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.keyguard
18 
19 import android.animation.Animator
20 import android.animation.AnimatorListenerAdapter
21 import android.animation.ValueAnimator
22 import android.app.WallpaperManager
23 import android.content.res.Resources
24 import android.graphics.Matrix
25 import android.graphics.Rect
26 import android.hardware.devicestate.DeviceStateManager
27 import android.os.DeadObjectException
28 import android.os.Handler
29 import android.os.PowerManager
30 import android.os.RemoteException
31 import android.os.Trace
32 import android.util.Log
33 import android.view.RemoteAnimationTarget
34 import android.view.SurfaceControl
35 import android.view.SyncRtSurfaceTransactionApplier
36 import android.view.View
37 import android.view.WindowManager
38 import androidx.annotation.VisibleForTesting
39 import androidx.core.math.MathUtils
40 import com.android.app.animation.Interpolators
41 import com.android.internal.R
42 import com.android.keyguard.KeyguardViewController
43 import com.android.systemui.Flags.fasterUnlockTransition
44 import com.android.systemui.dagger.SysUISingleton
45 import com.android.systemui.dagger.qualifiers.Main
46 import com.android.systemui.flags.FeatureFlags
47 import com.android.systemui.flags.Flags
48 import com.android.systemui.plugins.BcSmartspaceDataPlugin
49 import com.android.systemui.shared.recents.utilities.Utilities
50 import com.android.systemui.shared.system.ActivityManagerWrapper
51 import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController
52 import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController
53 import com.android.systemui.shared.system.smartspace.SmartspaceState
54 import com.android.systemui.statusbar.NotificationShadeWindowController
55 import com.android.systemui.statusbar.SysuiStatusBarStateController
56 import com.android.systemui.statusbar.phone.BiometricUnlockController
57 import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK_FROM_DREAM
58 import com.android.systemui.statusbar.policy.KeyguardStateController
59 import com.android.systemui.util.Utils.isDeviceFoldable
60 import dagger.Lazy
61 import javax.inject.Inject
62 
63 const val TAG = "KeyguardUnlock"
64 
65 /**
66  * Starting scale factor for the app/launcher surface behind the keyguard, when it's animating in
67  * during keyguard exit.
68  */
69 const val SURFACE_BEHIND_START_SCALE_FACTOR = 0.95f
70 
71 /**
72  * How much to translate the surface behind the keyguard at the beginning of the exit animation, in
73  * terms of percentage of the surface's height.
74  */
75 const val SURFACE_BEHIND_START_TRANSLATION_Y = 0.05f
76 
77 /**
78  * Y coordinate of the pivot point for the scale effect on the surface behind the keyguard. This is
79  * expressed as percentage of the surface's height, so 0.66f means the surface will scale up from
80  * the point at (width / 2, height * 0.66).
81  */
82 const val SURFACE_BEHIND_SCALE_PIVOT_Y = 0.66f
83 
84 /**
85  * Dismiss amount at which to fade in the surface behind the keyguard. The surface will then animate
86  * along with the dismiss amount until [DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD] is reached.
87  *
88  * The dismiss amount is the inverse of the notification panel expansion, which decreases as the
89  * lock screen is swiped away.
90  */
91 const val DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD = 0.15f
92 
93 /**
94  * Dismiss amount at which to complete the keyguard exit animation and hide the keyguard.
95  *
96  * The dismiss amount is the inverse of the notification panel expansion, which decreases as the
97  * lock screen is swiped away.
98  */
99 const val DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD = 0.3f
100 
101 /**
102  * How long the canned unlock animation takes. This is used if we are unlocking from biometric auth,
103  * from a tap on the unlock icon, or from the bouncer. This is not relevant if the lockscreen is
104  * swiped away via a touch gesture, or when it's flinging expanded/collapsed after a swipe.
105  */
106 const val LEGACY_UNLOCK_ANIMATION_DURATION_MS = 200L
107 const val UNLOCK_ANIMATION_DURATION_MS = 300L
108 
109 /**
110  * If there are two different wallpapers on home and lock screen, duration and delay of the lock
111  * wallpaper fade out.
112  */
113 const val LOCK_WALLPAPER_FADE_OUT_DURATION = 150L
114 const val LOCK_WALLPAPER_FADE_OUT_START_DELAY = 150L
115 
116 /**
117  * How long the in-window launcher icon animation takes. This is used if the launcher is underneath
118  * the lock screen and supports in-window animations.
119  *
120  * This animation will take place entirely within the Launcher window. We can safely unlock the
121  * device, end remote animations, etc. even if this is still running.
122  */
123 const val LAUNCHER_ICONS_ANIMATION_DURATION_MS = 633L
124 
125 /**
126  * How long to wait for the shade to get out of the way before starting the canned unlock animation.
127  * If there are two different wallpapers on home and lock screen, this is also the duration and
128  * delay of the home wallpaper fade in.
129  */
130 const val LEGACY_CANNED_UNLOCK_START_DELAY = 100L
131 const val CANNED_UNLOCK_START_DELAY = 25L
132 
133 /**
134  * Duration for the alpha animation on the surface behind. This plays to fade in the surface during
135  * a swipe to unlock (and to fade it back out if the swipe is cancelled).
136  */
137 const val SURFACE_BEHIND_SWIPE_FADE_DURATION_MS = 175L
138 
139 /**
140  * Start delay for the surface behind animation, used so that the lockscreen can get out of the way
141  * before the surface begins appearing.
142  */
143 const val LEGACY_UNLOCK_ANIMATION_SURFACE_BEHIND_START_DELAY_MS = 75L
144 const val UNLOCK_ANIMATION_SURFACE_BEHIND_START_DELAY_MS = 67L
145 
146 /**
147  * Initiates, controls, and ends the keyguard unlock animation.
148  *
149  * The unlock animation transitions between the keyguard (lock screen) and the app/launcher surface
150  * behind the keyguard. If the user is swiping away the keyguard, this controller will decide when
151  * to animate in the surface, and synchronize its appearance with the swipe gesture. If the keyguard
152  * is animating away via a canned animation (due to biometric unlock, tapping a notification, etc.)
153  * this controller will play a canned animation on the surface as well.
154  *
155  * The surface behind the keyguard is manipulated via a RemoteAnimation passed to
156  * [notifyStartSurfaceBehindRemoteAnimation] by [KeyguardViewMediator].
157  */
158 @SysUISingleton
159 open class KeyguardUnlockAnimationController
160 @Inject
161 constructor(
162     private val windowManager: WindowManager,
163     @Main private val resources: Resources,
164     private val keyguardStateController: KeyguardStateController,
165     private val keyguardViewMediator: Lazy<KeyguardViewMediator>,
166     private val keyguardViewController: KeyguardViewController,
167     private val featureFlags: FeatureFlags,
168     private val biometricUnlockControllerLazy: Lazy<BiometricUnlockController>,
169     private val statusBarStateController: SysuiStatusBarStateController,
170     private val notificationShadeWindowController: NotificationShadeWindowController,
171     private val powerManager: PowerManager,
172     private val wallpaperManager: WallpaperManager,
173     private val deviceStateManager: DeviceStateManager,
174 ) : KeyguardStateController.Callback, ISysuiUnlockAnimationController.Stub() {
175 
176     interface KeyguardUnlockAnimationListener {
177         /**
178          * Called when the remote unlock animation, controlled by
179          * [KeyguardUnlockAnimationController], first starts.
180          *
181          * [playingCannedAnimation] indicates whether we are playing a canned animation to show the
182          * app/launcher behind the keyguard, vs. this being a swipe to unlock where the dismiss
183          * amount drives the animation.
184          *
185          * [fromWakeAndUnlock] tells us whether we are unlocking directly from AOD - in this case,
186          * the lockscreen is dismissed instantly, so we shouldn't run any animations that rely on it
187          * being visible.
188          *
189          * [unlockAnimationStartDelay] and [unlockAnimationDuration] provide the timing parameters
190          * for the canned animation (if applicable) so interested parties can sync with it. If no
191          * canned animation is playing, these are both 0.
192          */
193         fun onUnlockAnimationStarted(
194             playingCannedAnimation: Boolean,
195             isWakeAndUnlockNotFromDream: Boolean,
196             unlockAnimationStartDelay: Long,
197             unlockAnimationDuration: Long,
198         ) {}
199 
200         /**
201          * Called when the remote unlock animation ends, in all cases, canned or swipe-to-unlock.
202          * The keyguard is no longer visible in this state and the app/launcher behind the keyguard
203          * is now completely visible.
204          */
205         fun onUnlockAnimationFinished() {}
206     }
207 
208     /** The SmartSpace view on the lockscreen. */
209     var lockscreenSmartspace: View? = null
210 
211     /**
212      * The state of the Launcher's smartspace, delivered via [onLauncherSmartspaceStateUpdated].
213      * This is pushed to us from Launcher whenever their smartspace moves or its visibility changes.
214      * We'll animate the lockscreen smartspace to this location during an unlock.
215      */
216     var launcherSmartspaceState: SmartspaceState? = null
217 
218     /**
219      * Whether a canned unlock animation is playing, vs. currently unlocking in response to a swipe
220      * gesture or panel fling. If we're swiping/flinging, the unlock animation is driven by the
221      * dismiss amount, via [onKeyguardDismissAmountChanged]. If we're using a canned animation, it's
222      * being driven by ValueAnimators started in [playCannedUnlockAnimation].
223      */
224     var playingCannedUnlockAnimation = false
225 
226     /**
227      * Whether we reached the swipe gesture threshold to dismiss keyguard, or restore it, once and
228      * should ignore any future changes to the dismiss amount before the animation finishes.
229      */
230     var dismissAmountThresholdsReached = false
231 
232     /**
233      * Remote callback provided by Launcher that allows us to control the Launcher's unlock
234      * animation and smartspace.
235      *
236      * If this is null, we will not be animating any Launchers today and should fall back to window
237      * animations.
238      */
239     private var launcherUnlockController: ILauncherUnlockAnimationController? = null
240 
241     /** Fully qualified class name of the launcher activity */
242     private var launcherActivityClass: String? = null
243 
244     private val listeners = ArrayList<KeyguardUnlockAnimationListener>()
245 
246     /**
247      * Called from SystemUiProxy to pass us the launcher's unlock animation controller. If this
248      * doesn't happen, we won't use in-window animations or the smartspace shared element
249      * transition, but that's okay!
250      */
251     override fun setLauncherUnlockController(
252         activityClass: String,
253         callback: ILauncherUnlockAnimationController?,
254     ) {
255         launcherActivityClass = activityClass
256         launcherUnlockController = callback
257     }
258 
259     /**
260      * Called from SystemUiProxy to pass us the latest state of the Launcher's smartspace. This is
261      * only done when the state has changed in some way.
262      */
263     override fun onLauncherSmartspaceStateUpdated(state: SmartspaceState?) {
264         launcherSmartspaceState = state
265     }
266 
267     /**
268      * Information used to start, run, and finish a RemoteAnimation on the app or launcher surface
269      * behind the keyguard.
270      *
271      * If we're swiping to unlock, the "animation" is controlled via the gesture, tied to the
272      * dismiss amounts received in [onKeyguardDismissAmountChanged]. It does not have a fixed
273      * duration, and it ends when the gesture reaches a certain threshold or is cancell
274      *
275      * If we're unlocking via biometrics, PIN entry, or from clicking a notification, a canned
276      * animation is started in [playCannedUnlockAnimation].
277      */
278     @VisibleForTesting var surfaceTransactionApplier: SyncRtSurfaceTransactionApplier? = null
279     private var surfaceBehindRemoteAnimationTargets: Array<RemoteAnimationTarget>? = null
280     private var openingWallpaperTargets: Array<RemoteAnimationTarget>? = null
281     private var closingWallpaperTargets: Array<RemoteAnimationTarget>? = null
282     private var surfaceBehindRemoteAnimationStartTime: Long = 0
283 
284     /**
285      * Alpha value applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the
286      * app/launcher behind the keyguard.
287      *
288      * If we're doing a swipe gesture, we fade in the surface when the swipe passes a certain
289      * threshold. If we're doing a canned animation, it'll be faded in while a translate/scale
290      * animation plays.
291      */
292     private var surfaceBehindAlpha = 1f
293 
294     @VisibleForTesting var surfaceBehindAlphaAnimator = ValueAnimator.ofFloat(0f, 1f)
295 
296     var wallpaperCannedUnlockAnimator = ValueAnimator.ofFloat(0f, 1f)
297 
298     var wallpaperFadeOutUnlockAnimator = ValueAnimator.ofFloat(1f, 0f)
299 
300     /**
301      * Matrix applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the
302      * app/launcher behind the keyguard.
303      *
304      * This is used during the unlock animation/swipe gesture to scale and translate the surface.
305      */
306     private val surfaceBehindMatrix = Matrix()
307 
308     /**
309      * Animator that animates in the surface behind the keyguard. This is used to play a canned
310      * animation on the surface, if we're not doing a swipe gesture.
311      */
312     @VisibleForTesting val surfaceBehindEntryAnimator = ValueAnimator.ofFloat(0f, 1f)
313 
314     /** Rounded corner radius to apply to the surface behind the keyguard. */
315     private var roundedCornerRadius = 0f
316 
317     /**
318      * Whether we decided in [prepareForInWindowLauncherAnimations] that we are able to and want to
319      * play the in-window launcher unlock animations rather than simply animating the Launcher
320      * window like any other app. This can be true while [willUnlockWithSmartspaceTransition] is
321      * false, if the smartspace is not available or was not ready in time.
322      */
323     @VisibleForTesting var willUnlockWithInWindowLauncherAnimations: Boolean = false
324 
325     /**
326      * Whether we called [ILauncherUnlockAnimationController.prepareForUnlock], but have not yet
327      * called [ILauncherUnlockAnimationController.playUnlockAnimation]. This is used exclusively for
328      * logging purposes to help track down bugs where the Launcher surface is prepared for unlock
329      * but then never animated.
330      */
331     private var launcherPreparedForUnlock = false
332 
333     /**
334      * Whether we decided in [prepareForInWindowLauncherAnimations] that we are able to and want to
335      * play the smartspace shared element animation. If true,
336      * [willUnlockWithInWindowLauncherAnimations] will also always be true since in-window
337      * animations are a prerequisite for the smartspace transition.
338      */
339     private var willUnlockWithSmartspaceTransition: Boolean = false
340 
341     private val handler = Handler()
342 
343     private val tmpFloat = FloatArray(9)
344 
345     init {
346         with(surfaceBehindAlphaAnimator) {
347             duration = SURFACE_BEHIND_SWIPE_FADE_DURATION_MS
348             interpolator = Interpolators.LINEAR
349             addUpdateListener { valueAnimator: ValueAnimator ->
350                 surfaceBehindAlpha = valueAnimator.animatedValue as Float
351                 updateSurfaceBehindAppearAmount()
352             }
353             addListener(
354                 object : AnimatorListenerAdapter() {
355                     override fun onAnimationEnd(animation: Animator) {
356                         // If we animated the surface alpha to 0f, it means we cancelled a swipe to
357                         // dismiss. In this case, we should ask the KeyguardViewMediator to end the
358                         // remote animation to hide the surface behind the keyguard, but should
359                         // *not* call onKeyguardExitRemoteAnimationFinished since that will hide the
360                         // keyguard and unlock the device as well as hiding the surface.
361                         if (surfaceBehindAlpha == 0f) {
362                             Log.d(TAG, "surfaceBehindAlphaAnimator#onAnimationEnd")
363                             surfaceBehindRemoteAnimationTargets = null
364                             openingWallpaperTargets = null
365                             closingWallpaperTargets = null
366                             keyguardViewMediator
367                                 .get()
368                                 .finishSurfaceBehindRemoteAnimation(false /* cancelled */)
369                         } else {
370                             Log.d(
371                                 TAG,
372                                 "skip finishSurfaceBehindRemoteAnimation" +
373                                     " surfaceBehindAlpha=$surfaceBehindAlpha",
374                             )
375                         }
376                     }
377                 }
378             )
379         }
380 
381         with(wallpaperCannedUnlockAnimator) {
382             duration =
383                 if (fasterUnlockTransition()) UNLOCK_ANIMATION_DURATION_MS
384                 else LAUNCHER_ICONS_ANIMATION_DURATION_MS
385             interpolator =
386                 if (fasterUnlockTransition()) Interpolators.LINEAR else Interpolators.ALPHA_OUT
387             addUpdateListener { valueAnimator: ValueAnimator ->
388                 setWallpaperAppearAmount(
389                     valueAnimator.animatedValue as Float,
390                     openingWallpaperTargets,
391                 )
392             }
393             addListener(
394                 object : AnimatorListenerAdapter() {
395                     override fun onAnimationStart(animation: Animator) {
396                         super.onAnimationStart(animation)
397                         Trace.asyncTraceBegin(Trace.TRACE_TAG_APP, "WallpaperAlphaAnimation", 0)
398                     }
399 
400                     override fun onAnimationEnd(animation: Animator) {
401                         Log.d(TAG, "wallpaperCannedUnlockAnimator#onAnimationEnd")
402                         keyguardViewMediator
403                             .get()
404                             .exitKeyguardAndFinishSurfaceBehindRemoteAnimation(
405                                 false /* cancelled */
406                             )
407                         Trace.asyncTraceEnd(Trace.TRACE_TAG_APP, "WallpaperAlphaAnimation", 0)
408                     }
409                 }
410             )
411         }
412 
413         if (fasterUnlockTransition()) {
414             with(wallpaperFadeOutUnlockAnimator) {
415                 duration = LOCK_WALLPAPER_FADE_OUT_DURATION
416                 startDelay = LOCK_WALLPAPER_FADE_OUT_START_DELAY
417                 interpolator = Interpolators.LINEAR
418                 addUpdateListener { valueAnimator: ValueAnimator ->
419                     setWallpaperAppearAmount(
420                         valueAnimator.animatedValue as Float,
421                         closingWallpaperTargets,
422                     )
423                 }
424             }
425         }
426 
427         with(surfaceBehindEntryAnimator) {
428             duration = unlockAnimationDurationMs()
429             startDelay = surfaceBehindFadeOutStartDelayMs()
430             interpolator = Interpolators.TOUCH_RESPONSE
431             addUpdateListener { valueAnimator: ValueAnimator ->
432                 surfaceBehindAlpha = valueAnimator.animatedValue as Float
433                 setSurfaceBehindAppearAmount(valueAnimator.animatedValue as Float)
434             }
435             addListener(
436                 object : AnimatorListenerAdapter() {
437                     override fun onAnimationEnd(animation: Animator) {
438                         Log.d(TAG, "surfaceBehindEntryAnimator#onAnimationEnd")
439                         playingCannedUnlockAnimation = false
440                         keyguardViewMediator
441                             .get()
442                             .exitKeyguardAndFinishSurfaceBehindRemoteAnimation(
443                                 false /* cancelled */
444                             )
445                     }
446                 }
447             )
448         }
449 
450         // Listen for changes in the dismiss amount.
451         keyguardStateController.addCallback(this)
452 
453         roundedCornerRadius =
454             resources.getDimensionPixelSize(R.dimen.rounded_corner_radius).toFloat()
455     }
456 
457     /** Add a listener to be notified of various stages of the unlock animation. */
458     fun addKeyguardUnlockAnimationListener(listener: KeyguardUnlockAnimationListener) {
459         listeners.add(listener)
460     }
461 
462     fun removeKeyguardUnlockAnimationListener(listener: KeyguardUnlockAnimationListener) {
463         listeners.remove(listener)
464     }
465 
466     /**
467      * Whether we should be able to do the in-window launcher animations given the current state of
468      * the device.
469      */
470     fun canPerformInWindowLauncherAnimations(): Boolean {
471         // TODO(b/278086361): Refactor in-window animations.
472         return !KeyguardWmStateRefactor.isEnabled &&
473             isSupportedLauncherUnderneath() &&
474             // If the launcher is underneath, but we're about to launch an activity, don't do
475             // the animations since they won't be visible.
476             !notificationShadeWindowController.isLaunchingActivity &&
477             launcherUnlockController != null
478     }
479 
480     /**
481      * Logging helper to log the conditions under which we decide to perform the in-window
482      * animations. This is used if we prepare to unlock but then somehow decide later to not play
483      * the animation, which would leave Launcher in a bad state.
484      */
485     private fun logInWindowAnimationConditions() {
486         Log.wtf(TAG, "canPerformInWindowLauncherAnimations expected all of these to be true: ")
487         Log.wtf(TAG, "  isNexusLauncherUnderneath: ${isSupportedLauncherUnderneath()}")
488         Log.wtf(
489             TAG,
490             "  !notificationShadeWindowController.isLaunchingActivity: " +
491                 "${!notificationShadeWindowController.isLaunchingActivity}",
492         )
493         Log.wtf(TAG, "  launcherUnlockController != null: ${launcherUnlockController != null}")
494         Log.wtf(TAG, "  !isFoldable(context): ${!isDeviceFoldable(resources, deviceStateManager)}")
495     }
496 
497     /**
498      * Called from [KeyguardStateController] to let us know that the keyguard going away state has
499      * changed.
500      */
501     override fun onKeyguardGoingAwayChanged() {
502         if (
503             keyguardStateController.isKeyguardGoingAway &&
504                 !statusBarStateController.leaveOpenOnKeyguardHide()
505         ) {
506             prepareForInWindowLauncherAnimations()
507         }
508 
509         // If the keyguard is no longer going away and we were unlocking with in-window animations,
510         // make sure that we've left the launcher at 100% unlocked. This is a fail-safe to prevent
511         // against "tiny launcher" and similar states where the launcher is left in the prepared to
512         // animate state.
513         if (
514             !keyguardStateController.isKeyguardGoingAway && willUnlockWithInWindowLauncherAnimations
515         ) {
516             try {
517                 launcherUnlockController?.setUnlockAmount(
518                     1f,
519                     biometricUnlockControllerLazy.get().isWakeAndUnlock, /* forceIfAnimating */
520                 )
521             } catch (e: DeadObjectException) {
522                 Log.e(
523                     TAG,
524                     "launcherUnlockAnimationController was dead, but non-null in " +
525                         "onKeyguardGoingAwayChanged(). Catching exception as this should mean " +
526                         "Launcher is in the process of being destroyed, but the IPC to System UI " +
527                         "telling us hasn't arrived yet.",
528                 )
529             }
530         }
531     }
532 
533     /**
534      * Prepare for in-window Launcher unlock animations, if we're able to do so.
535      *
536      * The in-window animations consist of the staggered ring icon unlock animation, and optionally
537      * the shared element smartspace transition.
538      */
539     fun prepareForInWindowLauncherAnimations() {
540         willUnlockWithInWindowLauncherAnimations = canPerformInWindowLauncherAnimations()
541 
542         if (!willUnlockWithInWindowLauncherAnimations) {
543             return
544         }
545 
546         // There are additional conditions under which we should not perform the smartspace
547         // transition specifically, so check those.
548         willUnlockWithSmartspaceTransition = shouldPerformSmartspaceTransition()
549 
550         var lockscreenSmartspaceBounds = Rect()
551 
552         // Grab the bounds of our lockscreen smartspace and send them to launcher so they can
553         // position their smartspace there initially, then animate it to its resting position.
554         if (willUnlockWithSmartspaceTransition) {
555             lockscreenSmartspaceBounds =
556                 Rect().apply {
557                     lockscreenSmartspace!!.getBoundsOnScreen(this)
558 
559                     // The smartspace container on the lockscreen has left and top padding to align
560                     // it with other lockscreen content. This padding is inside the bounds on
561                     // screen, so add it to those bounds so that the padding-less launcher
562                     // smartspace is properly aligned.
563                     offset(lockscreenSmartspace!!.paddingLeft, lockscreenSmartspace!!.paddingTop)
564 
565                     // Also offset by the current card's top padding, if it has any. This allows us
566                     // to align the tops of the lockscreen/launcher smartspace cards. Some cards,
567                     // such as the three-line date/weather/alarm card, only have three lines on
568                     // lockscreen but two on launcher.
569                     offset(
570                         0,
571                         (lockscreenSmartspace as? BcSmartspaceDataPlugin.SmartspaceView)
572                             ?.currentCardTopPadding ?: 0,
573                     )
574                 }
575         }
576 
577         // Currently selected lockscreen smartspace page, or -1 if it's not available.
578         val selectedPage =
579             (lockscreenSmartspace as BcSmartspaceDataPlugin.SmartspaceView?)?.selectedPage ?: -1
580 
581         try {
582             // Let the launcher know to prepare for this animation.
583             launcherUnlockController?.prepareForUnlock(
584                 willUnlockWithSmartspaceTransition, /* willAnimateSmartspace */
585                 lockscreenSmartspaceBounds, /* lockscreenSmartspaceBounds */
586                 selectedPage, /* selectedPage */
587             )
588 
589             launcherPreparedForUnlock = true
590         } catch (e: RemoteException) {
591             Log.e(TAG, "Remote exception in prepareForInWindowUnlockAnimations.", e)
592         }
593     }
594 
595     /**
596      * Called from [KeyguardViewMediator] to tell us that the RemoteAnimation on the surface behind
597      * the keyguard has started successfully. We can use these parameters to directly manipulate the
598      * surface for the unlock gesture/animation.
599      *
600      * When we're done with it, we'll call [KeyguardViewMediator.finishSurfaceBehindRemoteAnimation]
601      * to end the RemoteAnimation. The KeyguardViewMediator will then end the animation and let us
602      * know that it's over by calling [notifyFinishedKeyguardExitAnimation].
603      *
604      * [requestedShowSurfaceBehindKeyguard] indicates whether the animation started because of a
605      * call to [KeyguardViewMediator.showSurfaceBehindKeyguard], as happens during a swipe gesture,
606      * as opposed to being called because the device was unlocked instantly by some other means
607      * (fingerprint, tap, etc.) and the keyguard is going away.
608      */
609     fun notifyStartSurfaceBehindRemoteAnimation(
610         targets: Array<RemoteAnimationTarget>,
611         openingWallpapers: Array<RemoteAnimationTarget>,
612         closingWallpapers: Array<RemoteAnimationTarget>,
613         startTime: Long,
614         requestedShowSurfaceBehindKeyguard: Boolean,
615     ) {
616         if (surfaceTransactionApplier == null) {
617             surfaceTransactionApplier =
618                 SyncRtSurfaceTransactionApplier(keyguardViewController.viewRootImpl.view)
619         }
620 
621         surfaceBehindRemoteAnimationTargets = targets
622         openingWallpaperTargets = openingWallpapers
623         closingWallpaperTargets = closingWallpapers
624         surfaceBehindRemoteAnimationStartTime = startTime
625 
626         // If we specifically requested that the surface behind be made visible (vs. it being made
627         // visible because we're unlocking), then we're in the middle of a swipe-to-unlock touch
628         // gesture and the surface behind the keyguard should be made visible so that we can animate
629         // it in.
630         if (requestedShowSurfaceBehindKeyguard) {
631             // If we're flinging to dismiss here, it means the touch gesture ended in a fling during
632             // the time it takes the keyguard exit animation to start. This is an edge case race
633             // condition, which we handle by just playing a canned animation on the now-visible
634             // surface behind the keyguard to finish unlocking.
635             if (keyguardStateController.isFlingingToDismissKeyguard) {
636                 playCannedUnlockAnimation()
637             } else if (
638                 keyguardStateController.isDismissingFromSwipe &&
639                     willUnlockWithInWindowLauncherAnimations
640             ) {
641                 // If we're swiping to unlock to the Launcher, and can play in-window animations,
642                 // make the launcher surface fully visible and play the in-window unlock animation
643                 // on the launcher icons. System UI will remain locked, using the swipe-to-unlock
644                 // translation logic on the launcher window, until the swipe gesture ends (either in
645                 // a successful unlock, or an aborted unlock).
646                 surfaceBehindAlpha = 1f
647                 setSurfaceBehindAppearAmount(1f)
648 
649                 try {
650                     launcherUnlockController?.playUnlockAnimation(
651                         true,
652                         unlockAnimationDurationMs() + cannedUnlockStartDelayMs(),
653                         0, /* startDelay */
654                     )
655                 } catch (e: DeadObjectException) {
656                     // Hello! If you are here investigating a bug where Launcher is blank (no icons)
657                     // then the below assumption about Launcher's destruction was incorrect. This
658                     // would mean prepareToUnlock was called (blanking Launcher in preparation for
659                     // the beginning of the unlock animation), but then somehow we were unable to
660                     // call playUnlockAnimation to animate the icons back in.
661                     Log.e(
662                         TAG,
663                         "launcherUnlockAnimationController was dead, but non-null. " +
664                             "Catching exception as this should mean Launcher is in the process " +
665                             "of being destroyed, but the IPC to System UI telling us hasn't " +
666                             "arrived yet.",
667                     )
668                 }
669 
670                 launcherPreparedForUnlock = false
671             } else {
672                 // Otherwise, we're swiping in an app and should just fade it in. The swipe gesture
673                 // will translate it until the end of the swipe gesture.
674                 fadeInSurfaceBehind()
675             }
676         } else {
677             // The surface was made visible since we're unlocking not from a swipe (fingerprint,
678             // lock icon long-press, etc). Play the full unlock animation.
679             playCannedUnlockAnimation()
680         }
681 
682         // Notify if waking from AOD only
683         val isWakeAndUnlockNotFromDream =
684             biometricUnlockControllerLazy.get().isWakeAndUnlock &&
685                 biometricUnlockControllerLazy.get().mode != MODE_WAKE_AND_UNLOCK_FROM_DREAM
686 
687         listeners.forEach {
688             it.onUnlockAnimationStarted(
689                 playingCannedUnlockAnimation /* playingCannedAnimation */,
690                 isWakeAndUnlockNotFromDream /* isWakeAndUnlockNotFromDream */,
691                 cannedUnlockStartDelayMs() /* unlockStartDelay */,
692                 LAUNCHER_ICONS_ANIMATION_DURATION_MS, /* unlockAnimationDuration */
693             )
694         }
695 
696         // Finish the keyguard remote animation if the dismiss amount has crossed the threshold.
697         // Check it here in case there is no more change to the dismiss amount after the last change
698         // that starts the keyguard animation. @see #updateKeyguardViewMediatorIfThresholdsReached()
699         if (!playingCannedUnlockAnimation) {
700             finishKeyguardExitRemoteAnimationIfReachThreshold()
701         }
702     }
703 
704     /**
705      * Play a canned unlock animation to unlock the device. This is used when we were *not* swiping
706      * to unlock using a touch gesture. If we were swiping to unlock, the animation will be driven
707      * by the dismiss amount via [onKeyguardDismissAmountChanged].
708      */
709     private fun playCannedUnlockAnimation() {
710         Log.d(TAG, "playCannedUnlockAnimation")
711         playingCannedUnlockAnimation = true
712 
713         when {
714             // If we're set up for in-window launcher animations, ask Launcher to play its in-window
715             // canned animation.
716             willUnlockWithInWindowLauncherAnimations -> {
717                 Log.d(TAG, "playCannedUnlockAnimation, unlockToLauncherWithInWindowAnimations")
718                 unlockToLauncherWithInWindowAnimations()
719             }
720 
721             // If we're waking and unlocking to a non-Launcher app surface (or Launcher in-window
722             // animations are not available), show it immediately and end the remote animation. The
723             // circular light reveal will show the app surface, and it looks weird if it's moving
724             // around behind that.
725             biometricUnlockControllerLazy.get().isWakeAndUnlock -> {
726                 Log.d(TAG, "playCannedUnlockAnimation, isWakeAndUnlock")
727                 setSurfaceBehindAppearAmount(1f)
728                 keyguardViewMediator
729                     .get()
730                     .exitKeyguardAndFinishSurfaceBehindRemoteAnimation(false /* cancelled */)
731             }
732 
733             // Otherwise, we're doing a normal full-window unlock. Start this animator, which will
734             // scale/translate the window underneath the lockscreen.
735             else -> {
736                 Log.d(TAG, "playCannedUnlockAnimation, surfaceBehindEntryAnimator#start")
737                 surfaceBehindEntryAnimator.start()
738             }
739         }
740 
741         if (launcherPreparedForUnlock && !willUnlockWithInWindowLauncherAnimations) {
742             Log.wtf(
743                 TAG,
744                 "Launcher is prepared for unlock, so we should have started the " +
745                     "in-window animation, however we apparently did not.",
746             )
747             logInWindowAnimationConditions()
748         }
749     }
750 
751     /**
752      * Unlock to the launcher, using in-window animations, and the smartspace shared element
753      * transition if possible.
754      */
755     @VisibleForTesting
756     fun unlockToLauncherWithInWindowAnimations() {
757         surfaceBehindAlpha = 1f
758         setSurfaceBehindAppearAmount(1f, wallpapers = false)
759 
760         try {
761             // Begin the animation, waiting for the shade to animate out.
762             launcherUnlockController?.playUnlockAnimation(
763                 true /* unlocked */,
764                 LAUNCHER_ICONS_ANIMATION_DURATION_MS /* duration */,
765                 cannedUnlockStartDelayMs(), /* startDelay */
766             )
767         } catch (e: DeadObjectException) {
768             // Hello! If you are here investigating a bug where Launcher is blank (no icons)
769             // then the below assumption about Launcher's destruction was incorrect. This
770             // would mean prepareToUnlock was called (blanking Launcher in preparation for
771             // the beginning of the unlock animation), but then somehow we were unable to
772             // call playUnlockAnimation to animate the icons back in.
773             Log.e(
774                 TAG,
775                 "launcherUnlockAnimationController was dead, but non-null. " +
776                     "Catching exception as this should mean Launcher is in the process " +
777                     "of being destroyed, but the IPC to System UI telling us hasn't " +
778                     "arrived yet.",
779             )
780         }
781 
782         launcherPreparedForUnlock = false
783 
784         // Now that the Launcher surface (with its smartspace positioned identically to ours) is
785         // visible, hide our smartspace.
786         if (
787             shouldPerformSmartspaceTransition() && lockscreenSmartspace?.visibility == View.VISIBLE
788         ) {
789             lockscreenSmartspace?.visibility = View.INVISIBLE
790         }
791 
792         // As soon as the shade starts animating out of the way, start the canned unlock animation,
793         // which will finish keyguard exit when it completes. The in-window animations in the
794         // Launcher window will end on their own.
795         if (fasterUnlockTransition() && openingWallpaperTargets?.isNotEmpty() == true) {
796             fadeOutWallpaper()
797         }
798 
799         handler.postDelayed(
800             {
801                 if (
802                     keyguardViewMediator.get().isShowingAndNotOccluded &&
803                         !keyguardStateController.isKeyguardGoingAway
804                 ) {
805                     Log.e(
806                         TAG,
807                         "Finish keyguard exit animation delayed Runnable ran, but we are " +
808                             "showing and not going away.",
809                     )
810                     return@postDelayed
811                 }
812 
813                 if (openingWallpaperTargets?.isNotEmpty() == true) {
814                     fadeInWallpaper()
815                     hideKeyguardViewAfterRemoteAnimation()
816                 } else {
817                     keyguardViewMediator
818                         .get()
819                         .exitKeyguardAndFinishSurfaceBehindRemoteAnimation(false /* cancelled */)
820                 }
821             },
822             cannedUnlockStartDelayMs(),
823         )
824     }
825 
826     /**
827      * Sets the appearance amount of the surface behind the keyguard, according to the current
828      * keyguard dismiss amount and the method of dismissal.
829      */
830     private fun updateSurfaceBehindAppearAmount() {
831         if (surfaceBehindRemoteAnimationTargets == null) {
832             return
833         }
834 
835         if (playingCannedUnlockAnimation) {
836             return
837         }
838 
839         // For fling animations, we want to animate the surface in over the full distance. If we're
840         // dismissing the keyguard via a swipe gesture (or cancelling the swipe gesture), we want to
841         // bring in the surface behind over a relatively short swipe distance (~15%), to keep the
842         // interaction tight.
843         if (keyguardStateController.isFlingingToDismissKeyguard) {
844             setSurfaceBehindAppearAmount(keyguardStateController.dismissAmount)
845         } else if (
846             keyguardStateController.isDismissingFromSwipe ||
847                 keyguardStateController.isSnappingKeyguardBackAfterSwipe
848         ) {
849             val totalSwipeDistanceToDismiss =
850                 (DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD - DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD)
851             val swipedDistanceSoFar: Float =
852                 keyguardStateController.dismissAmount - DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD
853             val progress = swipedDistanceSoFar / totalSwipeDistanceToDismiss
854             setSurfaceBehindAppearAmount(progress)
855         }
856     }
857 
858     override fun onKeyguardDismissAmountChanged() {
859         if (keyguardStateController.isShowing && !playingCannedUnlockAnimation) {
860             showOrHideSurfaceIfDismissAmountThresholdsReached()
861 
862             // If the surface is visible or it's about to be, start updating its appearance to
863             // reflect the new dismiss amount.
864             if (
865                 (keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard() ||
866                     keyguardViewMediator
867                         .get()
868                         .isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe) &&
869                     !playingCannedUnlockAnimation
870             ) {
871                 updateSurfaceBehindAppearAmount()
872             }
873         }
874     }
875 
876     /**
877      * Lets the KeyguardViewMediator know if the dismiss amount has crossed a threshold of interest,
878      * such as reaching the point in the dismiss swipe where we need to make the surface behind the
879      * keyguard visible.
880      */
881     private fun showOrHideSurfaceIfDismissAmountThresholdsReached() {
882         if (!featureFlags.isEnabled(Flags.NEW_UNLOCK_SWIPE_ANIMATION)) {
883             return
884         }
885 
886         // If we are playing the canned unlock animation, we flung away the keyguard to hide it and
887         // started a canned animation to show the surface behind the keyguard. The fling will cause
888         // panel height/dismiss amount updates, but we should ignore those updates here since the
889         // surface behind is already visible and animating.
890         if (playingCannedUnlockAnimation) {
891             return
892         }
893 
894         if (dismissAmountThresholdsReached) {
895             return
896         }
897 
898         if (!keyguardStateController.isShowing) {
899             return
900         }
901 
902         val dismissAmount = keyguardStateController.dismissAmount
903 
904         if (
905             dismissAmount >= DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD &&
906                 !keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()
907         ) {
908             keyguardViewMediator.get().showSurfaceBehindKeyguard()
909         } else if (
910             dismissAmount < DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD &&
911                 keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()
912         ) {
913             // We're no longer past the threshold but we are showing the surface. Animate it
914             // out.
915             keyguardViewMediator.get().hideSurfaceBehindKeyguard()
916             fadeOutSurfaceBehind()
917         }
918 
919         finishKeyguardExitRemoteAnimationIfReachThreshold()
920     }
921 
922     /**
923      * Hides the keyguard if we're fully dismissed, or if we're swiping to dismiss and have crossed
924      * the threshold to finish the dismissal.
925      */
926     private fun finishKeyguardExitRemoteAnimationIfReachThreshold() {
927         // no-op if keyguard is not showing or animation is not enabled.
928         if (!keyguardStateController.isShowing) {
929             return
930         }
931 
932         // no-op if we alreaddy reached a threshold.
933         if (dismissAmountThresholdsReached) {
934             return
935         }
936 
937         // no-op if animation is not requested yet.
938         if (
939             !keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard() ||
940                 !keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe
941         ) {
942             return
943         }
944 
945         val dismissAmount = keyguardStateController.dismissAmount
946         if (
947             dismissAmount >= 1f ||
948                 (keyguardStateController.isDismissingFromSwipe &&
949                     // Don't hide if we're flinging during a swipe, since we need to finish
950                     // animating it out. This will be called again after the fling ends.
951                     !keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture &&
952                     dismissAmount >= DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD)
953         ) {
954             setSurfaceBehindAppearAmount(1f)
955             dismissAmountThresholdsReached = true
956             keyguardViewMediator
957                 .get()
958                 .exitKeyguardAndFinishSurfaceBehindRemoteAnimation(false /* cancelled */)
959         }
960     }
961 
962     /**
963      * Scales in and translates up the surface behind the keyguard. This is used during unlock
964      * animations and swipe gestures to animate the surface's entry (and exit, if the swipe is
965      * cancelled). When called with [wallpapers]=true, if there are different home and lock screen
966      * wallpapers, this transitions between the two wallpapers
967      */
968     fun setSurfaceBehindAppearAmount(amount: Float, wallpapers: Boolean = true) {
969         val animationAlpha =
970             when {
971                 // If we're snapping the keyguard back, immediately begin fading it out.
972                 keyguardStateController.isSnappingKeyguardBackAfterSwipe -> amount
973                 // If the screen has turned back off, the unlock animation is going to be cancelled,
974                 // so set the surface alpha to 0f so it's no longer visible.
975                 !powerManager.isInteractive -> 0f
976                 else -> surfaceBehindAlpha
977             }
978 
979         surfaceBehindRemoteAnimationTargets?.forEach { surfaceBehindRemoteAnimationTarget ->
980             if (!KeyguardWmStateRefactor.isEnabled) {
981                 val surfaceHeight: Int =
982                     surfaceBehindRemoteAnimationTarget.screenSpaceBounds.height()
983 
984                 var scaleFactor =
985                     (SURFACE_BEHIND_START_SCALE_FACTOR +
986                         (1f - SURFACE_BEHIND_START_SCALE_FACTOR) * MathUtils.clamp(amount, 0f, 1f))
987 
988                 // If we're dismissing via swipe to the Launcher, we'll play in-window scale
989                 // animations, so don't also scale the window.
990                 if (
991                     keyguardStateController.isDismissingFromSwipe &&
992                         willUnlockWithInWindowLauncherAnimations
993                 ) {
994                     scaleFactor = 1f
995                 }
996 
997                 // Translate up from the bottom.
998                 surfaceBehindMatrix.setTranslate(
999                     surfaceBehindRemoteAnimationTarget.screenSpaceBounds.left.toFloat(),
1000                     surfaceBehindRemoteAnimationTarget.screenSpaceBounds.top.toFloat() +
1001                         surfaceHeight * SURFACE_BEHIND_START_TRANSLATION_Y * (1f - amount),
1002                 )
1003 
1004                 // Scale up from a point at the center-bottom of the surface.
1005                 surfaceBehindMatrix.postScale(
1006                     scaleFactor,
1007                     scaleFactor,
1008                     keyguardViewController.viewRootImpl.width / 2f,
1009                     surfaceHeight * SURFACE_BEHIND_SCALE_PIVOT_Y,
1010                 )
1011 
1012                 // SyncRtSurfaceTransactionApplier cannot apply transaction when the target view is
1013                 // unable to draw
1014                 val sc: SurfaceControl? = surfaceBehindRemoteAnimationTarget.leash
1015                 if (
1016                     keyguardViewController.viewRootImpl.view?.visibility != View.VISIBLE &&
1017                         sc?.isValid == true
1018                 ) {
1019                     with(SurfaceControl.Transaction()) {
1020                         setMatrix(sc, surfaceBehindMatrix, tmpFloat)
1021                         setCornerRadius(sc, roundedCornerRadius)
1022                         setAlpha(sc, animationAlpha)
1023                         apply()
1024                     }
1025                 } else {
1026                     applyParamsToSurface(
1027                         SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(
1028                                 surfaceBehindRemoteAnimationTarget.leash
1029                             )
1030                             .withMatrix(surfaceBehindMatrix)
1031                             .withCornerRadius(roundedCornerRadius)
1032                             .withAlpha(animationAlpha)
1033                             .build()
1034                     )
1035                 }
1036             }
1037         }
1038 
1039         if (wallpapers) {
1040             if (!fasterUnlockTransition()) setWallpaperAppearAmount(amount, openingWallpaperTargets)
1041             else {
1042                 // Use the amount to compute the fadeInAmount and fadeOutAmount of the home and lock
1043                 // screen wallpapers to manually imitate the canned unlock animation.
1044                 val total = (UNLOCK_ANIMATION_DURATION_MS + CANNED_UNLOCK_START_DELAY).toFloat()
1045                 val fadeInStart = CANNED_UNLOCK_START_DELAY / total
1046                 val fadeInAmount = maxOf(0f, (amount - fadeInStart) / (1f - fadeInStart))
1047 
1048                 val fadeOutStart = LOCK_WALLPAPER_FADE_OUT_START_DELAY / total
1049                 val fadeOutEnd = fadeOutStart + LOCK_WALLPAPER_FADE_OUT_DURATION / total
1050                 val fadeOutAmount =
1051                     ((amount - fadeOutStart) / (fadeOutEnd - fadeOutStart)).coerceIn(0f, 1f)
1052 
1053                 setWallpaperAppearAmount(fadeInAmount, openingWallpaperTargets)
1054                 setWallpaperAppearAmount(1 - fadeOutAmount, closingWallpaperTargets)
1055             }
1056         }
1057     }
1058 
1059     fun setWallpaperAppearAmount(amount: Float, wallpaperTargets: Array<RemoteAnimationTarget>?) {
1060         val animationAlpha = amount
1061         wallpaperTargets?.forEach { wallpaper ->
1062             // SyncRtSurfaceTransactionApplier cannot apply transaction when the target view is
1063             // unable to draw
1064             val sc: SurfaceControl? = wallpaper.leash
1065             if (
1066                 keyguardViewController.viewRootImpl.view?.visibility != View.VISIBLE &&
1067                     sc?.isValid == true
1068             ) {
1069                 with(SurfaceControl.Transaction()) {
1070                     setAlpha(sc, animationAlpha)
1071                     apply()
1072                 }
1073             } else {
1074                 applyParamsToSurface(
1075                     SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(wallpaper.leash)
1076                         .withAlpha(animationAlpha)
1077                         .build()
1078                 )
1079             }
1080         }
1081     }
1082 
1083     /**
1084      * Called by [KeyguardViewMediator] to let us know that the remote animation has finished, and
1085      * we should clean up all of our state. [showKeyguard] will tell us which surface should be
1086      * visible after the animation has been completed or canceled.
1087      *
1088      * This is generally triggered by us, calling
1089      * [KeyguardViewMediator.finishSurfaceBehindRemoteAnimation].
1090      */
1091     fun notifyFinishedKeyguardExitAnimation(showKeyguard: Boolean) {
1092         // Cancel any pending actions.
1093         handler.removeCallbacksAndMessages(null)
1094 
1095         // The lockscreen surface is gone, so it is now safe to re-show the smartspace.
1096         if (lockscreenSmartspace?.visibility == View.INVISIBLE) {
1097             lockscreenSmartspace?.visibility = View.VISIBLE
1098         }
1099 
1100         if (!showKeyguard) {
1101             // Make sure we made the surface behind fully visible, just in case. It should already
1102             // be fully visible. The exit animation is finished, and we should not hold the leash
1103             // anymore, so forcing it to 1f.
1104             surfaceBehindAlpha = 1f
1105             setSurfaceBehindAppearAmount(1f)
1106 
1107             try {
1108                 launcherUnlockController?.setUnlockAmount(1f, false /* forceIfAnimating */)
1109             } catch (e: RemoteException) {
1110                 Log.e(TAG, "Remote exception in notifyFinishedKeyguardExitAnimation", e)
1111             }
1112         }
1113 
1114         listeners.forEach { it.onUnlockAnimationFinished() }
1115 
1116         // Reset all state
1117         surfaceBehindAlphaAnimator.cancel()
1118         surfaceBehindEntryAnimator.cancel()
1119         wallpaperCannedUnlockAnimator.cancel()
1120         if (fasterUnlockTransition()) wallpaperFadeOutUnlockAnimator.cancel()
1121 
1122         // That target is no longer valid since the animation finished, null it out.
1123         surfaceBehindRemoteAnimationTargets = null
1124         openingWallpaperTargets = null
1125         if (fasterUnlockTransition()) closingWallpaperTargets = null
1126 
1127         playingCannedUnlockAnimation = false
1128         dismissAmountThresholdsReached = false
1129         willUnlockWithInWindowLauncherAnimations = false
1130         willUnlockWithSmartspaceTransition = false
1131     }
1132 
1133     /**
1134      * Asks the keyguard view to hide, using the start time from the beginning of the remote
1135      * animation.
1136      */
1137     fun hideKeyguardViewAfterRemoteAnimation() {
1138         if (keyguardStateController.isShowing) {
1139             // Hide the keyguard, with no fade out since we animated it away during the unlock.
1140 
1141             if (!KeyguardWmStateRefactor.isEnabled) {
1142                 keyguardViewController.hide(
1143                     surfaceBehindRemoteAnimationStartTime,
1144                     0, /* fadeOutDuration */
1145                 )
1146             }
1147         } else {
1148             Log.i(
1149                 TAG,
1150                 "#hideKeyguardViewAfterRemoteAnimation called when keyguard view is not " +
1151                     "showing. Ignoring...",
1152             )
1153         }
1154     }
1155 
1156     private fun applyParamsToSurface(params: SyncRtSurfaceTransactionApplier.SurfaceParams) {
1157         surfaceTransactionApplier!!.scheduleApply(params)
1158     }
1159 
1160     private fun fadeInSurfaceBehind() {
1161         Log.d(TAG, "fadeInSurfaceBehind")
1162         surfaceBehindAlphaAnimator.cancel()
1163         surfaceBehindAlphaAnimator.start()
1164     }
1165 
1166     private fun fadeInWallpaper() {
1167         Log.d(TAG, "fadeInWallpaper")
1168         wallpaperCannedUnlockAnimator.cancel()
1169         wallpaperCannedUnlockAnimator.start()
1170     }
1171 
1172     private fun fadeOutWallpaper() {
1173         Log.d(TAG, "fadeOutWallpaper")
1174         wallpaperFadeOutUnlockAnimator.cancel()
1175         wallpaperFadeOutUnlockAnimator.start()
1176     }
1177 
1178     private fun fadeOutSurfaceBehind() {
1179         Log.d(TAG, "fadeOutSurfaceBehind")
1180         surfaceBehindAlphaAnimator.cancel()
1181         surfaceBehindAlphaAnimator.reverse()
1182     }
1183 
1184     /** Note: declared open for ease of testing */
1185     open fun shouldPerformSmartspaceTransition(): Boolean {
1186         // Feature is disabled, so we don't want to.
1187         if (!featureFlags.isEnabled(Flags.SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED)) {
1188             return false
1189         }
1190 
1191         // If our controllers are null, or we haven't received a smartspace state from Launcher yet,
1192         // we will not be doing any smartspace transitions today.
1193         if (
1194             launcherUnlockController == null ||
1195                 lockscreenSmartspace == null ||
1196                 launcherSmartspaceState == null
1197         ) {
1198             return false
1199         }
1200 
1201         // If the launcher does not have a visible smartspace (either because it's paged off-screen,
1202         // or the smartspace just doesn't exist), we can't do the transition.
1203         if ((launcherSmartspaceState?.visibleOnScreen) != true) {
1204             return false
1205         }
1206 
1207         // If our launcher isn't underneath, then we're unlocking to an app or custom launcher,
1208         // neither of which have a smartspace.
1209         if (!isSupportedLauncherUnderneath()) {
1210             return false
1211         }
1212 
1213         // TODO(b/213910911): Unfortunately the keyguard is hidden instantly on wake and unlock, so
1214         // we won't have a lockscreen smartspace to animate. This is sad, and we should fix that!
1215         if (biometricUnlockControllerLazy.get().isWakeAndUnlock) {
1216             return false
1217         }
1218 
1219         // If we can't dismiss the lock screen via a swipe, then the only way we can do the shared
1220         // element transition is if we're doing a biometric unlock. Otherwise, it means the bouncer
1221         // is showing, and you can't see the lockscreen smartspace, so a shared element transition
1222         // would not make sense.
1223         if (
1224             !keyguardStateController.canDismissLockScreen() &&
1225                 !biometricUnlockControllerLazy.get().isBiometricUnlock
1226         ) {
1227             return false
1228         }
1229 
1230         // The smartspace is not visible if the bouncer is showing, so don't shared element it.
1231         if (keyguardStateController.isPrimaryBouncerShowing) {
1232             return false
1233         }
1234 
1235         // We started to swipe to dismiss, but now we're doing a fling animation to complete the
1236         // dismiss. In this case, the smartspace swiped away with the rest of the keyguard, so don't
1237         // do the shared element transition.
1238         if (keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture) {
1239             return false
1240         }
1241 
1242         // If we're swiping to dismiss, the smartspace will be swiped off the top of the screen
1243         // so we can't shared element animate it.
1244         if (keyguardStateController.isDismissingFromSwipe) {
1245             return false
1246         }
1247 
1248         // We don't do the shared element on large screens because the smartspace has to fly across
1249         // large distances, which is distracting.
1250         if (Utilities.isLargeScreen(windowManager, resources)) {
1251             return false
1252         }
1253 
1254         return true
1255     }
1256 
1257     /**
1258      * Whether we are currently in the process of unlocking the keyguard, and we are performing the
1259      * shared element SmartSpace transition.
1260      */
1261     fun isUnlockingWithSmartSpaceTransition(): Boolean {
1262         return willUnlockWithSmartspaceTransition
1263     }
1264 
1265     /** Whether the RemoteAnimation on the app/launcher surface behind the keyguard is 'running'. */
1266     fun isAnimatingBetweenKeyguardAndSurfaceBehind(): Boolean {
1267         return keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehind
1268     }
1269 
1270     /**
1271      * Whether we are playing a canned unlock animation, vs. unlocking from a touch gesture such as
1272      * a swipe.
1273      */
1274     fun isPlayingCannedUnlockAnimation(): Boolean {
1275         return playingCannedUnlockAnimation
1276     }
1277 
1278     /**
1279      * Return whether a launcher which supports coordinated transition is underneath the keyguard,
1280      * vs. some other launcher or an app. If so, we can communicate with it to perform
1281      * in-window/shared element transitions!
1282      */
1283     fun isSupportedLauncherUnderneath(): Boolean {
1284         return launcherActivityClass?.let {
1285             ActivityManagerWrapper.getInstance().runningTask?.topActivity?.className?.equals(it)
1286         } ?: false
1287     }
1288 
1289     /**
1290      * Temporary method for b/298186160 TODO (b/298186160) replace references with the constant
1291      * itself when flag is removed
1292      */
1293     private fun cannedUnlockStartDelayMs(): Long {
1294         return if (fasterUnlockTransition()) CANNED_UNLOCK_START_DELAY
1295         else LEGACY_CANNED_UNLOCK_START_DELAY
1296     }
1297 
1298     /**
1299      * Temporary method for b/298186160 TODO (b/298186160) replace references with the constant
1300      * itself when flag is removed
1301      */
1302     private fun unlockAnimationDurationMs(): Long {
1303         return if (fasterUnlockTransition()) UNLOCK_ANIMATION_DURATION_MS
1304         else LEGACY_UNLOCK_ANIMATION_DURATION_MS
1305     }
1306 
1307     /**
1308      * Temporary method for b/298186160 TODO (b/298186160) replace references with the constant
1309      * itself when flag is removed
1310      */
1311     private fun surfaceBehindFadeOutStartDelayMs(): Long {
1312         return if (fasterUnlockTransition()) UNLOCK_ANIMATION_SURFACE_BEHIND_START_DELAY_MS
1313         else LEGACY_UNLOCK_ANIMATION_SURFACE_BEHIND_START_DELAY_MS
1314     }
1315 }
1316