Loading packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt +3 −9 Original line number Diff line number Diff line Loading @@ -26,8 +26,6 @@ import com.android.systemui.biometrics.shared.model.DisplayRotation import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.biometrics.shared.model.isDefaultOrientation import com.android.systemui.dagger.SysUISingleton import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.flags.Flags import com.android.systemui.log.SideFpsLogger import com.android.systemui.res.R import java.util.Optional Loading @@ -48,7 +46,6 @@ constructor( fingerprintPropertyRepository: FingerprintPropertyRepository, windowManager: WindowManager, displayStateInteractor: DisplayStateInteractor, featureFlags: FeatureFlagsClassic, fingerprintInteractiveToAuthProvider: Optional<FingerprintInteractiveToAuthProvider>, private val logger: SideFpsLogger, ) { Loading @@ -65,14 +62,11 @@ constructor( val isAvailable: Flow<Boolean> = fingerprintPropertyRepository.sensorType.map { it == FingerprintSensorType.POWER_BUTTON } val authenticationDuration: Flow<Long> = flowOf(context.resources?.getInteger(R.integer.config_restToUnlockDuration)?.toLong() ?: 0L) val authenticationDuration: Long = context.resources?.getInteger(R.integer.config_restToUnlockDuration)?.toLong() ?: 0L val isProlongedTouchRequiredForAuthentication: Flow<Boolean> = if ( fingerprintInteractiveToAuthProvider.isEmpty || !featureFlags.isEnabled(Flags.REST_TO_UNLOCK) ) { if (fingerprintInteractiveToAuthProvider.isEmpty) { flowOf(false) } else { combine( Loading packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt +17 −2 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ import com.android.systemui.CoreStartable import com.android.systemui.biometrics.SideFpsController import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.flags.Flags import com.android.systemui.keyguard.ui.view.SideFpsProgressBar import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel import com.android.systemui.log.SideFpsLogger Loading @@ -31,6 +33,7 @@ import com.android.systemui.util.kotlin.Quint import java.io.PrintWriter import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch Loading @@ -47,15 +50,23 @@ constructor( private val sfpsController: dagger.Lazy<SideFpsController>, private val logger: SideFpsLogger, private val commandRegistry: CommandRegistry, private val featureFlagsClassic: FeatureFlagsClassic, ) : CoreStartable { override fun start() { if (!featureFlagsClassic.isEnabled(Flags.REST_TO_UNLOCK)) { return } // When the rest to unlock feature is disabled by the user, stop any coroutines that are // not required. var layoutJob: Job? = null var progressJob: Job? = null commandRegistry.registerCommand(spfsProgressBarCommand) { SfpsProgressBarCommand() } applicationScope.launch { viewModel.isProlongedTouchRequiredForAuthentication.collectLatest { enabled -> logger.isProlongedTouchRequiredForAuthenticationChanged(enabled) if (enabled) { launch { layoutJob = launch { combine( viewModel.isVisible, viewModel.progressBarLocation, Loading @@ -76,9 +87,13 @@ constructor( ) } } launch { viewModel.progress.collectLatest { view.setProgress(it) } } progressJob = launch { viewModel.progress.collectLatest { view.setProgress(it) } } } else { view.hide() layoutJob?.cancel() progressJob?.cancel() } } } Loading packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt +29 −14 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ import com.android.systemui.biometrics.shared.model.DisplayRotation import com.android.systemui.biometrics.shared.model.isDefaultOrientation import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.flags.Flags import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.shared.model.AcquiredFingerprintAuthenticationStatus import com.android.systemui.keyguard.shared.model.ErrorFingerprintAuthenticationStatus Loading @@ -34,13 +36,17 @@ import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticati import com.android.systemui.res.R import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @SysUISingleton Loading @@ -52,10 +58,12 @@ constructor( private val sfpsSensorInteractor: SideFpsSensorInteractor, displayStateInteractor: DisplayStateInteractor, @Application private val applicationScope: CoroutineScope, private val featureFlagsClassic: FeatureFlagsClassic, ) { private val _progress = MutableStateFlow(0.0f) private val _visible = MutableStateFlow(false) private var _animator: ValueAnimator? = null private var animatorJob: Job? = null private fun onFingerprintCaptureCompleted() { _visible.value = false Loading Loading @@ -147,26 +155,32 @@ constructor( sfpsSensorInteractor.isProlongedTouchRequiredForAuthentication init { applicationScope.launch { combine( sfpsSensorInteractor.isProlongedTouchRequiredForAuthentication, sfpsSensorInteractor.authenticationDuration, ::Pair ) .collectLatest { (enabled, authDuration) -> if (!enabled) return@collectLatest if (featureFlagsClassic.isEnabled(Flags.REST_TO_UNLOCK)) { launchAnimator() } } launch { fpAuthRepository.authenticationStatus.collectLatest { authStatus -> private fun launchAnimator() { applicationScope.launch { sfpsSensorInteractor.isProlongedTouchRequiredForAuthentication.collectLatest { enabled -> if (!enabled) { animatorJob?.cancel() return@collectLatest } animatorJob = fpAuthRepository.authenticationStatus .onEach { authStatus -> when (authStatus) { is AcquiredFingerprintAuthenticationStatus -> { if (authStatus.fingerprintCaptureStarted) { _visible.value = true _animator?.cancel() _animator = ValueAnimator.ofFloat(0.0f, 1.0f) .setDuration(authDuration) .setDuration( sfpsSensorInteractor.authenticationDuration ) .apply { addUpdateListener { _progress.value = it.animatedValue as Float Loading Loading @@ -196,7 +210,8 @@ constructor( else -> Unit } } } .onCompletion { _animator?.cancel() } .launchIn(applicationScope) } } } Loading packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt +1 −5 Original line number Diff line number Diff line Loading @@ -37,8 +37,6 @@ import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.biometrics.shared.model.SensorStrength import com.android.systemui.coroutines.collectLastValue import com.android.systemui.dump.logcatLogBuffer import com.android.systemui.flags.FakeFeatureFlagsClassic import com.android.systemui.flags.Flags.REST_TO_UNLOCK import com.android.systemui.log.SideFpsLogger import com.android.systemui.res.R import com.android.systemui.util.mockito.whenever Loading Loading @@ -94,7 +92,6 @@ class SideFpsSensorInteractorTest : SysuiTestCase() { whenever(displayStateInteractor.currentRotation).thenReturn(currentRotation) contextDisplayInfo.uniqueId = "current-display" val featureFlags = FakeFeatureFlagsClassic().apply { set(REST_TO_UNLOCK, true) } whenever(fingerprintInteractiveToAuthProvider.enabledForCurrentUser) .thenReturn(isRestToUnlockEnabled) underTest = Loading @@ -103,7 +100,6 @@ class SideFpsSensorInteractorTest : SysuiTestCase() { fingerprintRepository, windowManager, displayStateInteractor, featureFlags, Optional.of(fingerprintInteractiveToAuthProvider), SideFpsLogger(logcatLogBuffer("SfpsLogger")) ) Loading Loading @@ -136,7 +132,7 @@ class SideFpsSensorInteractorTest : SysuiTestCase() { @Test fun authenticationDurationIsAvailableWhenSFPSSensorIsAvailable() = testScope.runTest { assertThat(collectLastValue(underTest.authenticationDuration)()) assertThat(underTest.authenticationDuration) .isEqualTo(context.resources.getInteger(R.integer.config_restToUnlockDuration)) } Loading Loading
packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt +3 −9 Original line number Diff line number Diff line Loading @@ -26,8 +26,6 @@ import com.android.systemui.biometrics.shared.model.DisplayRotation import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.biometrics.shared.model.isDefaultOrientation import com.android.systemui.dagger.SysUISingleton import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.flags.Flags import com.android.systemui.log.SideFpsLogger import com.android.systemui.res.R import java.util.Optional Loading @@ -48,7 +46,6 @@ constructor( fingerprintPropertyRepository: FingerprintPropertyRepository, windowManager: WindowManager, displayStateInteractor: DisplayStateInteractor, featureFlags: FeatureFlagsClassic, fingerprintInteractiveToAuthProvider: Optional<FingerprintInteractiveToAuthProvider>, private val logger: SideFpsLogger, ) { Loading @@ -65,14 +62,11 @@ constructor( val isAvailable: Flow<Boolean> = fingerprintPropertyRepository.sensorType.map { it == FingerprintSensorType.POWER_BUTTON } val authenticationDuration: Flow<Long> = flowOf(context.resources?.getInteger(R.integer.config_restToUnlockDuration)?.toLong() ?: 0L) val authenticationDuration: Long = context.resources?.getInteger(R.integer.config_restToUnlockDuration)?.toLong() ?: 0L val isProlongedTouchRequiredForAuthentication: Flow<Boolean> = if ( fingerprintInteractiveToAuthProvider.isEmpty || !featureFlags.isEnabled(Flags.REST_TO_UNLOCK) ) { if (fingerprintInteractiveToAuthProvider.isEmpty) { flowOf(false) } else { combine( Loading
packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt +17 −2 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ import com.android.systemui.CoreStartable import com.android.systemui.biometrics.SideFpsController import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.flags.Flags import com.android.systemui.keyguard.ui.view.SideFpsProgressBar import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel import com.android.systemui.log.SideFpsLogger Loading @@ -31,6 +33,7 @@ import com.android.systemui.util.kotlin.Quint import java.io.PrintWriter import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch Loading @@ -47,15 +50,23 @@ constructor( private val sfpsController: dagger.Lazy<SideFpsController>, private val logger: SideFpsLogger, private val commandRegistry: CommandRegistry, private val featureFlagsClassic: FeatureFlagsClassic, ) : CoreStartable { override fun start() { if (!featureFlagsClassic.isEnabled(Flags.REST_TO_UNLOCK)) { return } // When the rest to unlock feature is disabled by the user, stop any coroutines that are // not required. var layoutJob: Job? = null var progressJob: Job? = null commandRegistry.registerCommand(spfsProgressBarCommand) { SfpsProgressBarCommand() } applicationScope.launch { viewModel.isProlongedTouchRequiredForAuthentication.collectLatest { enabled -> logger.isProlongedTouchRequiredForAuthenticationChanged(enabled) if (enabled) { launch { layoutJob = launch { combine( viewModel.isVisible, viewModel.progressBarLocation, Loading @@ -76,9 +87,13 @@ constructor( ) } } launch { viewModel.progress.collectLatest { view.setProgress(it) } } progressJob = launch { viewModel.progress.collectLatest { view.setProgress(it) } } } else { view.hide() layoutJob?.cancel() progressJob?.cancel() } } } Loading
packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt +29 −14 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ import com.android.systemui.biometrics.shared.model.DisplayRotation import com.android.systemui.biometrics.shared.model.isDefaultOrientation import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.flags.Flags import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.shared.model.AcquiredFingerprintAuthenticationStatus import com.android.systemui.keyguard.shared.model.ErrorFingerprintAuthenticationStatus Loading @@ -34,13 +36,17 @@ import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticati import com.android.systemui.res.R import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @SysUISingleton Loading @@ -52,10 +58,12 @@ constructor( private val sfpsSensorInteractor: SideFpsSensorInteractor, displayStateInteractor: DisplayStateInteractor, @Application private val applicationScope: CoroutineScope, private val featureFlagsClassic: FeatureFlagsClassic, ) { private val _progress = MutableStateFlow(0.0f) private val _visible = MutableStateFlow(false) private var _animator: ValueAnimator? = null private var animatorJob: Job? = null private fun onFingerprintCaptureCompleted() { _visible.value = false Loading Loading @@ -147,26 +155,32 @@ constructor( sfpsSensorInteractor.isProlongedTouchRequiredForAuthentication init { applicationScope.launch { combine( sfpsSensorInteractor.isProlongedTouchRequiredForAuthentication, sfpsSensorInteractor.authenticationDuration, ::Pair ) .collectLatest { (enabled, authDuration) -> if (!enabled) return@collectLatest if (featureFlagsClassic.isEnabled(Flags.REST_TO_UNLOCK)) { launchAnimator() } } launch { fpAuthRepository.authenticationStatus.collectLatest { authStatus -> private fun launchAnimator() { applicationScope.launch { sfpsSensorInteractor.isProlongedTouchRequiredForAuthentication.collectLatest { enabled -> if (!enabled) { animatorJob?.cancel() return@collectLatest } animatorJob = fpAuthRepository.authenticationStatus .onEach { authStatus -> when (authStatus) { is AcquiredFingerprintAuthenticationStatus -> { if (authStatus.fingerprintCaptureStarted) { _visible.value = true _animator?.cancel() _animator = ValueAnimator.ofFloat(0.0f, 1.0f) .setDuration(authDuration) .setDuration( sfpsSensorInteractor.authenticationDuration ) .apply { addUpdateListener { _progress.value = it.animatedValue as Float Loading Loading @@ -196,7 +210,8 @@ constructor( else -> Unit } } } .onCompletion { _animator?.cancel() } .launchIn(applicationScope) } } } Loading
packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt +1 −5 Original line number Diff line number Diff line Loading @@ -37,8 +37,6 @@ import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.biometrics.shared.model.SensorStrength import com.android.systemui.coroutines.collectLastValue import com.android.systemui.dump.logcatLogBuffer import com.android.systemui.flags.FakeFeatureFlagsClassic import com.android.systemui.flags.Flags.REST_TO_UNLOCK import com.android.systemui.log.SideFpsLogger import com.android.systemui.res.R import com.android.systemui.util.mockito.whenever Loading Loading @@ -94,7 +92,6 @@ class SideFpsSensorInteractorTest : SysuiTestCase() { whenever(displayStateInteractor.currentRotation).thenReturn(currentRotation) contextDisplayInfo.uniqueId = "current-display" val featureFlags = FakeFeatureFlagsClassic().apply { set(REST_TO_UNLOCK, true) } whenever(fingerprintInteractiveToAuthProvider.enabledForCurrentUser) .thenReturn(isRestToUnlockEnabled) underTest = Loading @@ -103,7 +100,6 @@ class SideFpsSensorInteractorTest : SysuiTestCase() { fingerprintRepository, windowManager, displayStateInteractor, featureFlags, Optional.of(fingerprintInteractiveToAuthProvider), SideFpsLogger(logcatLogBuffer("SfpsLogger")) ) Loading Loading @@ -136,7 +132,7 @@ class SideFpsSensorInteractorTest : SysuiTestCase() { @Test fun authenticationDurationIsAvailableWhenSFPSSensorIsAvailable() = testScope.runTest { assertThat(collectLastValue(underTest.authenticationDuration)()) assertThat(underTest.authenticationDuration) .isEqualTo(context.resources.getInteger(R.integer.config_restToUnlockDuration)) } Loading