Biometrics Enrollment refactor (7/N)
This cl moves the creation of repos and interactors to the SettingsApplication. Bug: 297082837 Test: atest Change-Id: I9049da6f03bb1dc18d4186961444bf613d773d0e
@@ -108,6 +108,8 @@ android_library {
|
||||
"telephony_flags_core_java_lib",
|
||||
"setupdesign-lottie-loading-layout",
|
||||
"device_policy_aconfig_flags_lib",
|
||||
"kotlinx-coroutines-core",
|
||||
"kotlinx-coroutines-android",
|
||||
],
|
||||
|
||||
plugins: ["androidx.room_room-compiler-plugin"],
|
||||
|
@@ -24,9 +24,11 @@ import android.provider.Settings;
|
||||
import android.util.FeatureFlagUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.settings.activityembedding.ActivityEmbeddingRulesController;
|
||||
import com.android.settings.activityembedding.ActivityEmbeddingUtils;
|
||||
import com.android.settings.biometrics.fingerprint2.BiometricsEnvironment;
|
||||
import com.android.settings.core.instrumentation.ElapsedTimeUtils;
|
||||
import com.android.settings.development.DeveloperOptionsActivityLifecycle;
|
||||
import com.android.settings.fuelgauge.BatterySettingsStorage;
|
||||
@@ -47,6 +49,7 @@ import java.lang.ref.WeakReference;
|
||||
public class SettingsApplication extends Application {
|
||||
|
||||
private WeakReference<SettingsHomepageActivity> mHomeActivity = new WeakReference<>(null);
|
||||
private BiometricsEnvironment mBiometricsEnvironment;
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context base) {
|
||||
@@ -70,6 +73,7 @@ public class SettingsApplication extends Application {
|
||||
|
||||
// Set Spa environment.
|
||||
setSpaEnvironment();
|
||||
mBiometricsEnvironment = new BiometricsEnvironment(this);
|
||||
|
||||
if (ActivityEmbeddingUtils.isSettingsSplitEnabled(this)
|
||||
&& FeatureFlagUtils.isEnabled(this,
|
||||
@@ -111,6 +115,11 @@ public class SettingsApplication extends Application {
|
||||
return mHomeActivity.get();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public BiometricsEnvironment getBiometricEnvironment() {
|
||||
return mBiometricsEnvironment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrimMemory(int level) {
|
||||
super.onTrimMemory(level);
|
||||
|
@@ -184,7 +184,6 @@ public class UdfpsEnrollHelper extends InstrumentedFragment {
|
||||
*/
|
||||
public void onAcquired(boolean isAcquiredGood) {
|
||||
if (mListener != null) {
|
||||
Log.e("JRM", "OnaCquired " + isAcquiredGood + " lastStepIsGood" + animateIfLastStep());
|
||||
mListener.onAcquired(isAcquiredGood && animateIfLastStep());
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import android.hardware.fingerprint.FingerprintManager
|
||||
import android.view.MotionEvent
|
||||
import android.view.accessibility.AccessibilityManager
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.ViewModelStore
|
||||
import androidx.lifecycle.ViewModelStoreOwner
|
||||
import com.android.internal.widget.LockPatternUtils
|
||||
import com.android.settings.SettingsApplication
|
||||
import com.android.settings.biometrics.GatekeeperPasswordProvider
|
||||
import com.android.settings.biometrics.fingerprint2.data.repository.DebuggingRepository
|
||||
import com.android.settings.biometrics.fingerprint2.data.repository.DebuggingRepositoryImpl
|
||||
import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepository
|
||||
import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepositoryImpl
|
||||
import com.android.settings.biometrics.fingerprint2.debug.data.repository.UdfpsEnrollDebugRepositoryImpl
|
||||
import com.android.settings.biometrics.fingerprint2.debug.domain.interactor.DebugTouchEventInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.AccessibilityInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.AccessibilityInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.DebuggingInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.DebuggingInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.DisplayDensityInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.DisplayDensityInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.EnrollStageInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.EnrollStageInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintEnrollInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintEnrollInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintSensorInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintSensorInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.TouchEventInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.UdfpsEnrollInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.UdfpsEnrollInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.Settings
|
||||
import java.util.concurrent.Executors
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.asCoroutineDispatcher
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
|
||||
/**
|
||||
* This class should handle all repo & interactor creation needed by the ViewModels for the
|
||||
* biometrics code.
|
||||
*
|
||||
* This code is instantiated within the [SettingsApplication], all repos should be private &
|
||||
* immutable and all interactors should public and immutable
|
||||
*/
|
||||
class BiometricsEnvironment(context: SettingsApplication) : ViewModelStoreOwner {
|
||||
|
||||
private val executorService = Executors.newSingleThreadExecutor()
|
||||
private val backgroundDispatcher = executorService.asCoroutineDispatcher()
|
||||
private val applicationScope = MainScope()
|
||||
private val gateKeeperPasswordProvider = GatekeeperPasswordProvider(LockPatternUtils(context))
|
||||
private val fingerprintManager =
|
||||
context.getSystemService(FragmentActivity.FINGERPRINT_SERVICE) as FingerprintManager?
|
||||
|
||||
private val fingerprintSensorRepository: FingerprintSensorRepository =
|
||||
FingerprintSensorRepositoryImpl(fingerprintManager, backgroundDispatcher, applicationScope)
|
||||
private val debuggingRepository: DebuggingRepository = DebuggingRepositoryImpl()
|
||||
private val udfpsDebugRepo = UdfpsEnrollDebugRepositoryImpl()
|
||||
|
||||
/** For now, interactors are public to those with access to the [BiometricsEnvironment] class */
|
||||
val fingerprintEnrollInteractor: FingerprintEnrollInteractor by lazy {
|
||||
FingerprintEnrollInteractorImpl(context, fingerprintManager, Settings)
|
||||
}
|
||||
|
||||
/** [FingerprintManagerInteractor] to be used to construct view models */
|
||||
val fingerprintManagerInteractor: FingerprintManagerInteractor by lazy {
|
||||
FingerprintManagerInteractorImpl(
|
||||
context,
|
||||
backgroundDispatcher,
|
||||
fingerprintManager,
|
||||
fingerprintSensorRepository,
|
||||
gateKeeperPasswordProvider,
|
||||
fingerprintEnrollInteractor,
|
||||
)
|
||||
}
|
||||
|
||||
val accessibilityInteractor: AccessibilityInteractor by lazy {
|
||||
AccessibilityInteractorImpl(
|
||||
context.getSystemService(AccessibilityManager::class.java)!!,
|
||||
applicationScope,
|
||||
)
|
||||
}
|
||||
|
||||
val foldStateInteractor: FoldStateInteractor by lazy { FoldStateInteractorImpl(context) }
|
||||
|
||||
val orientationInteractor: OrientationInteractor by lazy { OrientationInteractorImpl(context) }
|
||||
|
||||
val vibrationInteractor: VibrationInteractor by lazy { VibrationInteractorImpl(context) }
|
||||
|
||||
val displayDensityInteractor: DisplayDensityInteractor by lazy {
|
||||
DisplayDensityInteractorImpl(context, applicationScope)
|
||||
}
|
||||
|
||||
val debuggingInteractor: DebuggingInteractor by lazy {
|
||||
DebuggingInteractorImpl(debuggingRepository)
|
||||
}
|
||||
|
||||
val enrollStageInteractor: EnrollStageInteractor by lazy { EnrollStageInteractorImpl() }
|
||||
|
||||
val udfpsEnrollInteractor: UdfpsEnrollInteractor by lazy {
|
||||
UdfpsEnrollInteractorImpl(context, accessibilityInteractor)
|
||||
}
|
||||
|
||||
val sensorInteractor: FingerprintSensorInteractor by lazy {
|
||||
FingerprintSensorInteractorImpl(fingerprintSensorRepository)
|
||||
}
|
||||
|
||||
val touchEventInteractor: TouchEventInteractor by lazy {
|
||||
if (debuggingRepository.isDebuggingEnabled()) {
|
||||
DebugTouchEventInteractorImpl(udfpsDebugRepo)
|
||||
} else {
|
||||
object : TouchEventInteractor {
|
||||
override val touchEvent: Flow<MotionEvent> = flowOf()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val viewModelStore: ViewModelStore = ViewModelStore()
|
||||
}
|
@@ -23,6 +23,7 @@ interface DebuggingRepository {
|
||||
|
||||
/** A function that will return if a build is debuggable */
|
||||
fun isDebuggingEnabled(): Boolean
|
||||
|
||||
/** A function that will return if udfps enrollment should be swapped with debug repos */
|
||||
fun isUdfpsEnrollmentDebuggingEnabled(): Boolean
|
||||
}
|
||||
|
@@ -46,7 +46,7 @@ interface FingerprintSensorRepository {
|
||||
}
|
||||
|
||||
class FingerprintSensorRepositoryImpl(
|
||||
fingerprintManager: FingerprintManager,
|
||||
fingerprintManager: FingerprintManager?,
|
||||
backgroundDispatcher: CoroutineDispatcher,
|
||||
activityScope: CoroutineScope,
|
||||
) : FingerprintSensorRepository {
|
||||
@@ -73,12 +73,9 @@ class FingerprintSensorRepositoryImpl(
|
||||
.stateIn(activityScope, started = SharingStarted.Eagerly, initialValue = DEFAULT_PROPS)
|
||||
|
||||
override val fingerprintSensor: Flow<FingerprintSensor> =
|
||||
fingerprintPropsInternal.transform {
|
||||
emit(it.toFingerprintSensor())
|
||||
}
|
||||
fingerprintPropsInternal.transform { emit(it.toFingerprintSensor()) }
|
||||
|
||||
companion object {
|
||||
private const val TAG = "FingerprintSensorRepoImpl"
|
||||
|
||||
private val DEFAULT_PROPS =
|
||||
FingerprintSensorPropertiesInternal(
|
||||
|
@@ -17,6 +17,7 @@
|
||||
package com.android.settings.biometrics.fingerprint2.data.repository
|
||||
|
||||
import android.graphics.Point
|
||||
import android.view.MotionEvent
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
/**
|
||||
@@ -24,8 +25,6 @@ import kotlinx.coroutines.flow.Flow
|
||||
* that talkback is correct.
|
||||
*/
|
||||
interface SimulatedTouchEventsRepository {
|
||||
/**
|
||||
* A flow simulating user touches.
|
||||
*/
|
||||
val touchExplorationDebug: Flow<Point>
|
||||
/** A flow simulating user touches. */
|
||||
val touchExplorationDebug: Flow<MotionEvent>
|
||||
}
|
||||
|
@@ -14,10 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.biometrics.fingerprint2.data.repository
|
||||
package com.android.settings.biometrics.fingerprint2.debug.data.repository
|
||||
|
||||
import android.graphics.Point
|
||||
import android.graphics.Rect
|
||||
import android.hardware.fingerprint.FingerprintEnrollOptions
|
||||
import android.view.MotionEvent
|
||||
import android.view.MotionEvent.ACTION_HOVER_MOVE
|
||||
import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepository
|
||||
import com.android.settings.biometrics.fingerprint2.data.repository.SimulatedTouchEventsRepository
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintEnrollInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
|
||||
@@ -36,7 +40,11 @@ import kotlinx.coroutines.flow.flowOf
|
||||
class UdfpsEnrollDebugRepositoryImpl :
|
||||
FingerprintEnrollInteractor, FingerprintSensorRepository, SimulatedTouchEventsRepository {
|
||||
|
||||
override suspend fun enroll(hardwareAuthToken: ByteArray?, enrollReason: EnrollReason) = flow {
|
||||
override suspend fun enroll(
|
||||
hardwareAuthToken: ByteArray?,
|
||||
enrollReason: EnrollReason,
|
||||
fingerprintEnrollOptions: FingerprintEnrollOptions,
|
||||
) = flow {
|
||||
emit(FingerEnrollState.OverlayShown)
|
||||
delay(200)
|
||||
emit(FingerEnrollState.EnrollHelp(helpMsgId, "Hello world"))
|
||||
@@ -77,7 +85,7 @@ class UdfpsEnrollDebugRepositoryImpl :
|
||||
}
|
||||
|
||||
/** Provides touch events to the UdfpsEnrollFragment */
|
||||
override val touchExplorationDebug: Flow<Point> = flow {
|
||||
override val touchExplorationDebug: Flow<MotionEvent> = flow {
|
||||
delay(2000)
|
||||
emit(pointToLeftOfSensor(sensorRect))
|
||||
delay(2000)
|
||||
@@ -90,17 +98,45 @@ class UdfpsEnrollDebugRepositoryImpl :
|
||||
|
||||
override val fingerprintSensor: Flow<FingerprintSensor> = flowOf(sensorProps)
|
||||
|
||||
private fun pointToLeftOfSensor(sensorLocation: Rect) =
|
||||
Point(sensorLocation.right + 5, sensorLocation.centerY())
|
||||
private fun pointToLeftOfSensor(sensorLocation: Rect): MotionEvent =
|
||||
MotionEvent.obtain(
|
||||
100,
|
||||
100,
|
||||
ACTION_HOVER_MOVE,
|
||||
sensorLocation.right + 5.0f,
|
||||
sensorLocation.centerY().toFloat(),
|
||||
0,
|
||||
)
|
||||
|
||||
private fun pointToRightOfSensor(sensorLocation: Rect) =
|
||||
Point(sensorLocation.left - 5, sensorLocation.centerY())
|
||||
private fun pointToRightOfSensor(sensorLocation: Rect): MotionEvent =
|
||||
MotionEvent.obtain(
|
||||
100,
|
||||
100,
|
||||
ACTION_HOVER_MOVE,
|
||||
sensorLocation.right - 5.0f,
|
||||
sensorLocation.centerY().toFloat(),
|
||||
0,
|
||||
)
|
||||
|
||||
private fun pointBelowSensor(sensorLocation: Rect) =
|
||||
Point(sensorLocation.centerX(), sensorLocation.bottom + 5)
|
||||
private fun pointBelowSensor(sensorLocation: Rect): MotionEvent =
|
||||
MotionEvent.obtain(
|
||||
100,
|
||||
100,
|
||||
ACTION_HOVER_MOVE,
|
||||
sensorLocation.centerX().toFloat(),
|
||||
sensorLocation.bottom + 5.0f,
|
||||
0,
|
||||
)
|
||||
|
||||
private fun pointAboveSensor(sensorLocation: Rect) =
|
||||
Point(sensorLocation.centerX(), sensorLocation.top - 5)
|
||||
private fun pointAboveSensor(sensorLocation: Rect): MotionEvent =
|
||||
MotionEvent.obtain(
|
||||
100,
|
||||
100,
|
||||
ACTION_HOVER_MOVE,
|
||||
sensorLocation.centerX().toFloat(),
|
||||
sensorLocation.top - 5.0f,
|
||||
0,
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -109,10 +145,10 @@ class UdfpsEnrollDebugRepositoryImpl :
|
||||
private val sensorRadius = 100
|
||||
private val sensorRect =
|
||||
Rect(
|
||||
this.sensorLocationInternal.first - sensorRadius,
|
||||
this.sensorLocationInternal.second - sensorRadius,
|
||||
this.sensorLocationInternal.first + sensorRadius,
|
||||
this.sensorLocationInternal.second + sensorRadius,
|
||||
sensorLocationInternal.first - sensorRadius,
|
||||
sensorLocationInternal.second - sensorRadius,
|
||||
sensorLocationInternal.first + sensorRadius,
|
||||
sensorLocationInternal.second + sensorRadius,
|
||||
)
|
||||
val sensorProps =
|
||||
FingerprintSensor(
|
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.biometrics.fingerprint2.debug.domain.interactor
|
||||
|
||||
import android.view.MotionEvent
|
||||
import com.android.settings.biometrics.fingerprint2.data.repository.SimulatedTouchEventsRepository
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.TouchEventInteractor
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class DebugTouchEventInteractorImpl(
|
||||
udfpsSimulatedTouchEventsRepository: SimulatedTouchEventsRepository
|
||||
) : TouchEventInteractor {
|
||||
override val touchEvent: Flow<MotionEvent> =
|
||||
udfpsSimulatedTouchEventsRepository.touchExplorationDebug
|
||||
}
|
@@ -17,7 +17,7 @@
|
||||
package com.android.settings.biometrics.fingerprint2.domain.interactor
|
||||
|
||||
import android.view.accessibility.AccessibilityManager
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
@@ -26,27 +26,27 @@ import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
/** Represents all of the information on accessibility state. */
|
||||
interface AccessibilityInteractor {
|
||||
/** A flow that contains whether or not accessibility is enabled */
|
||||
val isAccessibilityEnabled: Flow<Boolean>
|
||||
/** A flow that contains whether or not accessibility is enabled */
|
||||
val isAccessibilityEnabled: Flow<Boolean>
|
||||
}
|
||||
|
||||
class AccessibilityInteractorImpl(
|
||||
accessibilityManager: AccessibilityManager,
|
||||
activityScope: LifecycleCoroutineScope
|
||||
accessibilityManager: AccessibilityManager,
|
||||
applicationScope: CoroutineScope,
|
||||
) : AccessibilityInteractor {
|
||||
/** A flow that contains whether or not accessibility is enabled */
|
||||
override val isAccessibilityEnabled: Flow<Boolean> =
|
||||
callbackFlow {
|
||||
val listener =
|
||||
AccessibilityManager.AccessibilityStateChangeListener { enabled -> trySend(enabled) }
|
||||
AccessibilityManager.AccessibilityStateChangeListener { enabled -> trySend(enabled) }
|
||||
accessibilityManager.addAccessibilityStateChangeListener(listener)
|
||||
|
||||
// This clause will be called when no one is listening to the flow
|
||||
awaitClose { accessibilityManager.removeAccessibilityStateChangeListener(listener) }
|
||||
}
|
||||
}
|
||||
.stateIn(
|
||||
activityScope, // This is going to tied to the activity scope
|
||||
SharingStarted.WhileSubscribed(), // When no longer subscribed, we removeTheListener
|
||||
false
|
||||
applicationScope, // This is going to tied to the activity scope
|
||||
SharingStarted.WhileSubscribed(), // When no longer subscribed, we removeTheListener
|
||||
false,
|
||||
)
|
||||
}
|
@@ -28,9 +28,7 @@ interface DebuggingInteractor {
|
||||
val udfpsEnrollmentDebuggingEnabled: Flow<Boolean>
|
||||
}
|
||||
|
||||
/**
|
||||
* This interactor essentially forwards the [DebuggingRepository]
|
||||
*/
|
||||
/** This interactor essentially forwards the [DebuggingRepository] */
|
||||
class DebuggingInteractorImpl(val debuggingRepository: DebuggingRepository) : DebuggingInteractor {
|
||||
override val debuggingEnabled: Flow<Boolean> = flow {
|
||||
emit(debuggingRepository.isDebuggingEnabled())
|
||||
|
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.settings.biometrics.fingerprint2.domain.interactor
|
||||
|
||||
import android.content.Context
|
||||
import com.android.settingslib.display.DisplayDensityUtils
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -50,12 +52,11 @@ interface DisplayDensityInteractor {
|
||||
* Implementation of the [DisplayDensityInteractor]. This interactor is used to forward activity
|
||||
* information to the rest of the application.
|
||||
*/
|
||||
class DisplayDensityInteractorImpl(
|
||||
currentFontScale: Float,
|
||||
currentDisplayDensity: Int,
|
||||
defaultDisplayDensity: Int,
|
||||
scope: CoroutineScope,
|
||||
) : DisplayDensityInteractor {
|
||||
class DisplayDensityInteractorImpl(context: Context, scope: CoroutineScope) :
|
||||
DisplayDensityInteractor {
|
||||
|
||||
val displayDensityUtils = DisplayDensityUtils(context)
|
||||
|
||||
override fun updateDisplayDensity(density: Int) {
|
||||
_displayDensity.update { density }
|
||||
}
|
||||
@@ -64,13 +65,18 @@ class DisplayDensityInteractorImpl(
|
||||
_fontScale.update { fontScale }
|
||||
}
|
||||
|
||||
private val _fontScale = MutableStateFlow(currentFontScale)
|
||||
private val _displayDensity = MutableStateFlow(currentDisplayDensity)
|
||||
private val _fontScale = MutableStateFlow(context.resources.configuration.fontScale)
|
||||
private val _displayDensity =
|
||||
MutableStateFlow(
|
||||
displayDensityUtils.defaultDisplayDensityValues[
|
||||
displayDensityUtils.currentIndexForDefaultDisplay]
|
||||
)
|
||||
|
||||
override val fontScale: Flow<Float> = _fontScale.asStateFlow()
|
||||
|
||||
override val displayDensity: Flow<Int> = _displayDensity.asStateFlow()
|
||||
|
||||
override val defaultDisplayDensity: Flow<Int> =
|
||||
flowOf(defaultDisplayDensity).shareIn(scope, SharingStarted.Eagerly, 1)
|
||||
flowOf(displayDensityUtils.defaultDensityForDefaultDisplay)
|
||||
.shareIn(scope, SharingStarted.Eagerly, 1)
|
||||
}
|
||||
|
@@ -33,7 +33,6 @@ import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.transform
|
||||
import kotlinx.coroutines.flow.update
|
||||
|
||||
/** This repository is responsible for collecting all state related to the enroll API. */
|
||||
@@ -45,13 +44,13 @@ interface FingerprintEnrollInteractor {
|
||||
suspend fun enroll(
|
||||
hardwareAuthToken: ByteArray?,
|
||||
enrollReason: EnrollReason,
|
||||
fingerprintEnrollOptions: FingerprintEnrollOptions,
|
||||
): Flow<FingerEnrollState>
|
||||
}
|
||||
|
||||
class FingerprintEnrollInteractorImpl(
|
||||
private val applicationContext: Context,
|
||||
private val fingerprintEnrollOptions: FingerprintEnrollOptions,
|
||||
private val fingerprintManager: FingerprintManager,
|
||||
private val fingerprintManager: FingerprintManager?,
|
||||
private val fingerprintFlow: FingerprintFlow,
|
||||
) : FingerprintEnrollInteractor {
|
||||
private val enrollRequestOutstanding = MutableStateFlow(false)
|
||||
@@ -59,6 +58,7 @@ class FingerprintEnrollInteractorImpl(
|
||||
override suspend fun enroll(
|
||||
hardwareAuthToken: ByteArray?,
|
||||
enrollReason: EnrollReason,
|
||||
fingerprintEnrollOptions: FingerprintEnrollOptions,
|
||||
): Flow<FingerEnrollState> = callbackFlow {
|
||||
// TODO (b/308456120) Improve this logic
|
||||
if (enrollRequestOutstanding.value) {
|
||||
@@ -135,7 +135,7 @@ class FingerprintEnrollInteractorImpl(
|
||||
|
||||
val cancellationSignal = CancellationSignal()
|
||||
|
||||
fingerprintManager.enroll(
|
||||
fingerprintManager?.enroll(
|
||||
hardwareAuthToken,
|
||||
cancellationSignal,
|
||||
applicationContext.userId,
|
||||
|
@@ -18,6 +18,7 @@ package com.android.settings.biometrics.fingerprint2.domain.interactor
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.hardware.fingerprint.FingerprintEnrollOptions
|
||||
import android.hardware.fingerprint.FingerprintManager
|
||||
import android.hardware.fingerprint.FingerprintManager.GenerateChallengeCallback
|
||||
import android.hardware.fingerprint.FingerprintManager.RemovalCallback
|
||||
@@ -45,7 +46,7 @@ private const val TAG = "FingerprintManagerInteractor"
|
||||
class FingerprintManagerInteractorImpl(
|
||||
applicationContext: Context,
|
||||
private val backgroundDispatcher: CoroutineDispatcher,
|
||||
private val fingerprintManager: FingerprintManager,
|
||||
private val fingerprintManager: FingerprintManager?,
|
||||
fingerprintSensorRepository: FingerprintSensorRepository,
|
||||
private val gatekeeperPasswordProvider: GatekeeperPasswordProvider,
|
||||
private val fingerprintEnrollStateRepository: FingerprintEnrollInteractor,
|
||||
@@ -57,7 +58,6 @@ class FingerprintManagerInteractorImpl(
|
||||
)
|
||||
private val applicationContext = applicationContext.applicationContext
|
||||
|
||||
|
||||
override suspend fun generateChallenge(gateKeeperPasswordHandle: Long): Pair<Long, ByteArray> =
|
||||
suspendCoroutine {
|
||||
val callback = GenerateChallengeCallback { _, userId, challenge ->
|
||||
@@ -70,21 +70,19 @@ class FingerprintManagerInteractorImpl(
|
||||
val p = Pair(challenge, challengeToken)
|
||||
it.resume(p)
|
||||
}
|
||||
fingerprintManager.generateChallenge(applicationContext.userId, callback)
|
||||
fingerprintManager?.generateChallenge(applicationContext.userId, callback)
|
||||
}
|
||||
|
||||
override val enrolledFingerprints: Flow<List<FingerprintData>> = flow {
|
||||
override val enrolledFingerprints: Flow<List<FingerprintData>?> = flow {
|
||||
emit(
|
||||
fingerprintManager
|
||||
.getEnrolledFingerprints(applicationContext.userId)
|
||||
.map { (FingerprintData(it.name.toString(), it.biometricId, it.deviceId)) }
|
||||
.toList()
|
||||
fingerprintManager?.getEnrolledFingerprints(applicationContext.userId)
|
||||
?.map { (FingerprintData(it.name.toString(), it.biometricId, it.deviceId)) }?.toList()
|
||||
)
|
||||
}
|
||||
|
||||
override val canEnrollFingerprints: Flow<Boolean> = flow {
|
||||
emit(
|
||||
fingerprintManager.getEnrolledFingerprints(applicationContext.userId).size < maxFingerprints
|
||||
fingerprintManager?.getEnrolledFingerprints(applicationContext.userId)?.size ?: maxFingerprints < maxFingerprints
|
||||
)
|
||||
}
|
||||
|
||||
@@ -92,8 +90,16 @@ class FingerprintManagerInteractorImpl(
|
||||
|
||||
override val maxEnrollableFingerprints = flow { emit(maxFingerprints) }
|
||||
|
||||
override suspend fun enroll(hardwareAuthToken: ByteArray?, enrollReason: EnrollReason): Flow<FingerEnrollState> =
|
||||
fingerprintEnrollStateRepository.enroll(hardwareAuthToken, enrollReason)
|
||||
override suspend fun enroll(
|
||||
hardwareAuthToken: ByteArray?,
|
||||
enrollReason: EnrollReason,
|
||||
fingerprintEnrollOptions: FingerprintEnrollOptions,
|
||||
): Flow<FingerEnrollState> =
|
||||
fingerprintEnrollStateRepository.enroll(
|
||||
hardwareAuthToken,
|
||||
enrollReason,
|
||||
fingerprintEnrollOptions,
|
||||
)
|
||||
|
||||
override suspend fun removeFingerprint(fp: FingerprintData): Boolean = suspendCoroutine {
|
||||
val callback =
|
||||
@@ -113,7 +119,7 @@ class FingerprintManagerInteractorImpl(
|
||||
it.resume(true)
|
||||
}
|
||||
}
|
||||
fingerprintManager.remove(
|
||||
fingerprintManager?.remove(
|
||||
android.hardware.fingerprint.Fingerprint(fp.name, fp.fingerId, fp.deviceId),
|
||||
applicationContext.userId,
|
||||
callback,
|
||||
@@ -122,12 +128,12 @@ class FingerprintManagerInteractorImpl(
|
||||
|
||||
override suspend fun renameFingerprint(fp: FingerprintData, newName: String) {
|
||||
withContext(backgroundDispatcher) {
|
||||
fingerprintManager.rename(fp.fingerId, applicationContext.userId, newName)
|
||||
fingerprintManager?.rename(fp.fingerId, applicationContext.userId, newName)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun hasSideFps(): Boolean = suspendCancellableCoroutine {
|
||||
it.resume(fingerprintManager.isPowerbuttonFps)
|
||||
override suspend fun hasSideFps(): Boolean? = suspendCancellableCoroutine {
|
||||
it.resume(fingerprintManager?.isPowerbuttonFps)
|
||||
}
|
||||
|
||||
override suspend fun authenticate(): FingerprintAuthAttemptModel =
|
||||
@@ -156,7 +162,7 @@ class FingerprintManagerInteractorImpl(
|
||||
|
||||
val cancellationSignal = CancellationSignal()
|
||||
c.invokeOnCancellation { cancellationSignal.cancel() }
|
||||
fingerprintManager.authenticate(
|
||||
fingerprintManager?.authenticate(
|
||||
null,
|
||||
cancellationSignal,
|
||||
authenticationCallback,
|
||||
@@ -164,5 +170,4 @@ class FingerprintManagerInteractorImpl(
|
||||
applicationContext.userId,
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.biometrics.fingerprint2.domain.interactor
|
||||
|
||||
import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepository
|
||||
import com.android.systemui.biometrics.shared.model.FingerprintSensor
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
/**
|
||||
* Interactor that propagates the type of [FingerprintSensor] this device supports.
|
||||
*/
|
||||
interface FingerprintSensorInteractor {
|
||||
/** Get the [FingerprintSensor] */
|
||||
val fingerprintSensor: Flow<FingerprintSensor>
|
||||
}
|
||||
|
||||
class FingerprintSensorInteractorImpl(repo: FingerprintSensorRepository) :
|
||||
FingerprintSensorInteractor {
|
||||
override val fingerprintSensor: Flow<FingerprintSensor> = repo.fingerprintSensor
|
||||
}
|
@@ -25,34 +25,30 @@ import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
|
||||
interface FoldStateInteractor {
|
||||
/** A flow that contains the fold state info */
|
||||
val isFolded: Flow<Boolean>
|
||||
/** A flow that contains the fold state info */
|
||||
val isFolded: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Indicates a configuration change has occurred, and the repo
|
||||
* should update the [isFolded] flow.
|
||||
*/
|
||||
fun onConfigurationChange(newConfig: Configuration)
|
||||
/**
|
||||
* Indicates a configuration change has occurred, and the repo should update the [isFolded] flow.
|
||||
*/
|
||||
fun onConfigurationChange(newConfig: Configuration)
|
||||
}
|
||||
|
||||
/**
|
||||
* Interactor which handles fold state
|
||||
*/
|
||||
/** Interactor which handles fold state */
|
||||
class FoldStateInteractorImpl(context: Context) : FoldStateInteractor {
|
||||
private val screenSizeFoldProvider = ScreenSizeFoldProvider(context)
|
||||
override val isFolded: Flow<Boolean> = callbackFlow {
|
||||
val foldStateListener = FoldProvider.FoldCallback { isFolded -> trySend(isFolded) }
|
||||
screenSizeFoldProvider.registerCallback(foldStateListener, context.mainExecutor)
|
||||
awaitClose { screenSizeFoldProvider.unregisterCallback(foldStateListener) }
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called by the root activity, indicating an orientation event has occurred.
|
||||
* When this happens, the [ScreenSizeFoldProvider] is notified and it will re-compute if the
|
||||
* device is folded or not, and notify the [FoldProvider.FoldCallback]
|
||||
*/
|
||||
override fun onConfigurationChange(newConfig: Configuration) {
|
||||
screenSizeFoldProvider.onConfigurationChange(newConfig)
|
||||
}
|
||||
private val screenSizeFoldProvider = ScreenSizeFoldProvider(context)
|
||||
override val isFolded: Flow<Boolean> = callbackFlow {
|
||||
val foldStateListener = FoldProvider.FoldCallback { isFolded -> trySend(isFolded) }
|
||||
screenSizeFoldProvider.registerCallback(foldStateListener, context.mainExecutor)
|
||||
awaitClose { screenSizeFoldProvider.unregisterCallback(foldStateListener) }
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called by the root activity, indicating an orientation event has occurred.
|
||||
* When this happens, the [ScreenSizeFoldProvider] is notified and it will re-compute if the
|
||||
* device is folded or not, and notify the [FoldProvider.FoldCallback]
|
||||
*/
|
||||
override fun onConfigurationChange(newConfig: Configuration) {
|
||||
screenSizeFoldProvider.onConfigurationChange(newConfig)
|
||||
}
|
||||
}
|
||||
|
@@ -60,10 +60,7 @@ class OrientationInteractorImpl(private val context: Context) : OrientationInter
|
||||
awaitClose { orientationEventListener.disable() }
|
||||
}
|
||||
|
||||
override val rotation: Flow<Int> =
|
||||
orientation.transform {
|
||||
emit(context.display!!.rotation)
|
||||
}
|
||||
override val rotation: Flow<Int> = orientation.transform { emit(context.display.rotation) }
|
||||
|
||||
override val rotationFromDefault: Flow<Int> = rotation.map { getRotationFromDefault(it) }
|
||||
|
||||
|
@@ -28,77 +28,67 @@ import kotlinx.coroutines.flow.flowOn
|
||||
|
||||
/** Interface that indicates if press to auth is on or off. */
|
||||
interface PressToAuthInteractor {
|
||||
/** Indicates true if the PressToAuth feature is enabled, false otherwise. */
|
||||
val isEnabled: Flow<Boolean>
|
||||
/** Indicates true if the PressToAuth feature is enabled, false otherwise. */
|
||||
val isEnabled: Flow<Boolean>
|
||||
}
|
||||
|
||||
/** Indicates whether or not the press to auth feature is enabled. */
|
||||
class PressToAuthInteractorImpl(
|
||||
private val context: Context,
|
||||
private val backgroundDispatcher: CoroutineDispatcher,
|
||||
private val context: Context,
|
||||
private val backgroundDispatcher: CoroutineDispatcher,
|
||||
) : PressToAuthInteractor {
|
||||
|
||||
/**
|
||||
* A flow that contains the status of the press to auth feature.
|
||||
*/
|
||||
override val isEnabled: Flow<Boolean> =
|
||||
|
||||
callbackFlow {
|
||||
val callback =
|
||||
object : ContentObserver(null) {
|
||||
override fun onChange(selfChange: Boolean) {
|
||||
Log.d(TAG, "SFPS_PERFORMANT_AUTH_ENABLED#onchange")
|
||||
trySend(
|
||||
getPressToAuth(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
context.contentResolver.registerContentObserver(
|
||||
Settings.Secure.getUriFor(Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED),
|
||||
false,
|
||||
callback,
|
||||
context.userId
|
||||
)
|
||||
trySend(getPressToAuth())
|
||||
awaitClose {
|
||||
context.contentResolver.unregisterContentObserver(callback)
|
||||
/** A flow that contains the status of the press to auth feature. */
|
||||
override val isEnabled: Flow<Boolean> =
|
||||
callbackFlow {
|
||||
val callback =
|
||||
object : ContentObserver(null) {
|
||||
override fun onChange(selfChange: Boolean) {
|
||||
Log.d(TAG, "SFPS_PERFORMANT_AUTH_ENABLED#onchange")
|
||||
trySend(getPressToAuth())
|
||||
}
|
||||
}.flowOn(backgroundDispatcher)
|
||||
}
|
||||
|
||||
context.contentResolver.registerContentObserver(
|
||||
Settings.Secure.getUriFor(Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED),
|
||||
false,
|
||||
callback,
|
||||
context.userId,
|
||||
)
|
||||
trySend(getPressToAuth())
|
||||
awaitClose { context.contentResolver.unregisterContentObserver(callback) }
|
||||
}
|
||||
.flowOn(backgroundDispatcher)
|
||||
|
||||
/**
|
||||
* Returns true if press to auth is enabled
|
||||
*/
|
||||
private fun getPressToAuth(): Boolean {
|
||||
var toReturn: Int =
|
||||
Settings.Secure.getIntForUser(
|
||||
context.contentResolver,
|
||||
Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED,
|
||||
-1,
|
||||
context.userId,
|
||||
)
|
||||
if (toReturn == -1) {
|
||||
toReturn =
|
||||
if (
|
||||
context.resources.getBoolean(com.android.internal.R.bool.config_performantAuthDefault)
|
||||
) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
Settings.Secure.putIntForUser(
|
||||
context.contentResolver,
|
||||
Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED,
|
||||
toReturn,
|
||||
context.userId,
|
||||
)
|
||||
/** Returns true if press to auth is enabled */
|
||||
private fun getPressToAuth(): Boolean {
|
||||
var toReturn: Int =
|
||||
Settings.Secure.getIntForUser(
|
||||
context.contentResolver,
|
||||
Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED,
|
||||
-1,
|
||||
context.userId,
|
||||
)
|
||||
if (toReturn == -1) {
|
||||
toReturn =
|
||||
if (
|
||||
context.resources.getBoolean(com.android.internal.R.bool.config_performantAuthDefault)
|
||||
) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
return toReturn == 1
|
||||
|
||||
Settings.Secure.putIntForUser(
|
||||
context.contentResolver,
|
||||
Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED,
|
||||
toReturn,
|
||||
context.userId,
|
||||
)
|
||||
}
|
||||
return toReturn == 1
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "PressToAuthInteractor"
|
||||
}
|
||||
companion object {
|
||||
const val TAG = "PressToAuthInteractor"
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.biometrics.fingerprint2.domain.interactor
|
||||
|
||||
import android.view.MotionEvent
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface TouchEventInteractor {
|
||||
|
||||
/** A flow simulating user touches. */
|
||||
val touchEvent: Flow<MotionEvent>
|
||||
}
|
||||
|
@@ -16,8 +16,9 @@
|
||||
|
||||
package com.android.settings.biometrics.fingerprint2.domain.interactor
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.PointF
|
||||
import android.util.Log
|
||||
import android.util.TypedValue
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
@@ -43,13 +44,18 @@ interface UdfpsEnrollInteractor {
|
||||
|
||||
/** Keeps track of which guided enrollment point we should be using */
|
||||
class UdfpsEnrollInteractorImpl(
|
||||
pixelsPerMillimeter: Float,
|
||||
applicationContext: Context,
|
||||
accessibilityInteractor: AccessibilityInteractor,
|
||||
) : UdfpsEnrollInteractor {
|
||||
|
||||
private var isGuidedEnrollment = MutableStateFlow(false)
|
||||
// Number of pixels per mm
|
||||
val px = pixelsPerMillimeter
|
||||
val px =
|
||||
TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_MM,
|
||||
1f,
|
||||
applicationContext.resources.displayMetrics,
|
||||
)
|
||||
private val guidedEnrollmentPoints: MutableList<PointF> =
|
||||
mutableListOf(
|
||||
PointF(2.00f * px, 0.00f * px),
|
||||
@@ -70,7 +76,6 @@ class UdfpsEnrollInteractorImpl(
|
||||
|
||||
override fun onEnrollmentStep(stepsRemaining: Int, totalStep: Int) {
|
||||
val index = (totalStep - stepsRemaining) % guidedEnrollmentPoints.size
|
||||
Log.e("JRM", "guided enroll step $index")
|
||||
_guidedEnrollment.update { guidedEnrollmentPoints[index] }
|
||||
}
|
||||
|
||||
|
@@ -36,6 +36,7 @@ sealed class FingerprintVibrationEffects {
|
||||
/** This vibration typically occurs when a help message is shown during UDFPS enrollment */
|
||||
data object UdfpsHelp : FingerprintVibrationEffects()
|
||||
}
|
||||
|
||||
/** Interface for sending haptic feedback */
|
||||
interface VibrationInteractor {
|
||||
/** This will send a haptic vibration */
|
||||
@@ -43,8 +44,9 @@ interface VibrationInteractor {
|
||||
}
|
||||
|
||||
/** Implementation of the VibrationInteractor interface */
|
||||
class VibrationInteractorImpl(val vibrator: Vibrator, val applicationContext: Context) :
|
||||
VibrationInteractor {
|
||||
class VibrationInteractorImpl(val applicationContext: Context) : VibrationInteractor {
|
||||
val vibrator = applicationContext.getSystemService(Vibrator::class.java)!!
|
||||
|
||||
override fun vibrate(effect: FingerprintVibrationEffects, caller: String) {
|
||||
val callerString = "$caller::$effect"
|
||||
val res =
|
||||
|
@@ -16,7 +16,7 @@
|
||||
|
||||
package com.android.settings.biometrics.fingerprint2.lib.domain.interactor
|
||||
|
||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
|
||||
import android.hardware.fingerprint.FingerprintEnrollOptions
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel
|
||||
@@ -32,7 +32,7 @@ import kotlinx.coroutines.flow.Flow
|
||||
*/
|
||||
interface FingerprintManagerInteractor {
|
||||
/** Returns the list of current fingerprints. */
|
||||
val enrolledFingerprints: Flow<List<FingerprintData>>
|
||||
val enrolledFingerprints: Flow<List<FingerprintData>?>
|
||||
|
||||
/** Returns the max enrollable fingerprints, note during SUW this might be 1 */
|
||||
val maxEnrollableFingerprints: Flow<Int>
|
||||
@@ -62,6 +62,7 @@ interface FingerprintManagerInteractor {
|
||||
suspend fun enroll(
|
||||
hardwareAuthToken: ByteArray?,
|
||||
enrollReason: EnrollReason,
|
||||
fingerprintEnrollOptions: FingerprintEnrollOptions,
|
||||
): Flow<FingerEnrollState>
|
||||
|
||||
/**
|
||||
@@ -74,5 +75,5 @@ interface FingerprintManagerInteractor {
|
||||
suspend fun renameFingerprint(fp: FingerprintData, newName: String)
|
||||
|
||||
/** Indicates if the device has side fingerprint */
|
||||
suspend fun hasSideFps(): Boolean
|
||||
suspend fun hasSideFps(): Boolean?
|
||||
}
|
||||
|
@@ -24,5 +24,5 @@ enum class EnrollReason {
|
||||
*/
|
||||
FindSensor,
|
||||
/** The enroll happens on enrolling screen. */
|
||||
EnrollEnrolling
|
||||
EnrollEnrolling,
|
||||
}
|
||||
|
@@ -22,16 +22,12 @@ import android.content.res.Configuration
|
||||
import android.hardware.fingerprint.FingerprintEnrollOptions
|
||||
import android.hardware.fingerprint.FingerprintManager
|
||||
import android.os.Bundle
|
||||
import android.os.Vibrator
|
||||
import android.util.Log
|
||||
import android.util.TypedValue
|
||||
import android.view.accessibility.AccessibilityManager
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.activity.viewModels
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.android.internal.widget.LockPatternUtils
|
||||
import com.android.settings.R
|
||||
import com.android.settings.SetupWizardUtils
|
||||
import com.android.settings.Utils.SETTINGS_PACKAGE_NAME
|
||||
@@ -40,27 +36,9 @@ import com.android.settings.biometrics.BiometricEnrollBase.CONFIRM_REQUEST
|
||||
import com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED
|
||||
import com.android.settings.biometrics.BiometricUtils
|
||||
import com.android.settings.biometrics.GatekeeperPasswordProvider
|
||||
import com.android.settings.biometrics.fingerprint2.data.repository.DebuggingRepositoryImpl
|
||||
import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepositoryImpl
|
||||
import com.android.settings.biometrics.fingerprint2.data.repository.UdfpsEnrollDebugRepositoryImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.AccessibilityInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.DebuggingInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.DisplayDensityInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.DisplayDensityInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.EnrollStageInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.EnrollStageInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintEnrollInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.UdfpsEnrollInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.UdfpsEnrollInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.Default
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.Settings
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.SetupWizard
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollConfirmationV2Fragment
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollEnrollingV2Fragment
|
||||
@@ -68,18 +46,12 @@ import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.Finge
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.education.RfpsEnrollFindSensorFragment
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.education.SfpsEnrollFindSensorFragment
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.education.UdfpsEnrollFindSensorFragment
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.common.util.toFingerprintEnrollOptions
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.fragment.RFPSEnrollFragment
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.viewmodel.RFPSViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.fragment.UdfpsEnrollFragment
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel.UdfpsLastStepViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel.UdfpsViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintAction
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollConfirmationViewModel
|
||||
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.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
|
||||
@@ -91,7 +63,6 @@ import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Fing
|
||||
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.GatekeeperInfo
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Transition
|
||||
import com.android.settings.flags.Flags
|
||||
@@ -113,23 +84,38 @@ private const val TAG = "FingerprintEnrollmentV2Activity"
|
||||
* children fragments.
|
||||
*/
|
||||
class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
||||
private lateinit var fingerprintEnrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel
|
||||
private lateinit var navigationViewModel: FingerprintNavigationViewModel
|
||||
private lateinit var gatekeeperViewModel: FingerprintGatekeeperViewModel
|
||||
private lateinit var fingerprintEnrollViewModel: FingerprintEnrollViewModel
|
||||
private lateinit var vibrationInteractor: VibrationInteractor
|
||||
private val navigationViewModel: FingerprintNavigationViewModel by viewModels {
|
||||
FingerprintNavigationViewModel.Factory
|
||||
}
|
||||
private val fingerprintFlowViewModel: FingerprintFlowViewModel by viewModels {
|
||||
FingerprintFlowViewModel.Factory
|
||||
}
|
||||
|
||||
private val gatekeeperViewModel: FingerprintGatekeeperViewModel by viewModels {
|
||||
FingerprintGatekeeperViewModel.Factory
|
||||
}
|
||||
|
||||
/**
|
||||
* View models below this line are not used by this class but must be initialized
|
||||
* in the activity view model store to be used by other view models.
|
||||
*/
|
||||
private val fingerprintEnrollViewModel: FingerprintEnrollViewModel by viewModels {
|
||||
FingerprintEnrollViewModel.Factory
|
||||
}
|
||||
|
||||
private val fingerprintEnrollEnrollingViewModel:
|
||||
FingerprintEnrollEnrollingViewModel by viewModels {
|
||||
FingerprintEnrollEnrollingViewModel.Factory
|
||||
}
|
||||
|
||||
private val udfpsLastStepViewModel: UdfpsLastStepViewModel by viewModels {
|
||||
UdfpsLastStepViewModel.Factory
|
||||
}
|
||||
|
||||
private val backgroundViewModel: BackgroundViewModel by viewModels { BackgroundViewModel.Factory }
|
||||
|
||||
private lateinit var foldStateInteractor: FoldStateInteractor
|
||||
private lateinit var orientationInteractor: OrientationInteractor
|
||||
private lateinit var displayDensityInteractor: DisplayDensityInteractor
|
||||
private lateinit var udfpsEnrollInteractor: UdfpsEnrollInteractor
|
||||
private lateinit var fingerprintScrollViewModel: FingerprintScrollViewModel
|
||||
private lateinit var backgroundViewModel: BackgroundViewModel
|
||||
private lateinit var fingerprintFlowViewModel: FingerprintFlowViewModel
|
||||
private lateinit var fingerprintEnrollConfirmationViewModel:
|
||||
FingerprintEnrollConfirmationViewModel
|
||||
private lateinit var udfpsLastStepViewModel: UdfpsLastStepViewModel
|
||||
private lateinit var udfpsViewModel: UdfpsViewModel
|
||||
private lateinit var enrollStageInteractor: EnrollStageInteractor
|
||||
private val coroutineDispatcher = Dispatchers.Default
|
||||
|
||||
/** Result listener for ChooseLock activity flow. */
|
||||
@@ -172,7 +158,7 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
||||
|
||||
private fun onConfirmDevice(resultCode: Int, data: Intent?) {
|
||||
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 {
|
||||
val confirmDeviceResult =
|
||||
@@ -204,6 +190,15 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
||||
finish()
|
||||
}
|
||||
|
||||
// Ensure that these view models are actually created and in this order
|
||||
navigationViewModel
|
||||
fingerprintFlowViewModel
|
||||
gatekeeperViewModel
|
||||
fingerprintEnrollViewModel
|
||||
backgroundViewModel
|
||||
fingerprintEnrollEnrollingViewModel
|
||||
udfpsLastStepViewModel
|
||||
|
||||
setTheme(SetupWizardUtils.getTheme(applicationContext, intent))
|
||||
ThemeHelper.trySetDynamicColor(applicationContext)
|
||||
|
||||
@@ -219,31 +214,7 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
||||
Default
|
||||
}
|
||||
|
||||
backgroundViewModel =
|
||||
ViewModelProvider(this, BackgroundViewModel.BackgroundViewModelFactory())[
|
||||
BackgroundViewModel::class.java]
|
||||
|
||||
fingerprintFlowViewModel =
|
||||
ViewModelProvider(this, FingerprintFlowViewModel.FingerprintFlowViewModelFactory(enrollType))[
|
||||
FingerprintFlowViewModel::class.java]
|
||||
val displayDensityUtils = DisplayDensityUtils(context)
|
||||
val currIndex = displayDensityUtils.currentIndexForDefaultDisplay
|
||||
val defaultDisplayDensity = displayDensityUtils.defaultDensityForDefaultDisplay
|
||||
displayDensityInteractor =
|
||||
DisplayDensityInteractorImpl(
|
||||
resources.configuration.fontScale,
|
||||
displayDensityUtils.defaultDisplayDensityValues[currIndex],
|
||||
defaultDisplayDensity,
|
||||
lifecycleScope,
|
||||
)
|
||||
|
||||
val debuggingRepo = DebuggingRepositoryImpl()
|
||||
val debuggingInteractor = DebuggingInteractorImpl(debuggingRepo)
|
||||
val udfpsEnrollDebugRepositoryImpl = UdfpsEnrollDebugRepositoryImpl()
|
||||
|
||||
val fingerprintSensorRepo =
|
||||
if (debuggingRepo.isUdfpsEnrollmentDebuggingEnabled()) udfpsEnrollDebugRepositoryImpl
|
||||
else FingerprintSensorRepositoryImpl(fingerprintManager, backgroundDispatcher, lifecycleScope)
|
||||
fingerprintFlowViewModel.updateFlowType(enrollType)
|
||||
|
||||
if (intent.getIntExtra(BiometricUtils.EXTRA_ENROLL_REASON, -1) === -1) {
|
||||
val isSuw: Boolean = WizardManagerHelper.isAnySetupWizard(intent)
|
||||
@@ -254,170 +225,18 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
|
||||
)
|
||||
}
|
||||
|
||||
val fingerprintEnrollStateRepository =
|
||||
if (debuggingRepo.isUdfpsEnrollmentDebuggingEnabled()) udfpsEnrollDebugRepositoryImpl
|
||||
else
|
||||
FingerprintEnrollInteractorImpl(
|
||||
context.applicationContext,
|
||||
intent.toFingerprintEnrollOptions(),
|
||||
fingerprintManager,
|
||||
Settings,
|
||||
)
|
||||
val accessibilityInteractor =
|
||||
AccessibilityInteractorImpl(
|
||||
getSystemService(AccessibilityManager::class.java)!!,
|
||||
lifecycleScope,
|
||||
)
|
||||
|
||||
val pixelsPerMillimeter =
|
||||
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1f, context.resources.displayMetrics)
|
||||
udfpsEnrollInteractor = UdfpsEnrollInteractorImpl(pixelsPerMillimeter, accessibilityInteractor)
|
||||
|
||||
val fingerprintManagerInteractor =
|
||||
FingerprintManagerInteractorImpl(
|
||||
context,
|
||||
backgroundDispatcher,
|
||||
fingerprintManager,
|
||||
fingerprintSensorRepo,
|
||||
GatekeeperPasswordProvider(LockPatternUtils(context)),
|
||||
fingerprintEnrollStateRepository,
|
||||
)
|
||||
|
||||
var challenge = intent.getExtra(BiometricEnrollBase.EXTRA_KEY_CHALLENGE) as Long?
|
||||
val token = intent.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_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 =
|
||||
ViewModelProvider(
|
||||
this,
|
||||
FingerprintGatekeeperViewModel.FingerprintGatekeeperViewModelFactory(
|
||||
gatekeeperInfo,
|
||||
fingerprintManagerInteractor,
|
||||
),
|
||||
)[FingerprintGatekeeperViewModel::class.java]
|
||||
|
||||
// Initialize FoldStateViewModel
|
||||
foldStateInteractor = FoldStateInteractorImpl(context)
|
||||
foldStateInteractor.onConfigurationChange(resources.configuration)
|
||||
|
||||
orientationInteractor = OrientationInteractorImpl(context)
|
||||
vibrationInteractor =
|
||||
VibrationInteractorImpl(context.getSystemService(Vibrator::class.java)!!, context)
|
||||
|
||||
// Initialize FingerprintViewModel
|
||||
fingerprintEnrollViewModel =
|
||||
ViewModelProvider(
|
||||
this,
|
||||
FingerprintEnrollViewModel.FingerprintEnrollViewModelFactory(
|
||||
fingerprintManagerInteractor,
|
||||
gatekeeperViewModel,
|
||||
navigationViewModel,
|
||||
),
|
||||
)[FingerprintEnrollViewModel::class.java]
|
||||
|
||||
// Initialize scroll view model
|
||||
fingerprintScrollViewModel =
|
||||
ViewModelProvider(this, FingerprintScrollViewModel.FingerprintScrollViewModelFactory())[
|
||||
FingerprintScrollViewModel::class.java]
|
||||
|
||||
// Initialize FingerprintEnrollEnrollingViewModel
|
||||
fingerprintEnrollEnrollingViewModel =
|
||||
ViewModelProvider(
|
||||
this,
|
||||
FingerprintEnrollEnrollingViewModel.FingerprintEnrollEnrollingViewModelFactory(
|
||||
fingerprintEnrollViewModel,
|
||||
backgroundViewModel,
|
||||
),
|
||||
)[FingerprintEnrollEnrollingViewModel::class.java]
|
||||
|
||||
// Initialize FingerprintEnrollFindSensorViewModel
|
||||
ViewModelProvider(
|
||||
this,
|
||||
FingerprintEnrollFindSensorViewModel.FingerprintEnrollFindSensorViewModelFactory(
|
||||
navigationViewModel,
|
||||
fingerprintEnrollViewModel,
|
||||
gatekeeperViewModel,
|
||||
backgroundViewModel,
|
||||
accessibilityInteractor,
|
||||
foldStateInteractor,
|
||||
orientationInteractor,
|
||||
fingerprintFlowViewModel,
|
||||
fingerprintManagerInteractor,
|
||||
),
|
||||
)[FingerprintEnrollFindSensorViewModel::class.java]
|
||||
|
||||
// Initialize RFPS View Model
|
||||
ViewModelProvider(
|
||||
this,
|
||||
RFPSViewModel.RFPSViewModelFactory(
|
||||
fingerprintEnrollEnrollingViewModel,
|
||||
navigationViewModel,
|
||||
orientationInteractor,
|
||||
fingerprintManagerInteractor,
|
||||
),
|
||||
)[RFPSViewModel::class.java]
|
||||
|
||||
enrollStageInteractor = EnrollStageInteractorImpl()
|
||||
|
||||
udfpsLastStepViewModel =
|
||||
UdfpsLastStepViewModel(fingerprintEnrollEnrollingViewModel, vibrationInteractor)
|
||||
|
||||
udfpsViewModel =
|
||||
ViewModelProvider(
|
||||
this,
|
||||
UdfpsViewModel.UdfpsEnrollmentFactory(
|
||||
vibrationInteractor,
|
||||
displayDensityInteractor,
|
||||
navigationViewModel,
|
||||
debuggingInteractor,
|
||||
fingerprintEnrollEnrollingViewModel,
|
||||
udfpsEnrollDebugRepositoryImpl,
|
||||
enrollStageInteractor,
|
||||
orientationInteractor,
|
||||
backgroundViewModel,
|
||||
fingerprintSensorRepo,
|
||||
udfpsEnrollInteractor,
|
||||
fingerprintManagerInteractor,
|
||||
udfpsLastStepViewModel,
|
||||
accessibilityInteractor,
|
||||
),
|
||||
)[UdfpsViewModel::class.java]
|
||||
|
||||
fingerprintEnrollConfirmationViewModel =
|
||||
ViewModelProvider(
|
||||
this,
|
||||
FingerprintEnrollConfirmationViewModel.FingerprintEnrollConfirmationViewModelFactory(
|
||||
navigationViewModel,
|
||||
fingerprintManagerInteractor,
|
||||
),
|
||||
)[FingerprintEnrollConfirmationViewModel::class.java]
|
||||
navigationViewModel.updateFingerprintFlow(enrollType)
|
||||
navigationViewModel.hasConfirmedDeviceCredential(hasConfirmedDeviceCredential)
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
@@ -20,8 +20,8 @@ import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
@@ -39,31 +39,11 @@ import kotlinx.coroutines.launch
|
||||
* This page will display basic information about what a fingerprint can be used for and acts as the
|
||||
* final step of enrollment.
|
||||
*/
|
||||
class FingerprintEnrollConfirmationV2Fragment() :
|
||||
class FingerprintEnrollConfirmationV2Fragment(factory: ViewModelProvider.Factory? = null) :
|
||||
Fragment(R.layout.fingerprint_enroll_finish_base) {
|
||||
|
||||
companion object {
|
||||
const val TAG = "FingerprintEnrollConfirmationV2Fragment"
|
||||
}
|
||||
|
||||
/** Used for testing purposes */
|
||||
private var factory: ViewModelProvider.Factory? = null
|
||||
|
||||
@VisibleForTesting
|
||||
constructor(theFactory: ViewModelProvider.Factory) : this() {
|
||||
factory = theFactory
|
||||
}
|
||||
|
||||
private val viewModelProvider: ViewModelProvider by lazy {
|
||||
if (factory != null) {
|
||||
ViewModelProvider(requireActivity(), factory!!)
|
||||
} else {
|
||||
ViewModelProvider(requireActivity())
|
||||
}
|
||||
}
|
||||
|
||||
private val viewModel: FingerprintEnrollConfirmationViewModel by lazy {
|
||||
viewModelProvider[FingerprintEnrollConfirmationViewModel::class.java]
|
||||
private val viewModel: FingerprintEnrollConfirmationViewModel by activityViewModels {
|
||||
factory ?: FingerprintEnrollConfirmationViewModel.Factory
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
@@ -106,4 +86,8 @@ class FingerprintEnrollConfirmationV2Fragment() :
|
||||
private fun onNextButtonClick(view: View?) {
|
||||
viewModel.onNextButtonClicked()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "FingerprintEnrollConfirmationV2Fragment"
|
||||
}
|
||||
}
|
||||
|
@@ -30,8 +30,9 @@ import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.ScrollView
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.android.settings.R
|
||||
@@ -74,37 +75,22 @@ private data class TextModel(
|
||||
* 2. How the data will be stored
|
||||
* 3. How the user can access and remove their data
|
||||
*/
|
||||
class FingerprintEnrollIntroV2Fragment() : Fragment(R.layout.fingerprint_v2_enroll_introduction) {
|
||||
|
||||
/** Used for testing purposes */
|
||||
private var factory: ViewModelProvider.Factory? = null
|
||||
|
||||
@VisibleForTesting
|
||||
constructor(theFactory: ViewModelProvider.Factory) : this() {
|
||||
factory = theFactory
|
||||
}
|
||||
|
||||
private val viewModelProvider: ViewModelProvider by lazy {
|
||||
if (factory != null) {
|
||||
ViewModelProvider(requireActivity(), factory!!)
|
||||
} else {
|
||||
ViewModelProvider(requireActivity())
|
||||
}
|
||||
}
|
||||
class FingerprintEnrollIntroV2Fragment(testFactory: ViewModelProvider.Factory? = null) :
|
||||
Fragment(R.layout.fingerprint_v2_enroll_introduction) {
|
||||
|
||||
private lateinit var footerBarMixin: FooterBarMixin
|
||||
private lateinit var textModel: TextModel
|
||||
|
||||
private val viewModel: FingerprintEnrollIntroViewModel by lazy {
|
||||
viewModelProvider[FingerprintEnrollIntroViewModel::class.java]
|
||||
private val viewModel: FingerprintEnrollIntroViewModel by activityViewModels {
|
||||
testFactory ?: FingerprintEnrollIntroViewModel.Factory
|
||||
}
|
||||
|
||||
private val fingerprintScrollViewModel: FingerprintScrollViewModel by lazy {
|
||||
viewModelProvider[FingerprintScrollViewModel::class.java]
|
||||
private val fingerprintScrollViewModel: FingerprintScrollViewModel by viewModels {
|
||||
testFactory ?: FingerprintScrollViewModel.Factory
|
||||
}
|
||||
|
||||
private val gateKeeperViewModel: FingerprintGatekeeperViewModel by lazy {
|
||||
viewModelProvider[FingerprintGatekeeperViewModel::class.java]
|
||||
private val gateKeeperViewModel: FingerprintGatekeeperViewModel by activityViewModels {
|
||||
testFactory ?: FingerprintGatekeeperViewModel.Factory
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
|
@@ -23,11 +23,15 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.android.settings.R
|
||||
import com.android.settings.biometrics.fingerprint.FingerprintErrorDialog
|
||||
import com.android.settings.biometrics.fingerprint.FingerprintFindSensorAnimation
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.common.util.toFingerprintEnrollOptions
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollFindSensorViewModel
|
||||
import com.google.android.setupcompat.template.FooterBarMixin
|
||||
import com.google.android.setupcompat.template.FooterButton
|
||||
@@ -51,18 +55,10 @@ class RfpsEnrollFindSensorFragment() : Fragment() {
|
||||
factory = theFactory
|
||||
}
|
||||
|
||||
private val viewModelProvider: ViewModelProvider by lazy {
|
||||
if (factory != null) {
|
||||
ViewModelProvider(requireActivity(), factory!!)
|
||||
} else {
|
||||
ViewModelProvider(requireActivity())
|
||||
}
|
||||
}
|
||||
|
||||
private var animation: FingerprintFindSensorAnimation? = null
|
||||
|
||||
private val viewModel: FingerprintEnrollFindSensorViewModel by lazy {
|
||||
viewModelProvider[FingerprintEnrollFindSensorViewModel::class.java]
|
||||
private val viewModel: FingerprintEnrollFindSensorViewModel by activityViewModels {
|
||||
factory ?: FingerprintEnrollFindSensorViewModel.Factory
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
@@ -78,6 +74,12 @@ class RfpsEnrollFindSensorFragment() : Fragment() {
|
||||
// Set up footer bar
|
||||
val footerBarMixin = view.getMixin(FooterBarMixin::class.java)
|
||||
setupSecondaryButton(footerBarMixin)
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
viewModel.enroll(requireActivity().intent.toFingerprintEnrollOptions())
|
||||
}
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
viewModel.showPrimaryButton.collect { setupPrimaryButton(footerBarMixin) }
|
||||
}
|
||||
|
@@ -24,11 +24,15 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.airbnb.lottie.LottieAnimationView
|
||||
import com.android.settings.R
|
||||
import com.android.settings.biometrics.fingerprint.FingerprintErrorDialog
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.common.util.toFingerprintEnrollOptions
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollFindSensorViewModel
|
||||
import com.google.android.setupcompat.template.FooterBarMixin
|
||||
import com.google.android.setupcompat.template.FooterButton
|
||||
@@ -52,16 +56,8 @@ class SfpsEnrollFindSensorFragment() : Fragment() {
|
||||
factory = theFactory
|
||||
}
|
||||
|
||||
private val viewModelProvider: ViewModelProvider by lazy {
|
||||
if (factory != null) {
|
||||
ViewModelProvider(requireActivity(), factory!!)
|
||||
} else {
|
||||
ViewModelProvider(requireActivity())
|
||||
}
|
||||
}
|
||||
|
||||
private val viewModel: FingerprintEnrollFindSensorViewModel by lazy {
|
||||
viewModelProvider[FingerprintEnrollFindSensorViewModel::class.java]
|
||||
private val viewModel: FingerprintEnrollFindSensorViewModel by activityViewModels {
|
||||
factory ?: FingerprintEnrollFindSensorViewModel.Factory
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
@@ -78,6 +74,12 @@ class SfpsEnrollFindSensorFragment() : Fragment() {
|
||||
val footerBarMixin = view.getMixin(FooterBarMixin::class.java)
|
||||
setupSecondaryButton(footerBarMixin)
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
viewModel.enroll(requireActivity().intent.toFingerprintEnrollOptions())
|
||||
}
|
||||
}
|
||||
|
||||
// Set up lottie
|
||||
lifecycleScope.launch {
|
||||
viewModel.sfpsLottieInfo.collect { (isFolded, rotation) ->
|
||||
|
@@ -24,11 +24,15 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.airbnb.lottie.LottieAnimationView
|
||||
import com.android.settings.R
|
||||
import com.android.settings.biometrics.fingerprint.FingerprintErrorDialog
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.common.util.toFingerprintEnrollOptions
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollFindSensorViewModel
|
||||
import com.google.android.setupcompat.template.FooterBarMixin
|
||||
import com.google.android.setupcompat.template.FooterButton
|
||||
@@ -53,16 +57,8 @@ class UdfpsEnrollFindSensorFragment() : Fragment() {
|
||||
factory = theFactory
|
||||
}
|
||||
|
||||
private val viewModelProvider: ViewModelProvider by lazy {
|
||||
if (factory != null) {
|
||||
ViewModelProvider(requireActivity(), factory!!)
|
||||
} else {
|
||||
ViewModelProvider(requireActivity())
|
||||
}
|
||||
}
|
||||
|
||||
private val viewModel: FingerprintEnrollFindSensorViewModel by lazy {
|
||||
viewModelProvider[FingerprintEnrollFindSensorViewModel::class.java]
|
||||
private val viewModel: FingerprintEnrollFindSensorViewModel by activityViewModels {
|
||||
factory ?: FingerprintEnrollFindSensorViewModel.Factory
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
@@ -79,6 +75,12 @@ class UdfpsEnrollFindSensorFragment() : Fragment() {
|
||||
val footerBarMixin = view.getMixin(FooterBarMixin::class.java)
|
||||
setupSecondaryButton(footerBarMixin)
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
viewModel.enroll(requireActivity().intent.toFingerprintEnrollOptions())
|
||||
}
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
viewModel.showPrimaryButton.collect { setupPrimaryButton(footerBarMixin) }
|
||||
}
|
||||
|
@@ -28,12 +28,15 @@ import android.view.animation.Interpolator
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.android.settings.R
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.common.util.toFingerprintEnrollOptions
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.common.widget.FingerprintErrorDialog
|
||||
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
|
||||
@@ -62,29 +65,21 @@ class RFPSEnrollFragment() : Fragment(R.layout.fingerprint_v2_rfps_enroll_enroll
|
||||
factory = theFactory
|
||||
}
|
||||
|
||||
private val viewModelProvider: ViewModelProvider by lazy {
|
||||
if (factory != null) {
|
||||
ViewModelProvider(requireActivity(), factory!!)
|
||||
} else {
|
||||
ViewModelProvider(requireActivity())
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var linearOutSlowInInterpolator: Interpolator
|
||||
private lateinit var fastOutLinearInInterpolator: Interpolator
|
||||
private lateinit var textView: TextView
|
||||
private lateinit var progressBar: RFPSProgressBar
|
||||
|
||||
private val iconTouchViewModel: RFPSIconTouchViewModel by lazy {
|
||||
viewModelProvider[RFPSIconTouchViewModel::class.java]
|
||||
private val iconTouchViewModel: RFPSIconTouchViewModel by viewModels {
|
||||
RFPSIconTouchViewModel.Factory
|
||||
}
|
||||
|
||||
private val rfpsViewModel: RFPSViewModel by lazy { viewModelProvider[RFPSViewModel::class.java] }
|
||||
|
||||
private val backgroundViewModel: BackgroundViewModel by lazy {
|
||||
viewModelProvider[BackgroundViewModel::class.java]
|
||||
private val rfpsViewModel: RFPSViewModel by activityViewModels {
|
||||
factory ?: RFPSViewModel.Factory
|
||||
}
|
||||
|
||||
private val backgroundViewModel: BackgroundViewModel by activityViewModels()
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
@@ -131,6 +126,7 @@ class RFPSEnrollFragment() : Fragment(R.layout.fingerprint_v2_rfps_enroll_enroll
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
rfpsViewModel.enroll(requireActivity().intent.toFingerprintEnrollOptions())
|
||||
// Icon animation update
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
// TODO(b/324427704): Fix this delay
|
||||
|
@@ -19,6 +19,8 @@ package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrol
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
@@ -27,6 +29,7 @@ import kotlinx.coroutines.flow.transform
|
||||
import kotlinx.coroutines.flow.update
|
||||
|
||||
private const val touchesToShowDialog = 3
|
||||
|
||||
/**
|
||||
* This class is responsible for counting the number of touches on the fingerprint icon, and if this
|
||||
* number reaches a threshold it will produce an action via [shouldShowDialog] to indicate the ui
|
||||
@@ -52,10 +55,9 @@ class RFPSIconTouchViewModel : ViewModel() {
|
||||
_touches.update { _touches.value + 1 }
|
||||
}
|
||||
|
||||
class RFPSIconTouchViewModelFactory : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return RFPSIconTouchViewModel() as T
|
||||
companion object {
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer { RFPSIconTouchViewModel() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -16,9 +16,14 @@
|
||||
|
||||
package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.viewmodel
|
||||
|
||||
import android.hardware.fingerprint.FingerprintEnrollOptions
|
||||
import androidx.lifecycle.VIEW_MODEL_STORE_OWNER_KEY
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import com.android.settings.SettingsApplication
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
|
||||
@@ -158,27 +163,27 @@ class RFPSViewModel(
|
||||
enrollFlow = fingerprintEnrollViewModel.enrollFlow
|
||||
}
|
||||
|
||||
class RFPSViewModelFactory(
|
||||
private val fingerprintEnrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel,
|
||||
private val navigationViewModel: FingerprintNavigationViewModel,
|
||||
private val orientationInteractor: OrientationInteractor,
|
||||
private val fingerprintManager: FingerprintManagerInteractor,
|
||||
) : ViewModelProvider.Factory {
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return RFPSViewModel(
|
||||
fingerprintEnrollEnrollingViewModel,
|
||||
navigationViewModel,
|
||||
orientationInteractor,
|
||||
fingerprintManager,
|
||||
)
|
||||
as T
|
||||
}
|
||||
/** Starts enrollment. */
|
||||
fun enroll(enrollOptions: FingerprintEnrollOptions) {
|
||||
fingerprintEnrollViewModel.enroll(enrollOptions)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val navStep = Enrollment::class
|
||||
private const val TAG = "RFPSViewModel"
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer {
|
||||
val settingsApplication =
|
||||
this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as SettingsApplication
|
||||
val biometricEnvironment = settingsApplication.biometricEnvironment!!
|
||||
val provider = ViewModelProvider(this[VIEW_MODEL_STORE_OWNER_KEY]!!)
|
||||
RFPSViewModel(
|
||||
provider[FingerprintEnrollEnrollingViewModel::class],
|
||||
provider[FingerprintNavigationViewModel::class],
|
||||
biometricEnvironment.orientationInteractor,
|
||||
biometricEnvironment.fingerprintManagerInteractor,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -82,6 +82,7 @@ class RFPSProgressBar : RingProgressBar {
|
||||
|
||||
shouldAnimateInternal = shouldAnimate
|
||||
}
|
||||
|
||||
/** This function should only be called when actual progress has been made. */
|
||||
fun updateProgress(percentComplete: Float) {
|
||||
val progress = maxProgress - (percentComplete.coerceIn(0.0f, 100.0f) * maxProgress).toInt()
|
||||
|
@@ -18,8 +18,6 @@ package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrol
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.MotionEvent
|
||||
import android.view.MotionEvent.ACTION_HOVER_MOVE
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
@@ -27,6 +25,7 @@ import android.widget.Button
|
||||
import android.widget.FrameLayout
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
@@ -36,6 +35,7 @@ import com.airbnb.lottie.LottieCompositionFactory
|
||||
import com.android.settings.R
|
||||
import com.android.settings.biometrics.fingerprint2.data.model.EnrollStageModel
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.common.util.toFingerprintEnrollOptions
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.common.widget.FingerprintErrorDialog
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.model.DescriptionText
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.model.HeaderText
|
||||
@@ -50,17 +50,10 @@ class UdfpsEnrollFragment() : Fragment(R.layout.fingerprint_v2_udfps_enroll_enro
|
||||
|
||||
/** Used for testing purposes */
|
||||
private var factory: ViewModelProvider.Factory? = null
|
||||
private val viewModel: UdfpsViewModel by lazy { viewModelProvider[UdfpsViewModel::class.java] }
|
||||
private lateinit var udfpsEnrollView: UdfpsEnrollViewV2
|
||||
private lateinit var lottie: LottieAnimationView
|
||||
|
||||
private val viewModelProvider: ViewModelProvider by lazy {
|
||||
if (factory != null) {
|
||||
ViewModelProvider(requireActivity(), factory!!)
|
||||
} else {
|
||||
ViewModelProvider(requireActivity())
|
||||
}
|
||||
}
|
||||
private val viewModel: UdfpsViewModel by activityViewModels { factory ?: UdfpsViewModel.Factory }
|
||||
|
||||
@VisibleForTesting
|
||||
constructor(theFactory: ViewModelProvider.Factory) : this() {
|
||||
@@ -90,6 +83,7 @@ class UdfpsEnrollFragment() : Fragment(R.layout.fingerprint_v2_udfps_enroll_enro
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
viewModel.enroll(requireActivity().intent.toFingerprintEnrollOptions())
|
||||
launch {
|
||||
viewModel.sensorLocation.collect { sensor ->
|
||||
udfpsEnrollView.setSensorRect(sensor.sensorBounds, sensor.sensorType)
|
||||
@@ -204,12 +198,16 @@ class UdfpsEnrollFragment() : Fragment(R.layout.fingerprint_v2_udfps_enroll_enro
|
||||
}
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewModel.touchExplorationDebug.collect {
|
||||
udfpsEnrollView.sendDebugTouchExplorationEvent(
|
||||
MotionEvent.obtain(100, 100, ACTION_HOVER_MOVE, it.x.toFloat(), it.y.toFloat(), 0)
|
||||
)
|
||||
view.setOnTouchListener { _, motionEvent ->
|
||||
viewModel.onTouchEvent(motionEvent)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewModel.touchEvent.collect { udfpsEnrollView.onTouchEvent(it) }
|
||||
}
|
||||
|
||||
viewModel.readyForEnrollment()
|
||||
}
|
||||
|
||||
|
@@ -16,9 +16,13 @@
|
||||
|
||||
package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel
|
||||
|
||||
import androidx.lifecycle.VIEW_MODEL_STORE_OWNER_KEY
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import com.android.settings.SettingsApplication
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintVibrationEffects
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
|
||||
@@ -89,14 +93,18 @@ class UdfpsLastStepViewModel(
|
||||
}
|
||||
.filterNotNull()
|
||||
|
||||
class UdfpsLastStepViewModelFactory(
|
||||
private val fingerprintEnrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel,
|
||||
private val vibrationInteractor: VibrationInteractor,
|
||||
) : ViewModelProvider.Factory {
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return UdfpsLastStepViewModel(fingerprintEnrollEnrollingViewModel, vibrationInteractor) as T
|
||||
companion object {
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer {
|
||||
val settingsApplication =
|
||||
this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as SettingsApplication
|
||||
val biometricEnvironment = settingsApplication.biometricEnvironment
|
||||
val provider = ViewModelProvider(this[VIEW_MODEL_STORE_OWNER_KEY]!!)
|
||||
UdfpsLastStepViewModel(
|
||||
provider[FingerprintEnrollEnrollingViewModel::class],
|
||||
biometricEnvironment!!.vibrationInteractor,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -16,21 +16,26 @@
|
||||
|
||||
package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel
|
||||
|
||||
import android.graphics.Point
|
||||
import android.graphics.PointF
|
||||
import android.hardware.fingerprint.FingerprintEnrollOptions
|
||||
import android.view.MotionEvent
|
||||
import android.view.Surface
|
||||
import androidx.lifecycle.VIEW_MODEL_STORE_OWNER_KEY
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import com.android.settings.SettingsApplication
|
||||
import com.android.settings.biometrics.fingerprint2.data.model.EnrollStageModel
|
||||
import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepository
|
||||
import com.android.settings.biometrics.fingerprint2.data.repository.SimulatedTouchEventsRepository
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.AccessibilityInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.DebuggingInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.DisplayDensityInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.EnrollStageInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintSensorInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintVibrationEffects
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.TouchEventInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.UdfpsEnrollInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
|
||||
@@ -45,6 +50,7 @@ import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Fing
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.combineTransform
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
@@ -60,20 +66,20 @@ import kotlinx.coroutines.launch
|
||||
|
||||
/** ViewModel used to drive UDFPS Enrollment through [UdfpsEnrollFragment] */
|
||||
class UdfpsViewModel(
|
||||
val navigationViewModel: FingerprintNavigationViewModel,
|
||||
val fingerprintEnrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel,
|
||||
backgroundViewModel: BackgroundViewModel,
|
||||
val udfpsLastStepViewModel: UdfpsLastStepViewModel,
|
||||
val vibrationInteractor: VibrationInteractor,
|
||||
displayDensityInteractor: DisplayDensityInteractor,
|
||||
val navigationViewModel: FingerprintNavigationViewModel,
|
||||
debuggingInteractor: DebuggingInteractor,
|
||||
val fingerprintEnrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel,
|
||||
simulatedTouchEventsDebugRepository: SimulatedTouchEventsRepository,
|
||||
enrollStageInteractor: EnrollStageInteractor,
|
||||
orientationInteractor: OrientationInteractor,
|
||||
backgroundViewModel: BackgroundViewModel,
|
||||
sensorRepository: FingerprintSensorRepository,
|
||||
udfpsEnrollInteractor: UdfpsEnrollInteractor,
|
||||
fingerprintManager: FingerprintManagerInteractor,
|
||||
val udfpsLastStepViewModel: UdfpsLastStepViewModel,
|
||||
accessibilityInteractor: AccessibilityInteractor,
|
||||
sensorRepository: FingerprintSensorInteractor,
|
||||
touchEventInteractor: TouchEventInteractor,
|
||||
) : ViewModel() {
|
||||
|
||||
private val isSetupWizard = flowOf(false)
|
||||
@@ -191,15 +197,9 @@ class UdfpsViewModel(
|
||||
.transform { emit(it == Surface.ROTATION_90) }
|
||||
.distinctUntilChanged()
|
||||
|
||||
/** This sends touch exploration events only used for debugging purposes. */
|
||||
val touchExplorationDebug: Flow<Point> =
|
||||
debuggingInteractor.debuggingEnabled.combineTransform(
|
||||
simulatedTouchEventsDebugRepository.touchExplorationDebug
|
||||
) { enabled, point ->
|
||||
if (enabled) {
|
||||
emit(point)
|
||||
}
|
||||
}
|
||||
private val _touchEvent: MutableStateFlow<MotionEvent?> = MutableStateFlow(null)
|
||||
val touchEvent =
|
||||
_touchEvent.asStateFlow().filterNotNull()
|
||||
|
||||
/** Determines the current [EnrollStageModel] enrollment is in */
|
||||
private val enrollStage: Flow<EnrollStageModel> =
|
||||
@@ -266,6 +266,12 @@ class UdfpsViewModel(
|
||||
viewModelScope.launch {
|
||||
backgroundViewModel.background.filter { it }.collect { didGoToBackground() }
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
touchEventInteractor.touchEvent.collect {
|
||||
_touchEvent.update { it }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Indicates if we should show the lottie. */
|
||||
@@ -393,47 +399,43 @@ class UdfpsViewModel(
|
||||
)
|
||||
}
|
||||
|
||||
class UdfpsEnrollmentFactory(
|
||||
private val vibrationInteractor: VibrationInteractor,
|
||||
private val displayDensityInteractor: DisplayDensityInteractor,
|
||||
private val navigationViewModel: FingerprintNavigationViewModel,
|
||||
private val debuggingInteractor: DebuggingInteractor,
|
||||
private val fingerprintEnrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel,
|
||||
private val simulatedTouchEventsRepository: SimulatedTouchEventsRepository,
|
||||
private val enrollStageInteractor: EnrollStageInteractor,
|
||||
private val orientationInteractor: OrientationInteractor,
|
||||
private val backgroundViewModel: BackgroundViewModel,
|
||||
private val sensorRepository: FingerprintSensorRepository,
|
||||
private val udfpsEnrollInteractor: UdfpsEnrollInteractor,
|
||||
private val fingerprintManager: FingerprintManagerInteractor,
|
||||
private val udfpsLastStepViewModel: UdfpsLastStepViewModel,
|
||||
private val accessibilityInteractor: AccessibilityInteractor,
|
||||
) : ViewModelProvider.Factory {
|
||||
/** Starts enrollment. */
|
||||
fun enroll(enrollOptions: FingerprintEnrollOptions) {
|
||||
fingerprintEnrollEnrollingViewModel.enroll(enrollOptions)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return UdfpsViewModel(
|
||||
vibrationInteractor,
|
||||
displayDensityInteractor,
|
||||
navigationViewModel,
|
||||
debuggingInteractor,
|
||||
fingerprintEnrollEnrollingViewModel,
|
||||
simulatedTouchEventsRepository,
|
||||
enrollStageInteractor,
|
||||
orientationInteractor,
|
||||
backgroundViewModel,
|
||||
sensorRepository,
|
||||
udfpsEnrollInteractor,
|
||||
fingerprintManager,
|
||||
udfpsLastStepViewModel,
|
||||
accessibilityInteractor,
|
||||
)
|
||||
as T
|
||||
}
|
||||
/** Indicates a touch event has occurred. */
|
||||
fun onTouchEvent(event: MotionEvent) {
|
||||
_touchEvent.update { event }
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val navStep = FingerprintNavigationStep.Enrollment::class
|
||||
private const val TAG = "UDFPSViewModel"
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer {
|
||||
val settingsApplication =
|
||||
this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as SettingsApplication
|
||||
val biometricEnvironment = settingsApplication.biometricEnvironment!!
|
||||
val provider = ViewModelProvider(this[VIEW_MODEL_STORE_OWNER_KEY]!!)
|
||||
|
||||
UdfpsViewModel(
|
||||
provider[FingerprintNavigationViewModel::class],
|
||||
provider[FingerprintEnrollEnrollingViewModel::class],
|
||||
provider[BackgroundViewModel::class],
|
||||
provider[UdfpsLastStepViewModel::class],
|
||||
biometricEnvironment.vibrationInteractor,
|
||||
biometricEnvironment.displayDensityInteractor,
|
||||
biometricEnvironment.debuggingInteractor,
|
||||
biometricEnvironment.enrollStageInteractor,
|
||||
biometricEnvironment.orientationInteractor,
|
||||
biometricEnvironment.udfpsEnrollInteractor,
|
||||
biometricEnvironment.fingerprintManagerInteractor,
|
||||
biometricEnvironment.accessibilityInteractor,
|
||||
biometricEnvironment.sensorInteractor,
|
||||
biometricEnvironment.touchEventInteractor,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -210,6 +210,7 @@ class UdfpsEnrollProgressBarDrawableV2(private val context: Context, attrs: Attr
|
||||
override fun getOpacity(): Int {
|
||||
return PixelFormat.UNKNOWN
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the progress with locations [sensorLocationX] [sensorLocationY], note these must be with
|
||||
* respect to the parent framelayout.
|
||||
|
@@ -148,18 +148,10 @@ class UdfpsEnrollViewV2(context: Context, attrs: AttributeSet?) : FrameLayout(co
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a touch exploration event to the [onHoverListener] this should only be used for
|
||||
* debugging.
|
||||
*/
|
||||
fun sendDebugTouchExplorationEvent(motionEvent: MotionEvent) {
|
||||
touchExplorationAnnouncer.onTouch(motionEvent)
|
||||
}
|
||||
|
||||
/** Sets the addHoverListener, this should happen when talkback is enabled. */
|
||||
private fun addHoverListener() {
|
||||
onHoverListener = OnHoverListener { _: View, event: MotionEvent ->
|
||||
sendDebugTouchExplorationEvent(event)
|
||||
touchExplorationAnnouncer.onTouch(event)
|
||||
false
|
||||
}
|
||||
this.setOnHoverListener(onHoverListener)
|
||||
|
@@ -18,6 +18,8 @@ package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
@@ -39,10 +41,9 @@ class BackgroundViewModel : ViewModel() {
|
||||
_background.update { false }
|
||||
}
|
||||
|
||||
class BackgroundViewModelFactory : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return BackgroundViewModel() as T
|
||||
companion object {
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer { BackgroundViewModel() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -16,14 +16,17 @@
|
||||
|
||||
package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
|
||||
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.VIEW_MODEL_STORE_OWNER_KEY
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import com.android.settings.SettingsApplication
|
||||
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
/**
|
||||
* Models the UI state for [FingerprintEnrollConfirmationV2Fragment]
|
||||
*/
|
||||
/** Models the UI state for [FingerprintEnrollConfirmationV2Fragment] */
|
||||
class FingerprintEnrollConfirmationViewModel(
|
||||
private val navigationViewModel: FingerprintNavigationViewModel,
|
||||
fingerprintInteractor: FingerprintManagerInteractor,
|
||||
@@ -50,18 +53,20 @@ class FingerprintEnrollConfirmationViewModel(
|
||||
navigationViewModel.update(FingerprintAction.ADD_ANOTHER, navStep, "onAddAnotherButtonClicked")
|
||||
}
|
||||
|
||||
class FingerprintEnrollConfirmationViewModelFactory(
|
||||
private val navigationViewModel: FingerprintNavigationViewModel,
|
||||
private val fingerprintInteractor: FingerprintManagerInteractor,
|
||||
) : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return FingerprintEnrollConfirmationViewModel(navigationViewModel, fingerprintInteractor) as T
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "FingerprintEnrollConfirmationViewModel"
|
||||
private val navStep = FingerprintNavigationStep.Confirmation::class
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer {
|
||||
val settingsApplication =
|
||||
this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as SettingsApplication
|
||||
val biometricEnvironment = settingsApplication.biometricEnvironment
|
||||
val provider = ViewModelProvider(this[VIEW_MODEL_STORE_OWNER_KEY]!!)
|
||||
FingerprintEnrollConfirmationViewModel(
|
||||
provider[FingerprintNavigationViewModel::class],
|
||||
biometricEnvironment!!.fingerprintManagerInteractor,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -16,14 +16,15 @@
|
||||
|
||||
package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
|
||||
|
||||
import android.util.Log
|
||||
import android.hardware.fingerprint.FingerprintEnrollOptions
|
||||
import androidx.lifecycle.VIEW_MODEL_STORE_OWNER_KEY
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.android.systemui.biometrics.shared.model.FingerprintSensor
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.transformLatest
|
||||
import kotlinx.coroutines.flow.update
|
||||
|
||||
@@ -69,23 +70,24 @@ class FingerprintEnrollEnrollingViewModel(
|
||||
val enrollFlow =
|
||||
enrollFlowShouldBeRunning.transformLatest {
|
||||
if (it) {
|
||||
fingerprintEnrollViewModel.enrollFlow.collect { event ->
|
||||
emit(event) }
|
||||
fingerprintEnrollViewModel.enrollFlow.collect { event -> emit(event) }
|
||||
}
|
||||
}
|
||||
|
||||
class FingerprintEnrollEnrollingViewModelFactory(
|
||||
private val fingerprintEnrollViewModel: FingerprintEnrollViewModel,
|
||||
private val backgroundViewModel: BackgroundViewModel,
|
||||
) : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return FingerprintEnrollEnrollingViewModel(fingerprintEnrollViewModel, backgroundViewModel)
|
||||
as T
|
||||
}
|
||||
/** Indicates enrollment to start */
|
||||
fun enroll(enrollOptions: FingerprintEnrollOptions) {
|
||||
fingerprintEnrollViewModel.enroll(enrollOptions)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = "FingerprintEnrollEnrollingViewModel"
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer {
|
||||
val provider = ViewModelProvider(this[VIEW_MODEL_STORE_OWNER_KEY]!!)
|
||||
FingerprintEnrollEnrollingViewModel(
|
||||
provider[FingerprintEnrollViewModel::class],
|
||||
provider[BackgroundViewModel::class],
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -16,9 +16,14 @@
|
||||
|
||||
package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
|
||||
|
||||
import android.hardware.fingerprint.FingerprintEnrollOptions
|
||||
import androidx.lifecycle.VIEW_MODEL_STORE_OWNER_KEY
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import com.android.settings.SettingsApplication
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.AccessibilityInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor
|
||||
@@ -43,10 +48,10 @@ class FingerprintEnrollFindSensorViewModel(
|
||||
private val fingerprintEnrollViewModel: FingerprintEnrollViewModel,
|
||||
private val gatekeeperViewModel: FingerprintGatekeeperViewModel,
|
||||
backgroundViewModel: BackgroundViewModel,
|
||||
fingerprintFlowViewModel: FingerprintFlowViewModel,
|
||||
accessibilityInteractor: AccessibilityInteractor,
|
||||
foldStateInteractor: FoldStateInteractor,
|
||||
orientationInteractor: OrientationInteractor,
|
||||
fingerprintFlowViewModel: FingerprintFlowViewModel,
|
||||
fingerprintManagerInteractor: FingerprintManagerInteractor,
|
||||
) : ViewModel() {
|
||||
|
||||
@@ -64,6 +69,7 @@ class FingerprintEnrollFindSensorViewModel(
|
||||
val showPrimaryButton: Flow<Boolean> = _isUdfps.filter { it }
|
||||
|
||||
private val _showSfpsLottie = _isSfps.filter { it }
|
||||
|
||||
/** Represents the stream of showing sfps lottie and the information Pair(isFolded, rotation). */
|
||||
val sfpsLottieInfo: Flow<Pair<Boolean, Int>> =
|
||||
combineTransform(
|
||||
@@ -75,6 +81,7 @@ class FingerprintEnrollFindSensorViewModel(
|
||||
}
|
||||
|
||||
private val _showUdfpsLottie = _isUdfps.filter { it }
|
||||
|
||||
/** Represents the stream of showing udfps lottie and whether accessibility is enabled. */
|
||||
val udfpsLottieInfo: Flow<Boolean> =
|
||||
_showUdfpsLottie.combine(accessibilityInteractor.isAccessibilityEnabled) {
|
||||
@@ -87,11 +94,13 @@ class FingerprintEnrollFindSensorViewModel(
|
||||
val showRfpsAnimation: Flow<Boolean> = _isRearSfps.filter { it }
|
||||
|
||||
private val _showErrorDialog: MutableStateFlow<Pair<Int, Boolean>?> = MutableStateFlow(null)
|
||||
|
||||
/** Represents the stream of showing error dialog. */
|
||||
val showErrorDialog = _showErrorDialog.filterNotNull()
|
||||
|
||||
private var _didTryEducation = false
|
||||
private var _education: MutableStateFlow<Boolean> = MutableStateFlow(false)
|
||||
|
||||
/** Indicates if the education flow should be running. */
|
||||
private val educationFlowShouldBeRunning: Flow<Boolean> =
|
||||
_education.combine(backgroundViewModel.background) { shouldRunEducation, isInBackground ->
|
||||
@@ -167,6 +176,11 @@ class FingerprintEnrollFindSensorViewModel(
|
||||
_education.update { false }
|
||||
}
|
||||
|
||||
/** Indicates enrollment to start */
|
||||
fun enroll(enrollOptions: FingerprintEnrollOptions) {
|
||||
fingerprintEnrollViewModel.enroll(enrollOptions)
|
||||
}
|
||||
|
||||
/** Proceed to EnrollEnrolling page. */
|
||||
fun proceedToEnrolling() {
|
||||
stopEducation()
|
||||
@@ -182,36 +196,29 @@ class FingerprintEnrollFindSensorViewModel(
|
||||
)
|
||||
}
|
||||
|
||||
class FingerprintEnrollFindSensorViewModelFactory(
|
||||
private val navigationViewModel: FingerprintNavigationViewModel,
|
||||
private val fingerprintEnrollViewModel: FingerprintEnrollViewModel,
|
||||
private val gatekeeperViewModel: FingerprintGatekeeperViewModel,
|
||||
private val backgroundViewModel: BackgroundViewModel,
|
||||
private val accessibilityInteractor: AccessibilityInteractor,
|
||||
private val foldStateInteractor: FoldStateInteractor,
|
||||
private val orientationInteractor: OrientationInteractor,
|
||||
private val fingerprintFlowViewModel: FingerprintFlowViewModel,
|
||||
private val fingerprintManagerInteractor: FingerprintManagerInteractor,
|
||||
) : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return FingerprintEnrollFindSensorViewModel(
|
||||
navigationViewModel,
|
||||
fingerprintEnrollViewModel,
|
||||
gatekeeperViewModel,
|
||||
backgroundViewModel,
|
||||
accessibilityInteractor,
|
||||
foldStateInteractor,
|
||||
orientationInteractor,
|
||||
fingerprintFlowViewModel,
|
||||
fingerprintManagerInteractor,
|
||||
)
|
||||
as T
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "FingerprintEnrollFindSensorViewModel"
|
||||
private val navStep = Education::class
|
||||
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer {
|
||||
val settingsApplication =
|
||||
this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as SettingsApplication
|
||||
val biometricEnvironment = settingsApplication.biometricEnvironment!!
|
||||
val provider = ViewModelProvider(this[VIEW_MODEL_STORE_OWNER_KEY]!!)
|
||||
|
||||
FingerprintEnrollFindSensorViewModel(
|
||||
provider[FingerprintNavigationViewModel::class],
|
||||
provider[FingerprintEnrollViewModel::class],
|
||||
provider[FingerprintGatekeeperViewModel::class],
|
||||
provider[BackgroundViewModel::class],
|
||||
provider[FingerprintFlowViewModel::class],
|
||||
biometricEnvironment.accessibilityInteractor,
|
||||
biometricEnvironment.foldStateInteractor,
|
||||
biometricEnvironment.orientationInteractor,
|
||||
biometricEnvironment.fingerprintManagerInteractor,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -16,8 +16,12 @@
|
||||
|
||||
package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
|
||||
|
||||
import androidx.lifecycle.VIEW_MODEL_STORE_OWNER_KEY
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import com.android.settings.SettingsApplication
|
||||
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintFlow
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Introduction
|
||||
@@ -27,8 +31,8 @@ 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,
|
||||
fingerprintFlowViewModel: FingerprintFlowViewModel,
|
||||
fingerprintManagerInteractor: FingerprintManagerInteractor,
|
||||
) : ViewModel() {
|
||||
|
||||
/** Represents a stream of [FingerprintSensor] */
|
||||
@@ -51,25 +55,21 @@ class FingerprintEnrollIntroViewModel(
|
||||
)
|
||||
}
|
||||
|
||||
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"
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer {
|
||||
val settingsApplication =
|
||||
this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as SettingsApplication
|
||||
val biometricEnvironment = settingsApplication.biometricEnvironment
|
||||
val provider = ViewModelProvider(this[VIEW_MODEL_STORE_OWNER_KEY]!!)
|
||||
FingerprintEnrollIntroViewModel(
|
||||
provider[FingerprintNavigationViewModel::class],
|
||||
provider[FingerprintFlowViewModel::class],
|
||||
biometricEnvironment!!.fingerprintManagerInteractor,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -15,9 +15,15 @@
|
||||
*/
|
||||
package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
|
||||
|
||||
import android.hardware.fingerprint.FingerprintEnrollOptions
|
||||
import androidx.lifecycle.VIEW_MODEL_STORE_OWNER_KEY
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import com.android.settings.SettingsApplication
|
||||
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
|
||||
@@ -25,12 +31,14 @@ import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Fing
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Enrollment
|
||||
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
import kotlinx.coroutines.flow.transformLatest
|
||||
import kotlinx.coroutines.flow.update
|
||||
|
||||
/** Represents all of the fingerprint information needed for a fingerprint enrollment process. */
|
||||
class FingerprintEnrollViewModel(
|
||||
@@ -55,6 +63,8 @@ class FingerprintEnrollViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
private val enrollOptions: MutableStateFlow<FingerprintEnrollOptions?> = MutableStateFlow(null)
|
||||
|
||||
/** Represents the stream of [FingerprintSensorType] */
|
||||
val sensorType: Flow<FingerprintSensorType?> =
|
||||
fingerprintManagerInteractor.sensorPropertiesInternal.filterNotNull().map { it.sensorType }
|
||||
@@ -66,16 +76,23 @@ class FingerprintEnrollViewModel(
|
||||
* This flow should be the only flow which calls enroll().
|
||||
*/
|
||||
val _enrollFlow: Flow<FingerEnrollState> =
|
||||
combine(gatekeeperViewModel.gatekeeperInfo, _enrollReason) { hardwareAuthToken, enrollReason ->
|
||||
Pair(hardwareAuthToken, enrollReason)
|
||||
combine(gatekeeperViewModel.gatekeeperInfo, _enrollReason, enrollOptions) {
|
||||
hardwareAuthToken,
|
||||
enrollReason,
|
||||
enrollOptions ->
|
||||
Triple(hardwareAuthToken, enrollReason, enrollOptions)
|
||||
}
|
||||
.transformLatest {
|
||||
/** [transformLatest] is used as we want to make sure to cancel previous API call. */
|
||||
(hardwareAuthToken, enrollReason) ->
|
||||
if (hardwareAuthToken is GatekeeperInfo.GatekeeperPasswordInfo && enrollReason != null) {
|
||||
fingerprintManagerInteractor.enroll(hardwareAuthToken.token, enrollReason).collect {
|
||||
emit(it)
|
||||
}
|
||||
(hardwareAuthToken, enrollReason, enrollOptions) ->
|
||||
if (
|
||||
hardwareAuthToken is GatekeeperInfo.GatekeeperPasswordInfo &&
|
||||
enrollReason != null &&
|
||||
enrollOptions != null
|
||||
) {
|
||||
fingerprintManagerInteractor
|
||||
.enroll(hardwareAuthToken.token, enrollReason, enrollOptions)
|
||||
.collect { emit(it) }
|
||||
}
|
||||
}
|
||||
.shareIn(viewModelScope, SharingStarted.WhileSubscribed(), 0)
|
||||
@@ -108,14 +125,23 @@ class FingerprintEnrollViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
class FingerprintEnrollViewModelFactory(
|
||||
val interactor: FingerprintManagerInteractor,
|
||||
val gatekeeperViewModel: FingerprintGatekeeperViewModel,
|
||||
val navigationViewModel: FingerprintNavigationViewModel,
|
||||
) : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return FingerprintEnrollViewModel(interactor, gatekeeperViewModel, navigationViewModel) as T
|
||||
/** Starts enrollment. */
|
||||
fun enroll(options: FingerprintEnrollOptions) {
|
||||
enrollOptions.update { options }
|
||||
}
|
||||
|
||||
companion object {
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer {
|
||||
val settingsApplication = this[APPLICATION_KEY] as SettingsApplication
|
||||
val biometricEnvironment = settingsApplication.biometricEnvironment
|
||||
val provider = ViewModelProvider(this[VIEW_MODEL_STORE_OWNER_KEY]!!)
|
||||
FingerprintEnrollViewModel(
|
||||
biometricEnvironment!!.fingerprintManagerInteractor,
|
||||
provider[FingerprintGatekeeperViewModel::class],
|
||||
provider[FingerprintNavigationViewModel::class],
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -19,21 +19,28 @@ package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintFlow
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
import kotlinx.coroutines.flow.update
|
||||
|
||||
class FingerprintFlowViewModel(private val fingerprintFlowType: FingerprintFlow) : ViewModel() {
|
||||
val fingerprintFlow: Flow<FingerprintFlow> =
|
||||
flowOf(fingerprintFlowType).shareIn(viewModelScope, SharingStarted.Eagerly, 1)
|
||||
class FingerprintFlowViewModel() : ViewModel() {
|
||||
val _mutableFingerprintFlow: MutableStateFlow<FingerprintFlow?> = MutableStateFlow(null)
|
||||
val fingerprintFlow: Flow<FingerprintFlow?> =
|
||||
_mutableFingerprintFlow.shareIn(viewModelScope, SharingStarted.Eagerly, 1)
|
||||
|
||||
class FingerprintFlowViewModelFactory(val flowType: FingerprintFlow) : ViewModelProvider.Factory {
|
||||
/** Used to set the fingerprint flow type */
|
||||
fun updateFlowType(fingerprintFlowType: FingerprintFlow) {
|
||||
_mutableFingerprintFlow.update { fingerprintFlowType }
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return FingerprintFlowViewModel(flowType) as T
|
||||
companion object {
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer { FingerprintFlowViewModel() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -21,6 +21,9 @@ import android.util.Log
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import com.android.settings.SettingsApplication
|
||||
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -47,12 +50,10 @@ sealed interface GatekeeperInfo {
|
||||
* in as a parameter to this class.
|
||||
*/
|
||||
class FingerprintGatekeeperViewModel(
|
||||
theGatekeeperInfo: GatekeeperInfo?,
|
||||
private val fingerprintManagerInteractor: FingerprintManagerInteractor,
|
||||
private val fingerprintManagerInteractor: FingerprintManagerInteractor
|
||||
) : ViewModel() {
|
||||
|
||||
private var _gatekeeperInfo: MutableStateFlow<GatekeeperInfo?> =
|
||||
MutableStateFlow(theGatekeeperInfo)
|
||||
private var _gatekeeperInfo: MutableStateFlow<GatekeeperInfo?> = MutableStateFlow(null)
|
||||
|
||||
/** The gatekeeper info for fingerprint enrollment. */
|
||||
val gatekeeperInfo: Flow<GatekeeperInfo?> = _gatekeeperInfo.asStateFlow()
|
||||
@@ -61,26 +62,27 @@ class FingerprintGatekeeperViewModel(
|
||||
val hasValidGatekeeperInfo: Flow<Boolean> =
|
||||
gatekeeperInfo.map { it is GatekeeperInfo.GatekeeperPasswordInfo }
|
||||
|
||||
private var _credentialConfirmed: MutableStateFlow<Boolean?> = MutableStateFlow(null)
|
||||
val credentialConfirmed: Flow<Boolean?> = _credentialConfirmed.asStateFlow()
|
||||
|
||||
private var countDownTimer: CountDownTimer? = null
|
||||
|
||||
/** Timeout of 15 minutes for a generated challenge */
|
||||
private val TIMEOUT: Long = 15 * 60 * 1000
|
||||
|
||||
/** Called after a confirm device credential attempt has been made. */
|
||||
fun onConfirmDevice(wasSuccessful: Boolean, theGatekeeperPasswordHandle: Long?) {
|
||||
fun onConfirmDevice(
|
||||
wasSuccessful: Boolean,
|
||||
theGatekeeperPasswordHandle: Long?,
|
||||
shouldStartTimer: Boolean = true,
|
||||
) {
|
||||
if (!wasSuccessful) {
|
||||
Log.d(TAG, "confirmDevice failed")
|
||||
_gatekeeperInfo.update { GatekeeperInfo.Invalid }
|
||||
_credentialConfirmed.update { false }
|
||||
} else {
|
||||
viewModelScope.launch {
|
||||
val res = fingerprintManagerInteractor.generateChallenge(theGatekeeperPasswordHandle!!)
|
||||
_gatekeeperInfo.update { GatekeeperInfo.GatekeeperPasswordInfo(res.second, res.first) }
|
||||
_credentialConfirmed.update { true }
|
||||
startTimeout()
|
||||
if (shouldStartTimer) {
|
||||
startTimeout()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,19 +99,9 @@ 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 {
|
||||
private const val TAG = "FingerprintGatekeeperViewModel"
|
||||
|
||||
/**
|
||||
* A function that checks if the challenge and token are valid, in which case a
|
||||
* [GatekeeperInfo.GatekeeperPasswordInfo] is provided, else [GatekeeperInfo.Invalid]
|
||||
@@ -121,5 +113,14 @@ class FingerprintGatekeeperViewModel(
|
||||
}
|
||||
return GatekeeperInfo.GatekeeperPasswordInfo(token, challenge)
|
||||
}
|
||||
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer {
|
||||
val settingsApplication =
|
||||
this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as SettingsApplication
|
||||
val biometricEnvironment = settingsApplication.biometricEnvironment
|
||||
FingerprintGatekeeperViewModel(biometricEnvironment!!.fingerprintManagerInteractor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -20,7 +20,11 @@ import android.util.Log
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import com.android.settings.SettingsApplication
|
||||
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintFlow
|
||||
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
|
||||
@@ -28,39 +32,40 @@ import java.lang.NullPointerException
|
||||
import kotlin.reflect.KClass
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.combineTransform
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
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() {
|
||||
class FingerprintNavigationViewModel(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))
|
||||
}
|
||||
private val _flowInternal: MutableStateFlow<FingerprintFlow?> = MutableStateFlow(null)
|
||||
private val _hasConfirmedDeviceCredential: MutableStateFlow<Boolean> = MutableStateFlow(false)
|
||||
private val _navStateInternal: StateFlow<NavigationState?> =
|
||||
combine(
|
||||
_flowInternal,
|
||||
_hasConfirmedDeviceCredential,
|
||||
fingerprintManagerInteractor.sensorPropertiesInternal,
|
||||
) { flow, hasConfirmed, sensorType ->
|
||||
if (flow == null || sensorType == null) {
|
||||
return@combine null
|
||||
}
|
||||
.collect { navState -> _navStateInternal.update { navState } }
|
||||
}
|
||||
}
|
||||
return@combine NavigationState(flow, hasConfirmed, sensorType)
|
||||
}
|
||||
.stateIn(viewModelScope, SharingStarted.Eagerly, null)
|
||||
|
||||
private var _currentStep = MutableStateFlow<FingerprintNavigationStep?>(step)
|
||||
private var _currentStep =
|
||||
MutableStateFlow<FingerprintNavigationStep?>(FingerprintNavigationStep.Init)
|
||||
|
||||
private var _navigateTo: MutableStateFlow<UiStep?> = MutableStateFlow(null)
|
||||
val navigateTo: Flow<UiStep?> = _navigateTo.asStateFlow()
|
||||
@@ -85,6 +90,16 @@ class FingerprintNavigationViewModel(
|
||||
/** This indicates what screen should currently be presenting to the user. */
|
||||
val currentScreen: Flow<UiStep?> = _currentScreen.asStateFlow()
|
||||
|
||||
/** Updates the type of flow the navigation should begin */
|
||||
fun updateFingerprintFlow(flow: FingerprintFlow) {
|
||||
_flowInternal.update { flow }
|
||||
}
|
||||
|
||||
/** Indicates if we have confirmed device credential */
|
||||
fun hasConfirmedDeviceCredential(hasConfirmedDeviceCredential: Boolean) {
|
||||
_hasConfirmedDeviceCredential.update { hasConfirmedDeviceCredential }
|
||||
}
|
||||
|
||||
/** See [updateInternal] for more details */
|
||||
fun update(action: FingerprintAction, caller: KClass<*>, debugStr: String) {
|
||||
Log.d(TAG, "$caller.update($action) $debugStr")
|
||||
@@ -122,26 +137,15 @@ class FingerprintNavigationViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer {
|
||||
val settingsApplication =
|
||||
this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as SettingsApplication
|
||||
val biometricEnvironment = settingsApplication.biometricEnvironment
|
||||
FingerprintNavigationViewModel(biometricEnvironment!!.fingerprintManagerInteractor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -18,6 +18,8 @@ package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
@@ -36,11 +38,9 @@ class FingerprintScrollViewModel : ViewModel() {
|
||||
_hasReadConsentScreen.update { true }
|
||||
}
|
||||
|
||||
class FingerprintScrollViewModelFactory : ViewModelProvider.Factory {
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return FingerprintScrollViewModel() as T
|
||||
companion object {
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer { FingerprintScrollViewModel() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -18,24 +18,15 @@ package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
|
||||
|
||||
/** Indicates the type of transitions that can occur between fragments */
|
||||
sealed class Transition {
|
||||
/**
|
||||
* Indicates the new fragment should slide in from the left side
|
||||
*/
|
||||
/** Indicates the new fragment should slide in from the left side */
|
||||
data object EnterFromLeft : Transition()
|
||||
|
||||
/**
|
||||
* Indicates the new fragment should slide in from the right side
|
||||
*/
|
||||
/** Indicates the new fragment should slide in from the right side */
|
||||
data object EnterFromRight : Transition()
|
||||
|
||||
/**
|
||||
* Indicates the old fragment should slide out to the left side
|
||||
*/
|
||||
/** Indicates the old fragment should slide out to the left side */
|
||||
data object ExitToLeft : Transition()
|
||||
|
||||
/**
|
||||
* Indicates the old fragment should slide out to the right side
|
||||
*/
|
||||
/** Indicates the old fragment should slide out to the right side */
|
||||
data object ExitToRight : Transition()
|
||||
}
|
||||
|
||||
|
@@ -54,29 +54,40 @@ object FingerprintSettingsViewBinder {
|
||||
challenge: Long?,
|
||||
challengeToken: ByteArray?,
|
||||
)
|
||||
|
||||
/** Helper to launch an add fingerprint request */
|
||||
fun launchAddFingerprint(userId: Int, challengeToken: ByteArray?)
|
||||
|
||||
/**
|
||||
* Helper function that will try and launch confirm lock, if that fails we will prompt user to
|
||||
* choose a PIN/PATTERN/PASS.
|
||||
*/
|
||||
fun launchConfirmOrChooseLock(userId: Int)
|
||||
|
||||
/** Used to indicate that FingerprintSettings is finished. */
|
||||
fun finish()
|
||||
|
||||
/** Indicates what result should be set for the returning callee */
|
||||
fun setResultExternal(resultCode: Int)
|
||||
|
||||
/** Indicates the settings UI should be shown */
|
||||
fun showSettings(enrolledFingerprints: List<FingerprintData>)
|
||||
|
||||
/** Updates the add fingerprints preference */
|
||||
fun updateAddFingerprintsPreference(canEnroll: Boolean, maxFingerprints: Int)
|
||||
|
||||
/** Updates the sfps fingerprints preference */
|
||||
fun updateSfpsPreference(isSfpsPrefVisible: Boolean)
|
||||
|
||||
/** Indicates that a user has been locked out */
|
||||
fun userLockout(authAttemptViewModel: FingerprintAuthAttemptModel.Error)
|
||||
|
||||
/** Indicates a fingerprint preference should be highlighted */
|
||||
suspend fun highlightPref(fingerId: Int)
|
||||
|
||||
/** Indicates a user should be prompted to delete a fingerprint */
|
||||
suspend fun askUserToDeleteDialog(fingerprintViewModel: FingerprintData): Boolean
|
||||
|
||||
/** Indicates a user should be asked to renae ma dialog */
|
||||
suspend fun askUserToRenameDialog(
|
||||
fingerprintViewModel: FingerprintData
|
||||
|
@@ -45,14 +45,13 @@ import com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED
|
||||
import com.android.settings.biometrics.GatekeeperPasswordProvider
|
||||
import com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling
|
||||
import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroductionInternal
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintEnrollInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepositoryImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintEnrollInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.domain.interactor.PressToAuthInteractorImpl
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.Settings
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.common.util.toFingerprintEnrollOptions
|
||||
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.FingerprintSettingsViewModel
|
||||
@@ -227,7 +226,6 @@ class FingerprintSettingsV2Fragment :
|
||||
val fingerprintEnrollStateRepository =
|
||||
FingerprintEnrollInteractorImpl(
|
||||
requireContext().applicationContext,
|
||||
intent.toFingerprintEnrollOptions(),
|
||||
fingerprintManager,
|
||||
Settings,
|
||||
)
|
||||
|
@@ -52,7 +52,7 @@ class FingerprintSettingsNavigationViewModel(
|
||||
_nextStep.update { LaunchConfirmDeviceCredential(userId) }
|
||||
} else {
|
||||
viewModelScope.launch {
|
||||
if (fingerprintManagerInteractor.enrolledFingerprints.last().isEmpty()) {
|
||||
if (fingerprintManagerInteractor.enrolledFingerprints.last()?.isEmpty() == true) {
|
||||
_nextStep.update { EnrollFirstFingerprint(userId, null, challenge, token) }
|
||||
} else {
|
||||
showSettingsHelper()
|
||||
@@ -149,7 +149,7 @@ class FingerprintSettingsNavigationViewModel(
|
||||
|
||||
private suspend fun launchEnrollNextStep(gateKeeperPasswordHandle: Long?) {
|
||||
fingerprintManagerInteractor.enrolledFingerprints.collect {
|
||||
if (it.isEmpty()) {
|
||||
if (it?.isEmpty() == true) {
|
||||
_nextStep.update { EnrollFirstFingerprint(userId, gateKeeperPasswordHandle, null, null) }
|
||||
} else {
|
||||
viewModelScope.launch(backgroundDispatcher) {
|
||||
|
@@ -74,7 +74,7 @@ class FingerprintSettingsViewModel(
|
||||
/** Represents the stream of visibility of sfps preference. */
|
||||
val isSfpsPrefVisible: Flow<Boolean> =
|
||||
_enrolledFingerprints.filterOnlyWhenSettingsIsShown().transform {
|
||||
emit(fingerprintManagerInteractor.hasSideFps() && !it.isNullOrEmpty())
|
||||
emit(fingerprintManagerInteractor.hasSideFps() == true && !it.isNullOrEmpty())
|
||||
}
|
||||
|
||||
private val _isShowingDialog: MutableStateFlow<PreferenceViewModel?> = MutableStateFlow(null)
|
||||
|
@@ -67,7 +67,6 @@ class FingerprintEnrollIntroFragmentTest {
|
||||
|
||||
private val gatekeeperViewModel =
|
||||
FingerprintGatekeeperViewModel(
|
||||
GatekeeperInfo.GatekeeperPasswordInfo(byteArrayOf(1, 2, 3), 100L),
|
||||
interactor
|
||||
)
|
||||
private val backgroundDispatcher = StandardTestDispatcher()
|
||||
@@ -86,13 +85,10 @@ class FingerprintEnrollIntroFragmentTest {
|
||||
.toFingerprintSensor()
|
||||
|
||||
var enrollFlow = Default
|
||||
val flowViewModel = FingerprintFlowViewModel(enrollFlow)
|
||||
val flowViewModel = FingerprintFlowViewModel()
|
||||
|
||||
private val navigationViewModel =
|
||||
FingerprintNavigationViewModel(
|
||||
Introduction(),
|
||||
false,
|
||||
flowViewModel,
|
||||
interactor
|
||||
)
|
||||
|
||||
@@ -124,6 +120,11 @@ class FingerprintEnrollIntroFragmentTest {
|
||||
}
|
||||
}
|
||||
|
||||
gatekeeperViewModel.onConfirmDevice(true, 100L, false)
|
||||
flowViewModel.updateFlowType(enrollFlow)
|
||||
navigationViewModel.hasConfirmedDeviceCredential(true)
|
||||
navigationViewModel.updateFingerprintFlow(enrollFlow)
|
||||
|
||||
fragmentScenario =
|
||||
launchFragmentInContainer(Bundle(), R.style.SudThemeGlif) {
|
||||
FingerprintEnrollIntroV2Fragment(factory)
|
||||
|
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 101 KiB |
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 83 KiB |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 148 KiB |
@@ -42,7 +42,6 @@ import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Fing
|
||||
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.GatekeeperInfo
|
||||
import com.android.settings.testutils2.FakeFingerprintManagerInteractor
|
||||
import com.android.systemui.biometrics.shared.model.toFingerprintSensor
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@@ -95,23 +94,27 @@ class Injector(step: FingerprintNavigationStep.UiStep) {
|
||||
|
||||
override fun getRotationFromDefault(rotation: Int): Int = rotation
|
||||
}
|
||||
var gatekeeperViewModel =
|
||||
FingerprintGatekeeperViewModel(
|
||||
GatekeeperInfo.GatekeeperPasswordInfo(byteArrayOf(1, 2, 3), 100L),
|
||||
interactor,
|
||||
)
|
||||
var gatekeeperViewModel = FingerprintGatekeeperViewModel(fingerprintManagerInteractor)
|
||||
|
||||
val flowViewModel = FingerprintFlowViewModel(enrollFlow)
|
||||
val flowViewModel = FingerprintFlowViewModel()
|
||||
|
||||
var navigationViewModel = FingerprintNavigationViewModel(step, true, flowViewModel, interactor)
|
||||
var navigationViewModel = FingerprintNavigationViewModel(fingerprintManagerInteractor)
|
||||
var fingerprintViewModel =
|
||||
FingerprintEnrollIntroViewModel(navigationViewModel, flowViewModel, interactor)
|
||||
FingerprintEnrollIntroViewModel(
|
||||
navigationViewModel,
|
||||
flowViewModel,
|
||||
fingerprintManagerInteractor,
|
||||
)
|
||||
|
||||
var fingerprintScrollViewModel = FingerprintScrollViewModel()
|
||||
var backgroundViewModel = BackgroundViewModel()
|
||||
|
||||
var fingerprintEnrollViewModel =
|
||||
FingerprintEnrollViewModel(interactor, gatekeeperViewModel, navigationViewModel)
|
||||
FingerprintEnrollViewModel(
|
||||
fingerprintManagerInteractor,
|
||||
gatekeeperViewModel,
|
||||
navigationViewModel,
|
||||
)
|
||||
|
||||
var fingerprintEnrollEnrollingViewModel =
|
||||
FingerprintEnrollEnrollingViewModel(fingerprintEnrollViewModel, backgroundViewModel)
|
||||
@@ -122,11 +125,11 @@ class Injector(step: FingerprintNavigationStep.UiStep) {
|
||||
fingerprintEnrollEnrollingViewModel,
|
||||
navigationViewModel,
|
||||
orientationInteractor,
|
||||
interactor,
|
||||
fingerprintManagerInteractor,
|
||||
)
|
||||
|
||||
val fingerprintEnrollConfirmationViewModel =
|
||||
FingerprintEnrollConfirmationViewModel(navigationViewModel, interactor)
|
||||
FingerprintEnrollConfirmationViewModel(navigationViewModel, fingerprintManagerInteractor)
|
||||
|
||||
var fingerprintFindSensorViewModel =
|
||||
FingerprintEnrollFindSensorViewModel(
|
||||
@@ -134,11 +137,11 @@ class Injector(step: FingerprintNavigationStep.UiStep) {
|
||||
fingerprintEnrollViewModel,
|
||||
gatekeeperViewModel,
|
||||
backgroundViewModel,
|
||||
flowViewModel,
|
||||
accessibilityInteractor,
|
||||
foldStateInteractor,
|
||||
orientationInteractor,
|
||||
flowViewModel,
|
||||
interactor,
|
||||
fingerprintManagerInteractor,
|
||||
)
|
||||
|
||||
val factory =
|
||||
@@ -166,12 +169,16 @@ class Injector(step: FingerprintNavigationStep.UiStep) {
|
||||
|
||||
init {
|
||||
fingerprintEnrollViewModel.sensorTypeCached = fingerprintSensor.sensorType
|
||||
gatekeeperViewModel.onConfirmDevice(true, 100L)
|
||||
navigationViewModel.updateFingerprintFlow(enrollFlow)
|
||||
navigationViewModel.hasConfirmedDeviceCredential(true)
|
||||
flowViewModel.updateFlowType(enrollFlow)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val Phone = DisplaySpec("phone", width = 1080, height = 2340, densityDpi = 420)
|
||||
private const val screenshotPath = "/settings_screenshots"
|
||||
val interactor = FakeFingerprintManagerInteractor()
|
||||
val fingerprintManagerInteractor = FakeFingerprintManagerInteractor()
|
||||
|
||||
fun BiometricFragmentScreenShotRule() =
|
||||
FragmentScreenshotTestRule(
|
||||
|
@@ -17,7 +17,6 @@
|
||||
package com.android.settings.tests.screenshot.biometrics.fingerprint.fragment
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollConfirmationV2Fragment
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep
|
||||
import com.android.settings.tests.screenshot.biometrics.fingerprint.Injector
|
||||
@@ -28,17 +27,15 @@ import platform.test.screenshot.FragmentScreenshotTestRule
|
||||
import platform.test.screenshot.ViewScreenshotTestRule.Mode
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class FingerprintEnrollConfirmationScreenshotTest {
|
||||
class RfpsEnrollConfirmationScreenshotTest {
|
||||
private val injector: Injector = Injector(FingerprintNavigationStep.Confirmation)
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
var rule: FragmentScreenshotTestRule = Injector.BiometricFragmentScreenShotRule()
|
||||
@Rule @JvmField var rule: FragmentScreenshotTestRule = Injector.BiometricFragmentScreenShotRule()
|
||||
|
||||
@Test
|
||||
fun testConfirmation() {
|
||||
rule.screenshotTest(
|
||||
"fp_enroll_confirmation",
|
||||
"rfps_enroll_confirmation",
|
||||
Mode.MatchSize,
|
||||
FingerprintEnrollConfirmationV2Fragment(injector.factory),
|
||||
)
|
@@ -27,14 +27,14 @@ import platform.test.screenshot.FragmentScreenshotTestRule
|
||||
import platform.test.screenshot.ViewScreenshotTestRule.Mode
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class FingerprintEnrollEnrollingScreenshotTest {
|
||||
class RfpsEnrollEnrollingScreenshotTest {
|
||||
private val injector: Injector =
|
||||
Injector(FingerprintNavigationStep.Enrollment(Injector.interactor.sensorProp))
|
||||
Injector(FingerprintNavigationStep.Enrollment(Injector.fingerprintManagerInteractor.sensorProp))
|
||||
|
||||
@Rule @JvmField var rule: FragmentScreenshotTestRule = BiometricFragmentScreenShotRule()
|
||||
|
||||
@Test
|
||||
fun testEnrollEnrolling() {
|
||||
rule.screenshotTest("fp_enroll_enrolling", Mode.MatchSize, RFPSEnrollFragment(injector.factory))
|
||||
rule.screenshotTest("rfps_enroll_enrolling", Mode.MatchSize, RFPSEnrollFragment(injector.factory))
|
||||
}
|
||||
}
|
@@ -31,10 +31,6 @@ class RfpsEnrollFindSensorScreenshotTest {
|
||||
|
||||
@Test
|
||||
fun testEnrollFindSensor() {
|
||||
rule.screenshotTest(
|
||||
"fp_enroll_find_sensor",
|
||||
Mode.MatchSize,
|
||||
RfpsEnrollFindSensorFragment(),
|
||||
)
|
||||
rule.screenshotTest("rfps_enroll_find_sensor", Mode.MatchSize, RfpsEnrollFindSensorFragment())
|
||||
}
|
||||
}
|
||||
|
@@ -27,17 +27,15 @@ import platform.test.screenshot.FragmentScreenshotTestRule
|
||||
import platform.test.screenshot.ViewScreenshotTestRule.Mode
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class FingerprintEnrollIntroScreenshotTest {
|
||||
class RfpsEnrollIntroScreenshotTest {
|
||||
private val injector: Injector = Injector(FingerprintNavigationStep.Introduction())
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
var rule: FragmentScreenshotTestRule = Injector.BiometricFragmentScreenShotRule()
|
||||
@Rule @JvmField var rule: FragmentScreenshotTestRule = Injector.BiometricFragmentScreenShotRule()
|
||||
|
||||
@Test
|
||||
fun testEnrollIntro() {
|
||||
rule.screenshotTest(
|
||||
"fp_enroll_intro",
|
||||
"rfps_enroll_intro",
|
||||
Mode.MatchSize,
|
||||
FingerprintEnrollIntroV2Fragment(injector.factory),
|
||||
)
|
@@ -19,6 +19,7 @@ package com.android.settings.testutils2
|
||||
import android.hardware.biometrics.ComponentInfoInternal
|
||||
import android.hardware.biometrics.SensorLocationInternal
|
||||
import android.hardware.biometrics.SensorProperties
|
||||
import android.hardware.fingerprint.FingerprintEnrollOptions
|
||||
import android.hardware.fingerprint.FingerprintSensorProperties
|
||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
|
||||
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
|
||||
@@ -78,6 +79,7 @@ class FakeFingerprintManagerInteractor : FingerprintManagerInteractor {
|
||||
override suspend fun enroll(
|
||||
hardwareAuthToken: ByteArray?,
|
||||
enrollReason: EnrollReason,
|
||||
fingerprintEnrollOptions: FingerprintEnrollOptions
|
||||
): Flow<FingerEnrollState> = flowOf(*enrollStateViewModel.toTypedArray())
|
||||
|
||||
override suspend fun removeFingerprint(fp: FingerprintData): Boolean {
|
||||
|
@@ -109,12 +109,7 @@ class FingerprintManagerInteractorTest {
|
||||
fingerprintManager,
|
||||
fingerprintSensorRepository,
|
||||
gateKeeperPasswordProvider,
|
||||
FingerprintEnrollInteractorImpl(
|
||||
context,
|
||||
FingerprintEnrollOptions.Builder().build(),
|
||||
fingerprintManager,
|
||||
Default,
|
||||
),
|
||||
FingerprintEnrollInteractorImpl(context, fingerprintManager, Default),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -135,7 +130,7 @@ class FingerprintManagerInteractorTest {
|
||||
whenever(fingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(fingerprintList)
|
||||
|
||||
val list = underTest.enrolledFingerprints.last()
|
||||
assertThat(list.size).isEqualTo(fingerprintList.size)
|
||||
assertThat(list!!.size).isEqualTo(fingerprintList.size)
|
||||
val actual = list[0]
|
||||
assertThat(actual.name).isEqualTo(expected.name)
|
||||
assertThat(actual.fingerId).isEqualTo(expected.biometricId)
|
||||
@@ -318,7 +313,11 @@ class FingerprintManagerInteractorTest {
|
||||
testScope.runTest {
|
||||
val token = byteArrayOf(5, 3, 2)
|
||||
var result: FingerEnrollState? = null
|
||||
val job = launch { underTest.enroll(token, EnrollReason.FindSensor).collect { result = it } }
|
||||
val job = launch {
|
||||
underTest
|
||||
.enroll(token, EnrollReason.FindSensor, FingerprintEnrollOptions.Builder().build())
|
||||
.collect { result = it }
|
||||
}
|
||||
val enrollCallback: ArgumentCaptor<FingerprintManager.EnrollmentCallback> = argumentCaptor()
|
||||
runCurrent()
|
||||
|
||||
@@ -343,7 +342,11 @@ class FingerprintManagerInteractorTest {
|
||||
testScope.runTest {
|
||||
val token = byteArrayOf(5, 3, 2)
|
||||
var result: FingerEnrollState? = null
|
||||
val job = launch { underTest.enroll(token, EnrollReason.FindSensor).collect { result = it } }
|
||||
val job = launch {
|
||||
underTest
|
||||
.enroll(token, EnrollReason.FindSensor, FingerprintEnrollOptions.Builder().build())
|
||||
.collect { result = it }
|
||||
}
|
||||
val enrollCallback: ArgumentCaptor<FingerprintManager.EnrollmentCallback> = argumentCaptor()
|
||||
runCurrent()
|
||||
|
||||
@@ -368,7 +371,11 @@ class FingerprintManagerInteractorTest {
|
||||
testScope.runTest {
|
||||
val token = byteArrayOf(5, 3, 2)
|
||||
var result: FingerEnrollState? = null
|
||||
val job = launch { underTest.enroll(token, EnrollReason.FindSensor).collect { result = it } }
|
||||
val job = launch {
|
||||
underTest
|
||||
.enroll(token, EnrollReason.FindSensor, FingerprintEnrollOptions.Builder().build())
|
||||
.collect { result = it }
|
||||
}
|
||||
val enrollCallback: ArgumentCaptor<FingerprintManager.EnrollmentCallback> = argumentCaptor()
|
||||
runCurrent()
|
||||
|
||||
|
@@ -35,7 +35,6 @@ import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Fing
|
||||
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.FingerprintNavigationStep
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel
|
||||
import com.android.settings.testutils2.FakeFingerprintManagerInteractor
|
||||
import com.android.systemui.biometrics.shared.model.toFingerprintSensor
|
||||
@@ -90,45 +89,20 @@ class FingerprintEnrollFindSensorViewModelV2Test {
|
||||
Dispatchers.setMain(backgroundDispatcher)
|
||||
|
||||
fakeFingerprintManagerInteractor = FakeFingerprintManagerInteractor()
|
||||
gatekeeperViewModel =
|
||||
FingerprintGatekeeperViewModel.FingerprintGatekeeperViewModelFactory(
|
||||
null,
|
||||
fakeFingerprintManagerInteractor,
|
||||
)
|
||||
.create(FingerprintGatekeeperViewModel::class.java)
|
||||
gatekeeperViewModel = FingerprintGatekeeperViewModel(fakeFingerprintManagerInteractor)
|
||||
|
||||
val sensor =
|
||||
FingerprintSensorPropertiesInternal(
|
||||
0 /* sensorId */,
|
||||
SensorProperties.STRENGTH_STRONG,
|
||||
5 /* maxEnrollmentsPerUser */,
|
||||
listOf<ComponentInfoInternal>(),
|
||||
FingerprintSensorProperties.TYPE_POWER_BUTTON,
|
||||
false /* halControlsIllumination */,
|
||||
true /* resetLockoutRequiresHardwareAuthToken */,
|
||||
listOf<SensorLocationInternal>(SensorLocationInternal.DEFAULT),
|
||||
)
|
||||
.toFingerprintSensor()
|
||||
val fingerprintFlowViewModel = FingerprintFlowViewModel()
|
||||
fingerprintFlowViewModel.updateFlowType(Default)
|
||||
navigationViewModel = FingerprintNavigationViewModel(fakeFingerprintManagerInteractor)
|
||||
|
||||
val fingerprintFlowViewModel = FingerprintFlowViewModel(Default)
|
||||
navigationViewModel =
|
||||
FingerprintNavigationViewModel(
|
||||
FingerprintNavigationStep.Education(sensor),
|
||||
false,
|
||||
fingerprintFlowViewModel,
|
||||
fakeFingerprintManagerInteractor,
|
||||
)
|
||||
|
||||
backgroundViewModel =
|
||||
BackgroundViewModel.BackgroundViewModelFactory().create(BackgroundViewModel::class.java)
|
||||
backgroundViewModel = BackgroundViewModel()
|
||||
backgroundViewModel.inForeground()
|
||||
enrollViewModel =
|
||||
FingerprintEnrollViewModel.FingerprintEnrollViewModelFactory(
|
||||
fakeFingerprintManagerInteractor,
|
||||
gatekeeperViewModel,
|
||||
navigationViewModel,
|
||||
)
|
||||
.create(FingerprintEnrollViewModel::class.java)
|
||||
FingerprintEnrollViewModel(
|
||||
fakeFingerprintManagerInteractor,
|
||||
gatekeeperViewModel,
|
||||
navigationViewModel,
|
||||
)
|
||||
accessibilityInteractor =
|
||||
object : AccessibilityInteractor {
|
||||
override val isAccessibilityEnabled: Flow<Boolean> = flowOf(false)
|
||||
@@ -145,23 +119,23 @@ class FingerprintEnrollFindSensorViewModelV2Test {
|
||||
orientationInteractor =
|
||||
object : OrientationInteractor {
|
||||
override val orientation: Flow<Int> = flowOf(Configuration.ORIENTATION_LANDSCAPE)
|
||||
override val rotation: Flow<Int> = flowOf(Surface.ROTATION_0)
|
||||
override val rotationFromDefault: Flow<Int> = flowOf(Surface.ROTATION_0)
|
||||
override val rotation: Flow<Int> = flowOf(Surface.ROTATION_0)
|
||||
override val rotationFromDefault: Flow<Int> = flowOf(Surface.ROTATION_0)
|
||||
|
||||
override fun getRotationFromDefault(rotation: Int): Int = rotation
|
||||
}
|
||||
underTest =
|
||||
FingerprintEnrollFindSensorViewModel.FingerprintEnrollFindSensorViewModelFactory(
|
||||
navigationViewModel,
|
||||
enrollViewModel,
|
||||
gatekeeperViewModel,
|
||||
backgroundViewModel,
|
||||
accessibilityInteractor,
|
||||
foldStateInteractor,
|
||||
orientationInteractor,
|
||||
fingerprintFlowViewModel,
|
||||
fakeFingerprintManagerInteractor,
|
||||
)
|
||||
.create(FingerprintEnrollFindSensorViewModel::class.java)
|
||||
FingerprintEnrollFindSensorViewModel(
|
||||
navigationViewModel,
|
||||
enrollViewModel,
|
||||
gatekeeperViewModel,
|
||||
backgroundViewModel,
|
||||
fingerprintFlowViewModel,
|
||||
accessibilityInteractor,
|
||||
foldStateInteractor,
|
||||
orientationInteractor,
|
||||
fakeFingerprintManagerInteractor,
|
||||
)
|
||||
}
|
||||
|
||||
@After
|
||||
|
@@ -23,22 +23,23 @@ import android.hardware.fingerprint.FingerprintSensorProperties
|
||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import com.android.settings.biometrics.fingerprint2.lib.model.Default
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintAction
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollConfirmationViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintFlowViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel
|
||||
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.android.systemui.biometrics.shared.model.toFingerprintSensor
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.advanceUntilIdle
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.resetMain
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.coroutines.test.setMain
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
@@ -53,44 +54,70 @@ class FingerprintEnrollConfirmationViewModelTest {
|
||||
@get:Rule val instantTaskRule = InstantTaskExecutorRule()
|
||||
private var backgroundDispatcher = StandardTestDispatcher()
|
||||
private var testScope = TestScope(backgroundDispatcher)
|
||||
val fingerprintFlowViewModel = FingerprintFlowViewModel(Default)
|
||||
val fingerprintFlowViewModel = FingerprintFlowViewModel()
|
||||
val fakeFingerprintManagerInteractor = FakeFingerprintManagerInteractor()
|
||||
lateinit var navigationViewModel: FingerprintNavigationViewModel
|
||||
lateinit var underTest: FingerprintEnrollConfirmationViewModel
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
navigationViewModel =
|
||||
FingerprintNavigationViewModel(
|
||||
FingerprintNavigationStep.Confirmation,
|
||||
false,
|
||||
fingerprintFlowViewModel,
|
||||
fakeFingerprintManagerInteractor,
|
||||
)
|
||||
Dispatchers.setMain(backgroundDispatcher)
|
||||
fingerprintFlowViewModel.updateFlowType(Default)
|
||||
navigationViewModel = FingerprintNavigationViewModel(fakeFingerprintManagerInteractor)
|
||||
underTest =
|
||||
FingerprintEnrollConfirmationViewModel(navigationViewModel, fakeFingerprintManagerInteractor)
|
||||
navigationViewModel.updateFingerprintFlow(Default)
|
||||
navigationViewModel.hasConfirmedDeviceCredential(true)
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
Dispatchers.resetMain()
|
||||
}
|
||||
|
||||
private fun bringToConfirmation() {
|
||||
navigationViewModel.update(
|
||||
FingerprintAction.NEXT,
|
||||
FingerprintNavigationStep.Introduction::class,
|
||||
"Intro.Test.NEXT",
|
||||
)
|
||||
navigationViewModel.update(
|
||||
FingerprintAction.NEXT,
|
||||
FingerprintNavigationStep.Education::class,
|
||||
"Edu.Test.NEXT",
|
||||
)
|
||||
navigationViewModel.update(
|
||||
FingerprintAction.NEXT,
|
||||
FingerprintNavigationStep.Enrollment::class,
|
||||
"Enrollment.Test.NEXT",
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCanEnrollFingerprints() =
|
||||
testScope.runTest {
|
||||
fakeFingerprintManagerInteractor.sensorProp = FingerprintSensorPropertiesInternal(
|
||||
0 /* sensorId */,
|
||||
SensorProperties.STRENGTH_STRONG,
|
||||
5 /* maxEnrollmentsPerUser */,
|
||||
listOf<ComponentInfoInternal>(),
|
||||
FingerprintSensorProperties.TYPE_POWER_BUTTON,
|
||||
false /* halControlsIllumination */,
|
||||
true /* resetLockoutRequiresHardwareAuthToken */,
|
||||
listOf<SensorLocationInternal>(SensorLocationInternal.DEFAULT),
|
||||
)
|
||||
.toFingerprintSensor()
|
||||
advanceUntilIdle()
|
||||
bringToConfirmation()
|
||||
fakeFingerprintManagerInteractor.sensorProp =
|
||||
FingerprintSensorPropertiesInternal(
|
||||
0 /* sensorId */,
|
||||
SensorProperties.STRENGTH_STRONG,
|
||||
5 /* maxEnrollmentsPerUser */,
|
||||
listOf<ComponentInfoInternal>(),
|
||||
FingerprintSensorProperties.TYPE_POWER_BUTTON,
|
||||
false /* halControlsIllumination */,
|
||||
true /* resetLockoutRequiresHardwareAuthToken */,
|
||||
listOf<SensorLocationInternal>(SensorLocationInternal.DEFAULT),
|
||||
)
|
||||
.toFingerprintSensor()
|
||||
|
||||
fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = mutableListOf()
|
||||
fakeFingerprintManagerInteractor.enrollableFingerprints = 5
|
||||
|
||||
var canEnrollFingerprints: Boolean = false
|
||||
val job = launch { underTest.isAddAnotherButtonVisible.collect { canEnrollFingerprints = it } }
|
||||
val job = launch {
|
||||
underTest.isAddAnotherButtonVisible.collect { canEnrollFingerprints = it }
|
||||
}
|
||||
|
||||
advanceUntilIdle()
|
||||
assertThat(canEnrollFingerprints).isTrue()
|
||||
@@ -100,12 +127,14 @@ class FingerprintEnrollConfirmationViewModelTest {
|
||||
@Test
|
||||
fun testNextButtonSendsNextStep() =
|
||||
testScope.runTest {
|
||||
advanceUntilIdle()
|
||||
bringToConfirmation()
|
||||
var step: FingerprintNavigationStep.UiStep? = null
|
||||
val job = launch { navigationViewModel.navigateTo.collect { step = it } }
|
||||
|
||||
underTest.onNextButtonClicked()
|
||||
|
||||
runCurrent()
|
||||
advanceUntilIdle()
|
||||
|
||||
assertThat(step).isNull()
|
||||
job.cancel()
|
||||
@@ -114,14 +143,18 @@ class FingerprintEnrollConfirmationViewModelTest {
|
||||
@Test
|
||||
fun testAddAnotherSendsAction() =
|
||||
testScope.runTest {
|
||||
advanceUntilIdle()
|
||||
bringToConfirmation()
|
||||
advanceUntilIdle()
|
||||
|
||||
var step: FingerprintNavigationStep.UiStep? = null
|
||||
val job = launch { navigationViewModel.navigateTo.collect { step = it } }
|
||||
|
||||
underTest.onAddAnotherButtonClicked()
|
||||
|
||||
runCurrent()
|
||||
advanceUntilIdle()
|
||||
|
||||
assertThat(step).isInstanceOf(FingerprintNavigationStep.Enrollment::class.java)
|
||||
assertThat(step).isNull()
|
||||
job.cancel()
|
||||
}
|
||||
}
|
||||
|
@@ -28,9 +28,7 @@ import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Fing
|
||||
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.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.testutils2.FakeFingerprintManagerInteractor
|
||||
import com.android.systemui.biometrics.shared.model.toFingerprintSensor
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
@@ -61,20 +59,15 @@ class FingerprintEnrollEnrollingViewModelTest {
|
||||
private lateinit var backgroundViewModel: BackgroundViewModel
|
||||
private lateinit var gateKeeperViewModel: FingerprintGatekeeperViewModel
|
||||
private lateinit var navigationViewModel: FingerprintNavigationViewModel
|
||||
private val defaultGatekeeperInfo = GatekeeperInfo.GatekeeperPasswordInfo(byteArrayOf(1, 3), 3)
|
||||
private var testScope = TestScope(backgroundDispatcher)
|
||||
|
||||
private lateinit var fakeFingerprintManagerInteractor: FakeFingerprintManagerInteractor
|
||||
|
||||
private fun initialize(gatekeeperInfo: GatekeeperInfo = defaultGatekeeperInfo) {
|
||||
private fun initialize() {
|
||||
fakeFingerprintManagerInteractor = FakeFingerprintManagerInteractor()
|
||||
gateKeeperViewModel =
|
||||
FingerprintGatekeeperViewModel.FingerprintGatekeeperViewModelFactory(
|
||||
gatekeeperInfo,
|
||||
fakeFingerprintManagerInteractor,
|
||||
)
|
||||
.create(FingerprintGatekeeperViewModel::class.java)
|
||||
val sensor =
|
||||
|
||||
gateKeeperViewModel = FingerprintGatekeeperViewModel(fakeFingerprintManagerInteractor)
|
||||
fakeFingerprintManagerInteractor.sensorProp =
|
||||
FingerprintSensorPropertiesInternal(
|
||||
1 /* sensorId */,
|
||||
SensorProperties.STRENGTH_STRONG,
|
||||
@@ -86,32 +79,21 @@ class FingerprintEnrollEnrollingViewModelTest {
|
||||
listOf<SensorLocationInternal>(SensorLocationInternal.DEFAULT),
|
||||
)
|
||||
.toFingerprintSensor()
|
||||
val fingerprintFlowViewModel = FingerprintFlowViewModel(Default)
|
||||
val fingerprintFlowViewModel = FingerprintFlowViewModel()
|
||||
fingerprintFlowViewModel.updateFlowType(Default)
|
||||
|
||||
navigationViewModel =
|
||||
FingerprintNavigationViewModel(
|
||||
Enrollment(sensor),
|
||||
false,
|
||||
fingerprintFlowViewModel,
|
||||
fakeFingerprintManagerInteractor,
|
||||
)
|
||||
navigationViewModel = FingerprintNavigationViewModel(fakeFingerprintManagerInteractor)
|
||||
|
||||
backgroundViewModel =
|
||||
BackgroundViewModel.BackgroundViewModelFactory().create(BackgroundViewModel::class.java)
|
||||
backgroundViewModel = BackgroundViewModel()
|
||||
backgroundViewModel.inForeground()
|
||||
val fingerprintEnrollViewModel =
|
||||
FingerprintEnrollViewModel.FingerprintEnrollViewModelFactory(
|
||||
fakeFingerprintManagerInteractor,
|
||||
gateKeeperViewModel,
|
||||
navigationViewModel,
|
||||
)
|
||||
.create(FingerprintEnrollViewModel::class.java)
|
||||
FingerprintEnrollViewModel(
|
||||
fakeFingerprintManagerInteractor,
|
||||
gateKeeperViewModel,
|
||||
navigationViewModel,
|
||||
)
|
||||
enrollEnrollingViewModel =
|
||||
FingerprintEnrollEnrollingViewModel.FingerprintEnrollEnrollingViewModelFactory(
|
||||
fingerprintEnrollViewModel,
|
||||
backgroundViewModel,
|
||||
)
|
||||
.create(FingerprintEnrollEnrollingViewModel::class.java)
|
||||
FingerprintEnrollEnrollingViewModel(fingerprintEnrollViewModel, backgroundViewModel)
|
||||
}
|
||||
|
||||
@Before
|
||||
@@ -128,6 +110,7 @@ class FingerprintEnrollEnrollingViewModelTest {
|
||||
@Test
|
||||
fun testEnrollShouldBeFalse() =
|
||||
testScope.runTest {
|
||||
gateKeeperViewModel.onConfirmDevice(true, 3L, false)
|
||||
var shouldEnroll = false
|
||||
|
||||
val job = launch {
|
||||
@@ -147,6 +130,7 @@ class FingerprintEnrollEnrollingViewModelTest {
|
||||
@Test
|
||||
fun testEnrollShouldBeFalseWhenBackground() =
|
||||
testScope.runTest {
|
||||
gateKeeperViewModel.onConfirmDevice(true, 3L, false)
|
||||
var shouldEnroll = false
|
||||
|
||||
val job = launch {
|
||||
|