diff options
| author | 2023-04-07 17:54:00 +0000 | |
|---|---|---|
| committer | 2023-04-14 20:32:29 +0000 | |
| commit | 3a1d6c6353843d9dd86e8957fb65397780d85b44 (patch) | |
| tree | 046c188941463e5e213a34e2cfafb8df6d6cc4d5 | |
| parent | 6bd2d7c6c403e0c5fb140f96f7c54263b61cce6e (diff) | |
FingerprintSensorProperties refactor - data layer
Step 1/3, add repo layer for global application state of FingerprintProperty.
Bug: 276450632
Test: atest FingerprintRepositoryImplTest
Change-Id: I611524ed2a5e7d27488e841935cad6883264ff0f
6 files changed, 391 insertions, 0 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt index 67d2f308d326..f0b9f670f1e0 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt @@ -17,6 +17,8 @@ package com.android.systemui.biometrics.dagger import com.android.settingslib.udfps.UdfpsUtils +import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository +import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepositoryImpl import com.android.systemui.biometrics.data.repository.PromptRepository import com.android.systemui.biometrics.data.repository.PromptRepositoryImpl import com.android.systemui.biometrics.domain.interactor.CredentialInteractor @@ -41,6 +43,11 @@ interface BiometricsModule { @Binds @SysUISingleton + fun fingerprintRepository(impl: FingerprintPropertyRepositoryImpl): + FingerprintPropertyRepository + + @Binds + @SysUISingleton fun providesCredentialInteractor(impl: CredentialInteractorImpl): CredentialInteractor @Binds diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt new file mode 100644 index 000000000000..33fb36c15c2d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.biometrics.data.repository + +import android.hardware.biometrics.SensorLocationInternal +import android.hardware.fingerprint.FingerprintManager +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal +import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback +import com.android.systemui.biometrics.shared.model.FingerprintSensorType +import com.android.systemui.biometrics.shared.model.SensorStrength +import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging +import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.shareIn + +/** + * A repository for the global state of FingerprintProperty. + * + * There is never more than one instance of the FingerprintProperty at any given time. + */ +interface FingerprintPropertyRepository { + + /** + * If the repository is initialized or not. Other properties are defaults until this is true. + */ + val isInitialized: Flow<Boolean> + + /** The id of fingerprint sensor. */ + val sensorId: StateFlow<Int> + + /** The security strength of sensor (convenience, weak, strong). */ + val strength: StateFlow<SensorStrength> + + /** The types of fingerprint sensor (rear, ultrasonic, optical, etc.). */ + val sensorType: StateFlow<FingerprintSensorType> + + /** The primary sensor location relative to the default display. */ + val sensorLocation: StateFlow<SensorLocationInternal> + + // TODO(b/251476085): don't implement until we need it, but expose alternative locations as + // a map of display id -> location or similar. + /** The sensor location relative to each physical display. */ + // val sensorLocations<Map<String, SensorLocationInternal>> +} + +@SysUISingleton +class FingerprintPropertyRepositoryImpl +@Inject +constructor( + @Application private val applicationScope: CoroutineScope, + private val fingerprintManager: FingerprintManager +) : FingerprintPropertyRepository { + + override val isInitialized: Flow<Boolean> = + conflatedCallbackFlow { + val callback = + object : IFingerprintAuthenticatorsRegisteredCallback.Stub() { + override fun onAllAuthenticatorsRegistered( + sensors: List<FingerprintSensorPropertiesInternal> + ) { + if (sensors.isNotEmpty()) { + setProperties(sensors[0]) + trySendWithFailureLogging(true, TAG, "initialize properties") + } + } + } + fingerprintManager.addAuthenticatorsRegisteredCallback(callback) + trySendWithFailureLogging(false, TAG, "initial value defaulting to false") + awaitClose {} + } + .shareIn(scope = applicationScope, started = SharingStarted.Eagerly, replay = 1) + + private val _sensorId: MutableStateFlow<Int> = MutableStateFlow(-1) + override val sensorId: StateFlow<Int> = _sensorId.asStateFlow() + + private val _strength: MutableStateFlow<SensorStrength> = + MutableStateFlow(SensorStrength.CONVENIENCE) + override val strength = _strength.asStateFlow() + + private val _sensorType: MutableStateFlow<FingerprintSensorType> = + MutableStateFlow(FingerprintSensorType.UNKNOWN) + override val sensorType = _sensorType.asStateFlow() + + private val _sensorLocation: MutableStateFlow<SensorLocationInternal> = + MutableStateFlow(SensorLocationInternal.DEFAULT) + override val sensorLocation = _sensorLocation.asStateFlow() + + private fun setProperties(prop: FingerprintSensorPropertiesInternal) { + _sensorId.value = prop.sensorId + _strength.value = sensorStrengthIntToObject(prop.sensorStrength) + _sensorType.value = sensorTypeIntToObject(prop.sensorType) + _sensorLocation.value = prop.location + } + + companion object { + private const val TAG = "FingerprintPropertyRepositoryImpl" + } +} + +private fun sensorStrengthIntToObject(value: Int): SensorStrength { + return when (value) { + 0 -> SensorStrength.CONVENIENCE + 1 -> SensorStrength.WEAK + 2 -> SensorStrength.STRONG + else -> throw IllegalArgumentException("Invalid SensorStrength value: $value") + } +} + +private fun sensorTypeIntToObject(value: Int): FingerprintSensorType { + return when (value) { + 0 -> FingerprintSensorType.UNKNOWN + 1 -> FingerprintSensorType.REAR + 2 -> FingerprintSensorType.UDFPS_ULTRASONIC + 3 -> FingerprintSensorType.UDFPS_OPTICAL + 4 -> FingerprintSensorType.POWER_BUTTON + 5 -> FingerprintSensorType.HOME_BUTTON + else -> throw IllegalArgumentException("Invalid SensorType value: $value") + } +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt new file mode 100644 index 000000000000..df5cefdb876d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.biometrics.shared.model + +import android.hardware.fingerprint.FingerprintSensorProperties + +/** Fingerprint sensor types. Represents [FingerprintSensorProperties.SensorType]. */ +enum class FingerprintSensorType { + UNKNOWN, + REAR, + UDFPS_ULTRASONIC, + UDFPS_OPTICAL, + POWER_BUTTON, + HOME_BUTTON, +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt new file mode 100644 index 000000000000..2982d0be3764 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.biometrics.shared.model + +import android.hardware.biometrics.SensorProperties + +/** Fingerprint sensor security strength. Represents [SensorProperties.Strength]. */ +enum class SensorStrength { + CONVENIENCE, + WEAK, + STRONG, +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt new file mode 100644 index 000000000000..f3a100bd55e5 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.biometrics.data.repository + +import android.hardware.biometrics.ComponentInfoInternal +import android.hardware.biometrics.SensorLocationInternal +import android.hardware.biometrics.SensorProperties +import android.hardware.fingerprint.FingerprintManager +import android.hardware.fingerprint.FingerprintSensorProperties +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal +import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.shared.model.FingerprintSensorType +import com.android.systemui.biometrics.shared.model.SensorStrength +import com.android.systemui.coroutines.collectLastValue +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.mockito.ArgumentCaptor +import org.mockito.Captor +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.junit.MockitoJUnit + +@SmallTest +@RunWith(JUnit4::class) +class FingerprintRepositoryImplTest : SysuiTestCase() { + + @JvmField @Rule var mockitoRule = MockitoJUnit.rule() + private lateinit var testScope: TestScope + + @Mock private lateinit var fingerprintManager: FingerprintManager + private lateinit var repository: FingerprintPropertyRepositoryImpl + + @Captor + private lateinit var fingerprintAuthenticatorsCaptor: + ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback.Stub> + + @Before + fun setup() { + val dispatcher = StandardTestDispatcher() + testScope = TestScope(dispatcher) + repository = + FingerprintPropertyRepositoryImpl(testScope.backgroundScope, fingerprintManager) + testScope.runCurrent() + + verify(fingerprintManager) + .addAuthenticatorsRegisteredCallback(fingerprintAuthenticatorsCaptor.capture()) + } + + @Test + fun initializeProperties() = + testScope.runTest { + val isInitialized = collectLastValue(repository.isInitialized) + + assertDefaultProperties() + assertThat(isInitialized()).isFalse() + + val fingerprintProps = + listOf( + FingerprintSensorPropertiesInternal( + 1 /* sensorId */, + SensorProperties.STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, + listOf<ComponentInfoInternal>( + ComponentInfoInternal( + "sensor" /* componentId */, + "vendor/model/revision" /* hardwareVersion */, + "1.01" /* firmwareVersion */, + "00000001" /* serialNumber */, + "" /* softwareVersion */ + ) + ), + FingerprintSensorProperties.TYPE_REAR, + false /* halControlsIllumination */, + true /* resetLockoutRequiresHardwareAuthToken */, + listOf<SensorLocationInternal>( + SensorLocationInternal( + "" /* displayId */, + 540 /* sensorLocationX */, + 1636 /* sensorLocationY */, + 130 /* sensorRadius */ + ) + ) + ) + ) + + fingerprintAuthenticatorsCaptor.value.onAllAuthenticatorsRegistered(fingerprintProps) + + assertThat(repository.sensorId.value).isEqualTo(1) + assertThat(repository.strength.value).isEqualTo(SensorStrength.STRONG) + assertThat(repository.sensorType.value).isEqualTo(FingerprintSensorType.REAR) + with(repository.sensorLocation.value) { + assertThat(displayId).isEqualTo("") + assertThat(sensorLocationX).isEqualTo(540) + assertThat(sensorLocationY).isEqualTo(1636) + assertThat(sensorRadius).isEqualTo(130) + } + assertThat(isInitialized()).isTrue() + } + + private fun assertDefaultProperties() { + assertThat(repository.sensorId.value).isEqualTo(-1) + assertThat(repository.strength.value).isEqualTo(SensorStrength.CONVENIENCE) + assertThat(repository.sensorType.value).isEqualTo(FingerprintSensorType.UNKNOWN) + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt new file mode 100644 index 000000000000..d9012a527726 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.biometrics.data.repository + +import android.hardware.biometrics.SensorLocationInternal +import com.android.systemui.biometrics.shared.model.FingerprintSensorType +import com.android.systemui.biometrics.shared.model.SensorStrength +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow + +class FakeFingerprintPropertyRepository : FingerprintPropertyRepository { + + private val _isInitialized: MutableStateFlow<Boolean> = MutableStateFlow(false) + override val isInitialized = _isInitialized.asStateFlow() + + private val _sensorId: MutableStateFlow<Int> = MutableStateFlow(-1) + override val sensorId: StateFlow<Int> = _sensorId.asStateFlow() + + private val _strength: MutableStateFlow<SensorStrength> = + MutableStateFlow(SensorStrength.CONVENIENCE) + override val strength = _strength.asStateFlow() + + private val _sensorType: MutableStateFlow<FingerprintSensorType> = + MutableStateFlow(FingerprintSensorType.UNKNOWN) + override val sensorType: StateFlow<FingerprintSensorType> = _sensorType.asStateFlow() + + private val _sensorLocation: MutableStateFlow<SensorLocationInternal> = + MutableStateFlow(SensorLocationInternal.DEFAULT) + override val sensorLocation = _sensorLocation.asStateFlow() + + fun setProperties( + sensorId: Int, + strength: SensorStrength, + sensorType: FingerprintSensorType, + sensorLocation: SensorLocationInternal + ) { + _sensorId.value = sensorId + _strength.value = strength + _sensorType.value = sensorType + _sensorLocation.value = sensorLocation + _isInitialized.value = true + } +} |