1 /* 2 * Copyright (C) 2022 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.data.repository 18 19 import android.graphics.Point 20 import android.hardware.biometrics.BiometricSourceType 21 import com.android.keyguard.KeyguardUpdateMonitor 22 import com.android.keyguard.KeyguardUpdateMonitorCallback 23 import com.android.systemui.biometrics.AuthController 24 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging 25 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow 26 import com.android.systemui.common.shared.model.Position 27 import com.android.systemui.dagger.SysUISingleton 28 import com.android.systemui.doze.DozeHost 29 import com.android.systemui.doze.DozeMachine 30 import com.android.systemui.doze.DozeTransitionCallback 31 import com.android.systemui.doze.DozeTransitionListener 32 import com.android.systemui.dreams.DreamOverlayCallbackController 33 import com.android.systemui.keyguard.WakefulnessLifecycle 34 import com.android.systemui.keyguard.shared.model.BiometricUnlockModel 35 import com.android.systemui.keyguard.shared.model.BiometricUnlockSource 36 import com.android.systemui.keyguard.shared.model.DozeStateModel 37 import com.android.systemui.keyguard.shared.model.DozeTransitionModel 38 import com.android.systemui.keyguard.shared.model.StatusBarState 39 import com.android.systemui.keyguard.shared.model.WakefulnessModel 40 import com.android.systemui.plugins.statusbar.StatusBarStateController 41 import com.android.systemui.statusbar.phone.BiometricUnlockController 42 import com.android.systemui.statusbar.phone.BiometricUnlockController.WakeAndUnlockMode 43 import com.android.systemui.statusbar.phone.DozeParameters 44 import com.android.systemui.statusbar.policy.KeyguardStateController 45 import javax.inject.Inject 46 import kotlinx.coroutines.channels.awaitClose 47 import kotlinx.coroutines.flow.Flow 48 import kotlinx.coroutines.flow.MutableStateFlow 49 import kotlinx.coroutines.flow.StateFlow 50 import kotlinx.coroutines.flow.asStateFlow 51 import kotlinx.coroutines.flow.distinctUntilChanged 52 53 /** Defines interface for classes that encapsulate application state for the keyguard. */ 54 interface KeyguardRepository { 55 /** 56 * Observable for whether the bottom area UI should animate the transition out of doze state. 57 * 58 * To learn more about doze state, please see [isDozing]. 59 */ 60 val animateBottomAreaDozingTransitions: StateFlow<Boolean> 61 62 /** 63 * Observable for the current amount of alpha that should be used for rendering the bottom area. 64 * UI. 65 */ 66 val bottomAreaAlpha: StateFlow<Float> 67 68 /** 69 * Observable of the relative offset of the lock-screen clock from its natural position on the 70 * screen. 71 */ 72 val clockPosition: StateFlow<Position> 73 74 /** 75 * Observable for whether the keyguard is showing. 76 * 77 * Note: this is also `true` when the lock-screen is occluded with an `Activity` "above" it in 78 * the z-order (which is not really above the system UI window, but rather - the lock-screen 79 * becomes invisible to reveal the "occluding activity"). 80 */ 81 val isKeyguardShowing: Flow<Boolean> 82 83 /** Is the keyguard in a unlocked state? */ 84 val isKeyguardUnlocked: Flow<Boolean> 85 86 /** Is an activity showing over the keyguard? */ 87 val isKeyguardOccluded: Flow<Boolean> 88 89 /** Observable for the signal that keyguard is about to go away. */ 90 val isKeyguardGoingAway: Flow<Boolean> 91 92 /** Is the always-on display available to be used? */ 93 val isAodAvailable: Flow<Boolean> 94 95 /** 96 * Observable for whether we are in doze state. 97 * 98 * Doze state is the same as "Always on Display" or "AOD". It is the state that the device can 99 * enter to conserve battery when the device is locked and inactive. 100 * 101 * Note that it is possible for the system to be transitioning into doze while this flow still 102 * returns `false`. In order to account for that, observers should also use the 103 * [linearDozeAmount] flow to check if it's greater than `0` 104 */ 105 val isDozing: Flow<Boolean> 106 107 /** 108 * Observable for whether the device is dreaming. 109 * 110 * Dozing/AOD is a specific type of dream, but it is also possible for other non-systemui dreams 111 * to be active, such as screensavers. 112 */ 113 val isDreaming: Flow<Boolean> 114 115 /** Observable for whether the device is dreaming with an overlay, see [DreamOverlayService] */ 116 val isDreamingWithOverlay: Flow<Boolean> 117 118 /** 119 * Observable for the amount of doze we are currently in. 120 * 121 * While in doze state, this amount can change - driving a cycle of animations designed to avoid 122 * pixel burn-in, etc. 123 * 124 * Also note that the value here may be greater than `0` while [isDozing] is still `false`, this 125 * happens during an animation/transition into doze mode. An observer would be wise to account 126 * for both flows if needed. 127 */ 128 val linearDozeAmount: Flow<Float> 129 130 /** Doze state information, as it transitions */ 131 val dozeTransitionModel: Flow<DozeTransitionModel> 132 133 /** Observable for the [StatusBarState] */ 134 val statusBarState: Flow<StatusBarState> 135 136 /** Observable for device wake/sleep state */ 137 val wakefulness: Flow<WakefulnessModel> 138 139 /** Observable for biometric unlock modes */ 140 val biometricUnlockState: Flow<BiometricUnlockModel> 141 142 /** Approximate location on the screen of the fingerprint sensor. */ 143 val fingerprintSensorLocation: Flow<Point?> 144 145 /** Approximate location on the screen of the face unlock sensor/front facing camera. */ 146 val faceSensorLocation: Flow<Point?> 147 148 /** Source of the most recent biometric unlock, such as fingerprint or face. */ 149 val biometricUnlockSource: Flow<BiometricUnlockSource?> 150 151 /** Whether quick settings or quick-quick settings is visible. */ 152 val isQuickSettingsVisible: Flow<Boolean> 153 154 /** 155 * Returns `true` if the keyguard is showing; `false` otherwise. 156 * 157 * Note: this is also `true` when the lock-screen is occluded with an `Activity` "above" it in 158 * the z-order (which is not really above the system UI window, but rather - the lock-screen 159 * becomes invisible to reveal the "occluding activity"). 160 */ isKeyguardShowingnull161 fun isKeyguardShowing(): Boolean 162 163 /** Sets whether the bottom area UI should animate the transition out of doze state. */ 164 fun setAnimateDozingTransitions(animate: Boolean) 165 166 /** Sets the current amount of alpha that should be used for rendering the bottom area. */ 167 fun setBottomAreaAlpha(alpha: Float) 168 169 /** 170 * Sets the relative offset of the lock-screen clock from its natural position on the screen. 171 */ 172 fun setClockPosition(x: Int, y: Int) 173 174 /** 175 * Returns whether the keyguard bottom area should be constrained to the top of the lock icon 176 */ 177 fun isUdfpsSupported(): Boolean 178 179 /** Sets whether quick settings or quick-quick settings is visible. */ 180 fun setQuickSettingsVisible(isVisible: Boolean) 181 } 182 183 /** Encapsulates application state for the keyguard. */ 184 @SysUISingleton 185 class KeyguardRepositoryImpl 186 @Inject 187 constructor( 188 statusBarStateController: StatusBarStateController, 189 dozeHost: DozeHost, 190 wakefulnessLifecycle: WakefulnessLifecycle, 191 biometricUnlockController: BiometricUnlockController, 192 private val keyguardStateController: KeyguardStateController, 193 private val keyguardUpdateMonitor: KeyguardUpdateMonitor, 194 private val dozeTransitionListener: DozeTransitionListener, 195 private val dozeParameters: DozeParameters, 196 private val authController: AuthController, 197 private val dreamOverlayCallbackController: DreamOverlayCallbackController, 198 ) : KeyguardRepository { 199 private val _animateBottomAreaDozingTransitions = MutableStateFlow(false) 200 override val animateBottomAreaDozingTransitions = 201 _animateBottomAreaDozingTransitions.asStateFlow() 202 203 private val _bottomAreaAlpha = MutableStateFlow(1f) 204 override val bottomAreaAlpha = _bottomAreaAlpha.asStateFlow() 205 206 private val _clockPosition = MutableStateFlow(Position(0, 0)) 207 override val clockPosition = _clockPosition.asStateFlow() 208 209 override val isKeyguardShowing: Flow<Boolean> = 210 conflatedCallbackFlow { 211 val callback = 212 object : KeyguardStateController.Callback { 213 override fun onKeyguardShowingChanged() { 214 trySendWithFailureLogging( 215 keyguardStateController.isShowing, 216 TAG, 217 "updated isKeyguardShowing" 218 ) 219 } 220 } 221 222 keyguardStateController.addCallback(callback) 223 // Adding the callback does not send an initial update. 224 trySendWithFailureLogging( 225 keyguardStateController.isShowing, 226 TAG, 227 "initial isKeyguardShowing" 228 ) 229 230 awaitClose { keyguardStateController.removeCallback(callback) } 231 } 232 .distinctUntilChanged() 233 234 override val isAodAvailable: Flow<Boolean> = 235 conflatedCallbackFlow { 236 val callback = 237 object : DozeParameters.Callback { 238 override fun onAlwaysOnChange() { 239 trySendWithFailureLogging( 240 dozeParameters.getAlwaysOn(), 241 TAG, 242 "updated isAodAvailable" 243 ) 244 } 245 } 246 247 dozeParameters.addCallback(callback) 248 // Adding the callback does not send an initial update. 249 trySendWithFailureLogging( 250 dozeParameters.getAlwaysOn(), 251 TAG, 252 "initial isAodAvailable" 253 ) 254 255 awaitClose { dozeParameters.removeCallback(callback) } 256 } 257 .distinctUntilChanged() 258 259 override val isKeyguardOccluded: Flow<Boolean> = 260 conflatedCallbackFlow { 261 val callback = 262 object : KeyguardStateController.Callback { 263 override fun onKeyguardShowingChanged() { 264 trySendWithFailureLogging( 265 keyguardStateController.isOccluded, 266 TAG, 267 "updated isKeyguardOccluded" 268 ) 269 } 270 } 271 272 keyguardStateController.addCallback(callback) 273 // Adding the callback does not send an initial update. 274 trySendWithFailureLogging( 275 keyguardStateController.isOccluded, 276 TAG, 277 "initial isKeyguardOccluded" 278 ) 279 280 awaitClose { keyguardStateController.removeCallback(callback) } 281 } 282 .distinctUntilChanged() 283 284 override val isKeyguardUnlocked: Flow<Boolean> = 285 conflatedCallbackFlow { 286 val callback = 287 object : KeyguardStateController.Callback { 288 override fun onUnlockedChanged() { 289 trySendWithFailureLogging( 290 keyguardStateController.isUnlocked, 291 TAG, 292 "updated isKeyguardUnlocked" 293 ) 294 } 295 } 296 297 keyguardStateController.addCallback(callback) 298 // Adding the callback does not send an initial update. 299 trySendWithFailureLogging( 300 keyguardStateController.isUnlocked, 301 TAG, 302 "initial isKeyguardUnlocked" 303 ) 304 305 awaitClose { keyguardStateController.removeCallback(callback) } 306 } 307 .distinctUntilChanged() 308 309 override val isKeyguardGoingAway: Flow<Boolean> = conflatedCallbackFlow { 310 val callback = 311 object : KeyguardStateController.Callback { 312 override fun onKeyguardGoingAwayChanged() { 313 trySendWithFailureLogging( 314 keyguardStateController.isKeyguardGoingAway, 315 TAG, 316 "updated isKeyguardGoingAway" 317 ) 318 } 319 } 320 321 keyguardStateController.addCallback(callback) 322 // Adding the callback does not send an initial update. 323 trySendWithFailureLogging( 324 keyguardStateController.isKeyguardGoingAway, 325 TAG, 326 "initial isKeyguardGoingAway" 327 ) 328 329 awaitClose { keyguardStateController.removeCallback(callback) } 330 } 331 332 override val isDozing: Flow<Boolean> = 333 conflatedCallbackFlow { 334 val callback = 335 object : DozeHost.Callback { 336 override fun onDozingChanged(isDozing: Boolean) { 337 trySendWithFailureLogging(isDozing, TAG, "updated isDozing") 338 } 339 } 340 dozeHost.addCallback(callback) 341 trySendWithFailureLogging( 342 statusBarStateController.isDozing, 343 TAG, 344 "initial isDozing", 345 ) 346 347 awaitClose { dozeHost.removeCallback(callback) } 348 } 349 .distinctUntilChanged() 350 351 override val isDreamingWithOverlay: Flow<Boolean> = 352 conflatedCallbackFlow { 353 val callback = 354 object : DreamOverlayCallbackController.Callback { 355 override fun onStartDream() { 356 trySendWithFailureLogging(true, TAG, "updated isDreamingWithOverlay") 357 } 358 override fun onWakeUp() { 359 trySendWithFailureLogging(false, TAG, "updated isDreamingWithOverlay") 360 } 361 } 362 dreamOverlayCallbackController.addCallback(callback) 363 trySendWithFailureLogging( 364 dreamOverlayCallbackController.isDreaming, 365 TAG, 366 "initial isDreamingWithOverlay", 367 ) 368 369 awaitClose { dreamOverlayCallbackController.removeCallback(callback) } 370 } 371 .distinctUntilChanged() 372 373 override val isDreaming: Flow<Boolean> = 374 conflatedCallbackFlow { 375 val callback = 376 object : KeyguardUpdateMonitorCallback() { 377 override fun onDreamingStateChanged(isDreaming: Boolean) { 378 trySendWithFailureLogging(isDreaming, TAG, "updated isDreaming") 379 } 380 } 381 keyguardUpdateMonitor.registerCallback(callback) 382 trySendWithFailureLogging( 383 keyguardUpdateMonitor.isDreaming, 384 TAG, 385 "initial isDreaming", 386 ) 387 388 awaitClose { keyguardUpdateMonitor.removeCallback(callback) } 389 } 390 .distinctUntilChanged() 391 392 override val linearDozeAmount: Flow<Float> = conflatedCallbackFlow { 393 val callback = 394 object : StatusBarStateController.StateListener { 395 override fun onDozeAmountChanged(linear: Float, eased: Float) { 396 trySendWithFailureLogging(linear, TAG, "updated dozeAmount") 397 } 398 } 399 400 statusBarStateController.addCallback(callback) 401 trySendWithFailureLogging(statusBarStateController.dozeAmount, TAG, "initial dozeAmount") 402 403 awaitClose { statusBarStateController.removeCallback(callback) } 404 } 405 406 override val dozeTransitionModel: Flow<DozeTransitionModel> = conflatedCallbackFlow { 407 val callback = 408 object : DozeTransitionCallback { 409 override fun onDozeTransition( 410 oldState: DozeMachine.State, 411 newState: DozeMachine.State 412 ) { 413 trySendWithFailureLogging( 414 DozeTransitionModel( 415 from = dozeMachineStateToModel(oldState), 416 to = dozeMachineStateToModel(newState), 417 ), 418 TAG, 419 "doze transition model" 420 ) 421 } 422 } 423 424 dozeTransitionListener.addCallback(callback) 425 trySendWithFailureLogging( 426 DozeTransitionModel( 427 from = dozeMachineStateToModel(dozeTransitionListener.oldState), 428 to = dozeMachineStateToModel(dozeTransitionListener.newState), 429 ), 430 TAG, 431 "initial doze transition model" 432 ) 433 434 awaitClose { dozeTransitionListener.removeCallback(callback) } 435 } 436 437 override fun isKeyguardShowing(): Boolean { 438 return keyguardStateController.isShowing 439 } 440 441 override val statusBarState: Flow<StatusBarState> = conflatedCallbackFlow { 442 val callback = 443 object : StatusBarStateController.StateListener { 444 override fun onStateChanged(state: Int) { 445 trySendWithFailureLogging(statusBarStateIntToObject(state), TAG, "state") 446 } 447 } 448 449 statusBarStateController.addCallback(callback) 450 trySendWithFailureLogging( 451 statusBarStateIntToObject(statusBarStateController.getState()), 452 TAG, 453 "initial state" 454 ) 455 456 awaitClose { statusBarStateController.removeCallback(callback) } 457 } 458 459 override val biometricUnlockState: Flow<BiometricUnlockModel> = conflatedCallbackFlow { 460 fun dispatchUpdate() { 461 trySendWithFailureLogging( 462 biometricModeIntToObject(biometricUnlockController.mode), 463 TAG, 464 "biometric mode" 465 ) 466 } 467 468 val callback = 469 object : BiometricUnlockController.BiometricModeListener { 470 override fun onModeChanged(@WakeAndUnlockMode mode: Int) { 471 dispatchUpdate() 472 } 473 474 override fun onResetMode() { 475 dispatchUpdate() 476 } 477 } 478 479 biometricUnlockController.addBiometricModeListener(callback) 480 dispatchUpdate() 481 482 awaitClose { biometricUnlockController.removeBiometricModeListener(callback) } 483 } 484 485 override val wakefulness: Flow<WakefulnessModel> = conflatedCallbackFlow { 486 val observer = 487 object : WakefulnessLifecycle.Observer { 488 override fun onStartedWakingUp() { 489 dispatchNewState() 490 } 491 492 override fun onFinishedWakingUp() { 493 dispatchNewState() 494 } 495 496 override fun onPostFinishedWakingUp() { 497 dispatchNewState() 498 } 499 500 override fun onStartedGoingToSleep() { 501 dispatchNewState() 502 } 503 504 override fun onFinishedGoingToSleep() { 505 dispatchNewState() 506 } 507 508 private fun dispatchNewState() { 509 trySendWithFailureLogging( 510 WakefulnessModel.fromWakefulnessLifecycle(wakefulnessLifecycle), 511 TAG, 512 "updated wakefulness state" 513 ) 514 } 515 } 516 517 wakefulnessLifecycle.addObserver(observer) 518 trySendWithFailureLogging( 519 WakefulnessModel.fromWakefulnessLifecycle(wakefulnessLifecycle), 520 TAG, 521 "initial wakefulness state" 522 ) 523 524 awaitClose { wakefulnessLifecycle.removeObserver(observer) } 525 } 526 527 override val fingerprintSensorLocation: Flow<Point?> = conflatedCallbackFlow { 528 fun sendFpLocation() { 529 trySendWithFailureLogging( 530 authController.fingerprintSensorLocation, 531 TAG, 532 "AuthController.Callback#onFingerprintLocationChanged" 533 ) 534 } 535 536 val callback = 537 object : AuthController.Callback { 538 override fun onFingerprintLocationChanged() { 539 sendFpLocation() 540 } 541 } 542 543 authController.addCallback(callback) 544 sendFpLocation() 545 546 awaitClose { authController.removeCallback(callback) } 547 } 548 549 override val faceSensorLocation: Flow<Point?> = conflatedCallbackFlow { 550 fun sendSensorLocation() { 551 trySendWithFailureLogging( 552 authController.faceSensorLocation, 553 TAG, 554 "AuthController.Callback#onFingerprintLocationChanged" 555 ) 556 } 557 558 val callback = 559 object : AuthController.Callback { 560 override fun onFaceSensorLocationChanged() { 561 sendSensorLocation() 562 } 563 } 564 565 authController.addCallback(callback) 566 sendSensorLocation() 567 568 awaitClose { authController.removeCallback(callback) } 569 } 570 571 override val biometricUnlockSource: Flow<BiometricUnlockSource?> = conflatedCallbackFlow { 572 val callback = 573 object : KeyguardUpdateMonitorCallback() { 574 override fun onBiometricAuthenticated( 575 userId: Int, 576 biometricSourceType: BiometricSourceType?, 577 isStrongBiometric: Boolean 578 ) { 579 trySendWithFailureLogging( 580 BiometricUnlockSource.fromBiometricSourceType(biometricSourceType), 581 TAG, 582 "onBiometricAuthenticated" 583 ) 584 } 585 } 586 587 keyguardUpdateMonitor.registerCallback(callback) 588 trySendWithFailureLogging(null, TAG, "initial value") 589 awaitClose { keyguardUpdateMonitor.removeCallback(callback) } 590 } 591 592 private val _isQuickSettingsVisible = MutableStateFlow(false) 593 override val isQuickSettingsVisible: Flow<Boolean> = _isQuickSettingsVisible.asStateFlow() 594 595 override fun setAnimateDozingTransitions(animate: Boolean) { 596 _animateBottomAreaDozingTransitions.value = animate 597 } 598 599 override fun setBottomAreaAlpha(alpha: Float) { 600 _bottomAreaAlpha.value = alpha 601 } 602 603 override fun setClockPosition(x: Int, y: Int) { 604 _clockPosition.value = Position(x, y) 605 } 606 607 override fun isUdfpsSupported(): Boolean = keyguardUpdateMonitor.isUdfpsSupported 608 609 override fun setQuickSettingsVisible(isVisible: Boolean) { 610 _isQuickSettingsVisible.value = isVisible 611 } 612 613 private fun statusBarStateIntToObject(value: Int): StatusBarState { 614 return when (value) { 615 0 -> StatusBarState.SHADE 616 1 -> StatusBarState.KEYGUARD 617 2 -> StatusBarState.SHADE_LOCKED 618 else -> throw IllegalArgumentException("Invalid StatusBarState value: $value") 619 } 620 } 621 622 private fun biometricModeIntToObject(@WakeAndUnlockMode value: Int): BiometricUnlockModel { 623 return when (value) { 624 0 -> BiometricUnlockModel.NONE 625 1 -> BiometricUnlockModel.WAKE_AND_UNLOCK 626 2 -> BiometricUnlockModel.WAKE_AND_UNLOCK_PULSING 627 3 -> BiometricUnlockModel.SHOW_BOUNCER 628 4 -> BiometricUnlockModel.ONLY_WAKE 629 5 -> BiometricUnlockModel.UNLOCK_COLLAPSING 630 6 -> BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM 631 7 -> BiometricUnlockModel.DISMISS_BOUNCER 632 else -> throw IllegalArgumentException("Invalid BiometricUnlockModel value: $value") 633 } 634 } 635 636 private fun dozeMachineStateToModel(state: DozeMachine.State): DozeStateModel { 637 return when (state) { 638 DozeMachine.State.UNINITIALIZED -> DozeStateModel.UNINITIALIZED 639 DozeMachine.State.INITIALIZED -> DozeStateModel.INITIALIZED 640 DozeMachine.State.DOZE -> DozeStateModel.DOZE 641 DozeMachine.State.DOZE_SUSPEND_TRIGGERS -> DozeStateModel.DOZE_SUSPEND_TRIGGERS 642 DozeMachine.State.DOZE_AOD -> DozeStateModel.DOZE_AOD 643 DozeMachine.State.DOZE_REQUEST_PULSE -> DozeStateModel.DOZE_REQUEST_PULSE 644 DozeMachine.State.DOZE_PULSING -> DozeStateModel.DOZE_PULSING 645 DozeMachine.State.DOZE_PULSING_BRIGHT -> DozeStateModel.DOZE_PULSING_BRIGHT 646 DozeMachine.State.DOZE_PULSE_DONE -> DozeStateModel.DOZE_PULSE_DONE 647 DozeMachine.State.FINISH -> DozeStateModel.FINISH 648 DozeMachine.State.DOZE_AOD_PAUSED -> DozeStateModel.DOZE_AOD_PAUSED 649 DozeMachine.State.DOZE_AOD_PAUSING -> DozeStateModel.DOZE_AOD_PAUSING 650 DozeMachine.State.DOZE_AOD_DOCKED -> DozeStateModel.DOZE_AOD_DOCKED 651 else -> throw IllegalArgumentException("Invalid DozeMachine.State: state") 652 } 653 } 654 655 companion object { 656 private const val TAG = "KeyguardRepositoryImpl" 657 } 658 } 659