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