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.domain.interactor 18 19 import com.android.keyguard.KeyguardUpdateMonitor 20 import com.android.systemui.dagger.SysUISingleton 21 import com.android.systemui.flags.FeatureFlags 22 import com.android.systemui.flags.Flags 23 import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository 24 import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository 25 import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository 26 import com.android.systemui.plugins.statusbar.StatusBarStateController 27 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.LegacyAlternateBouncer 28 import com.android.systemui.statusbar.policy.KeyguardStateController 29 import com.android.systemui.util.time.SystemClock 30 import javax.inject.Inject 31 import kotlinx.coroutines.flow.Flow 32 33 /** Encapsulates business logic for interacting with the lock-screen alternate bouncer. */ 34 @SysUISingleton 35 class AlternateBouncerInteractor 36 @Inject 37 constructor( 38 private val statusBarStateController: StatusBarStateController, 39 private val keyguardStateController: KeyguardStateController, 40 private val bouncerRepository: KeyguardBouncerRepository, 41 private val biometricSettingsRepository: BiometricSettingsRepository, 42 private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository, 43 private val systemClock: SystemClock, 44 private val keyguardUpdateMonitor: KeyguardUpdateMonitor, 45 featureFlags: FeatureFlags, 46 ) { 47 val isModernAlternateBouncerEnabled = featureFlags.isEnabled(Flags.MODERN_ALTERNATE_BOUNCER) 48 var legacyAlternateBouncer: LegacyAlternateBouncer? = null 49 var legacyAlternateBouncerVisibleTime: Long = NOT_VISIBLE 50 51 val isVisible: Flow<Boolean> = bouncerRepository.alternateBouncerVisible 52 53 private val keyguardStateControllerCallback: KeyguardStateController.Callback = 54 object : KeyguardStateController.Callback { onUnlockedChangednull55 override fun onUnlockedChanged() { 56 maybeHide() 57 } 58 } 59 60 init { 61 keyguardStateController.addCallback(keyguardStateControllerCallback) 62 } 63 64 /** 65 * Sets the correct bouncer states to show the alternate bouncer if it can show. 66 * 67 * @return whether alternateBouncer is visible 68 */ shownull69 fun show(): Boolean { 70 return when { 71 isModernAlternateBouncerEnabled -> { 72 bouncerRepository.setAlternateVisible(canShowAlternateBouncerForFingerprint()) 73 isVisibleState() 74 } 75 canShowAlternateBouncerForFingerprint() -> { 76 if (legacyAlternateBouncer?.showAlternateBouncer() == true) { 77 legacyAlternateBouncerVisibleTime = systemClock.uptimeMillis() 78 true 79 } else { 80 false 81 } 82 } 83 else -> false 84 } 85 } 86 87 /** 88 * Sets the correct bouncer states to hide the bouncer. Should only be called through 89 * StatusBarKeyguardViewManager until ScrimController is refactored to use 90 * alternateBouncerInteractor. 91 * 92 * @return true if the alternate bouncer was newly hidden, else false. 93 */ hidenull94 fun hide(): Boolean { 95 return if (isModernAlternateBouncerEnabled) { 96 val wasAlternateBouncerVisible = isVisibleState() 97 bouncerRepository.setAlternateVisible(false) 98 wasAlternateBouncerVisible && !isVisibleState() 99 } else { 100 legacyAlternateBouncer?.hideAlternateBouncer() ?: false 101 } 102 } 103 isVisibleStatenull104 fun isVisibleState(): Boolean { 105 return if (isModernAlternateBouncerEnabled) { 106 bouncerRepository.alternateBouncerVisible.value 107 } else { 108 legacyAlternateBouncer?.isShowingAlternateBouncer ?: false 109 } 110 } 111 setAlternateBouncerUIAvailablenull112 fun setAlternateBouncerUIAvailable(isAvailable: Boolean) { 113 bouncerRepository.setAlternateBouncerUIAvailable(isAvailable) 114 } 115 canShowAlternateBouncerForFingerprintnull116 fun canShowAlternateBouncerForFingerprint(): Boolean { 117 return if (isModernAlternateBouncerEnabled) { 118 bouncerRepository.alternateBouncerUIAvailable.value && 119 biometricSettingsRepository.isFingerprintEnrolled.value && 120 biometricSettingsRepository.isStrongBiometricAllowed.value && 121 biometricSettingsRepository.isFingerprintEnabledByDevicePolicy.value && 122 !deviceEntryFingerprintAuthRepository.isLockedOut.value && 123 !keyguardStateController.isUnlocked && 124 !statusBarStateController.isDozing 125 } else { 126 legacyAlternateBouncer != null && 127 keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(true) 128 } 129 } 130 131 /** 132 * Whether the alt bouncer has shown for a minimum time before allowing touches to dismiss the 133 * alternate bouncer and show the primary bouncer. 134 */ hasAlternateBouncerShownWithMinTimenull135 fun hasAlternateBouncerShownWithMinTime(): Boolean { 136 return if (isModernAlternateBouncerEnabled) { 137 (systemClock.uptimeMillis() - bouncerRepository.lastAlternateBouncerVisibleTime) > 138 MIN_VISIBILITY_DURATION_UNTIL_TOUCHES_DISMISS_ALTERNATE_BOUNCER_MS 139 } else { 140 systemClock.uptimeMillis() - legacyAlternateBouncerVisibleTime > 200 141 } 142 } 143 maybeHidenull144 private fun maybeHide() { 145 if (isVisibleState() && !canShowAlternateBouncerForFingerprint()) { 146 hide() 147 } 148 } 149 150 companion object { 151 private const val MIN_VISIBILITY_DURATION_UNTIL_TOUCHES_DISMISS_ALTERNATE_BOUNCER_MS = 200L 152 private const val NOT_VISIBLE = -1L 153 } 154 } 155