Merge "[flexiglass] Implement lockscreen bypass." into udc-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
c78baa4f2b
@@ -63,14 +63,6 @@ interface AuthenticationRepository {
|
||||
*/
|
||||
val isUnlocked: StateFlow<Boolean>
|
||||
|
||||
/**
|
||||
* Whether lock screen bypass is enabled. When enabled, the lock screen will be automatically
|
||||
* dismisses once the authentication challenge is completed. For example, completing a biometric
|
||||
* authentication challenge via face unlock or fingerprint sensor can automatically bypass the
|
||||
* lock screen.
|
||||
*/
|
||||
val isBypassEnabled: StateFlow<Boolean>
|
||||
|
||||
/**
|
||||
* Whether the auto confirm feature is enabled for the currently-selected user.
|
||||
*
|
||||
@@ -113,9 +105,6 @@ interface AuthenticationRepository {
|
||||
*/
|
||||
suspend fun isLockscreenEnabled(): Boolean
|
||||
|
||||
/** See [isBypassEnabled]. */
|
||||
fun setBypassEnabled(isBypassEnabled: Boolean)
|
||||
|
||||
/** Reports an authentication attempt. */
|
||||
suspend fun reportAuthenticationAttempt(isSuccessful: Boolean)
|
||||
|
||||
@@ -157,7 +146,7 @@ constructor(
|
||||
private val lockPatternUtils: LockPatternUtils,
|
||||
) : AuthenticationRepository {
|
||||
|
||||
override val isUnlocked: StateFlow<Boolean> = keyguardRepository.isKeyguardUnlocked
|
||||
override val isUnlocked = keyguardRepository.isKeyguardUnlocked
|
||||
|
||||
override suspend fun isLockscreenEnabled(): Boolean {
|
||||
return withContext(backgroundDispatcher) {
|
||||
@@ -166,9 +155,6 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private val _isBypassEnabled = MutableStateFlow(false)
|
||||
override val isBypassEnabled: StateFlow<Boolean> = _isBypassEnabled.asStateFlow()
|
||||
|
||||
override val isAutoConfirmEnabled: StateFlow<Boolean> =
|
||||
userRepository.selectedUserInfo
|
||||
.map { it.id }
|
||||
@@ -225,10 +211,6 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun setBypassEnabled(isBypassEnabled: Boolean) {
|
||||
_isBypassEnabled.value = isBypassEnabled
|
||||
}
|
||||
|
||||
override suspend fun reportAuthenticationAttempt(isSuccessful: Boolean) {
|
||||
val selectedUserId = userRepository.selectedUserId
|
||||
withContext(backgroundDispatcher) {
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.android.systemui.authentication.shared.model.AuthenticationThrottling
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
import com.android.systemui.keyguard.data.repository.KeyguardRepository
|
||||
import com.android.systemui.user.data.repository.UserRepository
|
||||
import com.android.systemui.util.time.SystemClock
|
||||
import javax.inject.Inject
|
||||
@@ -51,6 +52,7 @@ constructor(
|
||||
private val repository: AuthenticationRepository,
|
||||
@Background private val backgroundDispatcher: CoroutineDispatcher,
|
||||
private val userRepository: UserRepository,
|
||||
private val keyguardRepository: KeyguardRepository,
|
||||
private val clock: SystemClock,
|
||||
) {
|
||||
/**
|
||||
@@ -76,14 +78,6 @@ constructor(
|
||||
initialValue = true,
|
||||
)
|
||||
|
||||
/**
|
||||
* Whether lock screen bypass is enabled. When enabled, the lock screen will be automatically
|
||||
* dismisses once the authentication challenge is completed. For example, completing a biometric
|
||||
* authentication challenge via face unlock or fingerprint sensor can automatically bypass the
|
||||
* lock screen.
|
||||
*/
|
||||
val isBypassEnabled: StateFlow<Boolean> = repository.isBypassEnabled
|
||||
|
||||
/** The current authentication throttling state, only meaningful if [isThrottled] is `true`. */
|
||||
val throttling: StateFlow<AuthenticationThrottlingModel> = repository.throttling
|
||||
|
||||
@@ -155,6 +149,16 @@ constructor(
|
||||
return !isUnlocked.value && getAuthenticationMethod().isSecure
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether lock screen bypass is enabled. When enabled, the lock screen will be automatically
|
||||
* dismisses once the authentication challenge is completed. For example, completing a biometric
|
||||
* authentication challenge via face unlock or fingerprint sensor can automatically bypass the
|
||||
* lock screen.
|
||||
*/
|
||||
fun isBypassEnabled(): Boolean {
|
||||
return keyguardRepository.isBypassEnabled()
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to authenticate the user and unlock the device.
|
||||
*
|
||||
@@ -218,11 +222,6 @@ constructor(
|
||||
return authenticationResult.isSuccessful
|
||||
}
|
||||
|
||||
/** See [isBypassEnabled]. */
|
||||
fun toggleBypassEnabled() {
|
||||
repository.setBypassEnabled(!repository.isBypassEnabled.value)
|
||||
}
|
||||
|
||||
/** Starts refreshing the throttling state every second. */
|
||||
private suspend fun startThrottlingCountdown() {
|
||||
cancelCountdown()
|
||||
|
||||
@@ -42,6 +42,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||
import com.android.systemui.statusbar.phone.BiometricUnlockController
|
||||
import com.android.systemui.statusbar.phone.BiometricUnlockController.WakeAndUnlockMode
|
||||
import com.android.systemui.statusbar.phone.DozeParameters
|
||||
import com.android.systemui.statusbar.phone.KeyguardBypassController
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
@@ -171,6 +172,14 @@ interface KeyguardRepository {
|
||||
*/
|
||||
fun isKeyguardShowing(): Boolean
|
||||
|
||||
/**
|
||||
* Whether lock screen bypass is enabled. When enabled, the lock screen will be automatically
|
||||
* dismissed once the authentication challenge is completed. For example, completing a biometric
|
||||
* authentication challenge via face unlock or fingerprint sensor can automatically bypass the
|
||||
* lock screen.
|
||||
*/
|
||||
fun isBypassEnabled(): Boolean
|
||||
|
||||
/** Sets whether the bottom area UI should animate the transition out of doze state. */
|
||||
fun setAnimateDozingTransitions(animate: Boolean)
|
||||
|
||||
@@ -206,6 +215,7 @@ constructor(
|
||||
wakefulnessLifecycle: WakefulnessLifecycle,
|
||||
biometricUnlockController: BiometricUnlockController,
|
||||
private val keyguardStateController: KeyguardStateController,
|
||||
private val keyguardBypassController: KeyguardBypassController,
|
||||
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
|
||||
private val dozeTransitionListener: DozeTransitionListener,
|
||||
private val dozeParameters: DozeParameters,
|
||||
@@ -252,23 +262,17 @@ constructor(
|
||||
override val isAodAvailable: Flow<Boolean> =
|
||||
conflatedCallbackFlow {
|
||||
val callback =
|
||||
object : DozeParameters.Callback {
|
||||
override fun onAlwaysOnChange() {
|
||||
trySendWithFailureLogging(
|
||||
dozeParameters.getAlwaysOn(),
|
||||
TAG,
|
||||
"updated isAodAvailable"
|
||||
)
|
||||
}
|
||||
DozeParameters.Callback {
|
||||
trySendWithFailureLogging(
|
||||
dozeParameters.alwaysOn,
|
||||
TAG,
|
||||
"updated isAodAvailable"
|
||||
)
|
||||
}
|
||||
|
||||
dozeParameters.addCallback(callback)
|
||||
// Adding the callback does not send an initial update.
|
||||
trySendWithFailureLogging(
|
||||
dozeParameters.getAlwaysOn(),
|
||||
TAG,
|
||||
"initial isAodAvailable"
|
||||
)
|
||||
trySendWithFailureLogging(dozeParameters.alwaysOn, TAG, "initial isAodAvailable")
|
||||
|
||||
awaitClose { dozeParameters.removeCallback(callback) }
|
||||
}
|
||||
@@ -464,6 +468,10 @@ constructor(
|
||||
return keyguardStateController.isShowing
|
||||
}
|
||||
|
||||
override fun isBypassEnabled(): Boolean {
|
||||
return keyguardBypassController.bypassEnabled
|
||||
}
|
||||
|
||||
override val statusBarState: Flow<StatusBarState> = conflatedCallbackFlow {
|
||||
val callback =
|
||||
object : StatusBarStateController.StateListener {
|
||||
|
||||
@@ -77,7 +77,7 @@ constructor(
|
||||
authenticationInteractor.isUnlocked
|
||||
.map { isUnlocked ->
|
||||
val currentSceneKey = sceneInteractor.currentScene(CONTAINER_NAME).value.key
|
||||
val isBypassEnabled = authenticationInteractor.isBypassEnabled.value
|
||||
val isBypassEnabled = authenticationInteractor.isBypassEnabled()
|
||||
when {
|
||||
isUnlocked ->
|
||||
when (currentSceneKey) {
|
||||
|
||||
@@ -50,12 +50,6 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr
|
||||
@DevicePostureInt private var postureState: Int = DEVICE_POSTURE_UNKNOWN
|
||||
private var pendingUnlock: PendingUnlock? = null
|
||||
private val listeners = mutableListOf<OnBypassStateChangedListener>()
|
||||
private val postureCallback = DevicePostureController.Callback { posture ->
|
||||
if (postureState != posture) {
|
||||
postureState = posture
|
||||
notifyListeners()
|
||||
}
|
||||
}
|
||||
private val faceAuthEnabledChangedCallback = object : KeyguardStateController.Callback {
|
||||
override fun onFaceAuthEnabledChanged() = notifyListeners()
|
||||
}
|
||||
@@ -162,10 +156,8 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr
|
||||
|
||||
val dismissByDefault = if (context.resources.getBoolean(
|
||||
com.android.internal.R.bool.config_faceAuthDismissesKeyguard)) 1 else 0
|
||||
tunerService.addTunable(object : TunerService.Tunable {
|
||||
override fun onTuningChanged(key: String?, newValue: String?) {
|
||||
bypassEnabled = tunerService.getValue(key, dismissByDefault) != 0
|
||||
}
|
||||
tunerService.addTunable({ key, _ ->
|
||||
bypassEnabled = tunerService.getValue(key, dismissByDefault) != 0
|
||||
}, Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD)
|
||||
lockscreenUserManager.addUserChangedListener(
|
||||
object : NotificationLockscreenUserManager.UserChangedListener {
|
||||
@@ -281,8 +273,6 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val BYPASS_FADE_DURATION = 67
|
||||
|
||||
private const val FACE_UNLOCK_BYPASS_NO_OVERRIDE = 0
|
||||
private const val FACE_UNLOCK_BYPASS_ALWAYS = 1
|
||||
private const val FACE_UNLOCK_BYPASS_NEVER = 2
|
||||
|
||||
@@ -102,19 +102,6 @@ class AuthenticationInteractorTest : SysuiTestCase() {
|
||||
assertThat(isUnlocked).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun toggleBypassEnabled() =
|
||||
testScope.runTest {
|
||||
val isBypassEnabled by collectLastValue(underTest.isBypassEnabled)
|
||||
assertThat(isBypassEnabled).isFalse()
|
||||
|
||||
underTest.toggleBypassEnabled()
|
||||
assertThat(isBypassEnabled).isTrue()
|
||||
|
||||
underTest.toggleBypassEnabled()
|
||||
assertThat(isBypassEnabled).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isAuthenticationRequired_lockedAndSecured_true() =
|
||||
testScope.runTest {
|
||||
|
||||
@@ -41,6 +41,7 @@ import com.android.systemui.keyguard.shared.model.WakefulnessState
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||
import com.android.systemui.statusbar.phone.BiometricUnlockController
|
||||
import com.android.systemui.statusbar.phone.DozeParameters
|
||||
import com.android.systemui.statusbar.phone.KeyguardBypassController
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||
import com.android.systemui.util.mockito.argumentCaptor
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
@@ -73,6 +74,7 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
|
||||
@Mock private lateinit var biometricUnlockController: BiometricUnlockController
|
||||
@Mock private lateinit var dozeTransitionListener: DozeTransitionListener
|
||||
@Mock private lateinit var authController: AuthController
|
||||
@Mock private lateinit var keyguardBypassController: KeyguardBypassController
|
||||
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
|
||||
@Mock private lateinit var dreamOverlayCallbackController: DreamOverlayCallbackController
|
||||
@Mock private lateinit var dozeParameters: DozeParameters
|
||||
@@ -92,6 +94,7 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
|
||||
wakefulnessLifecycle,
|
||||
biometricUnlockController,
|
||||
keyguardStateController,
|
||||
keyguardBypassController,
|
||||
keyguardUpdateMonitor,
|
||||
dozeTransitionListener,
|
||||
dozeParameters,
|
||||
@@ -185,6 +188,20 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isBypassEnabled_disabledInController() {
|
||||
whenever(keyguardBypassController.isBypassEnabled).thenReturn(false)
|
||||
whenever(keyguardBypassController.bypassEnabled).thenReturn(false)
|
||||
assertThat(underTest.isBypassEnabled()).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isBypassEnabled_enabledInController() {
|
||||
whenever(keyguardBypassController.isBypassEnabled).thenReturn(true)
|
||||
whenever(keyguardBypassController.bypassEnabled).thenReturn(true)
|
||||
assertThat(underTest.isBypassEnabled()).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isAodAvailable() = runTest {
|
||||
val flow = underTest.isAodAvailable
|
||||
|
||||
@@ -28,7 +28,6 @@ import com.android.systemui.scene.shared.model.SceneContainerNames
|
||||
import com.android.systemui.scene.shared.model.SceneKey
|
||||
import com.android.systemui.scene.shared.model.SceneModel
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
@@ -36,7 +35,6 @@ import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.JUnit4
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SmallTest
|
||||
@RunWith(JUnit4::class)
|
||||
class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
|
||||
@@ -385,7 +383,7 @@ class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
|
||||
) {
|
||||
featureFlags.set(Flags.SCENE_CONTAINER, isFeatureEnabled)
|
||||
authenticationRepository.setUnlocked(isDeviceUnlocked)
|
||||
authenticationRepository.setBypassEnabled(isBypassEnabled)
|
||||
keyguardRepository.setBypassEnabled(isBypassEnabled)
|
||||
initialSceneKey?.let {
|
||||
sceneInteractor.setCurrentScene(SceneContainerNames.SYSTEM_UI_DEFAULT, SceneModel(it))
|
||||
}
|
||||
|
||||
@@ -31,9 +31,6 @@ class FakeAuthenticationRepository(
|
||||
private val currentTime: () -> Long,
|
||||
) : AuthenticationRepository {
|
||||
|
||||
private val _isBypassEnabled = MutableStateFlow(false)
|
||||
override val isBypassEnabled: StateFlow<Boolean> = _isBypassEnabled
|
||||
|
||||
private val _isAutoConfirmEnabled = MutableStateFlow(false)
|
||||
override val isAutoConfirmEnabled: StateFlow<Boolean> = _isAutoConfirmEnabled.asStateFlow()
|
||||
|
||||
@@ -85,10 +82,6 @@ class FakeAuthenticationRepository(
|
||||
return (credentialOverride ?: DEFAULT_PIN).size
|
||||
}
|
||||
|
||||
override fun setBypassEnabled(isBypassEnabled: Boolean) {
|
||||
_isBypassEnabled.value = isBypassEnabled
|
||||
}
|
||||
|
||||
override suspend fun getFailedAuthenticationAttemptCount(): Int {
|
||||
return failedAttemptCount
|
||||
}
|
||||
|
||||
@@ -114,6 +114,11 @@ class FakeKeyguardRepository : KeyguardRepository {
|
||||
return _isKeyguardShowing.value
|
||||
}
|
||||
|
||||
private var _isBypassEnabled = false
|
||||
override fun isBypassEnabled(): Boolean {
|
||||
return _isBypassEnabled
|
||||
}
|
||||
|
||||
override fun setAnimateDozingTransitions(animate: Boolean) {
|
||||
_animateBottomAreaDozingTransitions.tryEmit(animate)
|
||||
}
|
||||
@@ -198,6 +203,10 @@ class FakeKeyguardRepository : KeyguardRepository {
|
||||
_isKeyguardUnlocked.value = isUnlocked
|
||||
}
|
||||
|
||||
fun setBypassEnabled(isEnabled: Boolean) {
|
||||
_isBypassEnabled = isEnabled
|
||||
}
|
||||
|
||||
override fun isUdfpsSupported(): Boolean {
|
||||
return _isUdfpsSupported.value
|
||||
}
|
||||
|
||||
@@ -142,6 +142,7 @@ class SceneTestUtils(
|
||||
repository = repository,
|
||||
backgroundDispatcher = testDispatcher,
|
||||
userRepository = userRepository,
|
||||
keyguardRepository = keyguardRepository,
|
||||
clock = mock { whenever(elapsedRealtime()).thenAnswer { testScope.currentTime } }
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user