diff --git a/src/com/android/settings/SettingsApplication.java b/src/com/android/settings/SettingsApplication.java index 5b052f22dc7..d208fdf09e1 100644 --- a/src/com/android/settings/SettingsApplication.java +++ b/src/com/android/settings/SettingsApplication.java @@ -18,7 +18,9 @@ package com.android.settings; import android.app.Application; import android.content.Context; +import android.content.pm.PackageManager; import android.database.ContentObserver; +import android.hardware.fingerprint.FingerprintManager; import android.net.Uri; import android.provider.Settings; import android.util.FeatureFlagUtils; @@ -74,9 +76,6 @@ public class SettingsApplication extends Application { // Set Spa environment. setSpaEnvironment(); - if (Flags.fingerprintV2Enrollment()) { - mBiometricsEnvironment = new BiometricsEnvironment(this); - } if (ActivityEmbeddingUtils.isSettingsSplitEnabled(this) && FeatureFlagUtils.isEnabled(this, @@ -120,7 +119,20 @@ public class SettingsApplication extends Application { @Nullable public BiometricsEnvironment getBiometricEnvironment() { - return mBiometricsEnvironment; + if (Flags.fingerprintV2Enrollment()) { + if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) { + final FingerprintManager fpm = getSystemService(FingerprintManager.class); + if (mBiometricsEnvironment == null) { + mBiometricsEnvironment = new BiometricsEnvironment(this, fpm); + } + return mBiometricsEnvironment; + + } else { + return null; + } + + } + return null; } @Override diff --git a/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt b/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt index 9bc920a96ba..e3233ed22b1 100644 --- a/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt +++ b/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt @@ -16,12 +16,9 @@ package com.android.settings.biometrics.fingerprint2 -import android.content.pm.PackageManager import android.hardware.fingerprint.FingerprintManager -import android.os.ServiceManager.ServiceNotFoundException import android.view.MotionEvent import android.view.accessibility.AccessibilityManager -import androidx.fragment.app.FragmentActivity import androidx.lifecycle.ViewModelStore import androidx.lifecycle.ViewModelStoreOwner import com.android.internal.widget.LockPatternUtils @@ -29,33 +26,47 @@ import com.android.settings.SettingsApplication import com.android.settings.biometrics.GatekeeperPasswordProvider import com.android.settings.biometrics.fingerprint2.data.repository.DebuggingRepository import com.android.settings.biometrics.fingerprint2.data.repository.DebuggingRepositoryImpl +import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintEnrollmentRepositoryImpl import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepository import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepositoryImpl +import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSettingsRepositoryImpl +import com.android.settings.biometrics.fingerprint2.data.repository.UserRepoImpl import com.android.settings.biometrics.fingerprint2.debug.data.repository.UdfpsEnrollDebugRepositoryImpl import com.android.settings.biometrics.fingerprint2.debug.domain.interactor.DebugTouchEventInteractorImpl import com.android.settings.biometrics.fingerprint2.domain.interactor.AccessibilityInteractor import com.android.settings.biometrics.fingerprint2.domain.interactor.AccessibilityInteractorImpl +import com.android.settings.biometrics.fingerprint2.domain.interactor.AuthenticateInteractorImpl +import com.android.settings.biometrics.fingerprint2.domain.interactor.CanEnrollFingerprintsInteractorImpl import com.android.settings.biometrics.fingerprint2.domain.interactor.DebuggingInteractor import com.android.settings.biometrics.fingerprint2.domain.interactor.DebuggingInteractorImpl import com.android.settings.biometrics.fingerprint2.domain.interactor.DisplayDensityInteractor import com.android.settings.biometrics.fingerprint2.domain.interactor.DisplayDensityInteractorImpl +import com.android.settings.biometrics.fingerprint2.domain.interactor.EnrollFingerprintInteractorImpl import com.android.settings.biometrics.fingerprint2.domain.interactor.EnrollStageInteractor import com.android.settings.biometrics.fingerprint2.domain.interactor.EnrollStageInteractorImpl -import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintEnrollInteractor -import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintEnrollInteractorImpl -import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl +import com.android.settings.biometrics.fingerprint2.domain.interactor.EnrolledFingerprintsInteractorImpl import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintSensorInteractor import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintSensorInteractorImpl import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateInteractor import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateInteractorImpl +import com.android.settings.biometrics.fingerprint2.domain.interactor.GenerateChallengeInteractorImpl import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractorImpl +import com.android.settings.biometrics.fingerprint2.domain.interactor.RemoveFingerprintsInteractorImpl +import com.android.settings.biometrics.fingerprint2.domain.interactor.RenameFingerprintsInteractorImpl +import com.android.settings.biometrics.fingerprint2.domain.interactor.SensorInteractorImpl import com.android.settings.biometrics.fingerprint2.domain.interactor.TouchEventInteractor import com.android.settings.biometrics.fingerprint2.domain.interactor.UdfpsEnrollInteractor import com.android.settings.biometrics.fingerprint2.domain.interactor.UdfpsEnrollInteractorImpl import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractor import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractorImpl -import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.AuthenitcateInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.CanEnrollFingerprintsInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.EnrollFingerprintInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.GenerateChallengeInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.RemoveFingerprintInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.RenameFingerprintInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.SensorInteractor import com.android.settings.biometrics.fingerprint2.lib.model.Settings import java.util.concurrent.Executors import kotlinx.coroutines.MainScope @@ -70,43 +81,53 @@ import kotlinx.coroutines.flow.flowOf * This code is instantiated within the [SettingsApplication], all repos should be private & * immutable and all interactors should public and immutable */ -class BiometricsEnvironment(context: SettingsApplication) : ViewModelStoreOwner { - +class BiometricsEnvironment( + val context: SettingsApplication, + private val fingerprintManager: FingerprintManager, +) : ViewModelStoreOwner { private val executorService = Executors.newSingleThreadExecutor() private val backgroundDispatcher = executorService.asCoroutineDispatcher() private val applicationScope = MainScope() private val gateKeeperPasswordProvider = GatekeeperPasswordProvider(LockPatternUtils(context)) - private val fingerprintManager = try { - if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) { - context.getSystemService(FragmentActivity.FINGERPRINT_SERVICE) as FingerprintManager? - } else { - null - } - } catch (exception: ServiceNotFoundException){ - null - } + private val userRepo = UserRepoImpl(context.userId) + private val fingerprintSettingsRepository = + FingerprintSettingsRepositoryImpl( + context.resources.getInteger( + com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser + ) + ) + private val fingerprintEnrollmentRepository = + FingerprintEnrollmentRepositoryImpl(fingerprintManager, userRepo, fingerprintSettingsRepository, + backgroundDispatcher, applicationScope) private val fingerprintSensorRepository: FingerprintSensorRepository = FingerprintSensorRepositoryImpl(fingerprintManager, backgroundDispatcher, applicationScope) private val debuggingRepository: DebuggingRepository = DebuggingRepositoryImpl() private val udfpsDebugRepo = UdfpsEnrollDebugRepositoryImpl() - /** For now, interactors are public to those with access to the [BiometricsEnvironment] class */ - val fingerprintEnrollInteractor: FingerprintEnrollInteractor by lazy { - FingerprintEnrollInteractorImpl(context, fingerprintManager, Settings) - } + fun createSensorPropertiesInteractor(): SensorInteractor = + SensorInteractorImpl(fingerprintSensorRepository) - /** [FingerprintManagerInteractor] to be used to construct view models */ - val fingerprintManagerInteractor: FingerprintManagerInteractor by lazy { - FingerprintManagerInteractorImpl( - context, - backgroundDispatcher, - fingerprintManager, - fingerprintSensorRepository, - gateKeeperPasswordProvider, - fingerprintEnrollInteractor, - ) - } + fun createCanEnrollFingerprintsInteractor(): CanEnrollFingerprintsInteractor = + CanEnrollFingerprintsInteractorImpl(fingerprintEnrollmentRepository) + + fun createGenerateChallengeInteractor(): GenerateChallengeInteractor = + GenerateChallengeInteractorImpl(fingerprintManager, context.userId, gateKeeperPasswordProvider) + + fun createFingerprintEnrollInteractor(): EnrollFingerprintInteractor = + EnrollFingerprintInteractorImpl(context.userId, fingerprintManager, Settings) + + fun createFingerprintsEnrolledInteractor(): EnrolledFingerprintsInteractorImpl = + EnrolledFingerprintsInteractorImpl(fingerprintManager, context.userId) + + fun createAuthenticateInteractor(): AuthenitcateInteractor = + AuthenticateInteractorImpl(fingerprintManager, context.userId) + + fun createRemoveFingerprintInteractor(): RemoveFingerprintInteractor = + RemoveFingerprintsInteractorImpl(fingerprintManager, context.userId) + + fun createRenameFingerprintInteractor(): RenameFingerprintInteractor = + RenameFingerprintsInteractorImpl(fingerprintManager, context.userId, backgroundDispatcher) val accessibilityInteractor: AccessibilityInteractor by lazy { AccessibilityInteractorImpl( diff --git a/src/com/android/settings/biometrics/fingerprint2/data/repository/FingerprintEnrollmentRepo.kt b/src/com/android/settings/biometrics/fingerprint2/data/repository/FingerprintEnrollmentRepo.kt new file mode 100644 index 00000000000..22904e9d2ac --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint2/data/repository/FingerprintEnrollmentRepo.kt @@ -0,0 +1,98 @@ +/* + * 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.settings.biometrics.fingerprint2.data.repository + +import android.hardware.biometrics.BiometricStateListener +import android.hardware.fingerprint.FingerprintManager +import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.withContext + +/** Repository that contains information about fingerprint enrollments. */ +interface FingerprintEnrollmentRepository { + /** The current enrollments of the user */ + val currentEnrollments: Flow?> + + /** Indicates if a user can enroll another fingerprint */ + val canEnrollUser: Flow + + fun maxFingerprintsEnrollable(): Int +} + +class FingerprintEnrollmentRepositoryImpl( + fingerprintManager: FingerprintManager, + userRepo: UserRepo, + private val settingsRepository: FingerprintSettingsRepository, + backgroundDispatcher: CoroutineDispatcher, + applicationScope: CoroutineScope, +) : FingerprintEnrollmentRepository { + + private val enrollmentChangedFlow: Flow = + callbackFlow { + val callback = + object : BiometricStateListener() { + override fun onEnrollmentsChanged(userId: Int, sensorId: Int, hasEnrollments: Boolean) { + trySend(userId) + } + } + withContext(backgroundDispatcher) { + fingerprintManager.registerBiometricStateListener(callback) + } + awaitClose { + // no way to unregister + } + } + .stateIn(applicationScope, started = SharingStarted.Eagerly, initialValue = null) + + override val currentEnrollments: Flow> = + userRepo.currentUser + .distinctUntilChanged() + .flatMapLatest { currentUser -> + enrollmentChangedFlow.map { enrollmentChanged -> + if (enrollmentChanged == null || enrollmentChanged == currentUser) { + fingerprintManager + .getEnrolledFingerprints(currentUser) + ?.map { (FingerprintData(it.name.toString(), it.biometricId, it.deviceId)) } + ?.toList() + } else { + null + } + } + } + .filterNotNull() + .flowOn(backgroundDispatcher) + + override val canEnrollUser: Flow = + currentEnrollments.map { + it?.size?.let { it < settingsRepository.maxEnrollableFingerprints() } ?: false + } + + override fun maxFingerprintsEnrollable(): Int { + return settingsRepository.maxEnrollableFingerprints() + } +} diff --git a/src/com/android/settings/biometrics/fingerprint2/data/repository/FingerprintSensorRepository.kt b/src/com/android/settings/biometrics/fingerprint2/data/repository/FingerprintSensorRepository.kt index 516549e65f4..1cca532c6ac 100644 --- a/src/com/android/settings/biometrics/fingerprint2/data/repository/FingerprintSensorRepository.kt +++ b/src/com/android/settings/biometrics/fingerprint2/data/repository/FingerprintSensorRepository.kt @@ -31,6 +31,8 @@ import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.transform import kotlinx.coroutines.withContext @@ -43,10 +45,13 @@ import kotlinx.coroutines.withContext interface FingerprintSensorRepository { /** Get the [FingerprintSensor] */ val fingerprintSensor: Flow + + /** Indicates if this device supports the side fingerprint sensor */ + val hasSideFps: Flow } class FingerprintSensorRepositoryImpl( - fingerprintManager: FingerprintManager?, + private val fingerprintManager: FingerprintManager, backgroundDispatcher: CoroutineDispatcher, activityScope: CoroutineScope, ) : FingerprintSensorRepository { @@ -66,7 +71,7 @@ class FingerprintSensorRepositoryImpl( } } withContext(backgroundDispatcher) { - fingerprintManager?.addAuthenticatorsRegisteredCallback(callback) + fingerprintManager.addAuthenticatorsRegisteredCallback(callback) } awaitClose {} } @@ -75,6 +80,9 @@ class FingerprintSensorRepositoryImpl( override val fingerprintSensor: Flow = fingerprintPropsInternal.transform { emit(it.toFingerprintSensor()) } + override val hasSideFps: Flow = + fingerprintSensor.flatMapLatest { flow { emit(fingerprintManager.isPowerbuttonFps()) } } + companion object { private val DEFAULT_PROPS = diff --git a/src/com/android/settings/biometrics/fingerprint2/data/repository/FingerprintSettingsRepository.kt b/src/com/android/settings/biometrics/fingerprint2/data/repository/FingerprintSettingsRepository.kt new file mode 100644 index 00000000000..fe6676c1608 --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint2/data/repository/FingerprintSettingsRepository.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.settings.biometrics.fingerprint2.data.repository + +/** + * Repository for storing metadata about fingerprint enrollments. + */ +interface FingerprintSettingsRepository { + /** + * Indicates the maximum number of fingerprints enrollable + */ + fun maxEnrollableFingerprints(): Int +} + +class FingerprintSettingsRepositoryImpl(private val maxFingerprintsEnrollable: Int) : + FingerprintSettingsRepository { + override fun maxEnrollableFingerprints() = maxFingerprintsEnrollable +} diff --git a/src/com/android/settings/biometrics/fingerprint2/data/repository/SimulatedTouchEventsRepository.kt b/src/com/android/settings/biometrics/fingerprint2/data/repository/SimulatedTouchEventsRepository.kt index 3c355e76853..9b7f2808ee7 100644 --- a/src/com/android/settings/biometrics/fingerprint2/data/repository/SimulatedTouchEventsRepository.kt +++ b/src/com/android/settings/biometrics/fingerprint2/data/repository/SimulatedTouchEventsRepository.kt @@ -16,7 +16,6 @@ package com.android.settings.biometrics.fingerprint2.data.repository -import android.graphics.Point import android.view.MotionEvent import kotlinx.coroutines.flow.Flow diff --git a/src/com/android/settings/biometrics/fingerprint2/data/repository/UserRepo.kt b/src/com/android/settings/biometrics/fingerprint2/data/repository/UserRepo.kt new file mode 100644 index 00000000000..720e7787d12 --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint2/data/repository/UserRepo.kt @@ -0,0 +1,34 @@ +/* + * 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.settings.biometrics.fingerprint2.data.repository + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf + +/** + * A repository responsible for indicating the current user. + */ +interface UserRepo { + /** + * This flow indicates the current user. + */ + val currentUser: Flow +} + +class UserRepoImpl(val currUser: Int): UserRepo { + override val currentUser: Flow = flowOf(currUser) +} diff --git a/src/com/android/settings/biometrics/fingerprint2/debug/data/repository/UdfpsEnrollDebugRepository.kt b/src/com/android/settings/biometrics/fingerprint2/debug/data/repository/UdfpsEnrollDebugRepository.kt index 0c3152a83ae..bc48f074329 100644 --- a/src/com/android/settings/biometrics/fingerprint2/debug/data/repository/UdfpsEnrollDebugRepository.kt +++ b/src/com/android/settings/biometrics/fingerprint2/debug/data/repository/UdfpsEnrollDebugRepository.kt @@ -97,6 +97,8 @@ class UdfpsEnrollDebugRepositoryImpl : } override val fingerprintSensor: Flow = flowOf(sensorProps) + override val hasSideFps: Flow + get() = flowOf(false) private fun pointToLeftOfSensor(sensorLocation: Rect): MotionEvent = MotionEvent.obtain( diff --git a/src/com/android/settings/biometrics/fingerprint2/debug/domain/interactor/DebugTouchEventInteractorImpl.kt b/src/com/android/settings/biometrics/fingerprint2/debug/domain/interactor/DebugTouchEventInteractorImpl.kt index fff6b6609fd..f6627e1d8e9 100644 --- a/src/com/android/settings/biometrics/fingerprint2/debug/domain/interactor/DebugTouchEventInteractorImpl.kt +++ b/src/com/android/settings/biometrics/fingerprint2/debug/domain/interactor/DebugTouchEventInteractorImpl.kt @@ -26,4 +26,4 @@ class DebugTouchEventInteractorImpl( ) : TouchEventInteractor { override val touchEvent: Flow = udfpsSimulatedTouchEventsRepository.touchExplorationDebug -} \ No newline at end of file +} diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/AuthenticateInteractorImpl.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/AuthenticateInteractorImpl.kt new file mode 100644 index 00000000000..df93092619f --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/AuthenticateInteractorImpl.kt @@ -0,0 +1,71 @@ +/* + * 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.settings.biometrics.fingerprint2.domain.interactor + +import android.hardware.fingerprint.FingerprintManager +import android.os.CancellationSignal +import android.util.Log +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.AuthenitcateInteractor +import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel +import kotlin.coroutines.resume +import kotlinx.coroutines.CancellableContinuation +import kotlinx.coroutines.suspendCancellableCoroutine + +class AuthenticateInteractorImpl( + private val fingerprintManager: FingerprintManager, + private val userId: Int, +) : AuthenitcateInteractor { + + override suspend fun authenticate(): FingerprintAuthAttemptModel = + suspendCancellableCoroutine { c: CancellableContinuation -> + val authenticationCallback = + object : FingerprintManager.AuthenticationCallback() { + + override fun onAuthenticationError(errorCode: Int, errString: CharSequence) { + super.onAuthenticationError(errorCode, errString) + if (c.isCompleted) { + Log.d(TAG, "framework sent down onAuthError after finish") + return + } + c.resume(FingerprintAuthAttemptModel.Error(errorCode, errString.toString())) + } + + override fun onAuthenticationSucceeded(result: FingerprintManager.AuthenticationResult) { + super.onAuthenticationSucceeded(result) + if (c.isCompleted) { + Log.d(TAG, "framework sent down onAuthError after finish") + return + } + c.resume(FingerprintAuthAttemptModel.Success(result.fingerprint?.biometricId ?: -1)) + } + } + + val cancellationSignal = CancellationSignal() + c.invokeOnCancellation { cancellationSignal.cancel() } + fingerprintManager.authenticate( + null, + cancellationSignal, + authenticationCallback, + null, + userId, + ) + } + + companion object { + private const val TAG = "AuthenticateInteractor" + } +} diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/CanEnrollFingerprintsInteractorImpl.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/CanEnrollFingerprintsInteractorImpl.kt new file mode 100644 index 00000000000..caeea4e4586 --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/CanEnrollFingerprintsInteractorImpl.kt @@ -0,0 +1,31 @@ +/* + * 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.settings.biometrics.fingerprint2.domain.interactor + +import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintEnrollmentRepository +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.CanEnrollFingerprintsInteractor +import kotlinx.coroutines.flow.Flow + +class CanEnrollFingerprintsInteractorImpl( + val fingerprintEnrollmentRepository: FingerprintEnrollmentRepository +) : CanEnrollFingerprintsInteractor { + override val canEnrollFingerprints: Flow = fingerprintEnrollmentRepository.canEnrollUser + /** Indicates the maximum fingerprints enrollable for a given user */ + override fun maxFingerprintsEnrollable(): Int { + return fingerprintEnrollmentRepository.maxFingerprintsEnrollable() + } +} diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/EnrollFingerprintInteractorImpl.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/EnrollFingerprintInteractorImpl.kt new file mode 100644 index 00000000000..3e14a640278 --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/EnrollFingerprintInteractorImpl.kt @@ -0,0 +1,146 @@ +/* + * 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.settings.biometrics.fingerprint2.domain.interactor + +import android.hardware.fingerprint.FingerprintEnrollOptions +import android.hardware.fingerprint.FingerprintManager +import android.os.CancellationSignal +import android.util.Log +import com.android.settings.biometrics.fingerprint2.conversion.Util.toEnrollError +import com.android.settings.biometrics.fingerprint2.conversion.Util.toOriginalReason +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.EnrollFingerprintInteractor +import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason +import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState +import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintFlow +import com.android.settings.biometrics.fingerprint2.lib.model.SetupWizard +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.channels.onFailure +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.update + +class EnrollFingerprintInteractorImpl( + private val userId: Int, + private val fingerprintManager: FingerprintManager, + private val fingerprintFlow: FingerprintFlow, +) : EnrollFingerprintInteractor { + private val enrollRequestOutstanding = MutableStateFlow(false) + + override suspend fun enroll( + hardwareAuthToken: ByteArray?, + enrollReason: EnrollReason, + fingerprintEnrollOptions: FingerprintEnrollOptions, + ): Flow = callbackFlow { + // TODO (b/308456120) Improve this logic + if (enrollRequestOutstanding.value) { + Log.d(TAG, "Outstanding enroll request, waiting 150ms") + delay(150) + if (enrollRequestOutstanding.value) { + Log.e(TAG, "Request still present, continuing") + } + } + + enrollRequestOutstanding.update { true } + + var streamEnded = false + var totalSteps: Int? = null + val enrollmentCallback = + object : FingerprintManager.EnrollmentCallback() { + override fun onEnrollmentProgress(remaining: Int) { + // This is sort of an implementation detail, but unfortunately the API isn't + // very expressive. If anything we should look at changing the FingerprintManager API. + if (totalSteps == null) { + totalSteps = remaining + 1 + } + + trySend(FingerEnrollState.EnrollProgress(remaining, totalSteps!!)).onFailure { error -> + Log.d(TAG, "onEnrollmentProgress($remaining) failed to send, due to $error") + } + + if (remaining == 0) { + streamEnded = true + enrollRequestOutstanding.update { false } + } + } + + override fun onEnrollmentHelp(helpMsgId: Int, helpString: CharSequence?) { + trySend(FingerEnrollState.EnrollHelp(helpMsgId, helpString.toString())).onFailure { error + -> + Log.d(TAG, "onEnrollmentHelp failed to send, due to $error") + } + } + + override fun onEnrollmentError(errMsgId: Int, errString: CharSequence?) { + trySend(errMsgId.toEnrollError(fingerprintFlow == SetupWizard)).onFailure { error -> + Log.d(TAG, "onEnrollmentError failed to send, due to $error") + } + Log.d(TAG, "onEnrollmentError($errMsgId)") + streamEnded = true + enrollRequestOutstanding.update { false } + } + + override fun onUdfpsPointerDown(sensorId: Int) { + trySend(FingerEnrollState.PointerDown(sensorId)).onFailure { error -> + Log.d(TAG, "onUdfpsPointerDown failed to send, due to $error") + } + } + + override fun onUdfpsPointerUp(sensorId: Int) { + trySend(FingerEnrollState.PointerUp(sensorId)).onFailure { error -> + Log.d(TAG, "onUdfpsPointerUp failed to send, due to $error") + } + } + + override fun onUdfpsOverlayShown() { + trySend(FingerEnrollState.OverlayShown).onFailure { error -> + Log.d(TAG, "OverlayShown failed to send, due to $error") + } + } + + override fun onAcquired(isAcquiredGood: Boolean) { + trySend(FingerEnrollState.Acquired(isAcquiredGood)).onFailure { error -> + Log.d(TAG, "Acquired failed to send, due to $error") + } + } + } + + val cancellationSignal = CancellationSignal() + + fingerprintManager.enroll( + hardwareAuthToken, + cancellationSignal, + userId, + enrollmentCallback, + enrollReason.toOriginalReason(), + fingerprintEnrollOptions, + ) + awaitClose { + // If the stream has not been ended, and the user has stopped collecting the flow + // before it was over, send cancel. + if (!streamEnded) { + Log.e(TAG, "Cancel is sent from settings for enroll()") + cancellationSignal.cancel() + } + } + } + + companion object { + private const val TAG = "FingerprintEnrollStateRepository" + } +} diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/EnrolledFingerprintsInteractorImpl.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/EnrolledFingerprintsInteractorImpl.kt new file mode 100644 index 00000000000..83b532ecd98 --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/EnrolledFingerprintsInteractorImpl.kt @@ -0,0 +1,37 @@ +/* + * 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.settings.biometrics.fingerprint2.domain.interactor + +import android.hardware.fingerprint.FingerprintManager +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.EnrolledFingerprintsInteractor +import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow + +class EnrolledFingerprintsInteractorImpl( + private val fingerprintManager: FingerprintManager, + userId: Int, +) : EnrolledFingerprintsInteractor { + override val enrolledFingerprints: Flow?> = flow { + emit( + fingerprintManager + .getEnrolledFingerprints(userId) + ?.map { (FingerprintData(it.name.toString(), it.biometricId, it.deviceId)) } + ?.toList() + ) + } +} diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintEnrollInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintEnrollInteractor.kt index a36832db076..56a125794b7 100644 --- a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintEnrollInteractor.kt +++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintEnrollInteractor.kt @@ -16,7 +16,6 @@ package com.android.settings.biometrics.fingerprint2.domain.interactor -import android.content.Context import android.hardware.fingerprint.FingerprintEnrollOptions import android.hardware.fingerprint.FingerprintManager import android.os.CancellationSignal @@ -49,7 +48,7 @@ interface FingerprintEnrollInteractor { } class FingerprintEnrollInteractorImpl( - private val applicationContext: Context, + private val userId: Int, private val fingerprintManager: FingerprintManager?, private val fingerprintFlow: FingerprintFlow, ) : FingerprintEnrollInteractor { @@ -138,7 +137,7 @@ class FingerprintEnrollInteractorImpl( fingerprintManager?.enroll( hardwareAuthToken, cancellationSignal, - applicationContext.userId, + userId, enrollmentCallback, enrollReason.toOriginalReason(), fingerprintEnrollOptions, diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintManagerInteractorImpl.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintManagerInteractorImpl.kt deleted file mode 100644 index f03c94ea047..00000000000 --- a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintManagerInteractorImpl.kt +++ /dev/null @@ -1,173 +0,0 @@ -/* - * 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.settings.biometrics.fingerprint2.domain.interactor - -import android.content.Context -import android.content.Intent -import android.hardware.fingerprint.FingerprintEnrollOptions -import android.hardware.fingerprint.FingerprintManager -import android.hardware.fingerprint.FingerprintManager.GenerateChallengeCallback -import android.hardware.fingerprint.FingerprintManager.RemovalCallback -import android.os.CancellationSignal -import android.util.Log -import com.android.settings.biometrics.GatekeeperPasswordProvider -import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepository -import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor -import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason -import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState -import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel -import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData -import com.android.settings.password.ChooseLockSettingsHelper -import kotlin.coroutines.resume -import kotlin.coroutines.suspendCoroutine -import kotlinx.coroutines.CancellableContinuation -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.suspendCancellableCoroutine -import kotlinx.coroutines.withContext - -private const val TAG = "FingerprintManagerInteractor" - -class FingerprintManagerInteractorImpl( - applicationContext: Context, - private val backgroundDispatcher: CoroutineDispatcher, - private val fingerprintManager: FingerprintManager?, - fingerprintSensorRepository: FingerprintSensorRepository, - private val gatekeeperPasswordProvider: GatekeeperPasswordProvider, - private val fingerprintEnrollStateRepository: FingerprintEnrollInteractor, -) : FingerprintManagerInteractor { - - private val maxFingerprints = - applicationContext.resources.getInteger( - com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser - ) - private val applicationContext = applicationContext.applicationContext - - override suspend fun generateChallenge(gateKeeperPasswordHandle: Long): Pair = - suspendCoroutine { - val callback = GenerateChallengeCallback { _, userId, challenge -> - val intent = Intent() - intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gateKeeperPasswordHandle) - val challengeToken = - gatekeeperPasswordProvider.requestGatekeeperHat(intent, challenge, userId) - - gatekeeperPasswordProvider.removeGatekeeperPasswordHandle(intent, false) - val p = Pair(challenge, challengeToken) - it.resume(p) - } - fingerprintManager?.generateChallenge(applicationContext.userId, callback) - } - - override val enrolledFingerprints: Flow?> = flow { - emit( - fingerprintManager?.getEnrolledFingerprints(applicationContext.userId) - ?.map { (FingerprintData(it.name.toString(), it.biometricId, it.deviceId)) }?.toList() - ) - } - - override val canEnrollFingerprints: Flow = flow { - emit( - fingerprintManager?.getEnrolledFingerprints(applicationContext.userId)?.size ?: maxFingerprints < maxFingerprints - ) - } - - override val sensorPropertiesInternal = fingerprintSensorRepository.fingerprintSensor - - override val maxEnrollableFingerprints = flow { emit(maxFingerprints) } - - override suspend fun enroll( - hardwareAuthToken: ByteArray?, - enrollReason: EnrollReason, - fingerprintEnrollOptions: FingerprintEnrollOptions, - ): Flow = - fingerprintEnrollStateRepository.enroll( - hardwareAuthToken, - enrollReason, - fingerprintEnrollOptions, - ) - - override suspend fun removeFingerprint(fp: FingerprintData): Boolean = suspendCoroutine { - val callback = - object : RemovalCallback() { - override fun onRemovalError( - fp: android.hardware.fingerprint.Fingerprint, - errMsgId: Int, - errString: CharSequence, - ) { - it.resume(false) - } - - override fun onRemovalSucceeded( - fp: android.hardware.fingerprint.Fingerprint?, - remaining: Int, - ) { - it.resume(true) - } - } - fingerprintManager?.remove( - android.hardware.fingerprint.Fingerprint(fp.name, fp.fingerId, fp.deviceId), - applicationContext.userId, - callback, - ) - } - - override suspend fun renameFingerprint(fp: FingerprintData, newName: String) { - withContext(backgroundDispatcher) { - fingerprintManager?.rename(fp.fingerId, applicationContext.userId, newName) - } - } - - override suspend fun hasSideFps(): Boolean? = suspendCancellableCoroutine { - it.resume(fingerprintManager?.isPowerbuttonFps) - } - - override suspend fun authenticate(): FingerprintAuthAttemptModel = - suspendCancellableCoroutine { c: CancellableContinuation -> - val authenticationCallback = - object : FingerprintManager.AuthenticationCallback() { - - override fun onAuthenticationError(errorCode: Int, errString: CharSequence) { - super.onAuthenticationError(errorCode, errString) - if (c.isCompleted) { - Log.d(TAG, "framework sent down onAuthError after finish") - return - } - c.resume(FingerprintAuthAttemptModel.Error(errorCode, errString.toString())) - } - - override fun onAuthenticationSucceeded(result: FingerprintManager.AuthenticationResult) { - super.onAuthenticationSucceeded(result) - if (c.isCompleted) { - Log.d(TAG, "framework sent down onAuthError after finish") - return - } - c.resume(FingerprintAuthAttemptModel.Success(result.fingerprint?.biometricId ?: -1)) - } - } - - val cancellationSignal = CancellationSignal() - c.invokeOnCancellation { cancellationSignal.cancel() } - fingerprintManager?.authenticate( - null, - cancellationSignal, - authenticationCallback, - null, - applicationContext.userId, - ) - } -} diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintSensorInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintSensorInteractor.kt index 073629c6537..7b1d4fd280c 100644 --- a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintSensorInteractor.kt +++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintSensorInteractor.kt @@ -20,9 +20,7 @@ import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintS import com.android.systemui.biometrics.shared.model.FingerprintSensor import kotlinx.coroutines.flow.Flow -/** - * Interactor that propagates the type of [FingerprintSensor] this device supports. - */ +/** Interactor that propagates the type of [FingerprintSensor] this device supports. */ interface FingerprintSensorInteractor { /** Get the [FingerprintSensor] */ val fingerprintSensor: Flow diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/GenerateChallengeInteractorImpl.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/GenerateChallengeInteractorImpl.kt new file mode 100644 index 00000000000..a2080fbb74f --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/GenerateChallengeInteractorImpl.kt @@ -0,0 +1,48 @@ +/* + * 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.settings.biometrics.fingerprint2.domain.interactor + +import android.content.Intent +import android.hardware.fingerprint.FingerprintManager +import com.android.settings.biometrics.GatekeeperPasswordProvider +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.GenerateChallengeInteractor +import com.android.settings.password.ChooseLockSettingsHelper +import kotlin.coroutines.resume +import kotlin.coroutines.suspendCoroutine + +class GenerateChallengeInteractorImpl( + private val fingerprintManager: FingerprintManager, + private val userId: Int, + private val gatekeeperPasswordProvider: GatekeeperPasswordProvider, +) : GenerateChallengeInteractor { + + override suspend fun generateChallenge(gateKeeperPasswordHandle: Long): Pair = + suspendCoroutine { + val callback = + FingerprintManager.GenerateChallengeCallback { _, userId, challenge -> + val intent = Intent() + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gateKeeperPasswordHandle) + val challengeToken = + gatekeeperPasswordProvider.requestGatekeeperHat(intent, challenge, userId) + + gatekeeperPasswordProvider.removeGatekeeperPasswordHandle(intent, false) + val p = Pair(challenge, challengeToken) + it.resume(p) + } + fingerprintManager.generateChallenge(userId, callback) + } +} diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/RemoveFingerprintsInteractorImpl.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/RemoveFingerprintsInteractorImpl.kt new file mode 100644 index 00000000000..4232963ad55 --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/RemoveFingerprintsInteractorImpl.kt @@ -0,0 +1,55 @@ +/* + * 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.settings.biometrics.fingerprint2.domain.interactor + +import android.hardware.fingerprint.FingerprintManager +import android.hardware.fingerprint.FingerprintManager.RemovalCallback +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.RemoveFingerprintInteractor +import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData +import kotlin.coroutines.resume +import kotlin.coroutines.suspendCoroutine + +class RemoveFingerprintsInteractorImpl( + private val fingerprintManager: FingerprintManager, + private val userId: Int, +) : RemoveFingerprintInteractor { + + override suspend fun removeFingerprint(fp: FingerprintData): Boolean = suspendCoroutine { + val callback = + object : RemovalCallback() { + override fun onRemovalError( + fp: android.hardware.fingerprint.Fingerprint, + errMsgId: Int, + errString: CharSequence, + ) { + it.resume(false) + } + + override fun onRemovalSucceeded( + fp: android.hardware.fingerprint.Fingerprint?, + remaining: Int, + ) { + it.resume(true) + } + } + fingerprintManager.remove( + android.hardware.fingerprint.Fingerprint(fp.name, fp.fingerId, fp.deviceId), + userId, + callback, + ) + } +} diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/RenameFingerprintsInteractorImpl.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/RenameFingerprintsInteractorImpl.kt new file mode 100644 index 00000000000..f238e7c4f2e --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/RenameFingerprintsInteractorImpl.kt @@ -0,0 +1,34 @@ +/* + * 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.settings.biometrics.fingerprint2.domain.interactor + +import android.hardware.fingerprint.FingerprintManager +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.RenameFingerprintInteractor +import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.withContext + +class RenameFingerprintsInteractorImpl( + private val fingerprintManager: FingerprintManager, + private val userId: Int, + private val backgroundDispatcher: CoroutineDispatcher, +) : RenameFingerprintInteractor { + + override suspend fun renameFingerprint(fp: FingerprintData, newName: String) { + withContext(backgroundDispatcher) { fingerprintManager.rename(fp.fingerId, userId, newName) } + } +} diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/SensorInteractorImpl.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/SensorInteractorImpl.kt new file mode 100644 index 00000000000..7df0795e4ec --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/SensorInteractorImpl.kt @@ -0,0 +1,27 @@ +/* + * 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.settings.biometrics.fingerprint2.domain.interactor + +import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepository +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.SensorInteractor +import kotlinx.coroutines.flow.Flow + +class SensorInteractorImpl(private val repo: FingerprintSensorRepository) : + SensorInteractor { + override val sensorPropertiesInternal = repo.fingerprintSensor + override val hasSideFps: Flow = repo.hasSideFps +} diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/TouchEventInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/TouchEventInteractor.kt index 4ef2afa0875..778837d84ea 100644 --- a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/TouchEventInteractor.kt +++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/TouchEventInteractor.kt @@ -24,4 +24,3 @@ interface TouchEventInteractor { /** A flow simulating user touches. */ val touchEvent: Flow } - diff --git a/src/com/android/settings/biometrics/fingerprint2/lib/AndroidManifest.xml b/src/com/android/settings/biometrics/fingerprint2/lib/AndroidManifest.xml index 250f0af83eb..0b7ea2841ef 100644 --- a/src/com/android/settings/biometrics/fingerprint2/lib/AndroidManifest.xml +++ b/src/com/android/settings/biometrics/fingerprint2/lib/AndroidManifest.xml @@ -13,6 +13,6 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - diff --git a/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/AuthenitcateInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/AuthenitcateInteractor.kt new file mode 100644 index 00000000000..4fc94137bc0 --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/AuthenitcateInteractor.kt @@ -0,0 +1,25 @@ +/* + * 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.settings.biometrics.fingerprint2.lib.domain.interactor + +import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel + +/** Interactor responsible for coordinating authentication. */ +interface AuthenitcateInteractor { + /** Runs the authenticate flow */ + suspend fun authenticate(): FingerprintAuthAttemptModel +} diff --git a/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/CanEnrollFingerprintsInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/CanEnrollFingerprintsInteractor.kt new file mode 100644 index 00000000000..11a9258ed88 --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/CanEnrollFingerprintsInteractor.kt @@ -0,0 +1,27 @@ +/* + * 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.settings.biometrics.fingerprint2.lib.domain.interactor + +import kotlinx.coroutines.flow.Flow + +/** Returns whether or not a user can enroll a fingerprint */ +interface CanEnrollFingerprintsInteractor { + /** Returns true if a user can enroll a fingerprint false otherwise. */ + val canEnrollFingerprints: Flow + /** Indicates the maximum fingerprints enrollable for a given user */ + fun maxFingerprintsEnrollable(): Int +} diff --git a/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/EnrollFingerprintInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/EnrollFingerprintInteractor.kt new file mode 100644 index 00000000000..be7b4d042ee --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/EnrollFingerprintInteractor.kt @@ -0,0 +1,35 @@ +/* + * 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.settings.biometrics.fingerprint2.lib.domain.interactor + +import android.hardware.fingerprint.FingerprintEnrollOptions +import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason +import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState +import kotlinx.coroutines.flow.Flow + +/** Interactor that enrolls a fingerprint */ +interface EnrollFingerprintInteractor { + /** + * Runs [FingerprintManager.enroll] with the [hardwareAuthToken] and [EnrollReason] for this + * enrollment. If successful data in the [fingerprintEnrollState] should be populated. + */ + suspend fun enroll( + hardwareAuthToken: ByteArray?, + enrollReason: EnrollReason, + fingerprintEnrollOptions: FingerprintEnrollOptions, + ): Flow +} diff --git a/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/EnrolledFingerprintsInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/EnrolledFingerprintsInteractor.kt new file mode 100644 index 00000000000..14fc1e5e215 --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/EnrolledFingerprintsInteractor.kt @@ -0,0 +1,26 @@ +/* + * 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.settings.biometrics.fingerprint2.lib.domain.interactor + +import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData +import kotlinx.coroutines.flow.Flow + +/** Interface to obtain the enrolled fingerprints */ +interface EnrolledFingerprintsInteractor { + /** Returns the list of current fingerprints. */ + val enrolledFingerprints: Flow?> +} diff --git a/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/FingerprintManagerInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/FingerprintManagerInteractor.kt deleted file mode 100644 index 5f4cecabab1..00000000000 --- a/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/FingerprintManagerInteractor.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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.settings.biometrics.fingerprint2.lib.domain.interactor - -import android.hardware.fingerprint.FingerprintEnrollOptions -import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason -import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState -import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel -import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData -import com.android.systemui.biometrics.shared.model.FingerprintSensor -import kotlinx.coroutines.flow.Flow - -/** - * Interface to obtain the necessary data for FingerprintEnrollment/Settings - * - * Note that this interface should not have dependencies on heavyweight libraries such as the - * framework, hidl/aidl, etc. This makes it much easier to test and create fakes for. - */ -interface FingerprintManagerInteractor { - /** Returns the list of current fingerprints. */ - val enrolledFingerprints: Flow?> - - /** Returns the max enrollable fingerprints, note during SUW this might be 1 */ - val maxEnrollableFingerprints: Flow - - /** Returns true if a user can enroll a fingerprint false otherwise. */ - val canEnrollFingerprints: Flow - - /** Retrieves the sensor properties of a device */ - val sensorPropertiesInternal: Flow - - /** Runs the authenticate flow */ - suspend fun authenticate(): FingerprintAuthAttemptModel - - /** - * Generates a challenge with the provided [gateKeeperPasswordHandle] and on success returns a - * challenge and challenge token. This info can be used for secure operations such as enrollment - * - * @param gateKeeperPasswordHandle GateKeeper password handle generated by a Confirm - * @return A [Pair] of the challenge and challenge token - */ - suspend fun generateChallenge(gateKeeperPasswordHandle: Long): Pair - - /** - * Runs [FingerprintManager.enroll] with the [hardwareAuthToken] and [EnrollReason] for this - * enrollment. If successful data in the [fingerprintEnrollState] should be populated. - */ - suspend fun enroll( - hardwareAuthToken: ByteArray?, - enrollReason: EnrollReason, - fingerprintEnrollOptions: FingerprintEnrollOptions, - ): Flow - - /** - * Removes the given fingerprint, returning true if it was successfully removed and false - * otherwise - */ - suspend fun removeFingerprint(fp: FingerprintData): Boolean - - /** Renames the given fingerprint if one exists */ - suspend fun renameFingerprint(fp: FingerprintData, newName: String) - - /** Indicates if the device has side fingerprint */ - suspend fun hasSideFps(): Boolean? -} diff --git a/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/GenerateChallengeInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/GenerateChallengeInteractor.kt new file mode 100644 index 00000000000..82667fe0465 --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/GenerateChallengeInteractor.kt @@ -0,0 +1,29 @@ +/* + * 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.settings.biometrics.fingerprint2.lib.domain.interactor + +/** This interactor is responsible for generating a challenge. */ +interface GenerateChallengeInteractor { + /** + * Generates a challenge with the provided [gateKeeperPasswordHandle] and on success returns a + * challenge and challenge token. This info can be used for secure operations such as enrollment + * + * @param gateKeeperPasswordHandle GateKeeper password handle generated by a Confirm + * @return A [Pair] of the challenge and challenge token + */ + suspend fun generateChallenge(gateKeeperPasswordHandle: Long): Pair +} diff --git a/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/RemoveFingerprintInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/RemoveFingerprintInteractor.kt new file mode 100644 index 00000000000..6d0e5641079 --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/RemoveFingerprintInteractor.kt @@ -0,0 +1,28 @@ +/* + * 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.settings.biometrics.fingerprint2.lib.domain.interactor + +import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData + +/** Interactor in charge of removing a fingerprint */ +interface RemoveFingerprintInteractor { + /** + * Removes the given fingerprint, returning true if it was successfully removed and false + * otherwise + */ + suspend fun removeFingerprint(fp: FingerprintData): Boolean +} diff --git a/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/RenameFingerprintInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/RenameFingerprintInteractor.kt new file mode 100644 index 00000000000..d7fe1c0850f --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/RenameFingerprintInteractor.kt @@ -0,0 +1,25 @@ +/* + * 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.settings.biometrics.fingerprint2.lib.domain.interactor + +import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData + +/** Interactor that can rename a fingerprint. */ +interface RenameFingerprintInteractor { + /** Renames the given fingerprint if one exists */ + suspend fun renameFingerprint(fp: FingerprintData, newName: String) +} diff --git a/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/SensorInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/SensorInteractor.kt new file mode 100644 index 00000000000..f265c327af3 --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint2/lib/domain/interactor/SensorInteractor.kt @@ -0,0 +1,28 @@ +/* + * 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.settings.biometrics.fingerprint2.lib.domain.interactor + +import com.android.systemui.biometrics.shared.model.FingerprintSensor +import kotlinx.coroutines.flow.Flow + +/** Interactor that has various information about a fingerprint sensor */ +interface SensorInteractor { + /** Retrieves the sensor properties of the device */ + val sensorPropertiesInternal: Flow + /** Indicates if the device supports side fps */ + val hasSideFps: Flow +} diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt index 421548fabf9..77d070e5026 100644 --- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt +++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt @@ -96,8 +96,8 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() { } /** - * View models below this line are not used by this class but must be initialized - * in the activity view model store to be used by other view models. + * View models below this line are not used by this class but must be initialized in the activity + * view model store to be used by other view models. */ private val fingerprintEnrollViewModel: FingerprintEnrollViewModel by viewModels { FingerprintEnrollViewModel.Factory diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/rfps/ui/viewmodel/RFPSViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/rfps/ui/viewmodel/RFPSViewModel.kt index c95020dff3c..932c40839af 100644 --- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/rfps/ui/viewmodel/RFPSViewModel.kt +++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/rfps/ui/viewmodel/RFPSViewModel.kt @@ -25,7 +25,7 @@ import androidx.lifecycle.viewmodel.initializer import androidx.lifecycle.viewmodel.viewModelFactory import com.android.settings.SettingsApplication import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor -import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.SensorInteractor import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintAction import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollEnrollingViewModel @@ -46,10 +46,10 @@ import kotlinx.coroutines.flow.update /** View Model used by the rear fingerprint enrollment fragment. */ class RFPSViewModel( - private val fingerprintEnrollViewModel: FingerprintEnrollEnrollingViewModel, - private val navigationViewModel: FingerprintNavigationViewModel, - orientationInteractor: OrientationInteractor, - private val fingerprintManager: FingerprintManagerInteractor, + private val fingerprintEnrollViewModel: FingerprintEnrollEnrollingViewModel, + private val navigationViewModel: FingerprintNavigationViewModel, + orientationInteractor: OrientationInteractor, + private val sensorInteractor: SensorInteractor, ) : ViewModel() { private val _textViewIsVisible = MutableStateFlow(false) @@ -62,7 +62,7 @@ class RFPSViewModel( val shouldAnimateIcon = _shouldAnimateIcon private var enrollFlow: Flow = - fingerprintManager.sensorPropertiesInternal.filterNotNull().combine( + sensorInteractor.sensorPropertiesInternal.filterNotNull().combine( fingerprintEnrollViewModel.enrollFlow ) { props, enroll -> if (props.sensorType == FingerprintSensorType.REAR) { @@ -181,7 +181,7 @@ class RFPSViewModel( provider[FingerprintEnrollEnrollingViewModel::class], provider[FingerprintNavigationViewModel::class], biometricEnvironment.orientationInteractor, - biometricEnvironment.fingerprintManagerInteractor, + biometricEnvironment.createSensorPropertiesInteractor(), ) } } diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/viewmodel/UdfpsViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/viewmodel/UdfpsViewModel.kt index 3396cdc5243..658c6c747c2 100644 --- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/viewmodel/UdfpsViewModel.kt +++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/viewmodel/UdfpsViewModel.kt @@ -38,7 +38,7 @@ import com.android.settings.biometrics.fingerprint2.domain.interactor.Orientatio import com.android.settings.biometrics.fingerprint2.domain.interactor.TouchEventInteractor import com.android.settings.biometrics.fingerprint2.domain.interactor.UdfpsEnrollInteractor import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractor -import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.SensorInteractor import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.model.DescriptionText import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.model.HeaderText @@ -76,17 +76,17 @@ class UdfpsViewModel( enrollStageInteractor: EnrollStageInteractor, orientationInteractor: OrientationInteractor, udfpsEnrollInteractor: UdfpsEnrollInteractor, - fingerprintManager: FingerprintManagerInteractor, accessibilityInteractor: AccessibilityInteractor, sensorRepository: FingerprintSensorInteractor, touchEventInteractor: TouchEventInteractor, + sensorInteractor: SensorInteractor, ) : ViewModel() { private val isSetupWizard = flowOf(false) private var shouldResetErollment = false private var _enrollState: Flow = - fingerprintManager.sensorPropertiesInternal.filterNotNull().combine( + sensorInteractor.sensorPropertiesInternal.filterNotNull().combine( fingerprintEnrollEnrollingViewModel.enrollFlow ) { props, enroll -> if (props.sensorType.isUdfps()) { @@ -198,8 +198,7 @@ class UdfpsViewModel( .distinctUntilChanged() private val _touchEvent: MutableStateFlow = MutableStateFlow(null) - val touchEvent = - _touchEvent.asStateFlow().filterNotNull() + val touchEvent = _touchEvent.asStateFlow().filterNotNull() /** Determines the current [EnrollStageModel] enrollment is in */ private val enrollStage: Flow = @@ -267,11 +266,7 @@ class UdfpsViewModel( backgroundViewModel.background.filter { it }.collect { didGoToBackground() } } - viewModelScope.launch { - touchEventInteractor.touchEvent.collect { - _touchEvent.update { it } - } - } + viewModelScope.launch { touchEventInteractor.touchEvent.collect { _touchEvent.update { it } } } } /** Indicates if we should show the lottie. */ @@ -430,10 +425,10 @@ class UdfpsViewModel( biometricEnvironment.enrollStageInteractor, biometricEnvironment.orientationInteractor, biometricEnvironment.udfpsEnrollInteractor, - biometricEnvironment.fingerprintManagerInteractor, biometricEnvironment.accessibilityInteractor, biometricEnvironment.sensorInteractor, biometricEnvironment.touchEventInteractor, + biometricEnvironment.createSensorPropertiesInteractor(), ) } } diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollConfirmationViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollConfirmationViewModel.kt index 5ce2ed756d8..0803f890a48 100644 --- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollConfirmationViewModel.kt +++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollConfirmationViewModel.kt @@ -16,27 +16,27 @@ package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel -import android.util.Log import androidx.lifecycle.VIEW_MODEL_STORE_OWNER_KEY import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewmodel.initializer import androidx.lifecycle.viewmodel.viewModelFactory import com.android.settings.SettingsApplication -import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.CanEnrollFingerprintsInteractor import kotlinx.coroutines.flow.Flow /** Models the UI state for [FingerprintEnrollConfirmationV2Fragment] */ class FingerprintEnrollConfirmationViewModel( private val navigationViewModel: FingerprintNavigationViewModel, - fingerprintInteractor: FingerprintManagerInteractor, + private val canEnrollFingerprintsInteractor: CanEnrollFingerprintsInteractor, ) : ViewModel() { /** * Indicates if the add another button is possible. This should only be true when the user is able * to enroll more fingerprints. */ - val isAddAnotherButtonVisible: Flow = fingerprintInteractor.canEnrollFingerprints + val isAddAnotherButtonVisible: Flow = + canEnrollFingerprintsInteractor.canEnrollFingerprints /** * Indicates that the user has clicked the next button and is done with fingerprint enrollment. @@ -64,7 +64,7 @@ class FingerprintEnrollConfirmationViewModel( val provider = ViewModelProvider(this[VIEW_MODEL_STORE_OWNER_KEY]!!) FingerprintEnrollConfirmationViewModel( provider[FingerprintNavigationViewModel::class], - biometricEnvironment!!.fingerprintManagerInteractor, + biometricEnvironment!!.createCanEnrollFingerprintsInteractor(), ) } } diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollFindSensorViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollFindSensorViewModel.kt index 3568dbdd511..9b2cdde7cef 100644 --- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollFindSensorViewModel.kt +++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollFindSensorViewModel.kt @@ -27,7 +27,7 @@ import com.android.settings.SettingsApplication import com.android.settings.biometrics.fingerprint2.domain.interactor.AccessibilityInteractor import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateInteractor import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor -import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.SensorInteractor import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState import com.android.settings.biometrics.fingerprint2.lib.model.SetupWizard import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Education @@ -44,20 +44,20 @@ import kotlinx.coroutines.launch /** Models the UI state for fingerprint enroll education */ class FingerprintEnrollFindSensorViewModel( - private val navigationViewModel: FingerprintNavigationViewModel, - private val fingerprintEnrollViewModel: FingerprintEnrollViewModel, - private val gatekeeperViewModel: FingerprintGatekeeperViewModel, - backgroundViewModel: BackgroundViewModel, - fingerprintFlowViewModel: FingerprintFlowViewModel, - accessibilityInteractor: AccessibilityInteractor, - foldStateInteractor: FoldStateInteractor, - orientationInteractor: OrientationInteractor, - fingerprintManagerInteractor: FingerprintManagerInteractor, + private val navigationViewModel: FingerprintNavigationViewModel, + private val fingerprintEnrollViewModel: FingerprintEnrollViewModel, + private val gatekeeperViewModel: FingerprintGatekeeperViewModel, + backgroundViewModel: BackgroundViewModel, + fingerprintFlowViewModel: FingerprintFlowViewModel, + accessibilityInteractor: AccessibilityInteractor, + foldStateInteractor: FoldStateInteractor, + orientationInteractor: OrientationInteractor, + sensorInteractor: SensorInteractor, ) : ViewModel() { /** Represents the stream of sensor type. */ val sensorType: Flow = - fingerprintManagerInteractor.sensorPropertiesInternal.filterNotNull().map { it.sensorType } + sensorInteractor.sensorPropertiesInternal.filterNotNull().map { it.sensorType } private val _isUdfps: Flow = sensorType.map { it == FingerprintSensorType.UDFPS_OPTICAL || it == FingerprintSensorType.UDFPS_ULTRASONIC @@ -216,7 +216,7 @@ class FingerprintEnrollFindSensorViewModel( biometricEnvironment.accessibilityInteractor, biometricEnvironment.foldStateInteractor, biometricEnvironment.orientationInteractor, - biometricEnvironment.fingerprintManagerInteractor, + biometricEnvironment.createSensorPropertiesInteractor(), ) } } diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollIntroViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollIntroViewModel.kt index 6ec204815e1..e103cbc47fc 100644 --- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollIntroViewModel.kt +++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollIntroViewModel.kt @@ -22,7 +22,7 @@ import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewmodel.initializer import androidx.lifecycle.viewmodel.viewModelFactory import com.android.settings.SettingsApplication -import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.SensorInteractor import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintFlow import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Introduction import com.android.systemui.biometrics.shared.model.FingerprintSensor @@ -30,13 +30,13 @@ import kotlinx.coroutines.flow.Flow /** A view model for fingerprint enroll introduction. */ class FingerprintEnrollIntroViewModel( - val navigationViewModel: FingerprintNavigationViewModel, - fingerprintFlowViewModel: FingerprintFlowViewModel, - fingerprintManagerInteractor: FingerprintManagerInteractor, + val navigationViewModel: FingerprintNavigationViewModel, + fingerprintFlowViewModel: FingerprintFlowViewModel, + sensorInteractor: SensorInteractor, ) : ViewModel() { /** Represents a stream of [FingerprintSensor] */ - val sensor: Flow = fingerprintManagerInteractor.sensorPropertiesInternal + val sensor: Flow = sensorInteractor.sensorPropertiesInternal /** Represents a stream of [FingerprintFlow] */ val fingerprintFlow: Flow = fingerprintFlowViewModel.fingerprintFlow @@ -67,7 +67,7 @@ class FingerprintEnrollIntroViewModel( FingerprintEnrollIntroViewModel( provider[FingerprintNavigationViewModel::class], provider[FingerprintFlowViewModel::class], - biometricEnvironment!!.fingerprintManagerInteractor, + biometricEnvironment!!.createSensorPropertiesInteractor(), ) } } diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollViewModel.kt index 2669b8bbe5b..fb8a182ab40 100644 --- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollViewModel.kt +++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollViewModel.kt @@ -24,7 +24,8 @@ import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.initializer import androidx.lifecycle.viewmodel.viewModelFactory import com.android.settings.SettingsApplication -import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.EnrollFingerprintInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.SensorInteractor import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Education @@ -42,9 +43,10 @@ import kotlinx.coroutines.flow.update /** Represents all of the fingerprint information needed for a fingerprint enrollment process. */ class FingerprintEnrollViewModel( - private val fingerprintManagerInteractor: FingerprintManagerInteractor, - gatekeeperViewModel: FingerprintGatekeeperViewModel, - val navigationViewModel: FingerprintNavigationViewModel, + gatekeeperViewModel: FingerprintGatekeeperViewModel, + val navigationViewModel: FingerprintNavigationViewModel, + private val sensorInteractor: SensorInteractor, + private val fingerprintEnrollInteractor: EnrollFingerprintInteractor, ) : ViewModel() { /** @@ -67,7 +69,7 @@ class FingerprintEnrollViewModel( /** Represents the stream of [FingerprintSensorType] */ val sensorType: Flow = - fingerprintManagerInteractor.sensorPropertiesInternal.filterNotNull().map { it.sensorType } + sensorInteractor.sensorPropertiesInternal.filterNotNull().map { it.sensorType } /** * A flow that contains a [FingerprintEnrollViewModel] which contains the relevant information for @@ -90,7 +92,7 @@ class FingerprintEnrollViewModel( enrollReason != null && enrollOptions != null ) { - fingerprintManagerInteractor + fingerprintEnrollInteractor .enroll(hardwareAuthToken.token, enrollReason, enrollOptions) .collect { emit(it) } } @@ -137,9 +139,10 @@ class FingerprintEnrollViewModel( val biometricEnvironment = settingsApplication.biometricEnvironment val provider = ViewModelProvider(this[VIEW_MODEL_STORE_OWNER_KEY]!!) FingerprintEnrollViewModel( - biometricEnvironment!!.fingerprintManagerInteractor, provider[FingerprintGatekeeperViewModel::class], provider[FingerprintNavigationViewModel::class], + biometricEnvironment!!.createSensorPropertiesInteractor(), + biometricEnvironment!!.createFingerprintEnrollInteractor(), ) } } diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintGatekeeperViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintGatekeeperViewModel.kt index b5be165056e..c2b0a0f23d9 100644 --- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintGatekeeperViewModel.kt +++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintGatekeeperViewModel.kt @@ -24,7 +24,7 @@ import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.initializer import androidx.lifecycle.viewmodel.viewModelFactory import com.android.settings.SettingsApplication -import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.GenerateChallengeInteractor import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow @@ -50,7 +50,7 @@ sealed interface GatekeeperInfo { * in as a parameter to this class. */ class FingerprintGatekeeperViewModel( - private val fingerprintManagerInteractor: FingerprintManagerInteractor + private val generateChallengeInteractor: GenerateChallengeInteractor ) : ViewModel() { private var _gatekeeperInfo: MutableStateFlow = MutableStateFlow(null) @@ -78,7 +78,7 @@ class FingerprintGatekeeperViewModel( _gatekeeperInfo.update { GatekeeperInfo.Invalid } } else { viewModelScope.launch { - val res = fingerprintManagerInteractor.generateChallenge(theGatekeeperPasswordHandle!!) + val res = generateChallengeInteractor.generateChallenge(theGatekeeperPasswordHandle!!) _gatekeeperInfo.update { GatekeeperInfo.GatekeeperPasswordInfo(res.second, res.first) } if (shouldStartTimer) { startTimeout() @@ -119,7 +119,7 @@ class FingerprintGatekeeperViewModel( val settingsApplication = this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as SettingsApplication val biometricEnvironment = settingsApplication.biometricEnvironment - FingerprintGatekeeperViewModel(biometricEnvironment!!.fingerprintManagerInteractor) + FingerprintGatekeeperViewModel(biometricEnvironment!!.createGenerateChallengeInteractor()) } } } diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintNavigationViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintNavigationViewModel.kt index caf7d2a8a9b..d9bcf7fd901 100644 --- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintNavigationViewModel.kt +++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintNavigationViewModel.kt @@ -23,7 +23,7 @@ import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.initializer import androidx.lifecycle.viewmodel.viewModelFactory import com.android.settings.SettingsApplication -import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.SensorInteractor import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintFlow import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Finish import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.TransitionStep @@ -46,7 +46,7 @@ import kotlinx.coroutines.flow.update * fragments/viewmodels that want to consume these events. It should provide no additional * functionality beyond what is available in [FingerprintNavigationStep]. */ -class FingerprintNavigationViewModel(fingerprintManagerInteractor: FingerprintManagerInteractor) : +class FingerprintNavigationViewModel(sensorInteractor: SensorInteractor) : ViewModel() { private val _flowInternal: MutableStateFlow = MutableStateFlow(null) @@ -55,7 +55,7 @@ class FingerprintNavigationViewModel(fingerprintManagerInteractor: FingerprintMa combine( _flowInternal, _hasConfirmedDeviceCredential, - fingerprintManagerInteractor.sensorPropertiesInternal, + sensorInteractor.sensorPropertiesInternal, ) { flow, hasConfirmed, sensorType -> if (flow == null || sensorType == null) { return@combine null @@ -144,7 +144,7 @@ class FingerprintNavigationViewModel(fingerprintManagerInteractor: FingerprintMa val settingsApplication = this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as SettingsApplication val biometricEnvironment = settingsApplication.biometricEnvironment - FingerprintNavigationViewModel(biometricEnvironment!!.fingerprintManagerInteractor) + FingerprintNavigationViewModel(biometricEnvironment!!.createSensorPropertiesInteractor()) } } } diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/settings/fragment/FingerprintSettingsV2Fragment.kt b/src/com/android/settings/biometrics/fingerprint2/ui/settings/fragment/FingerprintSettingsV2Fragment.kt index 4c3773bb3e9..241eaea0b28 100644 --- a/src/com/android/settings/biometrics/fingerprint2/ui/settings/fragment/FingerprintSettingsV2Fragment.kt +++ b/src/com/android/settings/biometrics/fingerprint2/ui/settings/fragment/FingerprintSettingsV2Fragment.kt @@ -35,19 +35,16 @@ import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.preference.Preference import androidx.preference.PreferenceCategory -import com.android.internal.widget.LockPatternUtils import com.android.settings.R +import com.android.settings.SettingsApplication import com.android.settings.Utils.SETTINGS_PACKAGE_NAME import com.android.settings.biometrics.BiometricEnrollBase import com.android.settings.biometrics.BiometricEnrollBase.CONFIRM_REQUEST import com.android.settings.biometrics.BiometricEnrollBase.EXTRA_FROM_SETTINGS_SUMMARY import com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED -import com.android.settings.biometrics.GatekeeperPasswordProvider import com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroductionInternal import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepositoryImpl -import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintEnrollInteractorImpl -import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl import com.android.settings.biometrics.fingerprint2.domain.interactor.PressToAuthInteractorImpl import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData @@ -223,35 +220,24 @@ class FingerprintSettingsV2Fragment : val fingerprintSensorProvider = FingerprintSensorRepositoryImpl(fingerprintManager, backgroundDispatcher, lifecycleScope) val pressToAuthInteractor = PressToAuthInteractorImpl(context, backgroundDispatcher) - val fingerprintEnrollStateRepository = - FingerprintEnrollInteractorImpl( - requireContext().applicationContext, - fingerprintManager, - Settings, - ) - - val interactor = - FingerprintManagerInteractorImpl( - context.applicationContext, - backgroundDispatcher, - fingerprintManager, - fingerprintSensorProvider, - GatekeeperPasswordProvider(LockPatternUtils(context.applicationContext)), - fingerprintEnrollStateRepository, - ) val token = intent.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN) val challenge = intent.getLongExtra(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, -1L) + val application = requireActivity().application as SettingsApplication + val environment = + application.biometricEnvironment + ?: throw IllegalStateException("The biometric environment must be present") navigationViewModel = ViewModelProvider( this, FingerprintSettingsNavigationViewModel.FingerprintSettingsNavigationModelFactory( userId, - interactor, backgroundDispatcher, token, challenge, + environment.createFingerprintsEnrolledInteractor(), + environment.createGenerateChallengeInteractor(), ), )[FingerprintSettingsNavigationViewModel::class.java] @@ -260,9 +246,14 @@ class FingerprintSettingsV2Fragment : this, FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory( userId, - interactor, backgroundDispatcher, navigationViewModel, + environment.createCanEnrollFingerprintsInteractor(), + environment.createSensorPropertiesInteractor(), + environment.createAuthenticateInteractor(), + environment.createRenameFingerprintInteractor(), + environment.createRemoveFingerprintInteractor(), + environment.createFingerprintsEnrolledInteractor(), ), )[FingerprintSettingsViewModel::class.java] diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/FingerprintSettingsNavigationViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/FingerprintSettingsNavigationViewModel.kt index 8a694aeac91..73b2b1cd3d3 100644 --- a/src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/FingerprintSettingsNavigationViewModel.kt +++ b/src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/FingerprintSettingsNavigationViewModel.kt @@ -21,7 +21,8 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope import com.android.settings.biometrics.BiometricEnrollBase -import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.EnrolledFingerprintsInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.GenerateChallengeInteractor import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -33,10 +34,11 @@ import kotlinx.coroutines.launch /** A Viewmodel that represents the navigation of the FingerprintSettings activity. */ class FingerprintSettingsNavigationViewModel( private val userId: Int, - private val fingerprintManagerInteractor: FingerprintManagerInteractor, private val backgroundDispatcher: CoroutineDispatcher, tokenInit: ByteArray?, challengeInit: Long?, + private val enrolledFingerprintsInteractor: EnrolledFingerprintsInteractor, + private val generateChallengeInteractor: GenerateChallengeInteractor, ) : ViewModel() { private var token = tokenInit @@ -52,7 +54,7 @@ class FingerprintSettingsNavigationViewModel( _nextStep.update { LaunchConfirmDeviceCredential(userId) } } else { viewModelScope.launch { - if (fingerprintManagerInteractor.enrolledFingerprints.last()?.isEmpty() == true) { + if (enrolledFingerprintsInteractor.enrolledFingerprints.last()?.isEmpty() == true) { _nextStep.update { EnrollFirstFingerprint(userId, null, challenge, token) } } else { showSettingsHelper() @@ -148,13 +150,13 @@ class FingerprintSettingsNavigationViewModel( } private suspend fun launchEnrollNextStep(gateKeeperPasswordHandle: Long?) { - fingerprintManagerInteractor.enrolledFingerprints.collect { + enrolledFingerprintsInteractor.enrolledFingerprints.collect { if (it?.isEmpty() == true) { _nextStep.update { EnrollFirstFingerprint(userId, gateKeeperPasswordHandle, null, null) } } else { viewModelScope.launch(backgroundDispatcher) { val challengePair = - fingerprintManagerInteractor.generateChallenge(gateKeeperPasswordHandle!!) + generateChallengeInteractor.generateChallenge(gateKeeperPasswordHandle!!) challenge = challengePair.first token = challengePair.second @@ -174,10 +176,11 @@ class FingerprintSettingsNavigationViewModel( class FingerprintSettingsNavigationModelFactory( private val userId: Int, - private val interactor: FingerprintManagerInteractor, private val backgroundDispatcher: CoroutineDispatcher, private val token: ByteArray?, private val challenge: Long?, + private val enrolledFingerprintsInteractor: EnrolledFingerprintsInteractor, + private val generateChallengeInteractor: GenerateChallengeInteractor, ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") @@ -185,10 +188,11 @@ class FingerprintSettingsNavigationViewModel( return FingerprintSettingsNavigationViewModel( userId, - interactor, backgroundDispatcher, token, challenge, + enrolledFingerprintsInteractor, + generateChallengeInteractor, ) as T } diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/FingerprintSettingsViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/FingerprintSettingsViewModel.kt index cf8c527d6d4..c306c7870b9 100644 --- a/src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/FingerprintSettingsViewModel.kt +++ b/src/com/android/settings/biometrics/fingerprint2/ui/settings/viewmodel/FingerprintSettingsViewModel.kt @@ -21,7 +21,12 @@ import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.AuthenitcateInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.CanEnrollFingerprintsInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.EnrolledFingerprintsInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.RemoveFingerprintInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.RenameFingerprintInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.SensorInteractor import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData import com.android.systemui.biometrics.shared.model.FingerprintSensorType @@ -49,9 +54,14 @@ private const val DEBUG = false /** Models the UI state for fingerprint settings. */ class FingerprintSettingsViewModel( private val userId: Int, - private val fingerprintManagerInteractor: FingerprintManagerInteractor, private val backgroundDispatcher: CoroutineDispatcher, private val navigationViewModel: FingerprintSettingsNavigationViewModel, + private val canEnrollFingerprintsInteractor: CanEnrollFingerprintsInteractor, + private val sensorInteractor: SensorInteractor, + private val authenticateInteractor: AuthenitcateInteractor, + private val renameFingerprintInteractor: RenameFingerprintInteractor, + private val removeFingerprintInteractor: RemoveFingerprintInteractor, + private val enrolledFingerprintsInteractor: EnrolledFingerprintsInteractor, ) : ViewModel() { private val _enrolledFingerprints: MutableStateFlow?> = MutableStateFlow(null) @@ -62,19 +72,18 @@ class FingerprintSettingsViewModel( /** Represents the stream of the information of "Add Fingerprint" preference. */ val addFingerprintPrefInfo: Flow> = - _enrolledFingerprints.filterOnlyWhenSettingsIsShown().transform { - emit( - Pair( - fingerprintManagerInteractor.canEnrollFingerprints.first(), - fingerprintManagerInteractor.maxEnrollableFingerprints.first(), - ) - ) + _enrolledFingerprints.filterOnlyWhenSettingsIsShown().combine( + canEnrollFingerprintsInteractor.canEnrollFingerprints + ) { _, canEnrollFingerprints -> + Pair(canEnrollFingerprints, canEnrollFingerprintsInteractor.maxFingerprintsEnrollable()) } /** Represents the stream of visibility of sfps preference. */ val isSfpsPrefVisible: Flow = - _enrolledFingerprints.filterOnlyWhenSettingsIsShown().transform { - emit(fingerprintManagerInteractor.hasSideFps() == true && !it.isNullOrEmpty()) + _enrolledFingerprints.filterOnlyWhenSettingsIsShown().combine(sensorInteractor.hasSideFps) { + fingerprints, + hasSideFps -> + hasSideFps && !fingerprints.isNullOrEmpty() } private val _isShowingDialog: MutableStateFlow = MutableStateFlow(null) @@ -90,10 +99,10 @@ class FingerprintSettingsViewModel( private val _consumerShouldAuthenticate: MutableStateFlow = MutableStateFlow(false) private val _fingerprintSensorType: Flow = - fingerprintManagerInteractor.sensorPropertiesInternal.filterNotNull().map { it.sensorType } + sensorInteractor.sensorPropertiesInternal.filterNotNull().map { it.sensorType } private val _sensorNullOrEmpty: Flow = - fingerprintManagerInteractor.sensorPropertiesInternal.map { it == null } + sensorInteractor.sensorPropertiesInternal.map { it == null } private val _isLockedOut: MutableStateFlow = MutableStateFlow(null) @@ -172,7 +181,7 @@ class FingerprintSettingsViewModel( while (it && navigationViewModel.nextStep.value is ShowSettings) { Log.d(TAG, "canAuthenticate authing") attemptingAuth() - when (val authAttempt = fingerprintManagerInteractor.authenticate()) { + when (val authAttempt = authenticateInteractor.authenticate()) { is FingerprintAuthAttemptModel.Success -> { onAuthSuccess(authAttempt) emit(authAttempt) @@ -243,7 +252,7 @@ class FingerprintSettingsViewModel( /** A request to delete a fingerprint */ fun deleteFingerprint(fp: FingerprintData) { viewModelScope.launch(backgroundDispatcher) { - if (fingerprintManagerInteractor.removeFingerprint(fp)) { + if (removeFingerprintInteractor.removeFingerprint(fp)) { updateEnrolledFingerprints() } } @@ -252,7 +261,7 @@ class FingerprintSettingsViewModel( /** A request to rename a fingerprint */ fun renameFingerprint(fp: FingerprintData, newName: String) { viewModelScope.launch { - fingerprintManagerInteractor.renameFingerprint(fp, newName) + renameFingerprintInteractor.renameFingerprint(fp, newName) updateEnrolledFingerprints() } } @@ -271,7 +280,7 @@ class FingerprintSettingsViewModel( } private suspend fun updateEnrolledFingerprints() { - _enrolledFingerprints.update { fingerprintManagerInteractor.enrolledFingerprints.first() } + _enrolledFingerprints.update { enrolledFingerprintsInteractor.enrolledFingerprints.first() } } /** Used to indicate whether the consumer of the view model is ready for authentication. */ @@ -288,9 +297,14 @@ class FingerprintSettingsViewModel( class FingerprintSettingsViewModelFactory( private val userId: Int, - private val interactor: FingerprintManagerInteractor, private val backgroundDispatcher: CoroutineDispatcher, private val navigationViewModel: FingerprintSettingsNavigationViewModel, + private val canEnrollFingerprintsInteractor: CanEnrollFingerprintsInteractor, + private val sensorInteractor: SensorInteractor, + private val authenticateInteractor: AuthenitcateInteractor, + private val renameFingerprintInteractor: RenameFingerprintInteractor, + private val removeFingerprintInteractor: RemoveFingerprintInteractor, + private val enrolledFingerprintsInteractor: EnrolledFingerprintsInteractor, ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") @@ -298,9 +312,14 @@ class FingerprintSettingsViewModel( return FingerprintSettingsViewModel( userId, - interactor, backgroundDispatcher, navigationViewModel, + canEnrollFingerprintsInteractor, + sensorInteractor, + authenticateInteractor, + renameFingerprintInteractor, + removeFingerprintInteractor, + enrolledFingerprintsInteractor, ) as T } diff --git a/tests/screenshot/src/com/android/settings/tests/screenshot/biometrics/fingerprint/Injector.kt b/tests/screenshot/src/com/android/settings/tests/screenshot/biometrics/fingerprint/Injector.kt index 19433f3cb19..e7fc3ed3d66 100644 --- a/tests/screenshot/src/com/android/settings/tests/screenshot/biometrics/fingerprint/Injector.kt +++ b/tests/screenshot/src/com/android/settings/tests/screenshot/biometrics/fingerprint/Injector.kt @@ -111,9 +111,10 @@ class Injector(step: FingerprintNavigationStep.UiStep) { var fingerprintEnrollViewModel = FingerprintEnrollViewModel( - fingerprintManagerInteractor, gatekeeperViewModel, navigationViewModel, + fingerprintManagerInteractor, + fingerprintManagerInteractor, ) var fingerprintEnrollEnrollingViewModel = diff --git a/tests/shared/src/com/android/settings/testutils2/FakeFingerprintManagerInteractor.kt b/tests/shared/src/com/android/settings/testutils2/FakeFingerprintManagerInteractor.kt index 52df724b82d..f61a3d3a02e 100644 --- a/tests/shared/src/com/android/settings/testutils2/FakeFingerprintManagerInteractor.kt +++ b/tests/shared/src/com/android/settings/testutils2/FakeFingerprintManagerInteractor.kt @@ -22,7 +22,14 @@ import android.hardware.biometrics.SensorProperties import android.hardware.fingerprint.FingerprintEnrollOptions import android.hardware.fingerprint.FingerprintSensorProperties import android.hardware.fingerprint.FingerprintSensorPropertiesInternal -import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.AuthenitcateInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.CanEnrollFingerprintsInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.EnrollFingerprintInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.EnrolledFingerprintsInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.GenerateChallengeInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.RemoveFingerprintInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.RenameFingerprintInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.SensorInteractor import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel @@ -35,7 +42,15 @@ import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOf /** Fake to be used by other classes to easily fake the FingerprintManager implementation. */ -class FakeFingerprintManagerInteractor : FingerprintManagerInteractor { +class FakeFingerprintManagerInteractor : + AuthenitcateInteractor, + CanEnrollFingerprintsInteractor, + EnrolledFingerprintsInteractor, + EnrollFingerprintInteractor, + GenerateChallengeInteractor, + RemoveFingerprintInteractor, + RenameFingerprintInteractor, + SensorInteractor { var enrollableFingerprints: Int = 5 var enrolledFingerprintsInternal: MutableList = mutableListOf() @@ -67,19 +82,22 @@ class FakeFingerprintManagerInteractor : FingerprintManagerInteractor { override val enrolledFingerprints: Flow> = flow { emit(enrolledFingerprintsInternal) } - override val canEnrollFingerprints: Flow = flow { emit(enrolledFingerprintsInternal.size < enrollableFingerprints) } - override val sensorPropertiesInternal: Flow = flow { emit(sensorProp) } + override fun maxFingerprintsEnrollable(): Int { + return enrollableFingerprints + } - override val maxEnrollableFingerprints: Flow = flow { emit(enrollableFingerprints) } + override val sensorPropertiesInternal: Flow = flow { emit(sensorProp) } + override val hasSideFps: Flow = + flowOf(sensorProp.sensorType == FingerprintSensorType.POWER_BUTTON) override suspend fun enroll( hardwareAuthToken: ByteArray?, enrollReason: EnrollReason, - fingerprintEnrollOptions: FingerprintEnrollOptions + fingerprintEnrollOptions: FingerprintEnrollOptions, ): Flow = flowOf(*enrollStateViewModel.toTypedArray()) override suspend fun removeFingerprint(fp: FingerprintData): Boolean { @@ -92,7 +110,4 @@ class FakeFingerprintManagerInteractor : FingerprintManagerInteractor { } } - override suspend fun hasSideFps(): Boolean { - return sensorProp.sensorType == FingerprintSensorType.POWER_BUTTON - } } diff --git a/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FingerprintManagerInteractorTest.kt b/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FingerprintManagerInteractorTest.kt index 67a5957b9f5..691b6112bf7 100644 --- a/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FingerprintManagerInteractorTest.kt +++ b/tests/unit/src/com/android/settings/fingerprint2/domain/interactor/FingerprintManagerInteractorTest.kt @@ -16,7 +16,6 @@ package com.android.settings.fingerprint2.domain.interactor -import android.content.Context import android.content.Intent import android.hardware.biometrics.ComponentInfoInternal import android.hardware.biometrics.SensorLocationInternal @@ -30,23 +29,37 @@ import android.hardware.fingerprint.FingerprintSensorProperties import android.hardware.fingerprint.FingerprintSensorPropertiesInternal import android.os.CancellationSignal import android.os.Handler -import androidx.test.core.app.ApplicationProvider import com.android.settings.biometrics.GatekeeperPasswordProvider +import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintEnrollmentRepositoryImpl import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepository -import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintEnrollInteractorImpl -import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl -import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor +import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSettingsRepositoryImpl +import com.android.settings.biometrics.fingerprint2.data.repository.UserRepo +import com.android.settings.biometrics.fingerprint2.domain.interactor.AuthenticateInteractorImpl +import com.android.settings.biometrics.fingerprint2.domain.interactor.CanEnrollFingerprintsInteractorImpl +import com.android.settings.biometrics.fingerprint2.domain.interactor.EnrollFingerprintInteractorImpl +import com.android.settings.biometrics.fingerprint2.domain.interactor.EnrolledFingerprintsInteractorImpl +import com.android.settings.biometrics.fingerprint2.domain.interactor.GenerateChallengeInteractorImpl +import com.android.settings.biometrics.fingerprint2.domain.interactor.RemoveFingerprintsInteractorImpl +import com.android.settings.biometrics.fingerprint2.domain.interactor.RenameFingerprintsInteractorImpl +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.CanEnrollFingerprintsInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.EnrollFingerprintInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.EnrolledFingerprintsInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.GenerateChallengeInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.RemoveFingerprintInteractor +import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.RenameFingerprintInteractor import com.android.settings.biometrics.fingerprint2.lib.model.Default import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData +import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintFlow import com.android.settings.password.ChooseLockSettingsHelper import com.android.systemui.biometrics.shared.model.FingerprintSensor import com.android.systemui.biometrics.shared.model.toFingerprintSensor import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.last import kotlinx.coroutines.launch @@ -75,13 +88,28 @@ import org.mockito.stubbing.OngoingStubbing class FingerprintManagerInteractorTest { @JvmField @Rule var rule = MockitoJUnit.rule() - private lateinit var underTest: FingerprintManagerInteractor - private var context: Context = ApplicationProvider.getApplicationContext() + private lateinit var enrolledFingerprintsInteractorUnderTest: EnrolledFingerprintsInteractor + private lateinit var generateChallengeInteractorUnderTest: GenerateChallengeInteractor + private lateinit var removeFingerprintsInteractorUnderTest: RemoveFingerprintInteractor + private lateinit var renameFingerprintsInteractorUnderTest: RenameFingerprintInteractor + private lateinit var authenticateInteractorImplUnderTest: AuthenticateInteractorImpl + private lateinit var canEnrollFingerprintsInteractorUnderTest: CanEnrollFingerprintsInteractor + private lateinit var enrollInteractorUnderTest: EnrollFingerprintInteractor + + private val userId = 0 private var backgroundDispatcher = StandardTestDispatcher() @Mock private lateinit var fingerprintManager: FingerprintManager @Mock private lateinit var gateKeeperPasswordProvider: GatekeeperPasswordProvider private var testScope = TestScope(backgroundDispatcher) + private var backgroundScope = testScope.backgroundScope + private val flow: FingerprintFlow = Default + private val maxFingerprints = 5 + private val currUser = MutableStateFlow(0) + private val userRepo = + object : UserRepo { + override val currentUser: Flow = currUser + } @Before fun setup() { @@ -89,7 +117,7 @@ class FingerprintManagerInteractorTest { FingerprintSensorPropertiesInternal( 0 /* sensorId */, SensorProperties.STRENGTH_STRONG, - 5 /* maxEnrollmentsPerUser */, + maxFingerprints, listOf(), FingerprintSensorProperties.TYPE_POWER_BUTTON, false /* halControlsIllumination */, @@ -97,20 +125,37 @@ class FingerprintManagerInteractorTest { listOf(SensorLocationInternal.DEFAULT), ) .toFingerprintSensor() + val fingerprintSensorRepository = object : FingerprintSensorRepository { override val fingerprintSensor: Flow = flowOf(sensor) + override val hasSideFps: Flow = flowOf(false) } - underTest = - FingerprintManagerInteractorImpl( - context, - backgroundDispatcher, + val settingsRepository = FingerprintSettingsRepositoryImpl(maxFingerprints) + val fingerprintEnrollmentRepository = + FingerprintEnrollmentRepositoryImpl( fingerprintManager, - fingerprintSensorRepository, - gateKeeperPasswordProvider, - FingerprintEnrollInteractorImpl(context, fingerprintManager, Default), + userRepo, + settingsRepository, + backgroundDispatcher, + backgroundScope, ) + + enrolledFingerprintsInteractorUnderTest = + EnrolledFingerprintsInteractorImpl(fingerprintManager, userId) + generateChallengeInteractorUnderTest = + GenerateChallengeInteractorImpl(fingerprintManager, userId, gateKeeperPasswordProvider) + removeFingerprintsInteractorUnderTest = + RemoveFingerprintsInteractorImpl(fingerprintManager, userId) + renameFingerprintsInteractorUnderTest = + RenameFingerprintsInteractorImpl(fingerprintManager, userId, backgroundDispatcher) + authenticateInteractorImplUnderTest = AuthenticateInteractorImpl(fingerprintManager, userId) + + canEnrollFingerprintsInteractorUnderTest = + CanEnrollFingerprintsInteractorImpl(fingerprintEnrollmentRepository) + + enrollInteractorUnderTest = EnrollFingerprintInteractorImpl(userId, fingerprintManager, flow) } @Test @@ -119,7 +164,8 @@ class FingerprintManagerInteractorTest { whenever(fingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(emptyList()) val emptyFingerprintList: List = emptyList() - assertThat(underTest.enrolledFingerprints.last()).isEqualTo(emptyFingerprintList) + assertThat(enrolledFingerprintsInteractorUnderTest.enrolledFingerprints.last()) + .isEqualTo(emptyFingerprintList) } @Test @@ -129,7 +175,7 @@ class FingerprintManagerInteractorTest { val fingerprintList: List = listOf(expected) whenever(fingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(fingerprintList) - val list = underTest.enrolledFingerprints.last() + val list = enrolledFingerprintsInteractorUnderTest.enrolledFingerprints.last() assertThat(list!!.size).isEqualTo(fingerprintList.size) val actual = list[0] assertThat(actual.name).isEqualTo(expected.name) @@ -138,24 +184,51 @@ class FingerprintManagerInteractorTest { } @Test - fun testCanEnrollFingerprint() = + fun testCanEnrollFingerprintSucceeds() = testScope.runTest { - val fingerprintList1: List = + val fingerprintList: List = listOf( - Fingerprint("Finger 1,", 2, 3L), - Fingerprint("Finger 2,", 3, 3L), - Fingerprint("Finger 3,", 4, 3L), + Fingerprint("Finger 1", 2, 3L), + Fingerprint("Finger 2", 3, 3L), + Fingerprint("Finger 3", 4, 3L), ) - val fingerprintList2: List = - fingerprintList1.plus( - listOf(Fingerprint("Finger 4,", 5, 3L), Fingerprint("Finger 5,", 6, 3L)) - ) - whenever(fingerprintManager.getEnrolledFingerprints(anyInt())) - .thenReturn(fingerprintList1) - .thenReturn(fingerprintList2) + whenever(fingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(fingerprintList) - assertThat(underTest.canEnrollFingerprints.last()).isTrue() - assertThat(underTest.canEnrollFingerprints.last()).isFalse() + var result: Boolean? = null + val job = + testScope.launch { + canEnrollFingerprintsInteractorUnderTest.canEnrollFingerprints.collect { result = it } + } + + runCurrent() + job.cancelAndJoin() + + assertThat(result).isTrue() + } + + @Test + fun testCanEnrollFingerprintFails() = + testScope.runTest { + val fingerprintList: List = + listOf( + Fingerprint("Finger 1", 2, 3L), + Fingerprint("Finger 2", 3, 3L), + Fingerprint("Finger 3", 4, 3L), + Fingerprint("Finger 4", 5, 3L), + Fingerprint("Finger 5", 6, 3L), + ) + whenever(fingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(fingerprintList) + + var result: Boolean? = null + val job = + testScope.launch { + canEnrollFingerprintsInteractorUnderTest.canEnrollFingerprints.collect { result = it } + } + + runCurrent() + job.cancelAndJoin() + + assertThat(result).isFalse() } @Test @@ -178,7 +251,8 @@ class FingerprintManagerInteractorTest { argumentCaptor() var result: Pair? = null - val job = testScope.launch { result = underTest.generateChallenge(1L) } + val job = + testScope.launch { result = generateChallengeInteractorUnderTest.generateChallenge(1L) } runCurrent() verify(fingerprintManager).generateChallenge(anyInt(), capture(generateChallengeCallback)) @@ -201,7 +275,10 @@ class FingerprintManagerInteractorTest { var result: Boolean? = null val job = - testScope.launch { result = underTest.removeFingerprint(fingerprintViewModelToRemove) } + testScope.launch { + result = + removeFingerprintsInteractorUnderTest.removeFingerprint(fingerprintViewModelToRemove) + } runCurrent() verify(fingerprintManager) @@ -224,7 +301,10 @@ class FingerprintManagerInteractorTest { var result: Boolean? = null val job = - testScope.launch { result = underTest.removeFingerprint(fingerprintViewModelToRemove) } + testScope.launch { + result = + removeFingerprintsInteractorUnderTest.removeFingerprint(fingerprintViewModelToRemove) + } runCurrent() verify(fingerprintManager) @@ -246,7 +326,7 @@ class FingerprintManagerInteractorTest { testScope.runTest { val fingerprintToRename = FingerprintData("Finger 2", 1, 2L) - underTest.renameFingerprint(fingerprintToRename, "Woo") + renameFingerprintsInteractorUnderTest.renameFingerprint(fingerprintToRename, "Woo") verify(fingerprintManager).rename(eq(fingerprintToRename.fingerId), anyInt(), safeEq("Woo")) } @@ -257,7 +337,7 @@ class FingerprintManagerInteractorTest { val fingerprint = Fingerprint("Woooo", 100, 101L) var result: FingerprintAuthAttemptModel? = null - val job = launch { result = underTest.authenticate() } + val job = launch { result = authenticateInteractorImplUnderTest.authenticate() } val authCallback: ArgumentCaptor = argumentCaptor() @@ -284,7 +364,7 @@ class FingerprintManagerInteractorTest { fun testAuth_lockout() = testScope.runTest { var result: FingerprintAuthAttemptModel? = null - val job = launch { result = underTest.authenticate() } + val job = launch { result = authenticateInteractorImplUnderTest.authenticate() } val authCallback: ArgumentCaptor = argumentCaptor() @@ -314,7 +394,7 @@ class FingerprintManagerInteractorTest { val token = byteArrayOf(5, 3, 2) var result: FingerEnrollState? = null val job = launch { - underTest + enrollInteractorUnderTest .enroll(token, EnrollReason.FindSensor, FingerprintEnrollOptions.Builder().build()) .collect { result = it } } @@ -343,7 +423,7 @@ class FingerprintManagerInteractorTest { val token = byteArrayOf(5, 3, 2) var result: FingerEnrollState? = null val job = launch { - underTest + enrollInteractorUnderTest .enroll(token, EnrollReason.FindSensor, FingerprintEnrollOptions.Builder().build()) .collect { result = it } } @@ -372,7 +452,7 @@ class FingerprintManagerInteractorTest { val token = byteArrayOf(5, 3, 2) var result: FingerEnrollState? = null val job = launch { - underTest + enrollInteractorUnderTest .enroll(token, EnrollReason.FindSensor, FingerprintEnrollOptions.Builder().build()) .collect { result = it } } diff --git a/tests/unit/src/com/android/settings/fingerprint2/enrollment/viewmodel/FingerprintEnrollFindSensorViewModelV2Test.kt b/tests/unit/src/com/android/settings/fingerprint2/enrollment/viewmodel/FingerprintEnrollFindSensorViewModelV2Test.kt index 9662c39d94a..04cece83cd0 100644 --- a/tests/unit/src/com/android/settings/fingerprint2/enrollment/viewmodel/FingerprintEnrollFindSensorViewModelV2Test.kt +++ b/tests/unit/src/com/android/settings/fingerprint2/enrollment/viewmodel/FingerprintEnrollFindSensorViewModelV2Test.kt @@ -99,9 +99,10 @@ class FingerprintEnrollFindSensorViewModelV2Test { backgroundViewModel.inForeground() enrollViewModel = FingerprintEnrollViewModel( - fakeFingerprintManagerInteractor, gatekeeperViewModel, navigationViewModel, + fakeFingerprintManagerInteractor, + fakeFingerprintManagerInteractor, ) accessibilityInteractor = object : AccessibilityInteractor { diff --git a/tests/unit/src/com/android/settings/fingerprint2/ui/enrollment/modules/enrolling/rfps/viewmodel/RFPSIconTouchViewModelTest.kt b/tests/unit/src/com/android/settings/fingerprint2/ui/enrollment/modules/enrolling/rfps/viewmodel/RFPSIconTouchViewModelTest.kt index 46e883af33d..53f472691d6 100644 --- a/tests/unit/src/com/android/settings/fingerprint2/ui/enrollment/modules/enrolling/rfps/viewmodel/RFPSIconTouchViewModelTest.kt +++ b/tests/unit/src/com/android/settings/fingerprint2/ui/enrollment/modules/enrolling/rfps/viewmodel/RFPSIconTouchViewModelTest.kt @@ -49,8 +49,7 @@ class RFPSIconTouchViewModelTest { fun setup() { Dispatchers.setMain(backgroundDispatcher) testScope = TestScope(backgroundDispatcher) - rfpsIconTouchViewModel = - RFPSIconTouchViewModel() + rfpsIconTouchViewModel = RFPSIconTouchViewModel() } @After diff --git a/tests/unit/src/com/android/settings/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollEnrollingViewModelTest.kt b/tests/unit/src/com/android/settings/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollEnrollingViewModelTest.kt index c475cc47faa..cf2deec5bac 100644 --- a/tests/unit/src/com/android/settings/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollEnrollingViewModelTest.kt +++ b/tests/unit/src/com/android/settings/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrollEnrollingViewModelTest.kt @@ -88,9 +88,10 @@ class FingerprintEnrollEnrollingViewModelTest { backgroundViewModel.inForeground() val fingerprintEnrollViewModel = FingerprintEnrollViewModel( - fakeFingerprintManagerInteractor, gateKeeperViewModel, navigationViewModel, + fakeFingerprintManagerInteractor, + fakeFingerprintManagerInteractor, ) enrollEnrollingViewModel = FingerprintEnrollEnrollingViewModel(fingerprintEnrollViewModel, backgroundViewModel) diff --git a/tests/unit/src/com/android/settings/fingerprint2/ui/settings/FingerprintSettingsNavigationViewModelTest.kt b/tests/unit/src/com/android/settings/fingerprint2/ui/settings/FingerprintSettingsNavigationViewModelTest.kt index 201fffa608a..88f76dd23f2 100644 --- a/tests/unit/src/com/android/settings/fingerprint2/ui/settings/FingerprintSettingsNavigationViewModelTest.kt +++ b/tests/unit/src/com/android/settings/fingerprint2/ui/settings/FingerprintSettingsNavigationViewModelTest.kt @@ -67,10 +67,11 @@ class FingerprintSettingsNavigationViewModelTest { underTest = FingerprintSettingsNavigationViewModel.FingerprintSettingsNavigationModelFactory( defaultUserId, - fakeFingerprintManagerInteractor, backgroundDispatcher, null, null, + fakeFingerprintManagerInteractor, + fakeFingerprintManagerInteractor, ) .create(FingerprintSettingsNavigationViewModel::class.java) } @@ -272,10 +273,11 @@ class FingerprintSettingsNavigationViewModelTest { underTest = FingerprintSettingsNavigationViewModel.FingerprintSettingsNavigationModelFactory( defaultUserId, - fakeFingerprintManagerInteractor, backgroundDispatcher, token, challenge, + fakeFingerprintManagerInteractor, + fakeFingerprintManagerInteractor, ) .create(FingerprintSettingsNavigationViewModel::class.java) @@ -299,10 +301,11 @@ class FingerprintSettingsNavigationViewModelTest { underTest = FingerprintSettingsNavigationViewModel.FingerprintSettingsNavigationModelFactory( defaultUserId, - fakeFingerprintManagerInteractor, backgroundDispatcher, token, challenge, + fakeFingerprintManagerInteractor, + fakeFingerprintManagerInteractor, ) .create(FingerprintSettingsNavigationViewModel::class.java) @@ -331,10 +334,11 @@ class FingerprintSettingsNavigationViewModelTest { underTest = FingerprintSettingsNavigationViewModel.FingerprintSettingsNavigationModelFactory( defaultUserId, - fakeFingerprintManagerInteractor, backgroundDispatcher, token, challenge, + fakeFingerprintManagerInteractor, + fakeFingerprintManagerInteractor, ) .create(FingerprintSettingsNavigationViewModel::class.java) diff --git a/tests/unit/src/com/android/settings/fingerprint2/ui/settings/FingerprintSettingsViewModelTest.kt b/tests/unit/src/com/android/settings/fingerprint2/ui/settings/FingerprintSettingsViewModelTest.kt index 1618e16d904..79163d9a590 100644 --- a/tests/unit/src/com/android/settings/fingerprint2/ui/settings/FingerprintSettingsViewModelTest.kt +++ b/tests/unit/src/com/android/settings/fingerprint2/ui/settings/FingerprintSettingsViewModelTest.kt @@ -73,19 +73,25 @@ class FingerprintSettingsViewModelTest { navigationViewModel = FingerprintSettingsNavigationViewModel.FingerprintSettingsNavigationModelFactory( defaultUserId, - fakeFingerprintManagerInteractor, backgroundDispatcher, null, null, + fakeFingerprintManagerInteractor, + fakeFingerprintManagerInteractor, ) .create(FingerprintSettingsNavigationViewModel::class.java) underTest = FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory( defaultUserId, - fakeFingerprintManagerInteractor, backgroundDispatcher, navigationViewModel, + fakeFingerprintManagerInteractor, + fakeFingerprintManagerInteractor, + fakeFingerprintManagerInteractor, + fakeFingerprintManagerInteractor, + fakeFingerprintManagerInteractor, + fakeFingerprintManagerInteractor, ) .create(FingerprintSettingsViewModel::class.java) } @@ -114,14 +120,7 @@ class FingerprintSettingsViewModelTest { fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = mutableListOf(FingerprintData("a", 1, 3L)) - underTest = - FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory( - defaultUserId, - fakeFingerprintManagerInteractor, - backgroundDispatcher, - navigationViewModel, - ) - .create(FingerprintSettingsViewModel::class.java) + recreateSettingsViewModel() var authAttempt: FingerprintAuthAttemptModel? = null val job = launch { underTest.authFlow.take(5).collectLatest { authAttempt = it } } @@ -156,14 +155,7 @@ class FingerprintSettingsViewModelTest { fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = mutableListOf(FingerprintData("a", 1, 3L)) - underTest = - FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory( - defaultUserId, - fakeFingerprintManagerInteractor, - backgroundDispatcher, - navigationViewModel, - ) - .create(FingerprintSettingsViewModel::class.java) + recreateSettingsViewModel() var authAttempt: FingerprintAuthAttemptModel? = null val job = launch { underTest.authFlow.take(5).collectLatest { authAttempt = it } } @@ -198,14 +190,7 @@ class FingerprintSettingsViewModelTest { val success = FingerprintAuthAttemptModel.Success(1) fakeFingerprintManagerInteractor.authenticateAttempt = success - underTest = - FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory( - defaultUserId, - fakeFingerprintManagerInteractor, - backgroundDispatcher, - navigationViewModel, - ) - .create(FingerprintSettingsViewModel::class.java) + recreateSettingsViewModel() var authAttempt: FingerprintAuthAttemptModel? = null @@ -225,14 +210,7 @@ class FingerprintSettingsViewModelTest { fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = mutableListOf(fingerprintToDelete) - underTest = - FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory( - defaultUserId, - fakeFingerprintManagerInteractor, - backgroundDispatcher, - navigationViewModel, - ) - .create(FingerprintSettingsViewModel::class.java) + recreateSettingsViewModel() var dialog: PreferenceViewModel? = null val dialogJob = launch { underTest.isShowingDialog.collect { dialog = it } } @@ -261,14 +239,7 @@ class FingerprintSettingsViewModelTest { fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = mutableListOf(fingerprintToRename) - underTest = - FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory( - defaultUserId, - fakeFingerprintManagerInteractor, - backgroundDispatcher, - navigationViewModel, - ) - .create(FingerprintSettingsViewModel::class.java) + recreateSettingsViewModel() var dialog: PreferenceViewModel? = null val dialogJob = launch { underTest.isShowingDialog.collect { dialog = it } } @@ -299,14 +270,7 @@ class FingerprintSettingsViewModelTest { fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = mutableListOf(fingerprintToDelete) - underTest = - FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory( - defaultUserId, - fakeFingerprintManagerInteractor, - backgroundDispatcher, - navigationViewModel, - ) - .create(FingerprintSettingsViewModel::class.java) + recreateSettingsViewModel() var dialog: PreferenceViewModel? = null val dialogJob = launch { underTest.isShowingDialog.collect { dialog = it } } @@ -390,6 +354,22 @@ class FingerprintSettingsViewModelTest { assertThat(authAttempt).isEqualTo(null) } + private fun recreateSettingsViewModel() { + underTest = + FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory( + defaultUserId, + backgroundDispatcher, + navigationViewModel, + fakeFingerprintManagerInteractor, + fakeFingerprintManagerInteractor, + fakeFingerprintManagerInteractor, + fakeFingerprintManagerInteractor, + fakeFingerprintManagerInteractor, + fakeFingerprintManagerInteractor, + ) + .create(FingerprintSettingsViewModel::class.java) + } + private fun setupAuth(): MutableList { fakeFingerprintManagerInteractor.sensorProp = FingerprintSensorPropertiesInternal( @@ -409,14 +389,7 @@ class FingerprintSettingsViewModelTest { val success = FingerprintAuthAttemptModel.Success(1) fakeFingerprintManagerInteractor.authenticateAttempt = success - underTest = - FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory( - defaultUserId, - fakeFingerprintManagerInteractor, - backgroundDispatcher, - navigationViewModel, - ) - .create(FingerprintSettingsViewModel::class.java) + recreateSettingsViewModel() return fingerprints }