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