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