Updating navigation view model
Test: atest com.android.settings.fingerprint2.ui.enrollment.modules.enrolling.rfps.viewmodel com.android.settings.fingerprint2.ui.enrollment.viewmodel com.android.settings.fingerprint2.ui.settings com.android.settings.fingerprint2.domain.interactor com.android.settings.fingerprint2.enrollment.viewmodel Bug: 295205754 Change-Id: I210712ab76050b89452fb871cd2a4fb28bfd4012
This commit is contained in:
@@ -57,7 +57,7 @@ android_library {
|
|||||||
"src/**/*.kt",
|
"src/**/*.kt",
|
||||||
],
|
],
|
||||||
exclude_srcs: [
|
exclude_srcs: [
|
||||||
"src/com/android/settings/biometrics/fingerprint2/shared/**/*.kt",
|
"src/com/android/settings/biometrics/fingerprint2/lib/**/*.kt",
|
||||||
],
|
],
|
||||||
use_resource_processor: true,
|
use_resource_processor: true,
|
||||||
resource_dirs: [
|
resource_dirs: [
|
||||||
|
@@ -20,8 +20,8 @@ import android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERR
|
|||||||
import android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_UNABLE_TO_PROCESS
|
import android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_UNABLE_TO_PROCESS
|
||||||
import android.hardware.fingerprint.FingerprintManager
|
import android.hardware.fingerprint.FingerprintManager
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.EnrollReason
|
import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerEnrollState
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
|
||||||
|
|
||||||
object Util {
|
object Util {
|
||||||
fun EnrollReason.toOriginalReason(): Int {
|
fun EnrollReason.toOriginalReason(): Int {
|
||||||
@@ -71,6 +71,4 @@ object Util {
|
|||||||
this == FINGERPRINT_ERROR_CANCELED,
|
this == FINGERPRINT_ERROR_CANCELED,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* 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.ComponentInfoInternal
|
||||||
|
import android.hardware.biometrics.SensorLocationInternal
|
||||||
|
import android.hardware.biometrics.SensorProperties
|
||||||
|
import android.hardware.fingerprint.FingerprintManager
|
||||||
|
import android.hardware.fingerprint.FingerprintSensorProperties
|
||||||
|
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
|
||||||
|
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback
|
||||||
|
import com.android.systemui.biometrics.shared.model.FingerprintSensor
|
||||||
|
import com.android.systemui.biometrics.shared.model.toFingerprintSensor
|
||||||
|
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.stateIn
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the [FingerprintSensor]
|
||||||
|
*
|
||||||
|
* TODO(b/313493336): Move this to systemui
|
||||||
|
*/
|
||||||
|
interface FingerprintSensorRepo {
|
||||||
|
/** Get the [FingerprintSensor] */
|
||||||
|
val fingerprintSensor: Flow<FingerprintSensor>
|
||||||
|
}
|
||||||
|
|
||||||
|
class FingerprintSensorRepoImpl(
|
||||||
|
fingerprintManager: FingerprintManager,
|
||||||
|
backgroundDispatcher: CoroutineDispatcher,
|
||||||
|
activityScope: CoroutineScope,
|
||||||
|
) : FingerprintSensorRepo {
|
||||||
|
|
||||||
|
override val fingerprintSensor: Flow<FingerprintSensor> =
|
||||||
|
callbackFlow {
|
||||||
|
val callback =
|
||||||
|
object : IFingerprintAuthenticatorsRegisteredCallback.Stub() {
|
||||||
|
override fun onAllAuthenticatorsRegistered(
|
||||||
|
sensors: List<FingerprintSensorPropertiesInternal>
|
||||||
|
) {
|
||||||
|
if (sensors.isEmpty()) {
|
||||||
|
trySend(DEFAULT_PROPS)
|
||||||
|
} else {
|
||||||
|
trySend(sensors[0].toFingerprintSensor())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
withContext(backgroundDispatcher) {
|
||||||
|
fingerprintManager?.addAuthenticatorsRegisteredCallback(callback)
|
||||||
|
}
|
||||||
|
awaitClose {}
|
||||||
|
}
|
||||||
|
.stateIn(activityScope, started = SharingStarted.Eagerly, initialValue = DEFAULT_PROPS)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "FingerprintSensorRepoImpl"
|
||||||
|
|
||||||
|
private val DEFAULT_PROPS =
|
||||||
|
FingerprintSensorPropertiesInternal(
|
||||||
|
-1 /* sensorId */,
|
||||||
|
SensorProperties.STRENGTH_CONVENIENCE,
|
||||||
|
0 /* maxEnrollmentsPerUser */,
|
||||||
|
listOf<ComponentInfoInternal>(),
|
||||||
|
FingerprintSensorProperties.TYPE_UNKNOWN,
|
||||||
|
false /* halControlsIllumination */,
|
||||||
|
true /* resetLockoutRequiresHardwareAuthToken */,
|
||||||
|
listOf<SensorLocationInternal>(SensorLocationInternal.DEFAULT),
|
||||||
|
)
|
||||||
|
.toFingerprintSensor()
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2023 The Android Open Source Project
|
* Copyright (C) 2024 The Android Open Source Project
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -14,13 +14,24 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.settings.biometrics.fingerprint2.repository
|
package com.android.settings.biometrics.fingerprint2.data.repository
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.data.repository.PressToAuthProvider
|
|
||||||
|
|
||||||
class PressToAuthProviderImpl(val context: Context) : PressToAuthProvider {
|
/** Interface that indicates if press to auth is on or off. */
|
||||||
|
interface PressToAuthRepo {
|
||||||
|
/** Indicates true if the PressToAuth feature is enabled, false otherwise. */
|
||||||
|
val isEnabled: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Indicates whether or not the press to auth feature is enabled. */
|
||||||
|
class PressToAuthRepoImpl(private val context: Context) : PressToAuthRepo {
|
||||||
|
/**
|
||||||
|
* Gets the status of the press to auth feature.
|
||||||
|
*
|
||||||
|
* Returns whether or not the press to auth feature is enabled.
|
||||||
|
*/
|
||||||
override val isEnabled: Boolean
|
override val isEnabled: Boolean
|
||||||
get() {
|
get() {
|
||||||
var toReturn: Int =
|
var toReturn: Int =
|
||||||
@@ -43,7 +54,7 @@ class PressToAuthProviderImpl(val context: Context) : PressToAuthProvider {
|
|||||||
context.contentResolver,
|
context.contentResolver,
|
||||||
Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED,
|
Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED,
|
||||||
toReturn,
|
toReturn,
|
||||||
context.userId
|
context.userId,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return (toReturn == 1)
|
return (toReturn == 1)
|
@@ -26,16 +26,16 @@ import android.util.Log
|
|||||||
import com.android.settings.biometrics.GatekeeperPasswordProvider
|
import com.android.settings.biometrics.GatekeeperPasswordProvider
|
||||||
import com.android.settings.biometrics.fingerprint2.conversion.Util.toEnrollError
|
import com.android.settings.biometrics.fingerprint2.conversion.Util.toEnrollError
|
||||||
import com.android.settings.biometrics.fingerprint2.conversion.Util.toOriginalReason
|
import com.android.settings.biometrics.fingerprint2.conversion.Util.toOriginalReason
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.data.repository.PressToAuthProvider
|
import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepo
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.domain.interactor.FingerprintManagerInteractor
|
import com.android.settings.biometrics.fingerprint2.data.repository.PressToAuthRepo
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.EnrollReason
|
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintFlow
|
import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerEnrollState
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintAuthAttemptModel
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintData
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.SetupWizard
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintFlow
|
||||||
|
import com.android.settings.biometrics.fingerprint2.lib.model.SetupWizard
|
||||||
import com.android.settings.password.ChooseLockSettingsHelper
|
import com.android.settings.password.ChooseLockSettingsHelper
|
||||||
import com.android.systemui.biometrics.shared.model.toFingerprintSensor
|
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
import kotlin.coroutines.suspendCoroutine
|
import kotlin.coroutines.suspendCoroutine
|
||||||
import kotlinx.coroutines.CancellableContinuation
|
import kotlinx.coroutines.CancellableContinuation
|
||||||
@@ -57,8 +57,9 @@ class FingerprintManagerInteractorImpl(
|
|||||||
applicationContext: Context,
|
applicationContext: Context,
|
||||||
private val backgroundDispatcher: CoroutineDispatcher,
|
private val backgroundDispatcher: CoroutineDispatcher,
|
||||||
private val fingerprintManager: FingerprintManager,
|
private val fingerprintManager: FingerprintManager,
|
||||||
|
fingerprintSensorRepo: FingerprintSensorRepo,
|
||||||
private val gatekeeperPasswordProvider: GatekeeperPasswordProvider,
|
private val gatekeeperPasswordProvider: GatekeeperPasswordProvider,
|
||||||
private val pressToAuthProvider: PressToAuthProvider,
|
private val pressToAuthRepo: PressToAuthRepo,
|
||||||
private val fingerprintFlow: FingerprintFlow,
|
private val fingerprintFlow: FingerprintFlow,
|
||||||
) : FingerprintManagerInteractor {
|
) : FingerprintManagerInteractor {
|
||||||
|
|
||||||
@@ -100,13 +101,7 @@ class FingerprintManagerInteractorImpl(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val sensorPropertiesInternal = flow {
|
override val sensorPropertiesInternal = fingerprintSensorRepo.fingerprintSensor
|
||||||
val sensorPropertiesInternal = fingerprintManager.sensorPropertiesInternal
|
|
||||||
emit(
|
|
||||||
if (sensorPropertiesInternal.isEmpty()) null
|
|
||||||
else sensorPropertiesInternal.first().toFingerprintSensor()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val maxEnrollableFingerprints = flow { emit(maxFingerprints) }
|
override val maxEnrollableFingerprints = flow { emit(maxFingerprints) }
|
||||||
|
|
||||||
@@ -136,8 +131,7 @@ class FingerprintManagerInteractorImpl(
|
|||||||
totalSteps = remaining + 1
|
totalSteps = remaining + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
trySend(FingerEnrollState.EnrollProgress(remaining, totalSteps!!)).onFailure {
|
trySend(FingerEnrollState.EnrollProgress(remaining, totalSteps!!)).onFailure { error ->
|
||||||
error ->
|
|
||||||
Log.d(TAG, "onEnrollmentProgress($remaining) failed to send, due to $error")
|
Log.d(TAG, "onEnrollmentProgress($remaining) failed to send, due to $error")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,13 +142,16 @@ class FingerprintManagerInteractorImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onEnrollmentHelp(helpMsgId: Int, helpString: CharSequence?) {
|
override fun onEnrollmentHelp(helpMsgId: Int, helpString: CharSequence?) {
|
||||||
trySend(FingerEnrollState.EnrollHelp(helpMsgId, helpString.toString()))
|
trySend(FingerEnrollState.EnrollHelp(helpMsgId, helpString.toString())).onFailure { error
|
||||||
.onFailure { error -> Log.d(TAG, "onEnrollmentHelp failed to send, due to $error") }
|
->
|
||||||
|
Log.d(TAG, "onEnrollmentHelp failed to send, due to $error")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onEnrollmentError(errMsgId: Int, errString: CharSequence?) {
|
override fun onEnrollmentError(errMsgId: Int, errString: CharSequence?) {
|
||||||
trySend(errMsgId.toEnrollError(fingerprintFlow == SetupWizard))
|
trySend(errMsgId.toEnrollError(fingerprintFlow == SetupWizard)).onFailure { error ->
|
||||||
.onFailure { error -> Log.d(TAG, "onEnrollmentError failed to send, due to $error") }
|
Log.d(TAG, "onEnrollmentError failed to send, due to $error")
|
||||||
|
}
|
||||||
Log.d(TAG, "onEnrollmentError($errMsgId)")
|
Log.d(TAG, "onEnrollmentError($errMsgId)")
|
||||||
streamEnded = true
|
streamEnded = true
|
||||||
enrollRequestOutstanding.update { false }
|
enrollRequestOutstanding.update { false }
|
||||||
@@ -185,14 +182,14 @@ class FingerprintManagerInteractorImpl(
|
|||||||
override fun onRemovalError(
|
override fun onRemovalError(
|
||||||
fp: android.hardware.fingerprint.Fingerprint,
|
fp: android.hardware.fingerprint.Fingerprint,
|
||||||
errMsgId: Int,
|
errMsgId: Int,
|
||||||
errString: CharSequence
|
errString: CharSequence,
|
||||||
) {
|
) {
|
||||||
it.resume(false)
|
it.resume(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRemovalSucceeded(
|
override fun onRemovalSucceeded(
|
||||||
fp: android.hardware.fingerprint.Fingerprint?,
|
fp: android.hardware.fingerprint.Fingerprint?,
|
||||||
remaining: Int
|
remaining: Int,
|
||||||
) {
|
) {
|
||||||
it.resume(true)
|
it.resume(true)
|
||||||
}
|
}
|
||||||
@@ -200,7 +197,7 @@ class FingerprintManagerInteractorImpl(
|
|||||||
fingerprintManager.remove(
|
fingerprintManager.remove(
|
||||||
android.hardware.fingerprint.Fingerprint(fp.name, fp.fingerId, fp.deviceId),
|
android.hardware.fingerprint.Fingerprint(fp.name, fp.fingerId, fp.deviceId),
|
||||||
applicationContext.userId,
|
applicationContext.userId,
|
||||||
callback
|
callback,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,7 +212,7 @@ class FingerprintManagerInteractorImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun pressToAuthEnabled(): Boolean = suspendCancellableCoroutine {
|
override suspend fun pressToAuthEnabled(): Boolean = suspendCancellableCoroutine {
|
||||||
it.resume(pressToAuthProvider.isEnabled)
|
it.resume(pressToAuthRepo.isEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun authenticate(): FingerprintAuthAttemptModel =
|
override suspend fun authenticate(): FingerprintAuthAttemptModel =
|
||||||
@@ -249,7 +246,7 @@ class FingerprintManagerInteractorImpl(
|
|||||||
cancellationSignal,
|
cancellationSignal,
|
||||||
authenticationCallback,
|
authenticationCallback,
|
||||||
null,
|
null,
|
||||||
applicationContext.userId
|
applicationContext.userId,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -14,5 +14,5 @@
|
|||||||
~ limitations under the License.
|
~ limitations under the License.
|
||||||
-->
|
-->
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.android.settings.biometrics.fingerprint2.shared">
|
package="com.android.settings.biometrics.fingerprint2.lib">
|
||||||
</manifest>
|
</manifest>
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2023 The Android Open Source Project
|
* Copyright (C) 2024 The Android Open Source Project
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -14,12 +14,12 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.settings.biometrics.fingerprint2.shared.domain.interactor
|
package com.android.settings.biometrics.fingerprint2.lib.domain.interactor
|
||||||
|
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.EnrollReason
|
import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintAuthAttemptModel
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintData
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerEnrollState
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData
|
||||||
import com.android.systemui.biometrics.shared.model.FingerprintSensor
|
import com.android.systemui.biometrics.shared.model.FingerprintSensor
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
@@ -56,12 +56,12 @@ interface FingerprintManagerInteractor {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs [FingerprintManager.enroll] with the [hardwareAuthToken] and [EnrollReason] for this
|
* Runs [FingerprintManager.enroll] with the [hardwareAuthToken] and [EnrollReason] for this
|
||||||
* enrollment. Returning the [FingerEnrollState] that represents this fingerprint
|
* enrollment. Returning the [FingerEnrollState] that represents this fingerprint enrollment
|
||||||
* enrollment state.
|
* state.
|
||||||
*/
|
*/
|
||||||
suspend fun enroll(
|
suspend fun enroll(
|
||||||
hardwareAuthToken: ByteArray?,
|
hardwareAuthToken: ByteArray?,
|
||||||
enrollReason: EnrollReason,
|
enrollReason: EnrollReason,
|
||||||
): Flow<FingerEnrollState>
|
): Flow<FingerEnrollState>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -78,5 +78,4 @@ interface FingerprintManagerInteractor {
|
|||||||
|
|
||||||
/** Indicates if the press to auth feature has been enabled */
|
/** Indicates if the press to auth feature has been enabled */
|
||||||
suspend fun pressToAuthEnabled(): Boolean
|
suspend fun pressToAuthEnabled(): Boolean
|
||||||
|
|
||||||
}
|
}
|
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.settings.biometrics.fingerprint2.shared.model
|
package com.android.settings.biometrics.fingerprint2.lib.model
|
||||||
|
|
||||||
/** The reason for enrollment */
|
/** The reason for enrollment */
|
||||||
enum class EnrollReason {
|
enum class EnrollReason {
|
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.settings.biometrics.fingerprint2.shared.model
|
package com.android.settings.biometrics.fingerprint2.lib.model
|
||||||
|
|
||||||
import android.annotation.StringRes
|
import android.annotation.StringRes
|
||||||
|
|
||||||
@@ -28,16 +28,12 @@ sealed class FingerEnrollState {
|
|||||||
*
|
*
|
||||||
* Progress is obtained by (totalStepsRequired - remainingSteps) / totalStepsRequired
|
* Progress is obtained by (totalStepsRequired - remainingSteps) / totalStepsRequired
|
||||||
*/
|
*/
|
||||||
data class EnrollProgress(
|
data class EnrollProgress(val remainingSteps: Int, val totalStepsRequired: Int) :
|
||||||
val remainingSteps: Int,
|
FingerEnrollState()
|
||||||
val totalStepsRequired: Int,
|
|
||||||
) : FingerEnrollState()
|
|
||||||
|
|
||||||
/** Represents that recoverable error has been encountered during enrollment. */
|
/** Represents that recoverable error has been encountered during enrollment. */
|
||||||
data class EnrollHelp(
|
data class EnrollHelp(@StringRes val helpMsgId: Int, val helpString: String) :
|
||||||
@StringRes val helpMsgId: Int,
|
FingerEnrollState()
|
||||||
val helpString: String,
|
|
||||||
) : FingerEnrollState()
|
|
||||||
|
|
||||||
/** Represents that an unrecoverable error has been encountered and the operation is complete. */
|
/** Represents that an unrecoverable error has been encountered and the operation is complete. */
|
||||||
data class EnrollError(
|
data class EnrollError(
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2023 The Android Open Source Project
|
* Copyright (C) 2024 The Android Open Source Project
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -14,21 +14,13 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.settings.biometrics.fingerprint2.shared.model
|
package com.android.settings.biometrics.fingerprint2.lib.model
|
||||||
|
|
||||||
data class FingerprintData(
|
|
||||||
val name: String,
|
|
||||||
val fingerId: Int,
|
|
||||||
val deviceId: Long,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
/** Information indicating whether an auth was successful or not */
|
||||||
sealed class FingerprintAuthAttemptModel {
|
sealed class FingerprintAuthAttemptModel {
|
||||||
data class Success(
|
/** Indicates a successful auth attempt has occurred for [fingerId] */
|
||||||
val fingerId: Int,
|
data class Success(val fingerId: Int) : FingerprintAuthAttemptModel()
|
||||||
) : FingerprintAuthAttemptModel()
|
|
||||||
|
|
||||||
data class Error(
|
/** Indicates a failed auth attempt has occurred. */
|
||||||
val error: Int,
|
data class Error(val error: Int, val message: String) : FingerprintAuthAttemptModel()
|
||||||
val message: String,
|
|
||||||
) : FingerprintAuthAttemptModel()
|
|
||||||
}
|
}
|
@@ -14,14 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.settings.biometrics.fingerprint2.shared.data.repository
|
package com.android.settings.biometrics.fingerprint2.lib.model
|
||||||
|
|
||||||
/**
|
/** Basic information about an enrolled fingerprint */
|
||||||
* Interface that indicates if press to auth is on or off.
|
data class FingerprintData(val name: String, val fingerId: Int, val deviceId: Long)
|
||||||
*/
|
|
||||||
interface PressToAuthProvider {
|
|
||||||
/**
|
|
||||||
* Indicates true if the PressToAuth feature is enabled, false otherwise.
|
|
||||||
*/
|
|
||||||
val isEnabled: Boolean
|
|
||||||
}
|
|
@@ -14,10 +14,11 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.settings.biometrics.fingerprint2.shared.model
|
package com.android.settings.biometrics.fingerprint2.lib.model
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The [FingerprintFlow] for fingerprint enrollment indicates information on how the flow should behave.
|
* The [FingerprintFlow] for fingerprint enrollment indicates information on how the flow should
|
||||||
|
* behave.
|
||||||
*/
|
*/
|
||||||
sealed class FingerprintFlow
|
sealed class FingerprintFlow
|
||||||
|
|
||||||
@@ -32,3 +33,6 @@ data object Unicorn : FingerprintFlow()
|
|||||||
|
|
||||||
/** Flow to specify settings type */
|
/** Flow to specify settings type */
|
||||||
data object Settings : FingerprintFlow()
|
data object Settings : FingerprintFlow()
|
||||||
|
|
||||||
|
/** Indicates that the fast enroll experience should occur */
|
||||||
|
data object FastEnroll : FingerprintFlow()
|
@@ -21,7 +21,6 @@ import android.content.Intent
|
|||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.hardware.fingerprint.FingerprintManager
|
import android.hardware.fingerprint.FingerprintManager
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.Settings
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.accessibility.AccessibilityManager
|
import android.view.accessibility.AccessibilityManager
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
@@ -31,16 +30,18 @@ import androidx.lifecycle.ViewModelProvider
|
|||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.android.internal.widget.LockPatternUtils
|
import com.android.internal.widget.LockPatternUtils
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
|
import com.android.settings.SettingsApplication
|
||||||
import com.android.settings.SetupWizardUtils
|
import com.android.settings.SetupWizardUtils
|
||||||
import com.android.settings.Utils.SETTINGS_PACKAGE_NAME
|
import com.android.settings.Utils.SETTINGS_PACKAGE_NAME
|
||||||
import com.android.settings.biometrics.BiometricEnrollBase
|
import com.android.settings.biometrics.BiometricEnrollBase
|
||||||
import com.android.settings.biometrics.BiometricEnrollBase.CONFIRM_REQUEST
|
import com.android.settings.biometrics.BiometricEnrollBase.CONFIRM_REQUEST
|
||||||
import com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED
|
import com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED
|
||||||
import com.android.settings.biometrics.GatekeeperPasswordProvider
|
import com.android.settings.biometrics.GatekeeperPasswordProvider
|
||||||
|
import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepoImpl
|
||||||
|
import com.android.settings.biometrics.fingerprint2.data.repository.PressToAuthRepoImpl
|
||||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl
|
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.Default
|
import com.android.settings.biometrics.fingerprint2.lib.model.Default
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.SetupWizard
|
import com.android.settings.biometrics.fingerprint2.lib.model.SetupWizard
|
||||||
import com.android.settings.biometrics.fingerprint2.repository.PressToAuthProviderImpl
|
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollConfirmationV2Fragment
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollConfirmationV2Fragment
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollEnrollingV2Fragment
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollEnrollingV2Fragment
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollFindSensorV2Fragment
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollFindSensorV2Fragment
|
||||||
@@ -49,20 +50,24 @@ import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enroll
|
|||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.viewmodel.RFPSViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.viewmodel.RFPSViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.AccessibilityViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.AccessibilityViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Confirmation
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintAction
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Education
|
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Enrollment
|
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollEnrollingViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollEnrollingViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollFindSensorViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollFindSensorViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollNavigationViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollIntroViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollViewModel
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintFlowViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.ConfirmDeviceCredential
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Confirmation
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Education
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Enrollment
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Init
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Introduction
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.TransitionStep
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Finish
|
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FoldStateViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FoldStateViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Intro
|
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.LaunchConfirmDeviceCredential
|
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.OrientationStateViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.OrientationStateViewModel
|
||||||
import com.android.settings.password.ChooseLockGeneric
|
import com.android.settings.password.ChooseLockGeneric
|
||||||
import com.android.settings.password.ChooseLockSettingsHelper
|
import com.android.settings.password.ChooseLockSettingsHelper
|
||||||
@@ -71,7 +76,6 @@ import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
|||||||
import com.google.android.setupcompat.util.WizardManagerHelper
|
import com.google.android.setupcompat.util.WizardManagerHelper
|
||||||
import com.google.android.setupdesign.util.ThemeHelper
|
import com.google.android.setupdesign.util.ThemeHelper
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.combine
|
|
||||||
import kotlinx.coroutines.flow.filterNotNull
|
import kotlinx.coroutines.flow.filterNotNull
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@@ -83,7 +87,7 @@ private const val TAG = "FingerprintEnrollmentV2Activity"
|
|||||||
*/
|
*/
|
||||||
class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
||||||
private lateinit var fingerprintEnrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel
|
private lateinit var fingerprintEnrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel
|
||||||
private lateinit var navigationViewModel: FingerprintEnrollNavigationViewModel
|
private lateinit var navigationViewModel: FingerprintNavigationViewModel
|
||||||
private lateinit var gatekeeperViewModel: FingerprintGatekeeperViewModel
|
private lateinit var gatekeeperViewModel: FingerprintGatekeeperViewModel
|
||||||
private lateinit var fingerprintEnrollViewModel: FingerprintEnrollViewModel
|
private lateinit var fingerprintEnrollViewModel: FingerprintEnrollViewModel
|
||||||
private lateinit var accessibilityViewModel: AccessibilityViewModel
|
private lateinit var accessibilityViewModel: AccessibilityViewModel
|
||||||
@@ -91,6 +95,7 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
|||||||
private lateinit var orientationStateViewModel: OrientationStateViewModel
|
private lateinit var orientationStateViewModel: OrientationStateViewModel
|
||||||
private lateinit var fingerprintScrollViewModel: FingerprintScrollViewModel
|
private lateinit var fingerprintScrollViewModel: FingerprintScrollViewModel
|
||||||
private lateinit var backgroundViewModel: BackgroundViewModel
|
private lateinit var backgroundViewModel: BackgroundViewModel
|
||||||
|
private lateinit var fingerprintFlowViewModel: FingerprintFlowViewModel
|
||||||
private val coroutineDispatcher = Dispatchers.Default
|
private val coroutineDispatcher = Dispatchers.Default
|
||||||
|
|
||||||
/** Result listener for ChooseLock activity flow. */
|
/** Result listener for ChooseLock activity flow. */
|
||||||
@@ -119,6 +124,7 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
|||||||
super.onResume()
|
super.onResume()
|
||||||
backgroundViewModel.inForeground()
|
backgroundViewModel.inForeground()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||||
super.onConfigurationChanged(newConfig)
|
super.onConfigurationChanged(newConfig)
|
||||||
foldStateViewModel.onConfigurationChange(newConfig)
|
foldStateViewModel.onConfigurationChange(newConfig)
|
||||||
@@ -127,8 +133,20 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
|||||||
private fun onConfirmDevice(resultCode: Int, data: Intent?) {
|
private fun onConfirmDevice(resultCode: Int, data: Intent?) {
|
||||||
val wasSuccessful = resultCode == RESULT_FINISHED || resultCode == Activity.RESULT_OK
|
val wasSuccessful = resultCode == RESULT_FINISHED || resultCode == Activity.RESULT_OK
|
||||||
val gateKeeperPasswordHandle = data?.getExtra(EXTRA_KEY_GK_PW_HANDLE) as Long?
|
val gateKeeperPasswordHandle = data?.getExtra(EXTRA_KEY_GK_PW_HANDLE) as Long?
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
|
val confirmDeviceResult =
|
||||||
|
if (wasSuccessful) {
|
||||||
|
FingerprintAction.CONFIRM_DEVICE_SUCCESS
|
||||||
|
} else {
|
||||||
|
FingerprintAction.CONFIRM_DEVICE_FAIL
|
||||||
|
}
|
||||||
gatekeeperViewModel.onConfirmDevice(wasSuccessful, gateKeeperPasswordHandle)
|
gatekeeperViewModel.onConfirmDevice(wasSuccessful, gateKeeperPasswordHandle)
|
||||||
|
navigationViewModel.update(
|
||||||
|
confirmDeviceResult,
|
||||||
|
ConfirmDeviceCredential::class,
|
||||||
|
"$TAG#onConfirmDevice",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,14 +174,21 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
|||||||
ViewModelProvider(this, BackgroundViewModel.BackgroundViewModelFactory())[
|
ViewModelProvider(this, BackgroundViewModel.BackgroundViewModelFactory())[
|
||||||
BackgroundViewModel::class.java]
|
BackgroundViewModel::class.java]
|
||||||
|
|
||||||
|
fingerprintFlowViewModel =
|
||||||
|
ViewModelProvider(this, FingerprintFlowViewModel.FingerprintFlowViewModelFactory(enrollType))[
|
||||||
|
FingerprintFlowViewModel::class.java]
|
||||||
|
|
||||||
val interactor =
|
val fingerprintSensorRepo =
|
||||||
|
FingerprintSensorRepoImpl(fingerprintManager, backgroundDispatcher, lifecycleScope)
|
||||||
|
|
||||||
|
val fingerprintManagerInteractor =
|
||||||
FingerprintManagerInteractorImpl(
|
FingerprintManagerInteractorImpl(
|
||||||
context,
|
context,
|
||||||
backgroundDispatcher,
|
backgroundDispatcher,
|
||||||
fingerprintManager,
|
fingerprintManager,
|
||||||
|
fingerprintSensorRepo,
|
||||||
GatekeeperPasswordProvider(LockPatternUtils(context)),
|
GatekeeperPasswordProvider(LockPatternUtils(context)),
|
||||||
PressToAuthProviderImpl(context),
|
PressToAuthRepoImpl(context),
|
||||||
enrollType,
|
enrollType,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -171,27 +196,37 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
|||||||
val token = intent.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN)
|
val token = intent.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN)
|
||||||
val gatekeeperInfo = FingerprintGatekeeperViewModel.toGateKeeperInfo(challenge, token)
|
val gatekeeperInfo = FingerprintGatekeeperViewModel.toGateKeeperInfo(challenge, token)
|
||||||
|
|
||||||
|
val hasConfirmedDeviceCredential = gatekeeperInfo is GatekeeperInfo.GatekeeperPasswordInfo
|
||||||
|
|
||||||
|
navigationViewModel =
|
||||||
|
ViewModelProvider(
|
||||||
|
this,
|
||||||
|
FingerprintNavigationViewModel.FingerprintNavigationViewModelFactory(
|
||||||
|
Init,
|
||||||
|
hasConfirmedDeviceCredential,
|
||||||
|
fingerprintFlowViewModel,
|
||||||
|
fingerprintManagerInteractor,
|
||||||
|
),
|
||||||
|
)[FingerprintNavigationViewModel::class.java]
|
||||||
|
// Initialize FingerprintEnrollIntroViewModel
|
||||||
|
ViewModelProvider(
|
||||||
|
this,
|
||||||
|
FingerprintEnrollIntroViewModel.FingerprintEnrollIntoViewModelFactory(
|
||||||
|
navigationViewModel,
|
||||||
|
fingerprintFlowViewModel,
|
||||||
|
fingerprintManagerInteractor,
|
||||||
|
),
|
||||||
|
)[FingerprintEnrollIntroViewModel::class.java]
|
||||||
|
|
||||||
gatekeeperViewModel =
|
gatekeeperViewModel =
|
||||||
ViewModelProvider(
|
ViewModelProvider(
|
||||||
this,
|
this,
|
||||||
FingerprintGatekeeperViewModel.FingerprintGatekeeperViewModelFactory(
|
FingerprintGatekeeperViewModel.FingerprintGatekeeperViewModelFactory(
|
||||||
gatekeeperInfo,
|
gatekeeperInfo,
|
||||||
interactor,
|
fingerprintManagerInteractor,
|
||||||
)
|
),
|
||||||
)[FingerprintGatekeeperViewModel::class.java]
|
)[FingerprintGatekeeperViewModel::class.java]
|
||||||
|
|
||||||
navigationViewModel =
|
|
||||||
ViewModelProvider(
|
|
||||||
this,
|
|
||||||
FingerprintEnrollNavigationViewModel.FingerprintEnrollNavigationViewModelFactory(
|
|
||||||
backgroundDispatcher,
|
|
||||||
interactor,
|
|
||||||
gatekeeperViewModel,
|
|
||||||
gatekeeperInfo is GatekeeperInfo.GatekeeperPasswordInfo,
|
|
||||||
enrollType,
|
|
||||||
)
|
|
||||||
)[FingerprintEnrollNavigationViewModel::class.java]
|
|
||||||
|
|
||||||
// Initialize FoldStateViewModel
|
// Initialize FoldStateViewModel
|
||||||
foldStateViewModel =
|
foldStateViewModel =
|
||||||
ViewModelProvider(this, FoldStateViewModel.FoldStateViewModelFactory(context))[
|
ViewModelProvider(this, FoldStateViewModel.FoldStateViewModelFactory(context))[
|
||||||
@@ -203,10 +238,10 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
|||||||
ViewModelProvider(
|
ViewModelProvider(
|
||||||
this,
|
this,
|
||||||
FingerprintEnrollViewModel.FingerprintEnrollViewModelFactory(
|
FingerprintEnrollViewModel.FingerprintEnrollViewModelFactory(
|
||||||
interactor,
|
fingerprintManagerInteractor,
|
||||||
gatekeeperViewModel,
|
gatekeeperViewModel,
|
||||||
navigationViewModel,
|
navigationViewModel,
|
||||||
)
|
),
|
||||||
)[FingerprintEnrollViewModel::class.java]
|
)[FingerprintEnrollViewModel::class.java]
|
||||||
|
|
||||||
// Initialize scroll view model
|
// Initialize scroll view model
|
||||||
@@ -220,7 +255,7 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
|||||||
this,
|
this,
|
||||||
AccessibilityViewModel.AccessibilityViewModelFactory(
|
AccessibilityViewModel.AccessibilityViewModelFactory(
|
||||||
getSystemService(AccessibilityManager::class.java)!!
|
getSystemService(AccessibilityManager::class.java)!!
|
||||||
)
|
),
|
||||||
)[AccessibilityViewModel::class.java]
|
)[AccessibilityViewModel::class.java]
|
||||||
|
|
||||||
// Initialize OrientationViewModel
|
// Initialize OrientationViewModel
|
||||||
@@ -234,8 +269,8 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
|||||||
this,
|
this,
|
||||||
FingerprintEnrollEnrollingViewModel.FingerprintEnrollEnrollingViewModelFactory(
|
FingerprintEnrollEnrollingViewModel.FingerprintEnrollEnrollingViewModelFactory(
|
||||||
fingerprintEnrollViewModel,
|
fingerprintEnrollViewModel,
|
||||||
backgroundViewModel
|
backgroundViewModel,
|
||||||
)
|
),
|
||||||
)[FingerprintEnrollEnrollingViewModel::class.java]
|
)[FingerprintEnrollEnrollingViewModel::class.java]
|
||||||
|
|
||||||
// Initialize FingerprintEnrollFindSensorViewModel
|
// Initialize FingerprintEnrollFindSensorViewModel
|
||||||
@@ -248,36 +283,48 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
|||||||
backgroundViewModel,
|
backgroundViewModel,
|
||||||
accessibilityViewModel,
|
accessibilityViewModel,
|
||||||
foldStateViewModel,
|
foldStateViewModel,
|
||||||
orientationStateViewModel
|
orientationStateViewModel,
|
||||||
)
|
fingerprintFlowViewModel,
|
||||||
|
),
|
||||||
)[FingerprintEnrollFindSensorViewModel::class.java]
|
)[FingerprintEnrollFindSensorViewModel::class.java]
|
||||||
|
|
||||||
// Initialize RFPS View Model
|
// Initialize RFPS View Model
|
||||||
ViewModelProvider(
|
ViewModelProvider(
|
||||||
this,
|
this,
|
||||||
RFPSViewModel.RFPSViewModelFactory(fingerprintEnrollEnrollingViewModel)
|
RFPSViewModel.RFPSViewModelFactory(fingerprintEnrollEnrollingViewModel, navigationViewModel),
|
||||||
)[RFPSViewModel::class.java]
|
)[RFPSViewModel::class.java]
|
||||||
|
lifecycleScope.launch {
|
||||||
|
navigationViewModel.currentStep.collect { step ->
|
||||||
|
if (step is Init) {
|
||||||
|
Log.d(TAG, "FingerprintNav.init($step)")
|
||||||
|
navigationViewModel.update(FingerprintAction.ACTIVITY_CREATED, Init::class, "$TAG#init")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
navigationViewModel.navigationViewModel
|
navigationViewModel.navigateTo.filterNotNull().collect { step ->
|
||||||
.filterNotNull()
|
if (step is ConfirmDeviceCredential) {
|
||||||
.combine(fingerprintEnrollViewModel.sensorType) { nav, sensorType -> Pair(nav, sensorType) }
|
launchConfirmOrChooseLock(userId)
|
||||||
.collect { (nav, sensorType) ->
|
navigationViewModel.update(
|
||||||
Log.d(TAG, "navigationStep $nav")
|
FingerprintAction.TRANSITION_FINISHED,
|
||||||
fingerprintEnrollViewModel.sensorTypeCached = sensorType
|
TransitionStep::class,
|
||||||
val isForward = nav.forward
|
"$TAG#launchConfirmOrChooseLock",
|
||||||
val currStep = nav.currStep
|
)
|
||||||
val theClass: Class<Fragment>? =
|
} else {
|
||||||
when (currStep) {
|
val theClass: Fragment? =
|
||||||
Confirmation -> FingerprintEnrollConfirmationV2Fragment::class.java as Class<Fragment>
|
when (step) {
|
||||||
Education -> FingerprintEnrollFindSensorV2Fragment::class.java as Class<Fragment>
|
Confirmation -> FingerprintEnrollConfirmationV2Fragment()
|
||||||
|
is Education -> {
|
||||||
|
FingerprintEnrollFindSensorV2Fragment(step.sensor.sensorType)
|
||||||
|
}
|
||||||
is Enrollment -> {
|
is Enrollment -> {
|
||||||
when (sensorType) {
|
when (step.sensor.sensorType) {
|
||||||
FingerprintSensorType.REAR -> RFPSEnrollFragment::class.java as Class<Fragment>
|
FingerprintSensorType.REAR -> RFPSEnrollFragment()
|
||||||
else -> FingerprintEnrollEnrollingV2Fragment::class.java as Class<Fragment>
|
else -> FingerprintEnrollEnrollingV2Fragment()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Intro -> FingerprintEnrollIntroV2Fragment::class.java as Class<Fragment>
|
Introduction -> FingerprintEnrollIntroV2Fragment()
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,19 +338,31 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
|||||||
.setReorderingAllowed(true)
|
.setReorderingAllowed(true)
|
||||||
.add(R.id.fragment_container_view, theClass, null)
|
.add(R.id.fragment_container_view, theClass, null)
|
||||||
.commit()
|
.commit()
|
||||||
} else {
|
navigationViewModel.update(
|
||||||
|
FingerprintAction.TRANSITION_FINISHED,
|
||||||
if (currStep is Finish) {
|
TransitionStep::class,
|
||||||
if (currStep.resultCode != null) {
|
"$TAG#fragmentManager.add($theClass)",
|
||||||
finishActivity(currStep.resultCode)
|
)
|
||||||
} else {
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
} else if (currStep == LaunchConfirmDeviceCredential) {
|
|
||||||
launchConfirmOrChooseLock(userId)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lifecycleScope.launch {
|
||||||
|
navigationViewModel.shouldFinish.filterNotNull().collect {
|
||||||
|
Log.d(TAG, "FingerprintSettingsNav.finishing($it)")
|
||||||
|
if (it.result != null) {
|
||||||
|
finishActivity(it.result as Int)
|
||||||
|
} else {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lifecycleScope.launch {
|
||||||
|
navigationViewModel.currentScreen.filterNotNull().collect { screen ->
|
||||||
|
Log.d(TAG, "FingerprintSettingsNav.currentScreen($screen)")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val fromSettingsSummary =
|
val fromSettingsSummary =
|
||||||
@@ -313,7 +372,7 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
|||||||
) {
|
) {
|
||||||
overridePendingTransition(
|
overridePendingTransition(
|
||||||
com.google.android.setupdesign.R.anim.sud_slide_next_in,
|
com.google.android.setupdesign.R.anim.sud_slide_next_in,
|
||||||
com.google.android.setupdesign.R.anim.sud_slide_next_out
|
com.google.android.setupdesign.R.anim.sud_slide_next_out,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,8 +18,6 @@ package com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollNavigationViewModel
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A fragment to indicate that fingerprint enrollment has been completed.
|
* A fragment to indicate that fingerprint enrollment has been completed.
|
||||||
@@ -31,9 +29,5 @@ class FingerprintEnrollConfirmationV2Fragment : Fragment() {
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
if (savedInstanceState == null) {
|
|
||||||
val navigationViewModel =
|
|
||||||
ViewModelProvider(requireActivity())[FingerprintEnrollNavigationViewModel::class.java]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,18 +18,12 @@ package com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollNavigationViewModel
|
|
||||||
|
|
||||||
/** A fragment that is responsible for enrolling a users fingerprint. */
|
/** A fragment that is responsible for enrolling a users fingerprint. */
|
||||||
class FingerprintEnrollEnrollingV2Fragment : Fragment(R.layout.fingerprint_enroll_enrolling) {
|
class FingerprintEnrollEnrollingV2Fragment : Fragment(R.layout.fingerprint_enroll_enrolling) {
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
if (savedInstanceState == null) {
|
|
||||||
val navigationViewModel =
|
|
||||||
ViewModelProvider(requireActivity())[FingerprintEnrollNavigationViewModel::class.java]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -50,7 +50,7 @@ private const val TAG = "FingerprintEnrollFindSensorV2Fragment"
|
|||||||
* 2. Explain to the user how the enrollment process shown by [FingerprintEnrollEnrollingV2Fragment]
|
* 2. Explain to the user how the enrollment process shown by [FingerprintEnrollEnrollingV2Fragment]
|
||||||
* will work.
|
* will work.
|
||||||
*/
|
*/
|
||||||
class FingerprintEnrollFindSensorV2Fragment : Fragment() {
|
class FingerprintEnrollFindSensorV2Fragment(val sensorType: FingerprintSensorType) : Fragment() {
|
||||||
// This is only for non-udfps or non-sfps sensor. For udfps and sfps, we show lottie.
|
// This is only for non-udfps or non-sfps sensor. For udfps and sfps, we show lottie.
|
||||||
private var animation: FingerprintFindSensorAnimation? = null
|
private var animation: FingerprintFindSensorAnimation? = null
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ class FingerprintEnrollFindSensorV2Fragment : Fragment() {
|
|||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?,
|
||||||
): View? {
|
): View? {
|
||||||
|
|
||||||
val sensorType =
|
val sensorType =
|
||||||
@@ -104,8 +104,7 @@ class FingerprintEnrollFindSensorV2Fragment : Fragment() {
|
|||||||
}
|
}
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
viewModel.showRfpsAnimation.collect {
|
viewModel.showRfpsAnimation.collect {
|
||||||
animation =
|
animation = view.findViewById(R.id.fingerprint_sensor_location_animation)
|
||||||
view.findViewById(R.id.fingerprint_sensor_location_animation)
|
|
||||||
animation!!.startAnimation()
|
animation!!.startAnimation()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -128,14 +127,7 @@ class FingerprintEnrollFindSensorV2Fragment : Fragment() {
|
|||||||
footerBarMixin.secondaryButton =
|
footerBarMixin.secondaryButton =
|
||||||
FooterButton.Builder(requireActivity())
|
FooterButton.Builder(requireActivity())
|
||||||
.setText(R.string.security_settings_fingerprint_enroll_enrolling_skip)
|
.setText(R.string.security_settings_fingerprint_enroll_enrolling_skip)
|
||||||
.setListener {
|
.setListener { viewModel.secondaryButtonClicked() }
|
||||||
run {
|
|
||||||
// TODO: Show the dialog for suw
|
|
||||||
Log.d(TAG, "onSkipClicked")
|
|
||||||
// TODO: Finish activity in the root activity instead.
|
|
||||||
requireActivity().finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.setButtonType(FooterButton.ButtonType.SKIP)
|
.setButtonType(FooterButton.ButtonType.SKIP)
|
||||||
.setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Secondary)
|
.setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Secondary)
|
||||||
.build()
|
.build()
|
||||||
@@ -146,10 +138,8 @@ class FingerprintEnrollFindSensorV2Fragment : Fragment() {
|
|||||||
FooterButton.Builder(requireActivity())
|
FooterButton.Builder(requireActivity())
|
||||||
.setText(R.string.security_settings_udfps_enroll_find_sensor_start_button)
|
.setText(R.string.security_settings_udfps_enroll_find_sensor_start_button)
|
||||||
.setListener {
|
.setListener {
|
||||||
run {
|
Log.d(TAG, "onStartButtonClick")
|
||||||
Log.d(TAG, "onStartButtonClick")
|
viewModel.proceedToEnrolling()
|
||||||
viewModel.proceedToEnrolling()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.setButtonType(FooterButton.ButtonType.NEXT)
|
.setButtonType(FooterButton.ButtonType.NEXT)
|
||||||
.setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary)
|
.setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary)
|
||||||
@@ -159,7 +149,7 @@ class FingerprintEnrollFindSensorV2Fragment : Fragment() {
|
|||||||
private fun setupLottie(
|
private fun setupLottie(
|
||||||
view: View,
|
view: View,
|
||||||
lottieAnimation: Int,
|
lottieAnimation: Int,
|
||||||
lottieClickListener: View.OnClickListener? = null
|
lottieClickListener: View.OnClickListener? = null,
|
||||||
) {
|
) {
|
||||||
val illustrationLottie: LottieAnimationView? = view.findViewById(R.id.illustration_lottie)
|
val illustrationLottie: LottieAnimationView? = view.findViewById(R.id.illustration_lottie)
|
||||||
illustrationLottie?.setAnimation(lottieAnimation)
|
illustrationLottie?.setAnimation(lottieAnimation)
|
||||||
|
@@ -24,7 +24,6 @@ import android.graphics.PorterDuffColorFilter
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Html
|
import android.text.Html
|
||||||
import android.text.method.LinkMovementMethod
|
import android.text.method.LinkMovementMethod
|
||||||
import android.util.Log
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@@ -36,9 +35,8 @@ import androidx.fragment.app.Fragment
|
|||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.Unicorn
|
import com.android.settings.biometrics.fingerprint2.lib.model.Unicorn
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollNavigationViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollIntroViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollViewModel
|
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel
|
||||||
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
||||||
@@ -48,6 +46,7 @@ import com.google.android.setupdesign.GlifLayout
|
|||||||
import com.google.android.setupdesign.template.RequireScrollMixin
|
import com.google.android.setupdesign.template.RequireScrollMixin
|
||||||
import com.google.android.setupdesign.util.DynamicColorPalette
|
import com.google.android.setupdesign.util.DynamicColorPalette
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.filterNotNull
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
private const val TAG = "FingerprintEnrollmentIntroV2Fragment"
|
private const val TAG = "FingerprintEnrollmentIntroV2Fragment"
|
||||||
@@ -96,16 +95,14 @@ class FingerprintEnrollIntroV2Fragment() : Fragment(R.layout.fingerprint_v2_enro
|
|||||||
private lateinit var footerBarMixin: FooterBarMixin
|
private lateinit var footerBarMixin: FooterBarMixin
|
||||||
private lateinit var textModel: TextModel
|
private lateinit var textModel: TextModel
|
||||||
|
|
||||||
// Note that the ViewModels cannot be requested before the onCreate call
|
private val viewModel: FingerprintEnrollIntroViewModel by lazy {
|
||||||
private val navigationViewModel: FingerprintEnrollNavigationViewModel by lazy {
|
viewModelProvider[FingerprintEnrollIntroViewModel::class.java]
|
||||||
viewModelProvider[FingerprintEnrollNavigationViewModel::class.java]
|
|
||||||
}
|
|
||||||
private val fingerprintViewModel: FingerprintEnrollViewModel by lazy {
|
|
||||||
viewModelProvider[FingerprintEnrollViewModel::class.java]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val fingerprintScrollViewModel: FingerprintScrollViewModel by lazy {
|
private val fingerprintScrollViewModel: FingerprintScrollViewModel by lazy {
|
||||||
viewModelProvider[FingerprintScrollViewModel::class.java]
|
viewModelProvider[FingerprintScrollViewModel::class.java]
|
||||||
}
|
}
|
||||||
|
|
||||||
private val gateKeeperViewModel: FingerprintGatekeeperViewModel by lazy {
|
private val gateKeeperViewModel: FingerprintGatekeeperViewModel by lazy {
|
||||||
viewModelProvider[FingerprintGatekeeperViewModel::class.java]
|
viewModelProvider[FingerprintGatekeeperViewModel::class.java]
|
||||||
}
|
}
|
||||||
@@ -113,17 +110,16 @@ class FingerprintEnrollIntroV2Fragment() : Fragment(R.layout.fingerprint_v2_enro
|
|||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?,
|
||||||
): View? =
|
): View? =
|
||||||
super.onCreateView(inflater, container, savedInstanceState).also { theView ->
|
super.onCreateView(inflater, container, savedInstanceState).also { theView ->
|
||||||
val view = theView!!
|
val view = theView!!
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
combine(
|
combine(viewModel.fingerprintFlow, viewModel.sensor.filterNotNull()) {
|
||||||
navigationViewModel.fingerprintFlow,
|
enrollType,
|
||||||
fingerprintViewModel.sensorType,
|
sensorType ->
|
||||||
) { enrollType, sensorType ->
|
Pair(enrollType, sensorType.sensorType)
|
||||||
Pair(enrollType, sensorType)
|
|
||||||
}
|
}
|
||||||
.collect { (enrollType, sensorType) ->
|
.collect { (enrollType, sensorType) ->
|
||||||
textModel =
|
textModel =
|
||||||
@@ -147,7 +143,7 @@ class FingerprintEnrollIntroV2Fragment() : Fragment(R.layout.fingerprint_v2_enro
|
|||||||
R.id.icon_trash_can,
|
R.id.icon_trash_can,
|
||||||
R.id.icon_info,
|
R.id.icon_info,
|
||||||
R.id.icon_shield,
|
R.id.icon_shield,
|
||||||
R.id.icon_link
|
R.id.icon_link,
|
||||||
)
|
)
|
||||||
.forEach { icon ->
|
.forEach { icon ->
|
||||||
view.requireViewById<ImageView>(icon).drawable.colorFilter = colorFilter
|
view.requireViewById<ImageView>(icon).drawable.colorFilter = colorFilter
|
||||||
@@ -186,31 +182,24 @@ class FingerprintEnrollIntroV2Fragment() : Fragment(R.layout.fingerprint_v2_enro
|
|||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** TODO (b/305269201): This link isn't displaying for screenshot tests. */
|
||||||
* TODO (b/305269201): This link isn't displaying for screenshot tests.
|
|
||||||
*/
|
|
||||||
private fun setFooterLink(view: View) {
|
private fun setFooterLink(view: View) {
|
||||||
val footerLink: TextView = view.requireViewById(R.id.footer_learn_more)
|
val footerLink: TextView = view.requireViewById(R.id.footer_learn_more)
|
||||||
footerLink.movementMethod = LinkMovementMethod.getInstance()
|
footerLink.movementMethod = LinkMovementMethod.getInstance()
|
||||||
footerLink.text =
|
footerLink.text =
|
||||||
Html.fromHtml(
|
Html.fromHtml(
|
||||||
getString(R.string.security_settings_fingerprint_v2_enroll_introduction_message_learn_more),
|
getString(R.string.security_settings_fingerprint_v2_enroll_introduction_message_learn_more),
|
||||||
Html.FROM_HTML_MODE_LEGACY
|
Html.FROM_HTML_MODE_LEGACY,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupFooterBarAndScrollView(
|
private fun setupFooterBarAndScrollView(view: View) {
|
||||||
view: View,
|
|
||||||
) {
|
|
||||||
val scrollView: ScrollView =
|
val scrollView: ScrollView =
|
||||||
view.requireViewById(com.google.android.setupdesign.R.id.sud_scroll_view)
|
view.requireViewById(com.google.android.setupdesign.R.id.sud_scroll_view)
|
||||||
scrollView.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES
|
scrollView.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES
|
||||||
// Next button responsible for starting the next fragment.
|
// Next button responsible for starting the next fragment.
|
||||||
val onNextButtonClick: View.OnClickListener =
|
val onNextButtonClick: View.OnClickListener =
|
||||||
View.OnClickListener {
|
View.OnClickListener { viewModel.primaryButtonClicked() }
|
||||||
Log.d(TAG, "OnNextClicked")
|
|
||||||
navigationViewModel.nextStep()
|
|
||||||
}
|
|
||||||
|
|
||||||
val layout: GlifLayout = view.findViewById(R.id.setup_wizard_layout)!!
|
val layout: GlifLayout = view.findViewById(R.id.setup_wizard_layout)!!
|
||||||
footerBarMixin = layout.getMixin(FooterBarMixin::class.java)
|
footerBarMixin = layout.getMixin(FooterBarMixin::class.java)
|
||||||
@@ -225,11 +214,11 @@ class FingerprintEnrollIntroV2Fragment() : Fragment(R.layout.fingerprint_v2_enro
|
|||||||
footerBarMixin.setSecondaryButton(
|
footerBarMixin.setSecondaryButton(
|
||||||
FooterButton.Builder(requireContext())
|
FooterButton.Builder(requireContext())
|
||||||
.setText(textModel.negativeButton)
|
.setText(textModel.negativeButton)
|
||||||
.setListener({ Log.d(TAG, "prevClicked") })
|
.setListener { viewModel.onSecondaryButtonClicked() }
|
||||||
.setButtonType(FooterButton.ButtonType.NEXT)
|
.setButtonType(FooterButton.ButtonType.NEXT)
|
||||||
.setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary)
|
.setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary)
|
||||||
.build(),
|
.build(),
|
||||||
true /* usePrimaryStyle */
|
true, /* usePrimaryStyle */
|
||||||
)
|
)
|
||||||
|
|
||||||
val primaryButton = footerBarMixin.primaryButton
|
val primaryButton = footerBarMixin.primaryButton
|
||||||
@@ -242,7 +231,7 @@ class FingerprintEnrollIntroV2Fragment() : Fragment(R.layout.fingerprint_v2_enro
|
|||||||
requireContext(),
|
requireContext(),
|
||||||
primaryButton,
|
primaryButton,
|
||||||
R.string.security_settings_face_enroll_introduction_more,
|
R.string.security_settings_face_enroll_introduction_more,
|
||||||
onNextButtonClick
|
onNextButtonClick,
|
||||||
)
|
)
|
||||||
|
|
||||||
requireScrollMixin.setOnRequireScrollStateChangedListener { scrollNeeded: Boolean ->
|
requireScrollMixin.setOnRequireScrollStateChangedListener { scrollNeeded: Boolean ->
|
||||||
@@ -257,7 +246,7 @@ class FingerprintEnrollIntroV2Fragment() : Fragment(R.layout.fingerprint_v2_enro
|
|||||||
if (consented) {
|
if (consented) {
|
||||||
primaryButton.setText(
|
primaryButton.setText(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
R.string.security_settings_fingerprint_enroll_introduction_agree
|
R.string.security_settings_fingerprint_enroll_introduction_agree,
|
||||||
)
|
)
|
||||||
secondaryButton.visibility = View.VISIBLE
|
secondaryButton.visibility = View.VISIBLE
|
||||||
} else {
|
} else {
|
||||||
@@ -309,7 +298,7 @@ class FingerprintEnrollIntroV2Fragment() : Fragment(R.layout.fingerprint_v2_enro
|
|||||||
private fun getIconColorFilter(): PorterDuffColorFilter {
|
private fun getIconColorFilter(): PorterDuffColorFilter {
|
||||||
return PorterDuffColorFilter(
|
return PorterDuffColorFilter(
|
||||||
DynamicColorPalette.getColor(context, DynamicColorPalette.ColorType.ACCENT),
|
DynamicColorPalette.getColor(context, DynamicColorPalette.ColorType.ACCENT),
|
||||||
PorterDuff.Mode.SRC_IN
|
PorterDuff.Mode.SRC_IN,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -32,13 +32,15 @@ import androidx.lifecycle.ViewModelProvider
|
|||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerEnrollState
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.viewmodel.RFPSIconTouchViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.viewmodel.RFPSIconTouchViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.viewmodel.RFPSViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.viewmodel.RFPSViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.widget.FingerprintErrorDialog
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.widget.FingerprintErrorDialog
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.widget.IconTouchDialog
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.widget.IconTouchDialog
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.widget.RFPSProgressBar
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.widget.RFPSProgressBar
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.OrientationStateViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.OrientationStateViewModel
|
||||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment
|
import com.android.settings.core.instrumentation.InstrumentedDialogFragment
|
||||||
import com.google.android.setupcompat.template.FooterBarMixin
|
import com.google.android.setupcompat.template.FooterBarMixin
|
||||||
@@ -49,8 +51,6 @@ import kotlinx.coroutines.flow.filter
|
|||||||
import kotlinx.coroutines.flow.filterNotNull
|
import kotlinx.coroutines.flow.filterNotNull
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
private const val TAG = "RFPSEnrollFragment"
|
|
||||||
|
|
||||||
/** This fragment is responsible for taking care of rear fingerprint enrollment. */
|
/** This fragment is responsible for taking care of rear fingerprint enrollment. */
|
||||||
class RFPSEnrollFragment : Fragment(R.layout.fingerprint_v2_rfps_enroll_enrolling) {
|
class RFPSEnrollFragment : Fragment(R.layout.fingerprint_v2_rfps_enroll_enrolling) {
|
||||||
|
|
||||||
@@ -74,11 +74,14 @@ class RFPSEnrollFragment : Fragment(R.layout.fingerprint_v2_rfps_enroll_enrollin
|
|||||||
private val backgroundViewModel: BackgroundViewModel by lazy {
|
private val backgroundViewModel: BackgroundViewModel by lazy {
|
||||||
ViewModelProvider(requireActivity())[BackgroundViewModel::class.java]
|
ViewModelProvider(requireActivity())[BackgroundViewModel::class.java]
|
||||||
}
|
}
|
||||||
|
private val navigationViewModel: FingerprintNavigationViewModel by lazy {
|
||||||
|
ViewModelProvider(requireActivity())[FingerprintNavigationViewModel::class.java]
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?,
|
||||||
): View? {
|
): View? {
|
||||||
val view = super.onCreateView(inflater, container, savedInstanceState)!!
|
val view = super.onCreateView(inflater, container, savedInstanceState)!!
|
||||||
val fragment = this
|
val fragment = this
|
||||||
@@ -99,7 +102,7 @@ class RFPSEnrollFragment : Fragment(R.layout.fingerprint_v2_rfps_enroll_enrollin
|
|||||||
footerBarMixin.secondaryButton =
|
footerBarMixin.secondaryButton =
|
||||||
FooterButton.Builder(context)
|
FooterButton.Builder(context)
|
||||||
.setText(R.string.security_settings_fingerprint_enroll_enrolling_skip)
|
.setText(R.string.security_settings_fingerprint_enroll_enrolling_skip)
|
||||||
.setListener { Log.e(TAG, "skip enrollment!") }
|
.setListener { rfpsViewModel.negativeButtonClicked() }
|
||||||
.setButtonType(FooterButton.ButtonType.SKIP)
|
.setButtonType(FooterButton.ButtonType.SKIP)
|
||||||
.setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Secondary)
|
.setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Secondary)
|
||||||
.build()
|
.build()
|
||||||
@@ -150,7 +153,7 @@ class RFPSEnrollFragment : Fragment(R.layout.fingerprint_v2_rfps_enroll_enrollin
|
|||||||
viewLifecycleOwner.lifecycleScope.launch {
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
backgroundViewModel.background
|
backgroundViewModel.background
|
||||||
.filter { inBackground -> inBackground }
|
.filter { inBackground -> inBackground }
|
||||||
.collect { rfpsViewModel.stopEnrollment() }
|
.collect { rfpsViewModel.didGoToBackground() }
|
||||||
}
|
}
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
@@ -171,7 +174,6 @@ class RFPSEnrollFragment : Fragment(R.layout.fingerprint_v2_rfps_enroll_enrollin
|
|||||||
.setDuration(200)
|
.setDuration(200)
|
||||||
.setInterpolator(linearOutSlowInInterpolator)
|
.setInterpolator(linearOutSlowInInterpolator)
|
||||||
.start()
|
.start()
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,6 +209,12 @@ class RFPSEnrollFragment : Fragment(R.layout.fingerprint_v2_rfps_enroll_enrollin
|
|||||||
dismissDialogs()
|
dismissDialogs()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
|
rfpsViewModel.didCompleteEnrollment
|
||||||
|
.filter { it }
|
||||||
|
.collect { rfpsViewModel.finishedSuccessfully() }
|
||||||
|
}
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,29 +223,19 @@ class RFPSEnrollFragment : Fragment(R.layout.fingerprint_v2_rfps_enroll_enrollin
|
|||||||
viewLifecycleOwner.lifecycleScope.launch {
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
try {
|
try {
|
||||||
val shouldRestartEnrollment = FingerprintErrorDialog.showInstance(error, fragment)
|
val shouldRestartEnrollment = FingerprintErrorDialog.showInstance(error, fragment)
|
||||||
|
rfpsViewModel.userClickedStopEnrollDialog()
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
Log.e(TAG, "Exception occurred $exception")
|
Log.e(TAG, "Exception occurred $exception")
|
||||||
}
|
}
|
||||||
onEnrollmentFailed()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onEnrollmentFailed() {
|
|
||||||
rfpsViewModel.stopEnrollment()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleEnrollProgress(progress: FingerEnrollState.EnrollProgress) {
|
private fun handleEnrollProgress(progress: FingerEnrollState.EnrollProgress) {
|
||||||
progressBar.updateProgress(
|
progressBar.updateProgress(
|
||||||
progress.remainingSteps.toFloat() / progress.totalStepsRequired.toFloat()
|
progress.remainingSteps.toFloat() / progress.totalStepsRequired.toFloat()
|
||||||
)
|
)
|
||||||
|
|
||||||
if (progress.remainingSteps == 0) {
|
|
||||||
performNextStepSuccess()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun performNextStepSuccess() {}
|
|
||||||
|
|
||||||
private fun dismissDialogs() {
|
private fun dismissDialogs() {
|
||||||
val transaction = parentFragmentManager.beginTransaction()
|
val transaction = parentFragmentManager.beginTransaction()
|
||||||
for (frag in parentFragmentManager.fragments) {
|
for (frag in parentFragmentManager.fragments) {
|
||||||
@@ -249,4 +247,9 @@ class RFPSEnrollFragment : Fragment(R.layout.fingerprint_v2_rfps_enroll_enrollin
|
|||||||
}
|
}
|
||||||
transaction.commitAllowingStateLoss()
|
transaction.commitAllowingStateLoss()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "RFPSEnrollFragment"
|
||||||
|
private val navStep = FingerprintNavigationStep.Enrollment::class
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -38,9 +38,9 @@ class RFPSIconTouchViewModel : ViewModel() {
|
|||||||
private val _touches: MutableStateFlow<Int> = MutableStateFlow(0)
|
private val _touches: MutableStateFlow<Int> = MutableStateFlow(0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the UI should be showing the dialog. By making this SharingStarted.Eagerly
|
* Whether or not the UI should be showing the dialog. By making this SharingStarted.Eagerly the
|
||||||
* the first event 0 % 3 == 0 will fire as soon as this view model is created, so it should
|
* first event 0 % 3 == 0 will fire as soon as this view model is created, so it should be ignored
|
||||||
* be ignored and work as intended.
|
* and work as intended.
|
||||||
*/
|
*/
|
||||||
val shouldShowDialog: Flow<Boolean> =
|
val shouldShowDialog: Flow<Boolean> =
|
||||||
_touches
|
_touches
|
||||||
|
@@ -19,13 +19,17 @@ package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrol
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerEnrollState
|
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
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollEnrollingViewModel
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Enrollment
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.flow.filterIsInstance
|
import kotlinx.coroutines.flow.filterIsInstance
|
||||||
|
import kotlinx.coroutines.flow.filterNotNull
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.shareIn
|
import kotlinx.coroutines.flow.shareIn
|
||||||
import kotlinx.coroutines.flow.transform
|
import kotlinx.coroutines.flow.transform
|
||||||
@@ -34,9 +38,10 @@ import kotlinx.coroutines.flow.update
|
|||||||
/** View Model used by the rear fingerprint enrollment fragment. */
|
/** View Model used by the rear fingerprint enrollment fragment. */
|
||||||
class RFPSViewModel(
|
class RFPSViewModel(
|
||||||
private val fingerprintEnrollViewModel: FingerprintEnrollEnrollingViewModel,
|
private val fingerprintEnrollViewModel: FingerprintEnrollEnrollingViewModel,
|
||||||
|
private val navigationViewModel: FingerprintNavigationViewModel,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
/** Value to indicate if the text view is visible or not **/
|
/** Value to indicate if the text view is visible or not */
|
||||||
private val _textViewIsVisible = MutableStateFlow<Boolean>(false)
|
private val _textViewIsVisible = MutableStateFlow<Boolean>(false)
|
||||||
val textViewIsVisible: Flow<Boolean> = _textViewIsVisible.asStateFlow()
|
val textViewIsVisible: Flow<Boolean> = _textViewIsVisible.asStateFlow()
|
||||||
|
|
||||||
@@ -61,9 +66,8 @@ class RFPSViewModel(
|
|||||||
val helpMessage: Flow<FingerEnrollState.EnrollHelp?> =
|
val helpMessage: Flow<FingerEnrollState.EnrollHelp?> =
|
||||||
enrollFlow
|
enrollFlow
|
||||||
.filterIsInstance<FingerEnrollState.EnrollHelp>()
|
.filterIsInstance<FingerEnrollState.EnrollHelp>()
|
||||||
.shareIn(viewModelScope, SharingStarted.Eagerly, 0).transform {
|
.shareIn(viewModelScope, SharingStarted.Eagerly, 0)
|
||||||
_textViewIsVisible.update { true }
|
.transform { _textViewIsVisible.update { true } }
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The error message should only be shown once, for scenarios like screen rotations, we don't want
|
* The error message should only be shown once, for scenarios like screen rotations, we don't want
|
||||||
@@ -74,6 +78,8 @@ class RFPSViewModel(
|
|||||||
.filterIsInstance<FingerEnrollState.EnrollError>()
|
.filterIsInstance<FingerEnrollState.EnrollError>()
|
||||||
.shareIn(viewModelScope, SharingStarted.Eagerly, 0)
|
.shareIn(viewModelScope, SharingStarted.Eagerly, 0)
|
||||||
|
|
||||||
|
val didCompleteEnrollment: Flow<Boolean> = progress.filterNotNull().map { it.remainingSteps == 0 }
|
||||||
|
|
||||||
/** Indicates if the consumer is ready for enrollment */
|
/** Indicates if the consumer is ready for enrollment */
|
||||||
fun readyForEnrollment() {
|
fun readyForEnrollment() {
|
||||||
fingerprintEnrollViewModel.canEnroll()
|
fingerprintEnrollViewModel.canEnroll()
|
||||||
@@ -88,15 +94,51 @@ class RFPSViewModel(
|
|||||||
_textViewIsVisible.update { isVisible }
|
_textViewIsVisible.update { isVisible }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Indicates that the user is done with trying to enroll a fingerprint */
|
||||||
|
fun userClickedStopEnrollDialog() {
|
||||||
|
navigationViewModel.update(
|
||||||
|
FingerprintAction.USER_CLICKED_FINISH,
|
||||||
|
navStep,
|
||||||
|
"${TAG}#userClickedStopEnrollingDialog",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Indicates that the application went to the background. */
|
||||||
|
fun didGoToBackground() {
|
||||||
|
navigationViewModel.update(
|
||||||
|
FingerprintAction.DID_GO_TO_BACKGROUND,
|
||||||
|
navStep,
|
||||||
|
"${TAG}#didGoToBackground",
|
||||||
|
)
|
||||||
|
stopEnrollment()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Indicates the negative button has been clicked */
|
||||||
|
fun negativeButtonClicked() {
|
||||||
|
navigationViewModel.update(
|
||||||
|
FingerprintAction.NEGATIVE_BUTTON_PRESSED,
|
||||||
|
navStep,
|
||||||
|
"${TAG}negativeButtonClicked",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun finishedSuccessfully() {
|
||||||
|
navigationViewModel.update(FingerprintAction.NEXT, navStep, "${TAG}#progressFinished")
|
||||||
|
}
|
||||||
|
|
||||||
class RFPSViewModelFactory(
|
class RFPSViewModelFactory(
|
||||||
private val fingerprintEnrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel,
|
private val fingerprintEnrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel,
|
||||||
|
private val navigationViewModel: FingerprintNavigationViewModel,
|
||||||
) : ViewModelProvider.Factory {
|
) : ViewModelProvider.Factory {
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun <T : ViewModel> create(
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
modelClass: Class<T>,
|
return RFPSViewModel(fingerprintEnrollEnrollingViewModel, navigationViewModel) as T
|
||||||
): T {
|
|
||||||
return RFPSViewModel(fingerprintEnrollEnrollingViewModel) as T
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val navStep = Enrollment::class
|
||||||
|
private const val TAG = "RFPSViewModel"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -24,7 +24,7 @@ import android.os.Bundle
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerEnrollState
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
|
||||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment
|
import com.android.settings.core.instrumentation.InstrumentedDialogFragment
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
@@ -86,39 +86,28 @@ class FingerprintErrorDialog : InstrumentedDialogFragment() {
|
|||||||
private const val KEY_TITLE = "fingerprint_title"
|
private const val KEY_TITLE = "fingerprint_title"
|
||||||
private const val KEY_SHOULD_TRY_AGAIN = "should_try_again"
|
private const val KEY_SHOULD_TRY_AGAIN = "should_try_again"
|
||||||
|
|
||||||
suspend fun showInstance(
|
suspend fun showInstance(error: FingerEnrollState.EnrollError, fragment: Fragment) =
|
||||||
error: FingerEnrollState.EnrollError,
|
suspendCancellableCoroutine { continuation ->
|
||||||
fragment: Fragment,
|
val dialog = FingerprintErrorDialog()
|
||||||
) = suspendCancellableCoroutine { continuation ->
|
dialog.onTryAgain = DialogInterface.OnClickListener { _, _ -> continuation.resume(true) }
|
||||||
val dialog = FingerprintErrorDialog()
|
|
||||||
dialog.onTryAgain = DialogInterface.OnClickListener { _, _ -> continuation.resume(true) }
|
|
||||||
|
|
||||||
dialog.onContinue = DialogInterface.OnClickListener { _, _ -> continuation.resume(false) }
|
dialog.onContinue = DialogInterface.OnClickListener { _, _ -> continuation.resume(false) }
|
||||||
|
|
||||||
dialog.onCancelListener =
|
dialog.onCancelListener =
|
||||||
DialogInterface.OnCancelListener {
|
DialogInterface.OnCancelListener {
|
||||||
Log.d(TAG, "onCancelListener clicked $dialog")
|
Log.d(TAG, "onCancelListener clicked $dialog")
|
||||||
continuation.resume(null)
|
continuation.resume(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
continuation.invokeOnCancellation { Log.d(TAG, "invokeOnCancellation $dialog") }
|
continuation.invokeOnCancellation { Log.d(TAG, "invokeOnCancellation $dialog") }
|
||||||
|
|
||||||
val bundle = Bundle()
|
val bundle = Bundle()
|
||||||
bundle.putInt(
|
bundle.putInt(KEY_TITLE, error.errTitle)
|
||||||
KEY_TITLE,
|
bundle.putInt(KEY_MESSAGE, error.errString)
|
||||||
error.errTitle,
|
bundle.putBoolean(KEY_SHOULD_TRY_AGAIN, error.shouldRetryEnrollment)
|
||||||
)
|
dialog.arguments = bundle
|
||||||
bundle.putInt(
|
Log.d(TAG, "showing dialog $dialog")
|
||||||
KEY_MESSAGE,
|
dialog.show(fragment.parentFragmentManager, FingerprintErrorDialog::class.java.toString())
|
||||||
error.errString,
|
}
|
||||||
)
|
|
||||||
bundle.putBoolean(
|
|
||||||
KEY_SHOULD_TRY_AGAIN,
|
|
||||||
error.shouldRetryEnrollment,
|
|
||||||
)
|
|
||||||
dialog.arguments = bundle
|
|
||||||
Log.d(TAG, "showing dialog $dialog")
|
|
||||||
dialog.show(fragment.parentFragmentManager, FingerprintErrorDialog::class.java.toString())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -41,15 +41,13 @@ class AccessibilityViewModel(accessibilityManager: AccessibilityManager) : ViewM
|
|||||||
.stateIn(
|
.stateIn(
|
||||||
viewModelScope, // This is going to tied to the view model scope
|
viewModelScope, // This is going to tied to the view model scope
|
||||||
SharingStarted.WhileSubscribed(), // When no longer subscribed, we removeTheListener
|
SharingStarted.WhileSubscribed(), // When no longer subscribed, we removeTheListener
|
||||||
false
|
false,
|
||||||
)
|
)
|
||||||
|
|
||||||
class AccessibilityViewModelFactory(private val accessibilityManager: AccessibilityManager) :
|
class AccessibilityViewModelFactory(private val accessibilityManager: AccessibilityManager) :
|
||||||
ViewModelProvider.Factory {
|
ViewModelProvider.Factory {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun <T : ViewModel> create(
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
modelClass: Class<T>,
|
|
||||||
): T {
|
|
||||||
return AccessibilityViewModel(accessibilityManager) as T
|
return AccessibilityViewModel(accessibilityManager) as T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,8 +25,8 @@ import kotlinx.coroutines.flow.transformLatest
|
|||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is a wrapper around the [FingerprintEnrollViewModel] and decides when
|
* This class is a wrapper around the [FingerprintEnrollViewModel] and decides when the user should
|
||||||
* the user should or should not be enrolling.
|
* or should not be enrolling.
|
||||||
*/
|
*/
|
||||||
class FingerprintEnrollEnrollingViewModel(
|
class FingerprintEnrollEnrollingViewModel(
|
||||||
private val fingerprintEnrollViewModel: FingerprintEnrollViewModel,
|
private val fingerprintEnrollViewModel: FingerprintEnrollViewModel,
|
||||||
@@ -72,12 +72,10 @@ class FingerprintEnrollEnrollingViewModel(
|
|||||||
|
|
||||||
class FingerprintEnrollEnrollingViewModelFactory(
|
class FingerprintEnrollEnrollingViewModelFactory(
|
||||||
private val fingerprintEnrollViewModel: FingerprintEnrollViewModel,
|
private val fingerprintEnrollViewModel: FingerprintEnrollViewModel,
|
||||||
private val backgroundViewModel: BackgroundViewModel
|
private val backgroundViewModel: BackgroundViewModel,
|
||||||
) : ViewModelProvider.Factory {
|
) : ViewModelProvider.Factory {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun <T : ViewModel> create(
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
modelClass: Class<T>,
|
|
||||||
): T {
|
|
||||||
return FingerprintEnrollEnrollingViewModel(fingerprintEnrollViewModel, backgroundViewModel)
|
return FingerprintEnrollEnrollingViewModel(fingerprintEnrollViewModel, backgroundViewModel)
|
||||||
as T
|
as T
|
||||||
}
|
}
|
||||||
|
@@ -19,8 +19,10 @@ package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerEnrollState
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.SetupWizard
|
import com.android.settings.biometrics.fingerprint2.lib.model.SetupWizard
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollFindSensorV2Fragment
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Education
|
||||||
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
@@ -36,20 +38,22 @@ import kotlinx.coroutines.launch
|
|||||||
|
|
||||||
/** Models the UI state for [FingerprintEnrollFindSensorV2Fragment]. */
|
/** Models the UI state for [FingerprintEnrollFindSensorV2Fragment]. */
|
||||||
class FingerprintEnrollFindSensorViewModel(
|
class FingerprintEnrollFindSensorViewModel(
|
||||||
private val navigationViewModel: FingerprintEnrollNavigationViewModel,
|
private val navigationViewModel: FingerprintNavigationViewModel,
|
||||||
private val fingerprintEnrollViewModel: FingerprintEnrollViewModel,
|
private val fingerprintEnrollViewModel: FingerprintEnrollViewModel,
|
||||||
private val gatekeeperViewModel: FingerprintGatekeeperViewModel,
|
private val gatekeeperViewModel: FingerprintGatekeeperViewModel,
|
||||||
backgroundViewModel: BackgroundViewModel,
|
backgroundViewModel: BackgroundViewModel,
|
||||||
accessibilityViewModel: AccessibilityViewModel,
|
accessibilityViewModel: AccessibilityViewModel,
|
||||||
foldStateViewModel: FoldStateViewModel,
|
foldStateViewModel: FoldStateViewModel,
|
||||||
orientationStateViewModel: OrientationStateViewModel
|
orientationStateViewModel: OrientationStateViewModel,
|
||||||
|
fingerprintFlowViewModel: FingerprintFlowViewModel,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
/** Represents the stream of sensor type. */
|
/** Represents the stream of sensor type. */
|
||||||
val sensorType: Flow<FingerprintSensorType> =
|
val sensorType: Flow<FingerprintSensorType> =
|
||||||
fingerprintEnrollViewModel.sensorType.shareIn(
|
fingerprintEnrollViewModel.sensorType.shareIn(
|
||||||
viewModelScope,
|
viewModelScope,
|
||||||
SharingStarted.WhileSubscribed(),
|
SharingStarted.WhileSubscribed(),
|
||||||
1
|
1,
|
||||||
)
|
)
|
||||||
private val _isUdfps: Flow<Boolean> =
|
private val _isUdfps: Flow<Boolean> =
|
||||||
sensorType.map {
|
sensorType.map {
|
||||||
@@ -103,10 +107,10 @@ class FingerprintEnrollFindSensorViewModel(
|
|||||||
fingerprintEnrollViewModel.sensorType,
|
fingerprintEnrollViewModel.sensorType,
|
||||||
gatekeeperViewModel.hasValidGatekeeperInfo,
|
gatekeeperViewModel.hasValidGatekeeperInfo,
|
||||||
gatekeeperViewModel.gatekeeperInfo,
|
gatekeeperViewModel.gatekeeperInfo,
|
||||||
navigationViewModel.navigationViewModel
|
navigationViewModel.currentScreen,
|
||||||
) { sensorType, hasValidGatekeeperInfo, gatekeeperInfo, navigationViewModel ->
|
) { sensorType, hasValidGatekeeperInfo, gatekeeperInfo, currStep ->
|
||||||
val shouldStartEnroll =
|
val shouldStartEnroll =
|
||||||
navigationViewModel.currStep == Education &&
|
currStep is Education &&
|
||||||
sensorType != FingerprintSensorType.UDFPS_OPTICAL &&
|
sensorType != FingerprintSensorType.UDFPS_OPTICAL &&
|
||||||
sensorType != FingerprintSensorType.UDFPS_ULTRASONIC &&
|
sensorType != FingerprintSensorType.UDFPS_ULTRASONIC &&
|
||||||
hasValidGatekeeperInfo
|
hasValidGatekeeperInfo
|
||||||
@@ -128,22 +132,19 @@ class FingerprintEnrollFindSensorViewModel(
|
|||||||
// Only collect the flow when we should be running.
|
// Only collect the flow when we should be running.
|
||||||
if (it) {
|
if (it) {
|
||||||
combine(
|
combine(
|
||||||
navigationViewModel.fingerprintFlow,
|
|
||||||
fingerprintEnrollViewModel.educationEnrollFlow.filterNotNull(),
|
fingerprintEnrollViewModel.educationEnrollFlow.filterNotNull(),
|
||||||
) { enrollType, educationFlow ->
|
fingerprintFlowViewModel.fingerprintFlow,
|
||||||
Pair(enrollType, educationFlow)
|
) { educationFlow, type ->
|
||||||
|
Pair(educationFlow, type)
|
||||||
}
|
}
|
||||||
.collect { (enrollType, educationFlow) ->
|
.collect { (educationFlow, type) ->
|
||||||
when (educationFlow) {
|
when (educationFlow) {
|
||||||
// TODO: Cancel the enroll() when EnrollProgress is received instead of proceeding
|
|
||||||
// to
|
|
||||||
// Enrolling page. Otherwise Enrolling page will receive the EnrollError.
|
|
||||||
is FingerEnrollState.EnrollProgress -> proceedToEnrolling()
|
is FingerEnrollState.EnrollProgress -> proceedToEnrolling()
|
||||||
is FingerEnrollState.EnrollError -> {
|
is FingerEnrollState.EnrollError -> {
|
||||||
if (educationFlow.isCancelled) {
|
if (educationFlow.isCancelled) {
|
||||||
proceedToEnrolling()
|
proceedToEnrolling()
|
||||||
} else {
|
} else {
|
||||||
_showErrorDialog.update { Pair(educationFlow.errString, enrollType == SetupWizard) }
|
_showErrorDialog.update { Pair(educationFlow.errString, type == SetupWizard) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is FingerEnrollState.EnrollHelp -> {}
|
is FingerEnrollState.EnrollHelp -> {}
|
||||||
@@ -169,17 +170,28 @@ class FingerprintEnrollFindSensorViewModel(
|
|||||||
|
|
||||||
/** Proceed to EnrollEnrolling page. */
|
/** Proceed to EnrollEnrolling page. */
|
||||||
fun proceedToEnrolling() {
|
fun proceedToEnrolling() {
|
||||||
navigationViewModel.nextStep()
|
stopEducation()
|
||||||
|
navigationViewModel.update(FingerprintAction.NEXT, navStep, "$TAG#proceedToEnrolling")
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Indicates the secondary button has been clicked */
|
||||||
|
fun secondaryButtonClicked() {
|
||||||
|
navigationViewModel.update(
|
||||||
|
FingerprintAction.NEGATIVE_BUTTON_PRESSED,
|
||||||
|
navStep,
|
||||||
|
"${TAG}#secondaryButtonClicked",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
class FingerprintEnrollFindSensorViewModelFactory(
|
class FingerprintEnrollFindSensorViewModelFactory(
|
||||||
private val navigationViewModel: FingerprintEnrollNavigationViewModel,
|
private val navigationViewModel: FingerprintNavigationViewModel,
|
||||||
private val fingerprintEnrollViewModel: FingerprintEnrollViewModel,
|
private val fingerprintEnrollViewModel: FingerprintEnrollViewModel,
|
||||||
private val gatekeeperViewModel: FingerprintGatekeeperViewModel,
|
private val gatekeeperViewModel: FingerprintGatekeeperViewModel,
|
||||||
private val backgroundViewModel: BackgroundViewModel,
|
private val backgroundViewModel: BackgroundViewModel,
|
||||||
private val accessibilityViewModel: AccessibilityViewModel,
|
private val accessibilityViewModel: AccessibilityViewModel,
|
||||||
private val foldStateViewModel: FoldStateViewModel,
|
private val foldStateViewModel: FoldStateViewModel,
|
||||||
private val orientationStateViewModel: OrientationStateViewModel
|
private val orientationStateViewModel: OrientationStateViewModel,
|
||||||
|
private val fingerprintFlowViewModel: FingerprintFlowViewModel,
|
||||||
) : ViewModelProvider.Factory {
|
) : ViewModelProvider.Factory {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
@@ -190,9 +202,15 @@ class FingerprintEnrollFindSensorViewModel(
|
|||||||
backgroundViewModel,
|
backgroundViewModel,
|
||||||
accessibilityViewModel,
|
accessibilityViewModel,
|
||||||
foldStateViewModel,
|
foldStateViewModel,
|
||||||
orientationStateViewModel
|
orientationStateViewModel,
|
||||||
|
fingerprintFlowViewModel,
|
||||||
)
|
)
|
||||||
as T
|
as T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "FingerprintEnrollFindSensorViewModel"
|
||||||
|
private val navStep = Education::class
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* 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.ui.enrollment.viewmodel
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
|
||||||
|
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
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
/** A view model for fingerprint enroll introduction. */
|
||||||
|
class FingerprintEnrollIntroViewModel(
|
||||||
|
val navigationViewModel: FingerprintNavigationViewModel,
|
||||||
|
private val fingerprintFlowViewModel: FingerprintFlowViewModel,
|
||||||
|
private val fingerprintManagerInteractor: FingerprintManagerInteractor,
|
||||||
|
) : ViewModel() {
|
||||||
|
|
||||||
|
/** Represents a stream of [FingerprintSensor] */
|
||||||
|
val sensor: Flow<FingerprintSensor?> = fingerprintManagerInteractor.sensorPropertiesInternal
|
||||||
|
|
||||||
|
/** Represents a stream of [FingerprintFlow] */
|
||||||
|
val fingerprintFlow: Flow<FingerprintFlow?> = fingerprintFlowViewModel.fingerprintFlow
|
||||||
|
|
||||||
|
/** Indicates the primary button has been clicked */
|
||||||
|
fun primaryButtonClicked() {
|
||||||
|
navigationViewModel.update(FingerprintAction.NEXT, navStep, "${TAG}#onNextClicked")
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Indicates the secondary button has been clicked */
|
||||||
|
fun onSecondaryButtonClicked() {
|
||||||
|
navigationViewModel.update(
|
||||||
|
FingerprintAction.NEGATIVE_BUTTON_PRESSED,
|
||||||
|
navStep,
|
||||||
|
"${TAG}#negativeButtonClicked",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
class FingerprintEnrollIntoViewModelFactory(
|
||||||
|
val navigationViewModel: FingerprintNavigationViewModel,
|
||||||
|
val fingerprintFlowViewModel: FingerprintFlowViewModel,
|
||||||
|
val fingerprintManagerInteractor: FingerprintManagerInteractor,
|
||||||
|
) : ViewModelProvider.Factory {
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
|
return FingerprintEnrollIntroViewModel(
|
||||||
|
navigationViewModel,
|
||||||
|
fingerprintFlowViewModel,
|
||||||
|
fingerprintManagerInteractor,
|
||||||
|
)
|
||||||
|
as T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val navStep = Introduction::class
|
||||||
|
private const val TAG = "FingerprintEnrollIntroViewModel"
|
||||||
|
}
|
||||||
|
}
|
@@ -18,9 +18,11 @@ package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.domain.interactor.FingerprintManagerInteractor
|
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.EnrollReason
|
import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerEnrollState
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Education
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Enrollment
|
||||||
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
@@ -34,7 +36,7 @@ import kotlinx.coroutines.flow.transformLatest
|
|||||||
class FingerprintEnrollViewModel(
|
class FingerprintEnrollViewModel(
|
||||||
private val fingerprintManagerInteractor: FingerprintManagerInteractor,
|
private val fingerprintManagerInteractor: FingerprintManagerInteractor,
|
||||||
gatekeeperViewModel: FingerprintGatekeeperViewModel,
|
gatekeeperViewModel: FingerprintGatekeeperViewModel,
|
||||||
navigationViewModel: FingerprintEnrollNavigationViewModel,
|
val navigationViewModel: FingerprintNavigationViewModel,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,8 +47,8 @@ class FingerprintEnrollViewModel(
|
|||||||
*/
|
*/
|
||||||
var sensorTypeCached: FingerprintSensorType? = null
|
var sensorTypeCached: FingerprintSensorType? = null
|
||||||
private var _enrollReason: Flow<EnrollReason?> =
|
private var _enrollReason: Flow<EnrollReason?> =
|
||||||
navigationViewModel.navigationViewModel.map {
|
navigationViewModel.currentScreen.map {
|
||||||
when (it.currStep) {
|
when (it) {
|
||||||
is Enrollment -> EnrollReason.EnrollEnrolling
|
is Enrollment -> EnrollReason.EnrollEnrolling
|
||||||
is Education -> EnrollReason.FindSensor
|
is Education -> EnrollReason.FindSensor
|
||||||
else -> null
|
else -> null
|
||||||
@@ -64,8 +66,7 @@ class FingerprintEnrollViewModel(
|
|||||||
* This flow should be the only flow which calls enroll().
|
* This flow should be the only flow which calls enroll().
|
||||||
*/
|
*/
|
||||||
val _enrollFlow: Flow<FingerEnrollState> =
|
val _enrollFlow: Flow<FingerEnrollState> =
|
||||||
combine(gatekeeperViewModel.gatekeeperInfo, _enrollReason) { hardwareAuthToken, enrollReason,
|
combine(gatekeeperViewModel.gatekeeperInfo, _enrollReason) { hardwareAuthToken, enrollReason ->
|
||||||
->
|
|
||||||
Pair(hardwareAuthToken, enrollReason)
|
Pair(hardwareAuthToken, enrollReason)
|
||||||
}
|
}
|
||||||
.transformLatest {
|
.transformLatest {
|
||||||
@@ -110,18 +111,11 @@ class FingerprintEnrollViewModel(
|
|||||||
class FingerprintEnrollViewModelFactory(
|
class FingerprintEnrollViewModelFactory(
|
||||||
val interactor: FingerprintManagerInteractor,
|
val interactor: FingerprintManagerInteractor,
|
||||||
val gatekeeperViewModel: FingerprintGatekeeperViewModel,
|
val gatekeeperViewModel: FingerprintGatekeeperViewModel,
|
||||||
val navigationViewModel: FingerprintEnrollNavigationViewModel,
|
val navigationViewModel: FingerprintNavigationViewModel,
|
||||||
) : ViewModelProvider.Factory {
|
) : ViewModelProvider.Factory {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun <T : ViewModel> create(
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
modelClass: Class<T>,
|
return FingerprintEnrollViewModel(interactor, gatekeeperViewModel, navigationViewModel) as T
|
||||||
): T {
|
|
||||||
return FingerprintEnrollViewModel(
|
|
||||||
interactor,
|
|
||||||
gatekeeperViewModel,
|
|
||||||
navigationViewModel,
|
|
||||||
)
|
|
||||||
as T
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,141 +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.ui.enrollment.viewmodel
|
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.domain.interactor.FingerprintManagerInteractor
|
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintFlow
|
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
|
||||||
import kotlinx.coroutines.flow.filterNotNull
|
|
||||||
import kotlinx.coroutines.flow.shareIn
|
|
||||||
import kotlinx.coroutines.flow.update
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
private const val TAG = "FingerprintEnrollNavigationViewModel"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is responsible for sending a [NavigationStep] which indicates where the user is in the
|
|
||||||
* Fingerprint Enrollment flow
|
|
||||||
*/
|
|
||||||
class FingerprintEnrollNavigationViewModel(
|
|
||||||
private val dispatcher: CoroutineDispatcher,
|
|
||||||
private val fingerprintManagerInteractor: FingerprintManagerInteractor,
|
|
||||||
private val gatekeeperViewModel: FingerprintGatekeeperViewModel,
|
|
||||||
private val firstStep: NextStepViewModel,
|
|
||||||
private val navState: NavState,
|
|
||||||
private val theFingerprintFlow: FingerprintFlow,
|
|
||||||
) : ViewModel() {
|
|
||||||
|
|
||||||
private class InternalNavigationStep(
|
|
||||||
lastStep: NextStepViewModel,
|
|
||||||
nextStep: NextStepViewModel,
|
|
||||||
forward: Boolean,
|
|
||||||
var canNavigate: Boolean,
|
|
||||||
) : NavigationStep(lastStep, nextStep, forward)
|
|
||||||
|
|
||||||
private var _fingerprintFlow = MutableStateFlow<FingerprintFlow?>(theFingerprintFlow)
|
|
||||||
|
|
||||||
/** A flow that indicates the [FingerprintFlow] */
|
|
||||||
val fingerprintFlow: Flow<FingerprintFlow?> = _fingerprintFlow.asStateFlow()
|
|
||||||
|
|
||||||
private val _navigationStep =
|
|
||||||
MutableStateFlow(
|
|
||||||
InternalNavigationStep(PlaceHolderState, firstStep, forward = false, canNavigate = true)
|
|
||||||
)
|
|
||||||
|
|
||||||
init {
|
|
||||||
viewModelScope.launch {
|
|
||||||
gatekeeperViewModel.credentialConfirmed.filterNotNull().collect {
|
|
||||||
if (_navigationStep.value.currStep is LaunchConfirmDeviceCredential) {
|
|
||||||
if (it) nextStep() else finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A flow that contains the [NavigationStep] used to indicate where in the enrollment process the
|
|
||||||
* user is.
|
|
||||||
*/
|
|
||||||
val navigationViewModel: Flow<NavigationStep> = _navigationStep.asStateFlow()
|
|
||||||
|
|
||||||
/** This action indicates that the UI should actually update the navigation to the given step. */
|
|
||||||
val navigationAction: Flow<NavigationStep?> =
|
|
||||||
_navigationStep.shareIn(viewModelScope, SharingStarted.Lazily, 0)
|
|
||||||
|
|
||||||
/** Used to start the next step of Fingerprint Enrollment. */
|
|
||||||
fun nextStep() {
|
|
||||||
viewModelScope.launch {
|
|
||||||
val currStep = _navigationStep.value.currStep
|
|
||||||
val nextStep = currStep.next(navState)
|
|
||||||
Log.d(TAG, "nextStep(${currStep} -> $nextStep)")
|
|
||||||
_navigationStep.update {
|
|
||||||
InternalNavigationStep(currStep, nextStep, forward = true, canNavigate = false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Go back a step of fingerprint enrollment. */
|
|
||||||
fun prevStep() {
|
|
||||||
viewModelScope.launch {
|
|
||||||
val currStep = _navigationStep.value.currStep
|
|
||||||
val nextStep = currStep.prev(navState)
|
|
||||||
_navigationStep.update {
|
|
||||||
InternalNavigationStep(currStep, nextStep, forward = false, canNavigate = false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun finish() {
|
|
||||||
_navigationStep.update {
|
|
||||||
InternalNavigationStep(Finish(null), Finish(null), forward = false, canNavigate = false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class FingerprintEnrollNavigationViewModelFactory(
|
|
||||||
private val backgroundDispatcher: CoroutineDispatcher,
|
|
||||||
private val fingerprintManagerInteractor: FingerprintManagerInteractor,
|
|
||||||
private val fingerprintGatekeeperViewModel: FingerprintGatekeeperViewModel,
|
|
||||||
private val canSkipConfirm: Boolean,
|
|
||||||
private val fingerprintFlow: FingerprintFlow,
|
|
||||||
) : ViewModelProvider.Factory {
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
override fun <T : ViewModel> create(
|
|
||||||
modelClass: Class<T>,
|
|
||||||
): T {
|
|
||||||
|
|
||||||
val navState = NavState(canSkipConfirm)
|
|
||||||
return FingerprintEnrollNavigationViewModel(
|
|
||||||
backgroundDispatcher,
|
|
||||||
fingerprintManagerInteractor,
|
|
||||||
fingerprintGatekeeperViewModel,
|
|
||||||
Start.next(navState),
|
|
||||||
navState,
|
|
||||||
fingerprintFlow,
|
|
||||||
)
|
|
||||||
as T
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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.ui.enrollment.viewmodel
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintFlow
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.flowOf
|
||||||
|
import kotlinx.coroutines.flow.shareIn
|
||||||
|
|
||||||
|
class FingerprintFlowViewModel(private val fingerprintFlowType: FingerprintFlow) : ViewModel() {
|
||||||
|
val fingerprintFlow: Flow<FingerprintFlow> =
|
||||||
|
flowOf(fingerprintFlowType).shareIn(viewModelScope, SharingStarted.Eagerly, 1)
|
||||||
|
|
||||||
|
class FingerprintFlowViewModelFactory(val flowType: FingerprintFlow) : ViewModelProvider.Factory {
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
|
return FingerprintFlowViewModel(flowType) as T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -21,7 +21,7 @@ import android.util.Log
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.domain.interactor.FingerprintManagerInteractor
|
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
@@ -29,11 +29,11 @@ import kotlinx.coroutines.flow.map
|
|||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
private const val TAG = "FingerprintGatekeeperViewModel"
|
|
||||||
|
|
||||||
sealed interface GatekeeperInfo {
|
sealed interface GatekeeperInfo {
|
||||||
object Invalid : GatekeeperInfo
|
object Invalid : GatekeeperInfo
|
||||||
|
|
||||||
object Timeout : GatekeeperInfo
|
object Timeout : GatekeeperInfo
|
||||||
|
|
||||||
data class GatekeeperPasswordInfo(val token: ByteArray?, val passwordHandle: Long?) :
|
data class GatekeeperPasswordInfo(val token: ByteArray?, val passwordHandle: Long?) :
|
||||||
GatekeeperInfo
|
GatekeeperInfo
|
||||||
}
|
}
|
||||||
@@ -97,7 +97,19 @@ class FingerprintGatekeeperViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FingerprintGatekeeperViewModelFactory(
|
||||||
|
private val gatekeeperInfo: GatekeeperInfo?,
|
||||||
|
private val fingerprintManagerInteractor: FingerprintManagerInteractor,
|
||||||
|
) : ViewModelProvider.Factory {
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
|
return FingerprintGatekeeperViewModel(gatekeeperInfo, fingerprintManagerInteractor) as T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private const val TAG = "FingerprintGatekeeperViewModel"
|
||||||
/**
|
/**
|
||||||
* A function that checks if the challenge and token are valid, in which case a
|
* A function that checks if the challenge and token are valid, in which case a
|
||||||
* [GatekeeperInfo.GatekeeperPasswordInfo] is provided, else [GatekeeperInfo.Invalid]
|
* [GatekeeperInfo.GatekeeperPasswordInfo] is provided, else [GatekeeperInfo.Invalid]
|
||||||
@@ -110,17 +122,4 @@ class FingerprintGatekeeperViewModel(
|
|||||||
return GatekeeperInfo.GatekeeperPasswordInfo(token, challenge)
|
return GatekeeperInfo.GatekeeperPasswordInfo(token, challenge)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FingerprintGatekeeperViewModelFactory(
|
|
||||||
private val gatekeeperInfo: GatekeeperInfo?,
|
|
||||||
private val fingerprintManagerInteractor: FingerprintManagerInteractor,
|
|
||||||
) : ViewModelProvider.Factory {
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
override fun <T : ViewModel> create(
|
|
||||||
modelClass: Class<T>,
|
|
||||||
): T {
|
|
||||||
return FingerprintGatekeeperViewModel(gatekeeperInfo, fingerprintManagerInteractor) as T
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,186 @@
|
|||||||
|
/*
|
||||||
|
* 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.ui.enrollment.viewmodel
|
||||||
|
|
||||||
|
import com.android.settings.biometrics.fingerprint2.lib.model.FastEnroll
|
||||||
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintFlow
|
||||||
|
import com.android.systemui.biometrics.shared.model.FingerprintSensor
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A [FingerprintAction] event notifies the current [FingerprintNavigationStep] that an event
|
||||||
|
* occurred. Depending on the type of [FingerprintAction] and the current
|
||||||
|
* [FingerprintNavigationStep], the navstep will potentially produce a new
|
||||||
|
* [FingerprintNavigationStep] indicating either 1). Control flow has changed 2). The activity has
|
||||||
|
* finished 3). A transition is required
|
||||||
|
*/
|
||||||
|
enum class FingerprintAction {
|
||||||
|
NEXT,
|
||||||
|
PREV,
|
||||||
|
CONFIRM_DEVICE_SUCCESS,
|
||||||
|
CONFIRM_DEVICE_FAIL,
|
||||||
|
TRANSITION_FINISHED,
|
||||||
|
DID_GO_TO_BACKGROUND,
|
||||||
|
ACTIVITY_CREATED,
|
||||||
|
NEGATIVE_BUTTON_PRESSED,
|
||||||
|
USER_CLICKED_FINISH,
|
||||||
|
}
|
||||||
|
|
||||||
|
/** State that can be used to help a [FingerprintNavigationStep] determine the next step to take. */
|
||||||
|
data class NavigationState(
|
||||||
|
val flowType: FingerprintFlow,
|
||||||
|
val hasConfirmedDeviceCredential: Boolean,
|
||||||
|
val fingerprintSensor: FingerprintSensor?,
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A generic interface for operating on (state, action) -> state? which will produce either another
|
||||||
|
* FingerprintNavStep if something is required, or nothing.
|
||||||
|
*
|
||||||
|
* Note during the lifetime of the Activity, their should only be one [FingerprintNavigationStep] at
|
||||||
|
* a time.
|
||||||
|
*/
|
||||||
|
sealed interface FingerprintNavigationStep {
|
||||||
|
fun update(state: NavigationState, action: FingerprintAction): FingerprintNavigationStep?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This indicates that a transition should occur from one screen to another. This class should
|
||||||
|
* contain all necessary info about the transition.
|
||||||
|
*
|
||||||
|
* A transition step will cause a screen to change ownership from the current screen to the
|
||||||
|
* [nextUiStep], after the transition has been completed and a
|
||||||
|
* [FingerprintAction.TRANSITION_FINISHED] has been sent, the [nextUiStep] will be given control.
|
||||||
|
*/
|
||||||
|
class TransitionStep(val nextUiStep: UiStep) : FingerprintNavigationStep {
|
||||||
|
override fun update(
|
||||||
|
state: NavigationState,
|
||||||
|
action: FingerprintAction,
|
||||||
|
): FingerprintNavigationStep? {
|
||||||
|
return when (action) {
|
||||||
|
FingerprintAction.TRANSITION_FINISHED -> nextUiStep
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String = "TransitionStep(nextUiStep=$nextUiStep)"
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Indicates we should finish the enrolling activity */
|
||||||
|
data class Finish(val result: Int?) : FingerprintNavigationStep {
|
||||||
|
override fun update(
|
||||||
|
state: NavigationState,
|
||||||
|
action: FingerprintAction,
|
||||||
|
): FingerprintNavigationStep? = null
|
||||||
|
}
|
||||||
|
|
||||||
|
/** UiSteps should have a 1 to 1 mapping between each screen of FingerprintEnrollment */
|
||||||
|
sealed class UiStep : FingerprintNavigationStep
|
||||||
|
|
||||||
|
/** This is the landing page for enrollment, where no content is shown. */
|
||||||
|
data object Init : UiStep() {
|
||||||
|
override fun update(
|
||||||
|
state: NavigationState,
|
||||||
|
action: FingerprintAction,
|
||||||
|
): FingerprintNavigationStep? {
|
||||||
|
return when (action) {
|
||||||
|
FingerprintAction.ACTIVITY_CREATED -> {
|
||||||
|
if (!state.hasConfirmedDeviceCredential) {
|
||||||
|
TransitionStep(ConfirmDeviceCredential)
|
||||||
|
} else if (state.flowType is FastEnroll) {
|
||||||
|
TransitionStep(Enrollment(state.fingerprintSensor!!))
|
||||||
|
} else {
|
||||||
|
TransitionStep(Introduction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Indicates the ConfirmDeviceCredential activity is being presented to the user */
|
||||||
|
data object ConfirmDeviceCredential : UiStep() {
|
||||||
|
override fun update(
|
||||||
|
state: NavigationState,
|
||||||
|
action: FingerprintAction,
|
||||||
|
): FingerprintNavigationStep? {
|
||||||
|
return when (action) {
|
||||||
|
FingerprintAction.CONFIRM_DEVICE_SUCCESS -> TransitionStep(Introduction)
|
||||||
|
FingerprintAction.CONFIRM_DEVICE_FAIL -> Finish(null)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Indicates the FingerprintIntroduction screen is being presented to the user */
|
||||||
|
data object Introduction : UiStep() {
|
||||||
|
override fun update(
|
||||||
|
state: NavigationState,
|
||||||
|
action: FingerprintAction,
|
||||||
|
): FingerprintNavigationStep? {
|
||||||
|
return when (action) {
|
||||||
|
FingerprintAction.NEXT -> TransitionStep(Education(state.fingerprintSensor!!))
|
||||||
|
FingerprintAction.NEGATIVE_BUTTON_PRESSED,
|
||||||
|
FingerprintAction.PREV -> Finish(null)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Indicates the FingerprintEducation screen is being presented to the user */
|
||||||
|
data class Education(val sensor: FingerprintSensor) : UiStep() {
|
||||||
|
override fun update(
|
||||||
|
state: NavigationState,
|
||||||
|
action: FingerprintAction,
|
||||||
|
): FingerprintNavigationStep? {
|
||||||
|
return when (action) {
|
||||||
|
FingerprintAction.NEXT -> TransitionStep(Enrollment(state.fingerprintSensor!!))
|
||||||
|
FingerprintAction.NEGATIVE_BUTTON_PRESSED,
|
||||||
|
FingerprintAction.PREV -> TransitionStep(Introduction)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Indicates the Enrollment screen is being presented to the user */
|
||||||
|
data class Enrollment(val sensor: FingerprintSensor) : UiStep() {
|
||||||
|
override fun update(
|
||||||
|
state: NavigationState,
|
||||||
|
action: FingerprintAction,
|
||||||
|
): FingerprintNavigationStep? {
|
||||||
|
return when (action) {
|
||||||
|
FingerprintAction.NEXT -> TransitionStep(Confirmation)
|
||||||
|
FingerprintAction.NEGATIVE_BUTTON_PRESSED,
|
||||||
|
FingerprintAction.USER_CLICKED_FINISH,
|
||||||
|
FingerprintAction.DID_GO_TO_BACKGROUND -> Finish(null)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Indicates the Confirmation screen is being presented to the user */
|
||||||
|
data object Confirmation : UiStep() {
|
||||||
|
override fun update(
|
||||||
|
state: NavigationState,
|
||||||
|
action: FingerprintAction,
|
||||||
|
): FingerprintNavigationStep? {
|
||||||
|
return when (action) {
|
||||||
|
FingerprintAction.NEXT -> Finish(null)
|
||||||
|
FingerprintAction.PREV -> TransitionStep(Education(state.fingerprintSensor!!))
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* 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.ui.enrollment.viewmodel
|
||||||
|
|
||||||
|
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.ui.enrollment.viewmodel.FingerprintNavigationStep.Finish
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.TransitionStep
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.UiStep
|
||||||
|
import java.lang.NullPointerException
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import kotlinx.coroutines.flow.combineTransform
|
||||||
|
import kotlinx.coroutines.flow.filterNotNull
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is essentially a wrapper around [FingerprintNavigationStep] that will be used by
|
||||||
|
* fragments/viewmodels that want to consume these events. It should provide no additional
|
||||||
|
* functionality beyond what is available in [FingerprintNavigationStep].
|
||||||
|
*/
|
||||||
|
class FingerprintNavigationViewModel(
|
||||||
|
step: UiStep,
|
||||||
|
hasConfirmedDeviceCredential: Boolean,
|
||||||
|
flowViewModel: FingerprintFlowViewModel,
|
||||||
|
fingerprintManagerInteractor: FingerprintManagerInteractor,
|
||||||
|
) : ViewModel() {
|
||||||
|
|
||||||
|
private var _navStateInternal: MutableStateFlow<NavigationState?> = MutableStateFlow(null)
|
||||||
|
|
||||||
|
init {
|
||||||
|
viewModelScope.launch {
|
||||||
|
flowViewModel.fingerprintFlow
|
||||||
|
.combineTransform(fingerprintManagerInteractor.sensorPropertiesInternal) { flow, props ->
|
||||||
|
if (props?.sensorId != -1) {
|
||||||
|
emit(NavigationState(flow, hasConfirmedDeviceCredential, props))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.collect { navState -> _navStateInternal.update { navState } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var _currentStep = MutableStateFlow<FingerprintNavigationStep?>(step)
|
||||||
|
|
||||||
|
private var _navigateTo: MutableStateFlow<UiStep?> = MutableStateFlow(null)
|
||||||
|
val navigateTo: Flow<UiStep?> = _navigateTo.asStateFlow()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This indicates a navigation event should occur. Navigation depends on navStateInternal being
|
||||||
|
* present.
|
||||||
|
*/
|
||||||
|
val currentStep: Flow<FingerprintNavigationStep> =
|
||||||
|
_currentStep.filterNotNull().combineTransform(_navStateInternal.filterNotNull()) { navigation, _
|
||||||
|
->
|
||||||
|
emit(navigation)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var _finishState = MutableStateFlow<Finish?>(null)
|
||||||
|
|
||||||
|
/** This indicates the activity should finish. */
|
||||||
|
val shouldFinish: Flow<Finish?> = _finishState.asStateFlow()
|
||||||
|
|
||||||
|
private var _currentScreen = MutableStateFlow<UiStep?>(null)
|
||||||
|
|
||||||
|
/** This indicates what screen should currently be presenting to the user. */
|
||||||
|
val currentScreen: Flow<UiStep?> = _currentScreen.asStateFlow()
|
||||||
|
|
||||||
|
/** See [updateInternal] for more details */
|
||||||
|
fun update(action: FingerprintAction, caller: KClass<*>, debugStr: String) {
|
||||||
|
Log.d(TAG, "$caller.update($action) $debugStr")
|
||||||
|
val currentStep = _currentStep.value
|
||||||
|
val isUiStep = currentStep is UiStep
|
||||||
|
if (currentStep == null) {
|
||||||
|
throw NullPointerException("current step is null")
|
||||||
|
}
|
||||||
|
if (isUiStep && currentStep::class != caller) {
|
||||||
|
throw IllegalAccessError(
|
||||||
|
"Error $currentStep != $caller, $caller should not be sending any events at this time"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val navState = _navStateInternal.value
|
||||||
|
if (navState == null) {
|
||||||
|
throw NullPointerException("nav state is null")
|
||||||
|
}
|
||||||
|
val nextStep = currentStep.update(navState, action) ?: return
|
||||||
|
Log.d(TAG, "nextStep=$nextStep")
|
||||||
|
// Whenever an state update occurs, everything should be cleared.
|
||||||
|
_currentStep.update { nextStep }
|
||||||
|
_finishState.update { null }
|
||||||
|
_currentScreen.update { null }
|
||||||
|
|
||||||
|
when (nextStep) {
|
||||||
|
is TransitionStep -> {
|
||||||
|
_navigateTo.update { nextStep.nextUiStep }
|
||||||
|
}
|
||||||
|
is Finish -> {
|
||||||
|
_finishState.update { nextStep }
|
||||||
|
}
|
||||||
|
is UiStep -> {
|
||||||
|
_currentScreen.update { nextStep }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FingerprintNavigationViewModelFactory(
|
||||||
|
private val step: UiStep,
|
||||||
|
private val hasConfirmedDeviceCredential: Boolean,
|
||||||
|
private val flowViewModel: FingerprintFlowViewModel,
|
||||||
|
private val fingerprintManagerInteractor: FingerprintManagerInteractor,
|
||||||
|
) : ViewModelProvider.Factory {
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
|
return FingerprintNavigationViewModel(
|
||||||
|
step,
|
||||||
|
hasConfirmedDeviceCredential,
|
||||||
|
flowViewModel,
|
||||||
|
fingerprintManagerInteractor,
|
||||||
|
)
|
||||||
|
as T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "FingerprintNavigationViewModel"
|
||||||
|
}
|
||||||
|
}
|
@@ -39,9 +39,7 @@ class FingerprintScrollViewModel : ViewModel() {
|
|||||||
class FingerprintScrollViewModelFactory : ViewModelProvider.Factory {
|
class FingerprintScrollViewModelFactory : ViewModelProvider.Factory {
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun <T : ViewModel> create(
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
modelClass: Class<T>,
|
|
||||||
): T {
|
|
||||||
return FingerprintScrollViewModel() as T
|
return FingerprintScrollViewModel() as T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -49,9 +49,7 @@ class FoldStateViewModel(context: Context) : ViewModel() {
|
|||||||
|
|
||||||
class FoldStateViewModelFactory(private val context: Context) : ViewModelProvider.Factory {
|
class FoldStateViewModelFactory(private val context: Context) : ViewModelProvider.Factory {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun <T : ViewModel> create(
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
modelClass: Class<T>,
|
|
||||||
): T {
|
|
||||||
return FoldStateViewModel(context) as T
|
return FoldStateViewModel(context) as T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,104 +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.ui.enrollment.viewmodel
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class that represents an action that the consumer should transition between lastStep and
|
|
||||||
* currStep and in what direction this transition is occurring (e.g. forward or backwards)
|
|
||||||
*/
|
|
||||||
open class NavigationStep(
|
|
||||||
val lastStep: NextStepViewModel,
|
|
||||||
val currStep: NextStepViewModel,
|
|
||||||
val forward: Boolean
|
|
||||||
) {
|
|
||||||
override fun toString(): String {
|
|
||||||
return "lastStep=$lastStep, currStep=$currStep, forward=$forward"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The navigation state used by a [NavStep] to determine what the [NextStepViewModel] should be. */
|
|
||||||
class NavState(val confirmedDevice: Boolean)
|
|
||||||
|
|
||||||
interface NavStep<T> {
|
|
||||||
fun next(state: NavState): T
|
|
||||||
fun prev(state: NavState): T
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class to represent a high level step (I.E. EnrollmentIntroduction) for FingerprintEnrollment.
|
|
||||||
*/
|
|
||||||
sealed class NextStepViewModel : NavStep<NextStepViewModel>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the initial state for the previous step, used to indicate that there have been no
|
|
||||||
* previous states.
|
|
||||||
*/
|
|
||||||
object PlaceHolderState : NextStepViewModel() {
|
|
||||||
override fun next(state: NavState): NextStepViewModel = Finish(null)
|
|
||||||
|
|
||||||
override fun prev(state: NavState): NextStepViewModel = Finish(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This state is the initial state for the current step, and will be used to determine if the user
|
|
||||||
* needs to [LaunchConfirmDeviceCredential] if not, it will go to [Intro]
|
|
||||||
*/
|
|
||||||
data object Start : NextStepViewModel() {
|
|
||||||
override fun next(state: NavState): NextStepViewModel =
|
|
||||||
if (state.confirmedDevice) Intro else LaunchConfirmDeviceCredential
|
|
||||||
|
|
||||||
override fun prev(state: NavState): NextStepViewModel = Finish(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** State indicating enrollment has been completed */
|
|
||||||
class Finish(val resultCode: Int?) : NextStepViewModel() {
|
|
||||||
override fun next(state: NavState): NextStepViewModel = Finish(resultCode)
|
|
||||||
override fun prev(state: NavState): NextStepViewModel = Finish(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** State for the FingerprintEnrollment introduction */
|
|
||||||
data object Intro : NextStepViewModel() {
|
|
||||||
override fun next(state: NavState): NextStepViewModel = Education
|
|
||||||
override fun prev(state: NavState): NextStepViewModel = Finish(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** State for the FingerprintEnrollment education */
|
|
||||||
data object Education : NextStepViewModel() {
|
|
||||||
override fun next(state: NavState): NextStepViewModel = Enrollment
|
|
||||||
override fun prev(state: NavState): NextStepViewModel = Intro
|
|
||||||
}
|
|
||||||
|
|
||||||
/** State for the FingerprintEnrollment enrollment */
|
|
||||||
data object Enrollment : NextStepViewModel() {
|
|
||||||
override fun next(state: NavState): NextStepViewModel = Confirmation
|
|
||||||
override fun prev(state: NavState): NextStepViewModel = Education
|
|
||||||
}
|
|
||||||
|
|
||||||
/** State for the FingerprintEnrollment confirmation */
|
|
||||||
object Confirmation : NextStepViewModel() {
|
|
||||||
override fun next(state: NavState): NextStepViewModel = Finish(0)
|
|
||||||
override fun prev(state: NavState): NextStepViewModel = Intro
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* State used to send the user to the ConfirmDeviceCredential activity. This activity can either
|
|
||||||
* confirm a users device credential, or have them create one.
|
|
||||||
*/
|
|
||||||
object LaunchConfirmDeviceCredential : NextStepViewModel() {
|
|
||||||
override fun next(state: NavState): NextStepViewModel = Intro
|
|
||||||
override fun prev(state: NavState): NextStepViewModel = Finish(0)
|
|
||||||
}
|
|
@@ -58,7 +58,7 @@ class OrientationStateViewModel(private val context: Context) : ViewModel() {
|
|||||||
.stateIn(
|
.stateIn(
|
||||||
viewModelScope, // This is going to tied to the view model scope
|
viewModelScope, // This is going to tied to the view model scope
|
||||||
SharingStarted.WhileSubscribed(), // When no longer subscribed, we removeTheListener
|
SharingStarted.WhileSubscribed(), // When no longer subscribed, we removeTheListener
|
||||||
context.display!!.rotation
|
context.display!!.rotation,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun getRotationFromDefault(rotation: Int): Int {
|
fun getRotationFromDefault(rotation: Int): Int {
|
||||||
@@ -73,9 +73,7 @@ class OrientationStateViewModel(private val context: Context) : ViewModel() {
|
|||||||
|
|
||||||
class OrientationViewModelFactory(private val context: Context) : ViewModelProvider.Factory {
|
class OrientationViewModelFactory(private val context: Context) : ViewModelProvider.Factory {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun <T : ViewModel> create(
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
modelClass: Class<T>,
|
|
||||||
): T {
|
|
||||||
return OrientationStateViewModel(context) as T
|
return OrientationStateViewModel(context) as T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,8 +19,8 @@ package com.android.settings.biometrics.fingerprint2.ui.settings.binder
|
|||||||
import android.hardware.fingerprint.FingerprintManager
|
import android.hardware.fingerprint.FingerprintManager
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.lifecycle.LifecycleCoroutineScope
|
import androidx.lifecycle.LifecycleCoroutineScope
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintAuthAttemptModel
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintData
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.settings.binder.FingerprintSettingsViewBinder.FingerprintView
|
import com.android.settings.biometrics.fingerprint2.ui.settings.binder.FingerprintSettingsViewBinder.FingerprintView
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.EnrollAdditionalFingerprint
|
import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.EnrollAdditionalFingerprint
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.EnrollFirstFingerprint
|
import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.EnrollFirstFingerprint
|
||||||
@@ -52,7 +52,7 @@ object FingerprintSettingsViewBinder {
|
|||||||
userId: Int,
|
userId: Int,
|
||||||
gateKeeperPasswordHandle: Long?,
|
gateKeeperPasswordHandle: Long?,
|
||||||
challenge: Long?,
|
challenge: Long?,
|
||||||
challengeToken: ByteArray?
|
challengeToken: ByteArray?,
|
||||||
)
|
)
|
||||||
/** Helper to launch an add fingerprint request */
|
/** Helper to launch an add fingerprint request */
|
||||||
fun launchAddFingerprint(userId: Int, challengeToken: ByteArray?)
|
fun launchAddFingerprint(userId: Int, challengeToken: ByteArray?)
|
||||||
@@ -158,7 +158,7 @@ object FingerprintSettingsViewBinder {
|
|||||||
nextStep.userId,
|
nextStep.userId,
|
||||||
nextStep.gateKeeperPasswordHandle,
|
nextStep.gateKeeperPasswordHandle,
|
||||||
nextStep.challenge,
|
nextStep.challenge,
|
||||||
nextStep.challengeToken
|
nextStep.challengeToken,
|
||||||
)
|
)
|
||||||
is EnrollAdditionalFingerprint ->
|
is EnrollAdditionalFingerprint ->
|
||||||
view.launchAddFingerprint(nextStep.userId, nextStep.challengeToken)
|
view.launchAddFingerprint(nextStep.userId, nextStep.challengeToken)
|
||||||
|
@@ -26,7 +26,7 @@ import android.os.Bundle
|
|||||||
import android.os.UserManager
|
import android.os.UserManager
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintData
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData
|
||||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment
|
import com.android.settings.core.instrumentation.InstrumentedDialogFragment
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
@@ -75,8 +75,7 @@ class FingerprintDeletionDialog : InstrumentedDialogFragment() {
|
|||||||
message =
|
message =
|
||||||
devicePolicyManager?.resources?.getString(messageId) {
|
devicePolicyManager?.resources?.getString(messageId) {
|
||||||
message + "\n\n" + context.getString(defaultMessageId)
|
message + "\n\n" + context.getString(defaultMessageId)
|
||||||
}
|
} ?: ""
|
||||||
?: ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
alertDialog =
|
alertDialog =
|
||||||
@@ -85,7 +84,7 @@ class FingerprintDeletionDialog : InstrumentedDialogFragment() {
|
|||||||
.setMessage(message)
|
.setMessage(message)
|
||||||
.setPositiveButton(
|
.setPositiveButton(
|
||||||
R.string.security_settings_fingerprint_enroll_dialog_delete,
|
R.string.security_settings_fingerprint_enroll_dialog_delete,
|
||||||
onClickListener
|
onClickListener,
|
||||||
)
|
)
|
||||||
.setNegativeButton(R.string.cancel, onNegativeClickListener)
|
.setNegativeButton(R.string.cancel, onNegativeClickListener)
|
||||||
.create()
|
.create()
|
||||||
@@ -94,10 +93,11 @@ class FingerprintDeletionDialog : InstrumentedDialogFragment() {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val KEY_FINGERPRINT = "fingerprint"
|
private const val KEY_FINGERPRINT = "fingerprint"
|
||||||
|
|
||||||
suspend fun showInstance(
|
suspend fun showInstance(
|
||||||
fp: FingerprintData,
|
fp: FingerprintData,
|
||||||
lastFingerprint: Boolean,
|
lastFingerprint: Boolean,
|
||||||
target: FingerprintSettingsV2Fragment,
|
target: FingerprintSettingsV2Fragment,
|
||||||
) = suspendCancellableCoroutine { continuation ->
|
) = suspendCancellableCoroutine { continuation ->
|
||||||
val dialog = FingerprintDeletionDialog()
|
val dialog = FingerprintDeletionDialog()
|
||||||
dialog.onClickListener = DialogInterface.OnClickListener { _, _ -> continuation.resume(true) }
|
dialog.onClickListener = DialogInterface.OnClickListener { _, _ -> continuation.resume(true) }
|
||||||
@@ -109,7 +109,7 @@ class FingerprintDeletionDialog : InstrumentedDialogFragment() {
|
|||||||
val bundle = Bundle()
|
val bundle = Bundle()
|
||||||
bundle.putObject(
|
bundle.putObject(
|
||||||
KEY_FINGERPRINT,
|
KEY_FINGERPRINT,
|
||||||
android.hardware.fingerprint.Fingerprint(fp.name, fp.fingerId, fp.deviceId)
|
android.hardware.fingerprint.Fingerprint(fp.name, fp.fingerId, fp.deviceId),
|
||||||
)
|
)
|
||||||
bundle.putBoolean(KEY_IS_LAST_FINGERPRINT, lastFingerprint)
|
bundle.putBoolean(KEY_IS_LAST_FINGERPRINT, lastFingerprint)
|
||||||
dialog.arguments = bundle
|
dialog.arguments = bundle
|
||||||
|
@@ -22,7 +22,7 @@ import android.view.View
|
|||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.preference.PreferenceViewHolder
|
import androidx.preference.PreferenceViewHolder
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintData
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData
|
||||||
import com.android.settingslib.widget.TwoTargetPreference
|
import com.android.settingslib.widget.TwoTargetPreference
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -30,10 +30,10 @@ import kotlinx.coroutines.launch
|
|||||||
private const val TAG = "FingerprintSettingsPreference"
|
private const val TAG = "FingerprintSettingsPreference"
|
||||||
|
|
||||||
class FingerprintSettingsPreference(
|
class FingerprintSettingsPreference(
|
||||||
context: Context,
|
context: Context,
|
||||||
val fingerprintViewModel: FingerprintData,
|
val fingerprintViewModel: FingerprintData,
|
||||||
val fragment: FingerprintSettingsV2Fragment,
|
val fragment: FingerprintSettingsV2Fragment,
|
||||||
val isLastFingerprint: Boolean
|
val isLastFingerprint: Boolean,
|
||||||
) : TwoTargetPreference(context) {
|
) : TwoTargetPreference(context) {
|
||||||
private lateinit var myView: View
|
private lateinit var myView: View
|
||||||
|
|
||||||
|
@@ -27,7 +27,7 @@ import android.util.Log
|
|||||||
import android.widget.ImeAwareEditText
|
import android.widget.ImeAwareEditText
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintData
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData
|
||||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment
|
import com.android.settings.core.instrumentation.InstrumentedDialogFragment
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
@@ -78,7 +78,7 @@ class FingerprintSettingsRenameDialog : InstrumentedDialogFragment() {
|
|||||||
end: Int,
|
end: Int,
|
||||||
dest: Spanned?,
|
dest: Spanned?,
|
||||||
dstart: Int,
|
dstart: Int,
|
||||||
dend: Int
|
dend: Int,
|
||||||
): CharSequence? {
|
): CharSequence? {
|
||||||
for (index in start until end) {
|
for (index in start until end) {
|
||||||
val c = source[index]
|
val c = source[index]
|
||||||
@@ -133,13 +133,13 @@ class FingerprintSettingsRenameDialog : InstrumentedDialogFragment() {
|
|||||||
val bundle = Bundle()
|
val bundle = Bundle()
|
||||||
bundle.putObject(
|
bundle.putObject(
|
||||||
KEY_FINGERPRINT,
|
KEY_FINGERPRINT,
|
||||||
android.hardware.fingerprint.Fingerprint(fp.name, fp.fingerId, fp.deviceId)
|
android.hardware.fingerprint.Fingerprint(fp.name, fp.fingerId, fp.deviceId),
|
||||||
)
|
)
|
||||||
dialog.arguments = bundle
|
dialog.arguments = bundle
|
||||||
Log.d(TAG, "showing dialog $dialog")
|
Log.d(TAG, "showing dialog $dialog")
|
||||||
dialog.show(
|
dialog.show(
|
||||||
target.parentFragmentManager,
|
target.parentFragmentManager,
|
||||||
FingerprintSettingsRenameDialog::class.java.toString()
|
FingerprintSettingsRenameDialog::class.java.toString(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -45,11 +45,12 @@ import com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED
|
|||||||
import com.android.settings.biometrics.GatekeeperPasswordProvider
|
import com.android.settings.biometrics.GatekeeperPasswordProvider
|
||||||
import com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling
|
import com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling
|
||||||
import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroductionInternal
|
import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroductionInternal
|
||||||
|
import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepoImpl
|
||||||
|
import com.android.settings.biometrics.fingerprint2.data.repository.PressToAuthRepoImpl
|
||||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl
|
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl
|
||||||
import com.android.settings.biometrics.fingerprint2.repository.PressToAuthProviderImpl
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintAuthAttemptModel
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintData
|
import com.android.settings.biometrics.fingerprint2.lib.model.Settings
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.Settings
|
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.settings.binder.FingerprintSettingsViewBinder
|
import com.android.settings.biometrics.fingerprint2.ui.settings.binder.FingerprintSettingsViewBinder
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FingerprintSettingsNavigationViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FingerprintSettingsNavigationViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FingerprintSettingsViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FingerprintSettingsViewModel
|
||||||
@@ -128,12 +129,12 @@ class FingerprintSettingsV2Fragment :
|
|||||||
if (resultCode == BiometricEnrollBase.RESULT_TIMEOUT) {
|
if (resultCode == BiometricEnrollBase.RESULT_TIMEOUT) {
|
||||||
navigationViewModel.onEnrollFirstFailure(
|
navigationViewModel.onEnrollFirstFailure(
|
||||||
"Received RESULT_TIMEOUT when enrolling",
|
"Received RESULT_TIMEOUT when enrolling",
|
||||||
resultCode
|
resultCode,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
navigationViewModel.onEnrollFirstFailure(
|
navigationViewModel.onEnrollFirstFailure(
|
||||||
"Incorrect resultCode or data was null",
|
"Incorrect resultCode or data was null",
|
||||||
resultCode
|
resultCode,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -212,21 +213,24 @@ class FingerprintSettingsV2Fragment :
|
|||||||
context.contentResolver,
|
context.contentResolver,
|
||||||
Secure.SFPS_PERFORMANT_AUTH_ENABLED,
|
Secure.SFPS_PERFORMANT_AUTH_ENABLED,
|
||||||
toReturn,
|
toReturn,
|
||||||
userHandle
|
userHandle,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
toReturn == 1
|
toReturn == 1
|
||||||
}
|
}
|
||||||
|
val fingerprintSensorProvider =
|
||||||
|
FingerprintSensorRepoImpl(fingerprintManager, backgroundDispatcher, lifecycleScope)
|
||||||
|
|
||||||
val interactor =
|
val interactor =
|
||||||
FingerprintManagerInteractorImpl(
|
FingerprintManagerInteractorImpl(
|
||||||
context.applicationContext,
|
context.applicationContext,
|
||||||
backgroundDispatcher,
|
backgroundDispatcher,
|
||||||
fingerprintManager,
|
fingerprintManager,
|
||||||
|
fingerprintSensorProvider,
|
||||||
GatekeeperPasswordProvider(LockPatternUtils(context.applicationContext)),
|
GatekeeperPasswordProvider(LockPatternUtils(context.applicationContext)),
|
||||||
PressToAuthProviderImpl(context),
|
PressToAuthRepoImpl(context),
|
||||||
isAnySuw
|
Settings,
|
||||||
)
|
)
|
||||||
|
|
||||||
val token = intent.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN)
|
val token = intent.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN)
|
||||||
@@ -240,8 +244,8 @@ class FingerprintSettingsV2Fragment :
|
|||||||
interactor,
|
interactor,
|
||||||
backgroundDispatcher,
|
backgroundDispatcher,
|
||||||
token,
|
token,
|
||||||
challenge
|
challenge,
|
||||||
)
|
),
|
||||||
)[FingerprintSettingsNavigationViewModel::class.java]
|
)[FingerprintSettingsNavigationViewModel::class.java]
|
||||||
|
|
||||||
settingsViewModel =
|
settingsViewModel =
|
||||||
@@ -252,15 +256,10 @@ class FingerprintSettingsV2Fragment :
|
|||||||
interactor,
|
interactor,
|
||||||
backgroundDispatcher,
|
backgroundDispatcher,
|
||||||
navigationViewModel,
|
navigationViewModel,
|
||||||
)
|
),
|
||||||
)[FingerprintSettingsViewModel::class.java]
|
)[FingerprintSettingsViewModel::class.java]
|
||||||
|
|
||||||
FingerprintSettingsViewBinder.bind(
|
FingerprintSettingsViewBinder.bind(this, settingsViewModel, navigationViewModel, lifecycleScope)
|
||||||
this,
|
|
||||||
settingsViewModel,
|
|
||||||
navigationViewModel,
|
|
||||||
lifecycleScope,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getMetricsCategory(): Int {
|
override fun getMetricsCategory(): Int {
|
||||||
@@ -364,7 +363,7 @@ class FingerprintSettingsV2Fragment :
|
|||||||
RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
|
RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
|
||||||
activity,
|
activity,
|
||||||
DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT,
|
DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT,
|
||||||
requireActivity().userId
|
requireActivity().userId,
|
||||||
)
|
)
|
||||||
val activity = requireActivity()
|
val activity = requireActivity()
|
||||||
val helpIntent =
|
val helpIntent =
|
||||||
@@ -404,7 +403,7 @@ class FingerprintSettingsV2Fragment :
|
|||||||
column.title =
|
column.title =
|
||||||
getString(
|
getString(
|
||||||
R.string.security_settings_fingerprint_enroll_introduction_v3_message,
|
R.string.security_settings_fingerprint_enroll_introduction_v3_message,
|
||||||
DeviceHelper.getDeviceName(requireActivity())
|
DeviceHelper.getDeviceName(requireActivity()),
|
||||||
)
|
)
|
||||||
column.learnMoreOnClickListener = learnMoreClickListener
|
column.learnMoreOnClickListener = learnMoreClickListener
|
||||||
column.learnMoreOverrideText =
|
column.learnMoreOverrideText =
|
||||||
@@ -437,13 +436,12 @@ class FingerprintSettingsV2Fragment :
|
|||||||
val willDelete =
|
val willDelete =
|
||||||
fingerprintPreferences()
|
fingerprintPreferences()
|
||||||
.first { it?.fingerprintViewModel == fingerprintViewModel }
|
.first { it?.fingerprintViewModel == fingerprintViewModel }
|
||||||
?.askUserToDeleteDialog()
|
?.askUserToDeleteDialog() ?: false
|
||||||
?: false
|
|
||||||
if (willDelete) {
|
if (willDelete) {
|
||||||
mMetricsFeatureProvider.action(
|
mMetricsFeatureProvider.action(
|
||||||
context,
|
context,
|
||||||
SettingsEnums.ACTION_FINGERPRINT_DELETE,
|
SettingsEnums.ACTION_FINGERPRINT_DELETE,
|
||||||
fingerprintViewModel.fingerId
|
fingerprintViewModel.fingerId,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return willDelete
|
return willDelete
|
||||||
@@ -466,7 +464,7 @@ class FingerprintSettingsV2Fragment :
|
|||||||
mMetricsFeatureProvider.action(
|
mMetricsFeatureProvider.action(
|
||||||
context,
|
context,
|
||||||
SettingsEnums.ACTION_FINGERPRINT_RENAME,
|
SettingsEnums.ACTION_FINGERPRINT_RENAME,
|
||||||
toReturn.first.fingerId
|
toReturn.first.fingerId,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return toReturn
|
return toReturn
|
||||||
@@ -518,12 +516,12 @@ class FingerprintSettingsV2Fragment :
|
|||||||
val intent = Intent()
|
val intent = Intent()
|
||||||
intent.setClassName(
|
intent.setClassName(
|
||||||
SETTINGS_PACKAGE_NAME,
|
SETTINGS_PACKAGE_NAME,
|
||||||
FingerprintEnrollIntroductionInternal::class.java.name
|
FingerprintEnrollIntroductionInternal::class.java.name,
|
||||||
)
|
)
|
||||||
intent.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, true)
|
intent.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, true)
|
||||||
intent.putExtra(
|
intent.putExtra(
|
||||||
SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE,
|
SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE,
|
||||||
SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE
|
SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE,
|
||||||
)
|
)
|
||||||
|
|
||||||
intent.putExtra(Intent.EXTRA_USER_ID, userId)
|
intent.putExtra(Intent.EXTRA_USER_ID, userId)
|
||||||
@@ -546,7 +544,7 @@ class FingerprintSettingsV2Fragment :
|
|||||||
val intent = Intent()
|
val intent = Intent()
|
||||||
intent.setClassName(
|
intent.setClassName(
|
||||||
SETTINGS_PACKAGE_NAME,
|
SETTINGS_PACKAGE_NAME,
|
||||||
FingerprintEnrollEnrolling::class.qualifiedName.toString()
|
FingerprintEnrollEnrolling::class.qualifiedName.toString(),
|
||||||
)
|
)
|
||||||
intent.putExtra(Intent.EXTRA_USER_ID, userId)
|
intent.putExtra(Intent.EXTRA_USER_ID, userId)
|
||||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, challengeToken)
|
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, challengeToken)
|
||||||
@@ -568,8 +566,7 @@ class FingerprintSettingsV2Fragment :
|
|||||||
|
|
||||||
return category?.let { cat ->
|
return category?.let { cat ->
|
||||||
cat.childrenToList().map { it as FingerprintSettingsPreference? }
|
cat.childrenToList().map { it as FingerprintSettingsPreference? }
|
||||||
}
|
} ?: emptyList()
|
||||||
?: emptyList()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun PreferenceCategory.childrenToList(): List<Preference> {
|
private fun PreferenceCategory.childrenToList(): List<Preference> {
|
||||||
|
@@ -21,7 +21,7 @@ import androidx.lifecycle.ViewModel
|
|||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.android.settings.biometrics.BiometricEnrollBase
|
import com.android.settings.biometrics.BiometricEnrollBase
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.domain.interactor.FingerprintManagerInteractor
|
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
@@ -32,11 +32,11 @@ import kotlinx.coroutines.launch
|
|||||||
|
|
||||||
/** A Viewmodel that represents the navigation of the FingerprintSettings activity. */
|
/** A Viewmodel that represents the navigation of the FingerprintSettings activity. */
|
||||||
class FingerprintSettingsNavigationViewModel(
|
class FingerprintSettingsNavigationViewModel(
|
||||||
private val userId: Int,
|
private val userId: Int,
|
||||||
private val fingerprintManagerInteractor: FingerprintManagerInteractor,
|
private val fingerprintManagerInteractor: FingerprintManagerInteractor,
|
||||||
private val backgroundDispatcher: CoroutineDispatcher,
|
private val backgroundDispatcher: CoroutineDispatcher,
|
||||||
tokenInit: ByteArray?,
|
tokenInit: ByteArray?,
|
||||||
challengeInit: Long?,
|
challengeInit: Long?,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private var token = tokenInit
|
private var token = tokenInit
|
||||||
@@ -173,17 +173,15 @@ class FingerprintSettingsNavigationViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FingerprintSettingsNavigationModelFactory(
|
class FingerprintSettingsNavigationModelFactory(
|
||||||
private val userId: Int,
|
private val userId: Int,
|
||||||
private val interactor: FingerprintManagerInteractor,
|
private val interactor: FingerprintManagerInteractor,
|
||||||
private val backgroundDispatcher: CoroutineDispatcher,
|
private val backgroundDispatcher: CoroutineDispatcher,
|
||||||
private val token: ByteArray?,
|
private val token: ByteArray?,
|
||||||
private val challenge: Long?,
|
private val challenge: Long?,
|
||||||
) : ViewModelProvider.Factory {
|
) : ViewModelProvider.Factory {
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun <T : ViewModel> create(
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
modelClass: Class<T>,
|
|
||||||
): T {
|
|
||||||
|
|
||||||
return FingerprintSettingsNavigationViewModel(
|
return FingerprintSettingsNavigationViewModel(
|
||||||
userId,
|
userId,
|
||||||
|
@@ -21,9 +21,9 @@ import android.util.Log
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.domain.interactor.FingerprintManagerInteractor
|
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintAuthAttemptModel
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintData
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData
|
||||||
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
@@ -66,7 +66,7 @@ class FingerprintSettingsViewModel(
|
|||||||
emit(
|
emit(
|
||||||
Pair(
|
Pair(
|
||||||
fingerprintManagerInteractor.canEnrollFingerprints.first(),
|
fingerprintManagerInteractor.canEnrollFingerprints.first(),
|
||||||
fingerprintManagerInteractor.maxEnrollableFingerprints.first()
|
fingerprintManagerInteractor.maxEnrollableFingerprints.first(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,7 @@ class FingerprintSettingsViewModel(
|
|||||||
_isLockedOut,
|
_isLockedOut,
|
||||||
_attemptsSoFar,
|
_attemptsSoFar,
|
||||||
_fingerprintSensorType,
|
_fingerprintSensorType,
|
||||||
_sensorNullOrEmpty
|
_sensorNullOrEmpty,
|
||||||
) {
|
) {
|
||||||
dialogShowing,
|
dialogShowing,
|
||||||
step,
|
step,
|
||||||
@@ -140,7 +140,7 @@ class FingerprintSettingsViewModel(
|
|||||||
"lockedOut=${isLockedOut}," +
|
"lockedOut=${isLockedOut}," +
|
||||||
"attempts=${attempts}," +
|
"attempts=${attempts}," +
|
||||||
"sensorType=${sensorType}" +
|
"sensorType=${sensorType}" +
|
||||||
"sensorNullOrEmpty=${sensorNullOrEmpty}"
|
"sensorNullOrEmpty=${sensorNullOrEmpty}",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (sensorNullOrEmpty) {
|
if (sensorNullOrEmpty) {
|
||||||
@@ -294,9 +294,7 @@ class FingerprintSettingsViewModel(
|
|||||||
) : ViewModelProvider.Factory {
|
) : ViewModelProvider.Factory {
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun <T : ViewModel> create(
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
modelClass: Class<T>,
|
|
||||||
): T {
|
|
||||||
|
|
||||||
return FingerprintSettingsViewModel(
|
return FingerprintSettingsViewModel(
|
||||||
userId,
|
userId,
|
||||||
@@ -318,7 +316,7 @@ private inline fun <T1, T2, T3, T4, T5, T6, T7, T8, R> combine(
|
|||||||
flow6: Flow<T6>,
|
flow6: Flow<T6>,
|
||||||
flow7: Flow<T7>,
|
flow7: Flow<T7>,
|
||||||
flow8: Flow<T8>,
|
flow8: Flow<T8>,
|
||||||
crossinline transform: suspend (T1, T2, T3, T4, T5, T6, T7, T8) -> R
|
crossinline transform: suspend (T1, T2, T3, T4, T5, T6, T7, T8) -> R,
|
||||||
): Flow<R> {
|
): Flow<R> {
|
||||||
return combine(flow, flow2, flow3, flow4, flow5, flow6, flow7, flow8) { args: Array<*> ->
|
return combine(flow, flow2, flow3, flow4, flow5, flow6, flow7, flow8) { args: Array<*> ->
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
@@ -29,10 +29,8 @@ data class EnrollFirstFingerprint(
|
|||||||
val challengeToken: ByteArray?,
|
val challengeToken: ByteArray?,
|
||||||
) : NextStepViewModel()
|
) : NextStepViewModel()
|
||||||
|
|
||||||
data class EnrollAdditionalFingerprint(
|
data class EnrollAdditionalFingerprint(val userId: Int, val challengeToken: ByteArray?) :
|
||||||
val userId: Int,
|
NextStepViewModel()
|
||||||
val challengeToken: ByteArray?,
|
|
||||||
) : NextStepViewModel()
|
|
||||||
|
|
||||||
data class FinishSettings(val reason: String) : NextStepViewModel()
|
data class FinishSettings(val reason: String) : NextStepViewModel()
|
||||||
|
|
||||||
|
@@ -16,15 +16,11 @@
|
|||||||
|
|
||||||
package com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel
|
package com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel
|
||||||
|
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintData
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData
|
||||||
|
|
||||||
/** Classed use to represent a Dialogs state. */
|
/** Classed use to represent a Dialogs state. */
|
||||||
sealed class PreferenceViewModel {
|
sealed class PreferenceViewModel {
|
||||||
data class RenameDialog(
|
data class RenameDialog(val fingerprintViewModel: FingerprintData) : PreferenceViewModel()
|
||||||
val fingerprintViewModel: FingerprintData,
|
|
||||||
) : PreferenceViewModel()
|
|
||||||
|
|
||||||
data class DeleteDialog(
|
data class DeleteDialog(val fingerprintViewModel: FingerprintData) : PreferenceViewModel()
|
||||||
val fingerprintViewModel: FingerprintData,
|
|
||||||
) : PreferenceViewModel()
|
|
||||||
}
|
}
|
||||||
|
@@ -33,16 +33,20 @@ import androidx.test.espresso.matcher.ViewMatchers.withId
|
|||||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
import androidx.test.runner.AndroidJUnit4
|
import androidx.test.runner.AndroidJUnit4
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.Default
|
import com.android.settings.biometrics.fingerprint2.lib.model.Default
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Introduction
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.NavigationState
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollIntroV2Fragment
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollIntroV2Fragment
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollNavigationViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollIntroViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintFlowViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Intro
|
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.NavState
|
|
||||||
import com.android.settings.testutils2.FakeFingerprintManagerInteractor
|
import com.android.settings.testutils2.FakeFingerprintManagerInteractor
|
||||||
|
import com.android.systemui.biometrics.shared.model.FingerprintSensor
|
||||||
|
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
||||||
|
import com.android.systemui.biometrics.shared.model.SensorStrength
|
||||||
import com.google.android.setupdesign.GlifLayout
|
import com.google.android.setupdesign.GlifLayout
|
||||||
import com.google.android.setupdesign.template.RequireScrollMixin
|
import com.google.android.setupdesign.template.RequireScrollMixin
|
||||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||||
@@ -62,18 +66,27 @@ class FingerprintEnrollIntroFragmentTest {
|
|||||||
)
|
)
|
||||||
private val backgroundDispatcher = StandardTestDispatcher()
|
private val backgroundDispatcher = StandardTestDispatcher()
|
||||||
private lateinit var fragmentScenario: FragmentScenario<FingerprintEnrollIntroV2Fragment>
|
private lateinit var fragmentScenario: FragmentScenario<FingerprintEnrollIntroV2Fragment>
|
||||||
|
private val fingerprintSensor =
|
||||||
|
FingerprintSensor(1, SensorStrength.STRONG, 5, FingerprintSensorType.POWER_BUTTON)
|
||||||
|
|
||||||
|
var enrollFlow = Default
|
||||||
|
val flowViewModel = FingerprintFlowViewModel(enrollFlow)
|
||||||
|
|
||||||
private val navigationViewModel =
|
private val navigationViewModel =
|
||||||
FingerprintEnrollNavigationViewModel(
|
FingerprintNavigationViewModel(
|
||||||
backgroundDispatcher,
|
Introduction,
|
||||||
interactor,
|
false,
|
||||||
gatekeeperViewModel,
|
flowViewModel,
|
||||||
Intro,
|
interactor
|
||||||
NavState(true),
|
|
||||||
Default,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
private var fingerprintViewModel =
|
private var fingerprintViewModel =
|
||||||
FingerprintEnrollViewModel(interactor, gatekeeperViewModel, navigationViewModel)
|
FingerprintEnrollIntroViewModel(
|
||||||
|
navigationViewModel,
|
||||||
|
flowViewModel,
|
||||||
|
interactor,
|
||||||
|
)
|
||||||
|
|
||||||
private var fingerprintScrollViewModel = FingerprintScrollViewModel()
|
private var fingerprintScrollViewModel = FingerprintScrollViewModel()
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -85,9 +98,9 @@ class FingerprintEnrollIntroFragmentTest {
|
|||||||
modelClass: Class<T>,
|
modelClass: Class<T>,
|
||||||
): T {
|
): T {
|
||||||
return when (modelClass) {
|
return when (modelClass) {
|
||||||
FingerprintEnrollViewModel::class.java -> fingerprintViewModel
|
FingerprintEnrollIntroViewModel::class.java -> fingerprintViewModel
|
||||||
FingerprintScrollViewModel::class.java -> fingerprintScrollViewModel
|
FingerprintScrollViewModel::class.java -> fingerprintScrollViewModel
|
||||||
FingerprintEnrollNavigationViewModel::class.java -> navigationViewModel
|
FingerprintNavigationViewModel::class.java -> navigationViewModel
|
||||||
FingerprintGatekeeperViewModel::class.java -> gatekeeperViewModel
|
FingerprintGatekeeperViewModel::class.java -> gatekeeperViewModel
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
@@ -30,16 +30,19 @@ import androidx.test.core.app.ApplicationProvider
|
|||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.Default
|
import com.android.settings.biometrics.fingerprint2.lib.model.Default
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollIntroV2Fragment
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollIntroV2Fragment
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollNavigationViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollIntroViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintFlowViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.NavState
|
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Start
|
|
||||||
import com.android.settings.testutils2.FakeFingerprintManagerInteractor
|
import com.android.settings.testutils2.FakeFingerprintManagerInteractor
|
||||||
|
import com.android.systemui.biometrics.shared.model.FingerprintSensor
|
||||||
|
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
||||||
|
import com.android.systemui.biometrics.shared.model.SensorStrength
|
||||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
@@ -60,7 +63,7 @@ class BasicScreenshotTest {
|
|||||||
InstrumentationRegistry.getInstrumentation()
|
InstrumentationRegistry.getInstrumentation()
|
||||||
.getTargetContext()
|
.getTargetContext()
|
||||||
.getFilesDir()
|
.getFilesDir()
|
||||||
.getAbsolutePath() + "/settings_screenshots"
|
.getAbsolutePath() + "/settings_screenshots",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -70,24 +73,27 @@ class BasicScreenshotTest {
|
|||||||
private val gatekeeperViewModel =
|
private val gatekeeperViewModel =
|
||||||
FingerprintGatekeeperViewModel(
|
FingerprintGatekeeperViewModel(
|
||||||
GatekeeperInfo.GatekeeperPasswordInfo(byteArrayOf(1, 2, 3), 100L),
|
GatekeeperInfo.GatekeeperPasswordInfo(byteArrayOf(1, 2, 3), 100L),
|
||||||
interactor
|
interactor,
|
||||||
)
|
)
|
||||||
|
|
||||||
private val backgroundDispatcher = StandardTestDispatcher()
|
private val backgroundDispatcher = StandardTestDispatcher()
|
||||||
private lateinit var fragmentScenario: FragmentScenario<FingerprintEnrollIntroV2Fragment>
|
private lateinit var fragmentScenario: FragmentScenario<FingerprintEnrollIntroV2Fragment>
|
||||||
val navState = NavState(true)
|
private val fingerprintSensor =
|
||||||
|
FingerprintSensor(1, SensorStrength.STRONG, 5, FingerprintSensorType.POWER_BUTTON)
|
||||||
|
|
||||||
private val navigationViewModel = FingerprintEnrollNavigationViewModel(
|
var enrollFlow = Default
|
||||||
backgroundDispatcher,
|
val flowViewModel = FingerprintFlowViewModel(enrollFlow)
|
||||||
|
|
||||||
|
private val navigationViewModel =
|
||||||
|
FingerprintNavigationViewModel(
|
||||||
|
FingerprintNavigationStep.Introduction,
|
||||||
|
false,
|
||||||
|
flowViewModel,
|
||||||
interactor,
|
interactor,
|
||||||
gatekeeperViewModel,
|
|
||||||
Start.next(navState),
|
|
||||||
navState,
|
|
||||||
Default,
|
|
||||||
)
|
|
||||||
private var fingerprintViewModel = FingerprintEnrollViewModel(
|
|
||||||
interactor, gatekeeperViewModel, navigationViewModel,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private var fingerprintViewModel =
|
||||||
|
FingerprintEnrollIntroViewModel(navigationViewModel, flowViewModel, interactor)
|
||||||
private var fingerprintScrollViewModel = FingerprintScrollViewModel()
|
private var fingerprintScrollViewModel = FingerprintScrollViewModel()
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -95,13 +101,11 @@ class BasicScreenshotTest {
|
|||||||
val factory =
|
val factory =
|
||||||
object : ViewModelProvider.Factory {
|
object : ViewModelProvider.Factory {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun <T : ViewModel> create(
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
modelClass: Class<T>,
|
|
||||||
): T {
|
|
||||||
return when (modelClass) {
|
return when (modelClass) {
|
||||||
FingerprintEnrollViewModel::class.java -> fingerprintViewModel
|
FingerprintEnrollIntroViewModel::class.java -> fingerprintViewModel
|
||||||
FingerprintScrollViewModel::class.java -> fingerprintScrollViewModel
|
FingerprintScrollViewModel::class.java -> fingerprintScrollViewModel
|
||||||
FingerprintEnrollNavigationViewModel::class.java -> navigationViewModel
|
FingerprintNavigationViewModel::class.java -> navigationViewModel
|
||||||
FingerprintGatekeeperViewModel::class.java -> gatekeeperViewModel
|
FingerprintGatekeeperViewModel::class.java -> gatekeeperViewModel
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
@@ -118,11 +122,7 @@ class BasicScreenshotTest {
|
|||||||
/** Renders a [view] into a [Bitmap]. */
|
/** Renders a [view] into a [Bitmap]. */
|
||||||
private fun viewToBitmap(view: View): Bitmap {
|
private fun viewToBitmap(view: View): Bitmap {
|
||||||
val bitmap =
|
val bitmap =
|
||||||
Bitmap.createBitmap(
|
Bitmap.createBitmap(view.measuredWidth, view.measuredHeight, Bitmap.Config.ARGB_8888)
|
||||||
view.measuredWidth,
|
|
||||||
view.measuredHeight,
|
|
||||||
Bitmap.Config.ARGB_8888,
|
|
||||||
)
|
|
||||||
val canvas = Canvas(bitmap)
|
val canvas = Canvas(bitmap)
|
||||||
view.draw(canvas)
|
view.draw(canvas)
|
||||||
return bitmap
|
return bitmap
|
||||||
@@ -136,12 +136,7 @@ class BasicScreenshotTest {
|
|||||||
}
|
}
|
||||||
fragmentScenario.onFragment { fragment ->
|
fragmentScenario.onFragment { fragment ->
|
||||||
val view = fragment.requireView().findViewById<View>(R.id.enroll_intro_content_view)!!
|
val view = fragment.requireView().findViewById<View>(R.id.enroll_intro_content_view)!!
|
||||||
rule.assertBitmapAgainstGolden(
|
rule.assertBitmapAgainstGolden(viewToBitmap(view), "fp_enroll_intro", MSSIMMatcher())
|
||||||
viewToBitmap(view),
|
|
||||||
"fp_enroll_intro",
|
|
||||||
MSSIMMatcher()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,11 +16,11 @@
|
|||||||
|
|
||||||
package com.android.settings.testutils2
|
package com.android.settings.testutils2
|
||||||
|
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.domain.interactor.FingerprintManagerInteractor
|
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.EnrollReason
|
import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerEnrollState
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintAuthAttemptModel
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintData
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData
|
||||||
import com.android.systemui.biometrics.shared.model.FingerprintSensor
|
import com.android.systemui.biometrics.shared.model.FingerprintSensor
|
||||||
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
||||||
import com.android.systemui.biometrics.shared.model.SensorStrength
|
import com.android.systemui.biometrics.shared.model.SensorStrength
|
||||||
|
@@ -26,17 +26,23 @@ import android.os.CancellationSignal
|
|||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import com.android.settings.biometrics.GatekeeperPasswordProvider
|
import com.android.settings.biometrics.GatekeeperPasswordProvider
|
||||||
|
import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepo
|
||||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl
|
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.data.repository.PressToAuthProvider
|
import com.android.settings.biometrics.fingerprint2.data.repository.PressToAuthRepo
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.domain.interactor.FingerprintManagerInteractor
|
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.Default
|
import com.android.settings.biometrics.fingerprint2.lib.model.Default
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.EnrollReason
|
import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerEnrollState
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintAuthAttemptModel
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintData
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData
|
||||||
import com.android.settings.password.ChooseLockSettingsHelper
|
import com.android.settings.password.ChooseLockSettingsHelper
|
||||||
|
import com.android.systemui.biometrics.shared.model.FingerprintSensor
|
||||||
|
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
||||||
|
import com.android.systemui.biometrics.shared.model.SensorStrength
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import kotlinx.coroutines.cancelAndJoin
|
import kotlinx.coroutines.cancelAndJoin
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.flow.last
|
import kotlinx.coroutines.flow.last
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||||
@@ -71,21 +77,28 @@ class FingerprintManagerInteractorTest {
|
|||||||
@Mock private lateinit var gateKeeperPasswordProvider: GatekeeperPasswordProvider
|
@Mock private lateinit var gateKeeperPasswordProvider: GatekeeperPasswordProvider
|
||||||
|
|
||||||
private var testScope = TestScope(backgroundDispatcher)
|
private var testScope = TestScope(backgroundDispatcher)
|
||||||
private var pressToAuthProvider =
|
private var pressToAuthRepo =
|
||||||
object : PressToAuthProvider {
|
object : PressToAuthRepo {
|
||||||
override val isEnabled: Boolean
|
override val isEnabled: Boolean
|
||||||
get() = false
|
get() = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setup() {
|
fun setup() {
|
||||||
|
val sensor = FingerprintSensor(1, SensorStrength.STRONG, 5, FingerprintSensorType.POWER_BUTTON)
|
||||||
|
val fingerprintSensorRepo =
|
||||||
|
object : FingerprintSensorRepo {
|
||||||
|
override val fingerprintSensor: Flow<FingerprintSensor> = flowOf(sensor)
|
||||||
|
}
|
||||||
|
|
||||||
underTest =
|
underTest =
|
||||||
FingerprintManagerInteractorImpl(
|
FingerprintManagerInteractorImpl(
|
||||||
context,
|
context,
|
||||||
backgroundDispatcher,
|
backgroundDispatcher,
|
||||||
fingerprintManager,
|
fingerprintManager,
|
||||||
|
fingerprintSensorRepo,
|
||||||
gateKeeperPasswordProvider,
|
gateKeeperPasswordProvider,
|
||||||
pressToAuthProvider,
|
pressToAuthRepo,
|
||||||
Default,
|
Default,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -21,16 +21,17 @@ import android.content.res.Configuration
|
|||||||
import android.view.accessibility.AccessibilityManager
|
import android.view.accessibility.AccessibilityManager
|
||||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.Default
|
import com.android.settings.biometrics.fingerprint2.lib.model.Default
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.AccessibilityViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.AccessibilityViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Education
|
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollFindSensorViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollFindSensorViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollNavigationViewModel
|
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollViewModel
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintFlowViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Education
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FoldStateViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FoldStateViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.NextStepViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.NavigationState
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.OrientationStateViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.OrientationStateViewModel
|
||||||
import com.android.settings.testutils2.FakeFingerprintManagerInteractor
|
import com.android.settings.testutils2.FakeFingerprintManagerInteractor
|
||||||
import com.android.systemui.biometrics.shared.model.FingerprintSensor
|
import com.android.systemui.biometrics.shared.model.FingerprintSensor
|
||||||
@@ -38,7 +39,6 @@ import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
|||||||
import com.android.systemui.biometrics.shared.model.SensorStrength
|
import com.android.systemui.biometrics.shared.model.SensorStrength
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
@@ -67,7 +67,7 @@ class FingerprintEnrollFindSensorViewModelV2Test {
|
|||||||
private lateinit var fakeFingerprintManagerInteractor: FakeFingerprintManagerInteractor
|
private lateinit var fakeFingerprintManagerInteractor: FakeFingerprintManagerInteractor
|
||||||
private lateinit var gatekeeperViewModel: FingerprintGatekeeperViewModel
|
private lateinit var gatekeeperViewModel: FingerprintGatekeeperViewModel
|
||||||
private lateinit var enrollViewModel: FingerprintEnrollViewModel
|
private lateinit var enrollViewModel: FingerprintEnrollViewModel
|
||||||
private lateinit var navigationViewModel: FingerprintEnrollNavigationViewModel
|
private lateinit var navigationViewModel: FingerprintNavigationViewModel
|
||||||
private lateinit var accessibilityViewModel: AccessibilityViewModel
|
private lateinit var accessibilityViewModel: AccessibilityViewModel
|
||||||
private lateinit var foldStateViewModel: FoldStateViewModel
|
private lateinit var foldStateViewModel: FoldStateViewModel
|
||||||
private lateinit var orientationStateViewModel: OrientationStateViewModel
|
private lateinit var orientationStateViewModel: OrientationStateViewModel
|
||||||
@@ -87,18 +87,19 @@ class FingerprintEnrollFindSensorViewModelV2Test {
|
|||||||
gatekeeperViewModel =
|
gatekeeperViewModel =
|
||||||
FingerprintGatekeeperViewModel.FingerprintGatekeeperViewModelFactory(
|
FingerprintGatekeeperViewModel.FingerprintGatekeeperViewModelFactory(
|
||||||
null,
|
null,
|
||||||
fakeFingerprintManagerInteractor
|
fakeFingerprintManagerInteractor,
|
||||||
)
|
)
|
||||||
.create(FingerprintGatekeeperViewModel::class.java)
|
.create(FingerprintGatekeeperViewModel::class.java)
|
||||||
|
|
||||||
|
val sensor = FingerprintSensor(1, SensorStrength.STRONG, 5, FingerprintSensorType.POWER_BUTTON)
|
||||||
|
val fingerprintFlowViewModel = FingerprintFlowViewModel(Default)
|
||||||
navigationViewModel =
|
navigationViewModel =
|
||||||
FingerprintEnrollNavigationViewModel.FingerprintEnrollNavigationViewModelFactory(
|
FingerprintNavigationViewModel(
|
||||||
backgroundDispatcher,
|
Education(sensor),
|
||||||
fakeFingerprintManagerInteractor,
|
false,
|
||||||
gatekeeperViewModel,
|
fingerprintFlowViewModel,
|
||||||
canSkipConfirm = true,
|
fakeFingerprintManagerInteractor,
|
||||||
Default,
|
)
|
||||||
)
|
|
||||||
.create(FingerprintEnrollNavigationViewModel::class.java)
|
|
||||||
|
|
||||||
backgroundViewModel =
|
backgroundViewModel =
|
||||||
BackgroundViewModel.BackgroundViewModelFactory().create(BackgroundViewModel::class.java)
|
BackgroundViewModel.BackgroundViewModelFactory().create(BackgroundViewModel::class.java)
|
||||||
@@ -126,12 +127,10 @@ class FingerprintEnrollFindSensorViewModelV2Test {
|
|||||||
backgroundViewModel,
|
backgroundViewModel,
|
||||||
accessibilityViewModel,
|
accessibilityViewModel,
|
||||||
foldStateViewModel,
|
foldStateViewModel,
|
||||||
orientationStateViewModel
|
orientationStateViewModel,
|
||||||
|
fingerprintFlowViewModel,
|
||||||
)
|
)
|
||||||
.create(FingerprintEnrollFindSensorViewModel::class.java)
|
.create(FingerprintEnrollFindSensorViewModel::class.java)
|
||||||
|
|
||||||
// Navigate to Education page
|
|
||||||
navigationViewModel.nextStep()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@@ -141,18 +140,6 @@ class FingerprintEnrollFindSensorViewModelV2Test {
|
|||||||
|
|
||||||
// TODO(b/305094585): test enroll() logic
|
// TODO(b/305094585): test enroll() logic
|
||||||
|
|
||||||
@Test
|
|
||||||
fun currentStepIsEducation() =
|
|
||||||
testScope.runTest {
|
|
||||||
var step: NextStepViewModel? = null
|
|
||||||
val job = launch {
|
|
||||||
navigationViewModel.navigationViewModel.collectLatest { step = it.currStep }
|
|
||||||
}
|
|
||||||
advanceUntilIdle()
|
|
||||||
assertThat(step).isEqualTo(Education)
|
|
||||||
job.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun udfpsLottieInfo() =
|
fun udfpsLottieInfo() =
|
||||||
testScope.runTest {
|
testScope.runTest {
|
||||||
@@ -161,7 +148,7 @@ class FingerprintEnrollFindSensorViewModelV2Test {
|
|||||||
0 /* sensorId */,
|
0 /* sensorId */,
|
||||||
SensorStrength.STRONG,
|
SensorStrength.STRONG,
|
||||||
5,
|
5,
|
||||||
FingerprintSensorType.UDFPS_OPTICAL
|
FingerprintSensorType.UDFPS_OPTICAL,
|
||||||
)
|
)
|
||||||
|
|
||||||
var udfpsLottieInfo: Boolean? = null
|
var udfpsLottieInfo: Boolean? = null
|
||||||
@@ -234,7 +221,7 @@ class FingerprintEnrollFindSensorViewModelV2Test {
|
|||||||
0 /* sensorId */,
|
0 /* sensorId */,
|
||||||
SensorStrength.STRONG,
|
SensorStrength.STRONG,
|
||||||
5,
|
5,
|
||||||
FingerprintSensorType.UDFPS_OPTICAL
|
FingerprintSensorType.UDFPS_OPTICAL,
|
||||||
)
|
)
|
||||||
|
|
||||||
var showPrimaryButton: Boolean? = null
|
var showPrimaryButton: Boolean? = null
|
||||||
|
@@ -17,16 +17,20 @@
|
|||||||
package com.android.settings.fingerprint2.ui.enrollment.viewmodel
|
package com.android.settings.fingerprint2.ui.enrollment.viewmodel
|
||||||
|
|
||||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.Default
|
import com.android.settings.biometrics.fingerprint2.lib.model.Default
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Enrollment
|
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollEnrollingViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollEnrollingViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollNavigationViewModel
|
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollViewModel
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintFlowViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Enrollment
|
||||||
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.NavState
|
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.NavigationState
|
||||||
import com.android.settings.testutils2.FakeFingerprintManagerInteractor
|
import com.android.settings.testutils2.FakeFingerprintManagerInteractor
|
||||||
|
import com.android.systemui.biometrics.shared.model.FingerprintSensor
|
||||||
|
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
||||||
|
import com.android.systemui.biometrics.shared.model.SensorStrength
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -54,7 +58,7 @@ class FingerprintEnrollEnrollingViewModelTest {
|
|||||||
private lateinit var enrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel
|
private lateinit var enrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel
|
||||||
private lateinit var backgroundViewModel: BackgroundViewModel
|
private lateinit var backgroundViewModel: BackgroundViewModel
|
||||||
private lateinit var gateKeeperViewModel: FingerprintGatekeeperViewModel
|
private lateinit var gateKeeperViewModel: FingerprintGatekeeperViewModel
|
||||||
private lateinit var navigationViewModel: FingerprintEnrollNavigationViewModel
|
private lateinit var navigationViewModel: FingerprintNavigationViewModel
|
||||||
private val defaultGatekeeperInfo = GatekeeperInfo.GatekeeperPasswordInfo(byteArrayOf(1, 3), 3)
|
private val defaultGatekeeperInfo = GatekeeperInfo.GatekeeperPasswordInfo(byteArrayOf(1, 3), 3)
|
||||||
private var testScope = TestScope(backgroundDispatcher)
|
private var testScope = TestScope(backgroundDispatcher)
|
||||||
|
|
||||||
@@ -65,18 +69,18 @@ class FingerprintEnrollEnrollingViewModelTest {
|
|||||||
gateKeeperViewModel =
|
gateKeeperViewModel =
|
||||||
FingerprintGatekeeperViewModel.FingerprintGatekeeperViewModelFactory(
|
FingerprintGatekeeperViewModel.FingerprintGatekeeperViewModelFactory(
|
||||||
gatekeeperInfo,
|
gatekeeperInfo,
|
||||||
fakeFingerprintManagerInteractor
|
fakeFingerprintManagerInteractor,
|
||||||
)
|
)
|
||||||
.create(FingerprintGatekeeperViewModel::class.java)
|
.create(FingerprintGatekeeperViewModel::class.java)
|
||||||
|
val sensor = FingerprintSensor(1, SensorStrength.STRONG, 5, FingerprintSensorType.POWER_BUTTON)
|
||||||
|
val fingerprintFlowViewModel = FingerprintFlowViewModel(Default)
|
||||||
|
|
||||||
navigationViewModel =
|
navigationViewModel =
|
||||||
FingerprintEnrollNavigationViewModel(
|
FingerprintNavigationViewModel(
|
||||||
backgroundDispatcher,
|
Enrollment(sensor),
|
||||||
|
false,
|
||||||
|
fingerprintFlowViewModel,
|
||||||
fakeFingerprintManagerInteractor,
|
fakeFingerprintManagerInteractor,
|
||||||
gateKeeperViewModel,
|
|
||||||
Enrollment,
|
|
||||||
NavState(true),
|
|
||||||
Default,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
backgroundViewModel =
|
backgroundViewModel =
|
||||||
|
@@ -18,7 +18,7 @@ package com.android.settings.fingerprint2.ui.settings
|
|||||||
|
|
||||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||||
import com.android.settings.biometrics.BiometricEnrollBase
|
import com.android.settings.biometrics.BiometricEnrollBase
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintData
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.EnrollFirstFingerprint
|
import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.EnrollFirstFingerprint
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FingerprintSettingsNavigationViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FingerprintSettingsNavigationViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FinishSettings
|
import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FinishSettings
|
||||||
|
@@ -17,8 +17,8 @@
|
|||||||
package com.android.settings.fingerprint2.ui.settings
|
package com.android.settings.fingerprint2.ui.settings
|
||||||
|
|
||||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintAuthAttemptModel
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel
|
||||||
import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintData
|
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FingerprintSettingsNavigationViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FingerprintSettingsNavigationViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FingerprintSettingsViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FingerprintSettingsViewModel
|
||||||
import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.PreferenceViewModel
|
import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.PreferenceViewModel
|
||||||
|
Reference in New Issue
Block a user