diff options
| author | 2024-01-12 21:15:37 +0000 | |
|---|---|---|
| committer | 2024-01-12 21:15:37 +0000 | |
| commit | 4ed5d552595bf193f3f04c8730c216d32e874d30 (patch) | |
| tree | bd2dfe72ce2480febb371fcb67d37f8c92c04ddf | |
| parent | 697e97bc53552faae6717010959f1aa3aa2a2418 (diff) | |
| parent | 87fa0068f32fdbf687f72ff4616cedccc4bfe8c2 (diff) | |
Merge "Introduce and use FingerprintPropertyInteractor" into main
8 files changed, 359 insertions, 11 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorTest.kt new file mode 100644 index 000000000000..ccf119ab3088 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorTest.kt @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2024 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.domain.interactor + +import android.hardware.biometrics.SensorLocationInternal +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository +import com.android.systemui.biometrics.shared.model.FingerprintSensorType +import com.android.systemui.biometrics.shared.model.SensorStrength +import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.display.data.repository.displayRepository +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(AndroidJUnit4::class) +class FingerprintPropertyInteractorTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val underTest = kosmos.fingerprintPropertyInteractor + private val repository = kosmos.fingerprintPropertyRepository + private val configurationRepository = kosmos.fakeConfigurationRepository + private val displayRepository = kosmos.displayRepository + + @Test + fun sensorLocation_resolution1f() = + testScope.runTest { + val currSensorLocation by collectLastValue(underTest.sensorLocation) + + displayRepository.emitDisplayChangeEvent(0) + runCurrent() + repository.setProperties( + sensorId = 0, + strength = SensorStrength.STRONG, + sensorType = FingerprintSensorType.UDFPS_OPTICAL, + sensorLocations = + mapOf( + Pair("", SensorLocationInternal("", 4, 4, 2)), + Pair("otherDisplay", SensorLocationInternal("", 1, 1, 1)) + ) + ) + runCurrent() + configurationRepository.setScaleForResolution(1f) + runCurrent() + + assertThat(currSensorLocation?.centerX).isEqualTo(4) + assertThat(currSensorLocation?.centerY).isEqualTo(4) + assertThat(currSensorLocation?.radius).isEqualTo(2) + } + + @Test + fun sensorLocation_resolution2f() = + testScope.runTest { + val currSensorLocation by collectLastValue(underTest.sensorLocation) + + displayRepository.emitDisplayChangeEvent(0) + runCurrent() + repository.setProperties( + sensorId = 0, + strength = SensorStrength.STRONG, + sensorType = FingerprintSensorType.UDFPS_OPTICAL, + sensorLocations = + mapOf( + Pair("", SensorLocationInternal("", 4, 4, 2)), + Pair("otherDisplay", SensorLocationInternal("", 1, 1, 1)) + ) + ) + runCurrent() + configurationRepository.setScaleForResolution(2f) + runCurrent() + + assertThat(currSensorLocation?.centerX).isEqualTo(4 * 2) + assertThat(currSensorLocation?.centerY).isEqualTo(4 * 2) + assertThat(currSensorLocation?.radius).isEqualTo(2 * 2) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt new file mode 100644 index 000000000000..e6939f06b642 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2024 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.domain.interactor + +import android.content.Context +import android.hardware.biometrics.SensorLocationInternal +import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository +import com.android.systemui.biometrics.shared.model.SensorLocation +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.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.map + +@SysUISingleton +class FingerprintPropertyInteractor +@Inject +constructor( + @Application private val context: Context, + repository: FingerprintPropertyRepository, + configurationInteractor: ConfigurationInteractor, + displayStateInteractor: DisplayStateInteractor, +) { + /** + * Devices with multiple physical displays use unique display ids to determine which sensor is + * on the active physical display. This value represents a unique physical display id. + */ + private val uniqueDisplayId: Flow<String> = + displayStateInteractor.displayChanges + .map { context.display?.uniqueId } + .filterNotNull() + .distinctUntilChanged() + + /** + * Sensor location for the: + * - current physical display + * - device's natural screen resolution + * - device's natural orientation + */ + private val unscaledSensorLocation: Flow<SensorLocationInternal> = + combine( + repository.sensorLocations, + uniqueDisplayId, + ) { locations, displayId -> + // Devices without multiple physical displays do not use the display id as the key; + // instead, the key is an empty string. + locations.getOrDefault( + displayId, + locations.getOrDefault("", SensorLocationInternal.DEFAULT) + ) + } + + /** + * Sensor location for the: + * - current physical display + * - current screen resolution + * - device's natural orientation + */ + val sensorLocation: Flow<SensorLocation> = + combine( + unscaledSensorLocation, + configurationInteractor.scaleForResolution, + ) { unscaledSensorLocation, scale -> + val sensorLocation = + SensorLocation( + unscaledSensorLocation.sensorLocationX, + unscaledSensorLocation.sensorLocationY, + unscaledSensorLocation.sensorRadius, + ) + sensorLocation.scale = scale + sensorLocation + } +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorLocation.kt b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorLocation.kt new file mode 100644 index 000000000000..dddadbd5e036 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorLocation.kt @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024 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 + +/** Provides current sensor location information in the current screen resolution [scale]. */ +data class SensorLocation( + private val naturalCenterX: Int, + private val naturalCenterY: Int, + private val naturalRadius: Int +) { + /** + * Scale to apply to the sensor location's natural parameters to support different screen + * resolutions. + */ + var scale: Float = 1f + + val centerX: Float + get() { + return naturalCenterX * scale + } + val centerY: Float + get() { + return naturalCenterY * scale + } + val radius: Float + get() { + return naturalRadius * scale + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt index fa4de044623d..ce4511237e40 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt @@ -17,14 +17,12 @@ package com.android.systemui.keyguard.ui.viewmodel import android.content.Context -import android.hardware.biometrics.SensorLocationInternal import com.android.settingslib.Utils -import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository +import com.android.systemui.biometrics.domain.interactor.FingerprintPropertyInteractor import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor import com.android.systemui.keyguard.ui.view.DeviceEntryIconView -import com.android.systemui.res.R import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow @@ -44,21 +42,24 @@ constructor( configurationInteractor: ConfigurationInteractor, deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, deviceEntryBackgroundViewModel: DeviceEntryBackgroundViewModel, - fingerprintPropertyRepository: FingerprintPropertyRepository, + fingerprintPropertyInteractor: FingerprintPropertyInteractor, udfpsOverlayInteractor: UdfpsOverlayInteractor, ) { private val isSupported: Flow<Boolean> = deviceEntryUdfpsInteractor.isUdfpsSupported + + /** + * UDFPS icon location in pixels for the current display and screen resolution, in natural + * orientation. + */ val iconLocation: Flow<IconLocation> = isSupported.flatMapLatest { supportsUI -> if (supportsUI) { - fingerprintPropertyRepository.sensorLocations.map { sensorLocations -> - val sensorLocation = - sensorLocations.getOrDefault("", SensorLocationInternal.DEFAULT) + fingerprintPropertyInteractor.sensorLocation.map { sensorLocation -> IconLocation( - left = sensorLocation.sensorLocationX - sensorLocation.sensorRadius, - top = sensorLocation.sensorLocationY - sensorLocation.sensorRadius, - right = sensorLocation.sensorLocationX + sensorLocation.sensorRadius, - bottom = sensorLocation.sensorLocationY + sensorLocation.sensorRadius, + left = (sensorLocation.centerX - sensorLocation.radius).toInt(), + top = (sensorLocation.centerY - sensorLocation.radius).toInt(), + right = (sensorLocation.centerX + sensorLocation.radius).toInt(), + bottom = (sensorLocation.centerY + sensorLocation.radius).toInt(), ) } } else { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractorKosmos.kt new file mode 100644 index 000000000000..4a089d3c6d7c --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractorKosmos.kt @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2024 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.domain.interactor + +import android.content.applicationContext +import com.android.systemui.display.data.repository.displayRepository +import com.android.systemui.display.data.repository.displayStateRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.util.mockito.mock +import java.util.concurrent.Executor + +val Kosmos.displayStateInteractor by Fixture { + DisplayStateInteractorImpl( + applicationScope = applicationCoroutineScope, + context = applicationContext, + mainExecutor = mock<Executor>(), + displayStateRepository = displayStateRepository, + displayRepository = displayRepository, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorKosmos.kt new file mode 100644 index 000000000000..e26206625c6d --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorKosmos.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2024 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.domain.interactor + +import android.content.applicationContext +import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository +import com.android.systemui.common.ui.domain.interactor.configurationInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture + +val Kosmos.fingerprintPropertyInteractor by Fixture { + FingerprintPropertyInteractor( + context = applicationContext, + repository = fingerprintPropertyRepository, + configurationInteractor = configurationInteractor, + displayStateInteractor = displayStateInteractor, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayRepositoryKosmos.kt new file mode 100644 index 000000000000..048ea3c25388 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayRepositoryKosmos.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2024 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.display.data.repository + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture + +val Kosmos.displayRepository by Fixture { FakeDisplayRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayStateRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayStateRepositoryKosmos.kt new file mode 100644 index 000000000000..4a71a099d0d5 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayStateRepositoryKosmos.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 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.display.data.repository + +import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture + +val Kosmos.displayStateRepository by Fixture { FakeDisplayStateRepository() } |