Merge "FingerprintSensorProperties refactor - data layer" into udc-dev
This commit is contained in:
@@ -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
|
||||
@@ -39,6 +41,11 @@ interface BiometricsModule {
|
||||
@SysUISingleton
|
||||
fun biometricPromptRepository(impl: PromptRepositoryImpl): PromptRepository
|
||||
|
||||
@Binds
|
||||
@SysUISingleton
|
||||
fun fingerprintRepository(impl: FingerprintPropertyRepositoryImpl):
|
||||
FingerprintPropertyRepository
|
||||
|
||||
@Binds
|
||||
@SysUISingleton
|
||||
fun providesCredentialInteractor(impl: CredentialInteractorImpl): CredentialInteractor
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user