Loading packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorTest.kt +11 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,17 @@ class FingerprintPropertyInteractorTest : SysuiTestCase() { private val configurationRepository by lazy { kosmos.fakeConfigurationRepository } private val displayRepository by lazy { kosmos.displayRepository } @Test fun propertiesInitialized() = testScope.runTest { val propertiesInitialized by collectLastValue(underTest.propertiesInitialized) assertThat(propertiesInitialized).isFalse() repository.supportsUdfps() runCurrent() assertThat(propertiesInitialized).isTrue() } @Test fun sensorLocation_resolution1f() = testScope.runTest { Loading packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt +32 −4 Original line number Diff line number Diff line Loading @@ -51,6 +51,8 @@ import kotlinx.coroutines.withContext * There is never more than one instance of the FingerprintProperty at any given time. */ interface FingerprintPropertyRepository { /** Whether the fingerprint properties have been initialized yet. */ val propertiesInitialized: StateFlow<Boolean> /** The id of fingerprint sensor. */ val sensorId: Flow<Int> Loading @@ -59,7 +61,7 @@ interface FingerprintPropertyRepository { val strength: Flow<SensorStrength> /** The types of fingerprint sensor (rear, ultrasonic, optical, etc.). */ val sensorType: Flow<FingerprintSensorType> val sensorType: StateFlow<FingerprintSensorType> /** The sensor location relative to each physical display. */ val sensorLocations: Flow<Map<String, SensorLocationInternal>> Loading Loading @@ -105,15 +107,30 @@ constructor( .stateIn( applicationScope, started = SharingStarted.Eagerly, initialValue = DEFAULT_PROPS, initialValue = UNINITIALIZED_PROPS, ) override val propertiesInitialized: StateFlow<Boolean> = props .map { it != UNINITIALIZED_PROPS } .stateIn( applicationScope, started = SharingStarted.WhileSubscribed(), initialValue = props.value != UNINITIALIZED_PROPS, ) override val sensorId: Flow<Int> = props.map { it.sensorId } override val strength: Flow<SensorStrength> = props.map { it.sensorStrength.toSensorStrength() } override val sensorType: Flow<FingerprintSensorType> = props.map { it.sensorType.toSensorType() } override val sensorType: StateFlow<FingerprintSensorType> = props .map { it.sensorType.toSensorType() } .stateIn( scope = applicationScope, started = SharingStarted.WhileSubscribed(), initialValue = props.value.sensorType.toSensorType(), ) override val sensorLocations: Flow<Map<String, SensorLocationInternal>> = props.map { Loading @@ -124,6 +141,17 @@ constructor( companion object { private const val TAG = "FingerprintPropertyRepositoryImpl" private val UNINITIALIZED_PROPS = FingerprintSensorPropertiesInternal( -2 /* sensorId */, SensorProperties.STRENGTH_CONVENIENCE, 0 /* maxEnrollmentsPerUser */, listOf<ComponentInfoInternal>(), FingerprintSensorProperties.TYPE_UNKNOWN, false /* halControlsIllumination */, true /* resetLockoutRequiresHardwareAuthToken */, listOf<SensorLocationInternal>(SensorLocationInternal.DEFAULT) ) private val DEFAULT_PROPS = FingerprintSensorPropertiesInternal( -1 /* sensorId */, Loading packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt +14 −1 Original line number Diff line number Diff line Loading @@ -24,22 +24,35 @@ import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn @SysUISingleton class FingerprintPropertyInteractor @Inject constructor( @Application private val applicationScope: CoroutineScope, @Application private val context: Context, repository: FingerprintPropertyRepository, configurationInteractor: ConfigurationInteractor, displayStateInteractor: DisplayStateInteractor, ) { val isUdfps: Flow<Boolean> = repository.sensorType.map { it.isUdfps() } val propertiesInitialized: StateFlow<Boolean> = repository.propertiesInitialized val isUdfps: StateFlow<Boolean> = repository.sensorType .map { it.isUdfps() } .stateIn( scope = applicationScope, started = SharingStarted.WhileSubscribed(), initialValue = repository.sensorType.value.isUdfps(), ) /** * Devices with multiple physical displays use unique display ids to determine which sensor is Loading packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractor.kt +4 −5 Original line number Diff line number Diff line Loading @@ -16,17 +16,17 @@ package com.android.systemui.deviceentry.domain.interactor import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository import com.android.systemui.biometrics.domain.interactor.FingerprintPropertyInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map /** Encapsulates business logic for device entry under-display fingerprint state changes. */ @ExperimentalCoroutinesApi Loading @@ -34,14 +34,13 @@ import kotlinx.coroutines.flow.map class DeviceEntryUdfpsInteractor @Inject constructor( fingerprintPropertyInteractor: FingerprintPropertyInteractor, // TODO (b/309655554): create & use interactors for these repositories fingerprintPropertyRepository: FingerprintPropertyRepository, fingerprintAuthRepository: DeviceEntryFingerprintAuthRepository, biometricSettingsRepository: BiometricSettingsRepository, ) { /** Whether the device supports an under display fingerprint sensor. */ val isUdfpsSupported: Flow<Boolean> = fingerprintPropertyRepository.sensorType.map { it.isUdfps() } val isUdfpsSupported: StateFlow<Boolean> = fingerprintPropertyInteractor.isUdfps /** Whether the under-display fingerprint sensor is enrolled and enabled for device entry. */ val isUdfpsEnrolledAndEnabled: Flow<Boolean> = Loading packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt +0 −4 Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.data.repository import android.os.Handler import android.util.Log import com.android.systemui.common.ui.data.repository.ConfigurationRepository import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.shared.model.KeyguardBlueprint Loading @@ -30,7 +29,6 @@ import com.android.systemui.util.ThreadAssert import java.io.PrintWriter import java.util.TreeMap import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow Loading @@ -49,7 +47,6 @@ import kotlinx.coroutines.flow.MutableStateFlow class KeyguardBlueprintRepository @Inject constructor( configurationRepository: ConfigurationRepository, blueprints: Set<@JvmSuppressWildcards KeyguardBlueprint>, @Main val handler: Handler, val assert: ThreadAssert, Loading @@ -60,7 +57,6 @@ constructor( TreeMap<String, KeyguardBlueprint>().apply { putAll(blueprints.associateBy { it.id }) } val blueprint: MutableStateFlow<KeyguardBlueprint> = MutableStateFlow(blueprintIdMap[DEFAULT]!!) val refreshTransition = MutableSharedFlow<Config>(extraBufferCapacity = 1) val configurationChange: Flow<Unit> = configurationRepository.onAnyConfigurationChange private var targetTransitionConfig: Config? = null /** Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorTest.kt +11 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,17 @@ class FingerprintPropertyInteractorTest : SysuiTestCase() { private val configurationRepository by lazy { kosmos.fakeConfigurationRepository } private val displayRepository by lazy { kosmos.displayRepository } @Test fun propertiesInitialized() = testScope.runTest { val propertiesInitialized by collectLastValue(underTest.propertiesInitialized) assertThat(propertiesInitialized).isFalse() repository.supportsUdfps() runCurrent() assertThat(propertiesInitialized).isTrue() } @Test fun sensorLocation_resolution1f() = testScope.runTest { Loading
packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt +32 −4 Original line number Diff line number Diff line Loading @@ -51,6 +51,8 @@ import kotlinx.coroutines.withContext * There is never more than one instance of the FingerprintProperty at any given time. */ interface FingerprintPropertyRepository { /** Whether the fingerprint properties have been initialized yet. */ val propertiesInitialized: StateFlow<Boolean> /** The id of fingerprint sensor. */ val sensorId: Flow<Int> Loading @@ -59,7 +61,7 @@ interface FingerprintPropertyRepository { val strength: Flow<SensorStrength> /** The types of fingerprint sensor (rear, ultrasonic, optical, etc.). */ val sensorType: Flow<FingerprintSensorType> val sensorType: StateFlow<FingerprintSensorType> /** The sensor location relative to each physical display. */ val sensorLocations: Flow<Map<String, SensorLocationInternal>> Loading Loading @@ -105,15 +107,30 @@ constructor( .stateIn( applicationScope, started = SharingStarted.Eagerly, initialValue = DEFAULT_PROPS, initialValue = UNINITIALIZED_PROPS, ) override val propertiesInitialized: StateFlow<Boolean> = props .map { it != UNINITIALIZED_PROPS } .stateIn( applicationScope, started = SharingStarted.WhileSubscribed(), initialValue = props.value != UNINITIALIZED_PROPS, ) override val sensorId: Flow<Int> = props.map { it.sensorId } override val strength: Flow<SensorStrength> = props.map { it.sensorStrength.toSensorStrength() } override val sensorType: Flow<FingerprintSensorType> = props.map { it.sensorType.toSensorType() } override val sensorType: StateFlow<FingerprintSensorType> = props .map { it.sensorType.toSensorType() } .stateIn( scope = applicationScope, started = SharingStarted.WhileSubscribed(), initialValue = props.value.sensorType.toSensorType(), ) override val sensorLocations: Flow<Map<String, SensorLocationInternal>> = props.map { Loading @@ -124,6 +141,17 @@ constructor( companion object { private const val TAG = "FingerprintPropertyRepositoryImpl" private val UNINITIALIZED_PROPS = FingerprintSensorPropertiesInternal( -2 /* sensorId */, SensorProperties.STRENGTH_CONVENIENCE, 0 /* maxEnrollmentsPerUser */, listOf<ComponentInfoInternal>(), FingerprintSensorProperties.TYPE_UNKNOWN, false /* halControlsIllumination */, true /* resetLockoutRequiresHardwareAuthToken */, listOf<SensorLocationInternal>(SensorLocationInternal.DEFAULT) ) private val DEFAULT_PROPS = FingerprintSensorPropertiesInternal( -1 /* sensorId */, Loading
packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt +14 −1 Original line number Diff line number Diff line Loading @@ -24,22 +24,35 @@ import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn @SysUISingleton class FingerprintPropertyInteractor @Inject constructor( @Application private val applicationScope: CoroutineScope, @Application private val context: Context, repository: FingerprintPropertyRepository, configurationInteractor: ConfigurationInteractor, displayStateInteractor: DisplayStateInteractor, ) { val isUdfps: Flow<Boolean> = repository.sensorType.map { it.isUdfps() } val propertiesInitialized: StateFlow<Boolean> = repository.propertiesInitialized val isUdfps: StateFlow<Boolean> = repository.sensorType .map { it.isUdfps() } .stateIn( scope = applicationScope, started = SharingStarted.WhileSubscribed(), initialValue = repository.sensorType.value.isUdfps(), ) /** * Devices with multiple physical displays use unique display ids to determine which sensor is Loading
packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractor.kt +4 −5 Original line number Diff line number Diff line Loading @@ -16,17 +16,17 @@ package com.android.systemui.deviceentry.domain.interactor import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository import com.android.systemui.biometrics.domain.interactor.FingerprintPropertyInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map /** Encapsulates business logic for device entry under-display fingerprint state changes. */ @ExperimentalCoroutinesApi Loading @@ -34,14 +34,13 @@ import kotlinx.coroutines.flow.map class DeviceEntryUdfpsInteractor @Inject constructor( fingerprintPropertyInteractor: FingerprintPropertyInteractor, // TODO (b/309655554): create & use interactors for these repositories fingerprintPropertyRepository: FingerprintPropertyRepository, fingerprintAuthRepository: DeviceEntryFingerprintAuthRepository, biometricSettingsRepository: BiometricSettingsRepository, ) { /** Whether the device supports an under display fingerprint sensor. */ val isUdfpsSupported: Flow<Boolean> = fingerprintPropertyRepository.sensorType.map { it.isUdfps() } val isUdfpsSupported: StateFlow<Boolean> = fingerprintPropertyInteractor.isUdfps /** Whether the under-display fingerprint sensor is enrolled and enabled for device entry. */ val isUdfpsEnrolledAndEnabled: Flow<Boolean> = Loading
packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt +0 −4 Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.data.repository import android.os.Handler import android.util.Log import com.android.systemui.common.ui.data.repository.ConfigurationRepository import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.shared.model.KeyguardBlueprint Loading @@ -30,7 +29,6 @@ import com.android.systemui.util.ThreadAssert import java.io.PrintWriter import java.util.TreeMap import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow Loading @@ -49,7 +47,6 @@ import kotlinx.coroutines.flow.MutableStateFlow class KeyguardBlueprintRepository @Inject constructor( configurationRepository: ConfigurationRepository, blueprints: Set<@JvmSuppressWildcards KeyguardBlueprint>, @Main val handler: Handler, val assert: ThreadAssert, Loading @@ -60,7 +57,6 @@ constructor( TreeMap<String, KeyguardBlueprint>().apply { putAll(blueprints.associateBy { it.id }) } val blueprint: MutableStateFlow<KeyguardBlueprint> = MutableStateFlow(blueprintIdMap[DEFAULT]!!) val refreshTransition = MutableSharedFlow<Config>(extraBufferCapacity = 1) val configurationChange: Flow<Unit> = configurationRepository.onAnyConfigurationChange private var targetTransitionConfig: Config? = null /** Loading