Biometrics Enrollment refactor (7/N)

This cl moves the creation of repos and interactors to the
SettingsApplication.
Bug: 297082837
Test: atest

Change-Id: I9049da6f03bb1dc18d4186961444bf613d773d0e
This commit is contained in:
Joshua McCloskey
2024-05-01 22:30:25 +00:00
committed by Joshua Mccloskey
parent b2f88a16c9
commit 584b6c9e96
68 changed files with 1068 additions and 939 deletions

View File

@@ -108,6 +108,8 @@ android_library {
"telephony_flags_core_java_lib", "telephony_flags_core_java_lib",
"setupdesign-lottie-loading-layout", "setupdesign-lottie-loading-layout",
"device_policy_aconfig_flags_lib", "device_policy_aconfig_flags_lib",
"kotlinx-coroutines-core",
"kotlinx-coroutines-android",
], ],
plugins: ["androidx.room_room-compiler-plugin"], plugins: ["androidx.room_room-compiler-plugin"],

View File

@@ -24,9 +24,11 @@ import android.provider.Settings;
import android.util.FeatureFlagUtils; import android.util.FeatureFlagUtils;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.settings.activityembedding.ActivityEmbeddingRulesController; import com.android.settings.activityembedding.ActivityEmbeddingRulesController;
import com.android.settings.activityembedding.ActivityEmbeddingUtils; import com.android.settings.activityembedding.ActivityEmbeddingUtils;
import com.android.settings.biometrics.fingerprint2.BiometricsEnvironment;
import com.android.settings.core.instrumentation.ElapsedTimeUtils; import com.android.settings.core.instrumentation.ElapsedTimeUtils;
import com.android.settings.development.DeveloperOptionsActivityLifecycle; import com.android.settings.development.DeveloperOptionsActivityLifecycle;
import com.android.settings.fuelgauge.BatterySettingsStorage; import com.android.settings.fuelgauge.BatterySettingsStorage;
@@ -47,6 +49,7 @@ import java.lang.ref.WeakReference;
public class SettingsApplication extends Application { public class SettingsApplication extends Application {
private WeakReference<SettingsHomepageActivity> mHomeActivity = new WeakReference<>(null); private WeakReference<SettingsHomepageActivity> mHomeActivity = new WeakReference<>(null);
private BiometricsEnvironment mBiometricsEnvironment;
@Override @Override
protected void attachBaseContext(Context base) { protected void attachBaseContext(Context base) {
@@ -70,6 +73,7 @@ public class SettingsApplication extends Application {
// Set Spa environment. // Set Spa environment.
setSpaEnvironment(); setSpaEnvironment();
mBiometricsEnvironment = new BiometricsEnvironment(this);
if (ActivityEmbeddingUtils.isSettingsSplitEnabled(this) if (ActivityEmbeddingUtils.isSettingsSplitEnabled(this)
&& FeatureFlagUtils.isEnabled(this, && FeatureFlagUtils.isEnabled(this,
@@ -111,6 +115,11 @@ public class SettingsApplication extends Application {
return mHomeActivity.get(); return mHomeActivity.get();
} }
@Nullable
public BiometricsEnvironment getBiometricEnvironment() {
return mBiometricsEnvironment;
}
@Override @Override
public void onTrimMemory(int level) { public void onTrimMemory(int level) {
super.onTrimMemory(level); super.onTrimMemory(level);

View File

@@ -184,7 +184,6 @@ public class UdfpsEnrollHelper extends InstrumentedFragment {
*/ */
public void onAcquired(boolean isAcquiredGood) { public void onAcquired(boolean isAcquiredGood) {
if (mListener != null) { if (mListener != null) {
Log.e("JRM", "OnaCquired " + isAcquiredGood + " lastStepIsGood" + animateIfLastStep());
mListener.onAcquired(isAcquiredGood && animateIfLastStep()); mListener.onAcquired(isAcquiredGood && animateIfLastStep());
} }
} }

View File

@@ -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()
}

View File

@@ -23,6 +23,7 @@ interface DebuggingRepository {
/** A function that will return if a build is debuggable */ /** A function that will return if a build is debuggable */
fun isDebuggingEnabled(): Boolean fun isDebuggingEnabled(): Boolean
/** A function that will return if udfps enrollment should be swapped with debug repos */ /** A function that will return if udfps enrollment should be swapped with debug repos */
fun isUdfpsEnrollmentDebuggingEnabled(): Boolean fun isUdfpsEnrollmentDebuggingEnabled(): Boolean
} }

View File

@@ -46,7 +46,7 @@ interface FingerprintSensorRepository {
} }
class FingerprintSensorRepositoryImpl( class FingerprintSensorRepositoryImpl(
fingerprintManager: FingerprintManager, fingerprintManager: FingerprintManager?,
backgroundDispatcher: CoroutineDispatcher, backgroundDispatcher: CoroutineDispatcher,
activityScope: CoroutineScope, activityScope: CoroutineScope,
) : FingerprintSensorRepository { ) : FingerprintSensorRepository {
@@ -73,12 +73,9 @@ class FingerprintSensorRepositoryImpl(
.stateIn(activityScope, started = SharingStarted.Eagerly, initialValue = DEFAULT_PROPS) .stateIn(activityScope, started = SharingStarted.Eagerly, initialValue = DEFAULT_PROPS)
override val fingerprintSensor: Flow<FingerprintSensor> = override val fingerprintSensor: Flow<FingerprintSensor> =
fingerprintPropsInternal.transform { fingerprintPropsInternal.transform { emit(it.toFingerprintSensor()) }
emit(it.toFingerprintSensor())
}
companion object { companion object {
private const val TAG = "FingerprintSensorRepoImpl"
private val DEFAULT_PROPS = private val DEFAULT_PROPS =
FingerprintSensorPropertiesInternal( FingerprintSensorPropertiesInternal(

View File

@@ -17,6 +17,7 @@
package com.android.settings.biometrics.fingerprint2.data.repository package com.android.settings.biometrics.fingerprint2.data.repository
import android.graphics.Point import android.graphics.Point
import android.view.MotionEvent
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
/** /**
@@ -24,8 +25,6 @@ import kotlinx.coroutines.flow.Flow
* that talkback is correct. * that talkback is correct.
*/ */
interface SimulatedTouchEventsRepository { interface SimulatedTouchEventsRepository {
/** /** A flow simulating user touches. */
* A flow simulating user touches. val touchExplorationDebug: Flow<MotionEvent>
*/
val touchExplorationDebug: Flow<Point>
} }

View File

@@ -14,10 +14,14 @@
* limitations under the License. * 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.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.domain.interactor.FingerprintEnrollInteractor
import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason 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.FingerEnrollState
@@ -36,7 +40,11 @@ import kotlinx.coroutines.flow.flowOf
class UdfpsEnrollDebugRepositoryImpl : class UdfpsEnrollDebugRepositoryImpl :
FingerprintEnrollInteractor, FingerprintSensorRepository, SimulatedTouchEventsRepository { 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) emit(FingerEnrollState.OverlayShown)
delay(200) delay(200)
emit(FingerEnrollState.EnrollHelp(helpMsgId, "Hello world")) emit(FingerEnrollState.EnrollHelp(helpMsgId, "Hello world"))
@@ -77,7 +85,7 @@ class UdfpsEnrollDebugRepositoryImpl :
} }
/** Provides touch events to the UdfpsEnrollFragment */ /** Provides touch events to the UdfpsEnrollFragment */
override val touchExplorationDebug: Flow<Point> = flow { override val touchExplorationDebug: Flow<MotionEvent> = flow {
delay(2000) delay(2000)
emit(pointToLeftOfSensor(sensorRect)) emit(pointToLeftOfSensor(sensorRect))
delay(2000) delay(2000)
@@ -90,17 +98,45 @@ class UdfpsEnrollDebugRepositoryImpl :
override val fingerprintSensor: Flow<FingerprintSensor> = flowOf(sensorProps) override val fingerprintSensor: Flow<FingerprintSensor> = flowOf(sensorProps)
private fun pointToLeftOfSensor(sensorLocation: Rect) = private fun pointToLeftOfSensor(sensorLocation: Rect): MotionEvent =
Point(sensorLocation.right + 5, sensorLocation.centerY()) MotionEvent.obtain(
100,
100,
ACTION_HOVER_MOVE,
sensorLocation.right + 5.0f,
sensorLocation.centerY().toFloat(),
0,
)
private fun pointToRightOfSensor(sensorLocation: Rect) = private fun pointToRightOfSensor(sensorLocation: Rect): MotionEvent =
Point(sensorLocation.left - 5, sensorLocation.centerY()) MotionEvent.obtain(
100,
100,
ACTION_HOVER_MOVE,
sensorLocation.right - 5.0f,
sensorLocation.centerY().toFloat(),
0,
)
private fun pointBelowSensor(sensorLocation: Rect) = private fun pointBelowSensor(sensorLocation: Rect): MotionEvent =
Point(sensorLocation.centerX(), sensorLocation.bottom + 5) MotionEvent.obtain(
100,
100,
ACTION_HOVER_MOVE,
sensorLocation.centerX().toFloat(),
sensorLocation.bottom + 5.0f,
0,
)
private fun pointAboveSensor(sensorLocation: Rect) = private fun pointAboveSensor(sensorLocation: Rect): MotionEvent =
Point(sensorLocation.centerX(), sensorLocation.top - 5) MotionEvent.obtain(
100,
100,
ACTION_HOVER_MOVE,
sensorLocation.centerX().toFloat(),
sensorLocation.top - 5.0f,
0,
)
companion object { companion object {
@@ -109,10 +145,10 @@ class UdfpsEnrollDebugRepositoryImpl :
private val sensorRadius = 100 private val sensorRadius = 100
private val sensorRect = private val sensorRect =
Rect( Rect(
this.sensorLocationInternal.first - sensorRadius, sensorLocationInternal.first - sensorRadius,
this.sensorLocationInternal.second - sensorRadius, sensorLocationInternal.second - sensorRadius,
this.sensorLocationInternal.first + sensorRadius, sensorLocationInternal.first + sensorRadius,
this.sensorLocationInternal.second + sensorRadius, sensorLocationInternal.second + sensorRadius,
) )
val sensorProps = val sensorProps =
FingerprintSensor( FingerprintSensor(

View File

@@ -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
}

View File

@@ -17,7 +17,7 @@
package com.android.settings.biometrics.fingerprint2.domain.interactor package com.android.settings.biometrics.fingerprint2.domain.interactor
import android.view.accessibility.AccessibilityManager import android.view.accessibility.AccessibilityManager
import androidx.lifecycle.LifecycleCoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
@@ -32,7 +32,7 @@ interface AccessibilityInteractor {
class AccessibilityInteractorImpl( class AccessibilityInteractorImpl(
accessibilityManager: AccessibilityManager, accessibilityManager: AccessibilityManager,
activityScope: LifecycleCoroutineScope applicationScope: CoroutineScope,
) : AccessibilityInteractor { ) : AccessibilityInteractor {
/** A flow that contains whether or not accessibility is enabled */ /** A flow that contains whether or not accessibility is enabled */
override val isAccessibilityEnabled: Flow<Boolean> = override val isAccessibilityEnabled: Flow<Boolean> =
@@ -45,8 +45,8 @@ class AccessibilityInteractorImpl(
awaitClose { accessibilityManager.removeAccessibilityStateChangeListener(listener) } awaitClose { accessibilityManager.removeAccessibilityStateChangeListener(listener) }
} }
.stateIn( .stateIn(
activityScope, // This is going to tied to the activity scope applicationScope, // This is going to tied to the activity scope
SharingStarted.WhileSubscribed(), // When no longer subscribed, we removeTheListener SharingStarted.WhileSubscribed(), // When no longer subscribed, we removeTheListener
false false,
) )
} }

View File

@@ -28,9 +28,7 @@ interface DebuggingInteractor {
val udfpsEnrollmentDebuggingEnabled: Flow<Boolean> val udfpsEnrollmentDebuggingEnabled: Flow<Boolean>
} }
/** /** This interactor essentially forwards the [DebuggingRepository] */
* This interactor essentially forwards the [DebuggingRepository]
*/
class DebuggingInteractorImpl(val debuggingRepository: DebuggingRepository) : DebuggingInteractor { class DebuggingInteractorImpl(val debuggingRepository: DebuggingRepository) : DebuggingInteractor {
override val debuggingEnabled: Flow<Boolean> = flow { override val debuggingEnabled: Flow<Boolean> = flow {
emit(debuggingRepository.isDebuggingEnabled()) emit(debuggingRepository.isDebuggingEnabled())

View File

@@ -16,6 +16,8 @@
package com.android.settings.biometrics.fingerprint2.domain.interactor 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.CoroutineScope
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@@ -50,12 +52,11 @@ interface DisplayDensityInteractor {
* Implementation of the [DisplayDensityInteractor]. This interactor is used to forward activity * Implementation of the [DisplayDensityInteractor]. This interactor is used to forward activity
* information to the rest of the application. * information to the rest of the application.
*/ */
class DisplayDensityInteractorImpl( class DisplayDensityInteractorImpl(context: Context, scope: CoroutineScope) :
currentFontScale: Float, DisplayDensityInteractor {
currentDisplayDensity: Int,
defaultDisplayDensity: Int, val displayDensityUtils = DisplayDensityUtils(context)
scope: CoroutineScope,
) : DisplayDensityInteractor {
override fun updateDisplayDensity(density: Int) { override fun updateDisplayDensity(density: Int) {
_displayDensity.update { density } _displayDensity.update { density }
} }
@@ -64,13 +65,18 @@ class DisplayDensityInteractorImpl(
_fontScale.update { fontScale } _fontScale.update { fontScale }
} }
private val _fontScale = MutableStateFlow(currentFontScale) private val _fontScale = MutableStateFlow(context.resources.configuration.fontScale)
private val _displayDensity = MutableStateFlow(currentDisplayDensity) private val _displayDensity =
MutableStateFlow(
displayDensityUtils.defaultDisplayDensityValues[
displayDensityUtils.currentIndexForDefaultDisplay]
)
override val fontScale: Flow<Float> = _fontScale.asStateFlow() override val fontScale: Flow<Float> = _fontScale.asStateFlow()
override val displayDensity: Flow<Int> = _displayDensity.asStateFlow() override val displayDensity: Flow<Int> = _displayDensity.asStateFlow()
override val defaultDisplayDensity: Flow<Int> = override val defaultDisplayDensity: Flow<Int> =
flowOf(defaultDisplayDensity).shareIn(scope, SharingStarted.Eagerly, 1) flowOf(displayDensityUtils.defaultDensityForDefaultDisplay)
.shareIn(scope, SharingStarted.Eagerly, 1)
} }

View File

@@ -33,7 +33,6 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.transform
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
/** This repository is responsible for collecting all state related to the enroll API. */ /** This repository is responsible for collecting all state related to the enroll API. */
@@ -45,13 +44,13 @@ interface FingerprintEnrollInteractor {
suspend fun enroll( suspend fun enroll(
hardwareAuthToken: ByteArray?, hardwareAuthToken: ByteArray?,
enrollReason: EnrollReason, enrollReason: EnrollReason,
fingerprintEnrollOptions: FingerprintEnrollOptions,
): Flow<FingerEnrollState> ): Flow<FingerEnrollState>
} }
class FingerprintEnrollInteractorImpl( class FingerprintEnrollInteractorImpl(
private val applicationContext: Context, private val applicationContext: Context,
private val fingerprintEnrollOptions: FingerprintEnrollOptions, private val fingerprintManager: FingerprintManager?,
private val fingerprintManager: FingerprintManager,
private val fingerprintFlow: FingerprintFlow, private val fingerprintFlow: FingerprintFlow,
) : FingerprintEnrollInteractor { ) : FingerprintEnrollInteractor {
private val enrollRequestOutstanding = MutableStateFlow(false) private val enrollRequestOutstanding = MutableStateFlow(false)
@@ -59,6 +58,7 @@ class FingerprintEnrollInteractorImpl(
override suspend fun enroll( override suspend fun enroll(
hardwareAuthToken: ByteArray?, hardwareAuthToken: ByteArray?,
enrollReason: EnrollReason, enrollReason: EnrollReason,
fingerprintEnrollOptions: FingerprintEnrollOptions,
): Flow<FingerEnrollState> = callbackFlow { ): Flow<FingerEnrollState> = callbackFlow {
// TODO (b/308456120) Improve this logic // TODO (b/308456120) Improve this logic
if (enrollRequestOutstanding.value) { if (enrollRequestOutstanding.value) {
@@ -135,7 +135,7 @@ class FingerprintEnrollInteractorImpl(
val cancellationSignal = CancellationSignal() val cancellationSignal = CancellationSignal()
fingerprintManager.enroll( fingerprintManager?.enroll(
hardwareAuthToken, hardwareAuthToken,
cancellationSignal, cancellationSignal,
applicationContext.userId, applicationContext.userId,

View File

@@ -18,6 +18,7 @@ package com.android.settings.biometrics.fingerprint2.domain.interactor
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.hardware.fingerprint.FingerprintEnrollOptions
import android.hardware.fingerprint.FingerprintManager import android.hardware.fingerprint.FingerprintManager
import android.hardware.fingerprint.FingerprintManager.GenerateChallengeCallback import android.hardware.fingerprint.FingerprintManager.GenerateChallengeCallback
import android.hardware.fingerprint.FingerprintManager.RemovalCallback import android.hardware.fingerprint.FingerprintManager.RemovalCallback
@@ -45,7 +46,7 @@ private const val TAG = "FingerprintManagerInteractor"
class FingerprintManagerInteractorImpl( class FingerprintManagerInteractorImpl(
applicationContext: Context, applicationContext: Context,
private val backgroundDispatcher: CoroutineDispatcher, private val backgroundDispatcher: CoroutineDispatcher,
private val fingerprintManager: FingerprintManager, private val fingerprintManager: FingerprintManager?,
fingerprintSensorRepository: FingerprintSensorRepository, fingerprintSensorRepository: FingerprintSensorRepository,
private val gatekeeperPasswordProvider: GatekeeperPasswordProvider, private val gatekeeperPasswordProvider: GatekeeperPasswordProvider,
private val fingerprintEnrollStateRepository: FingerprintEnrollInteractor, private val fingerprintEnrollStateRepository: FingerprintEnrollInteractor,
@@ -57,7 +58,6 @@ class FingerprintManagerInteractorImpl(
) )
private val applicationContext = applicationContext.applicationContext private val applicationContext = applicationContext.applicationContext
override suspend fun generateChallenge(gateKeeperPasswordHandle: Long): Pair<Long, ByteArray> = override suspend fun generateChallenge(gateKeeperPasswordHandle: Long): Pair<Long, ByteArray> =
suspendCoroutine { suspendCoroutine {
val callback = GenerateChallengeCallback { _, userId, challenge -> val callback = GenerateChallengeCallback { _, userId, challenge ->
@@ -70,21 +70,19 @@ class FingerprintManagerInteractorImpl(
val p = Pair(challenge, challengeToken) val p = Pair(challenge, challengeToken)
it.resume(p) 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( emit(
fingerprintManager fingerprintManager?.getEnrolledFingerprints(applicationContext.userId)
.getEnrolledFingerprints(applicationContext.userId) ?.map { (FingerprintData(it.name.toString(), it.biometricId, it.deviceId)) }?.toList()
.map { (FingerprintData(it.name.toString(), it.biometricId, it.deviceId)) }
.toList()
) )
} }
override val canEnrollFingerprints: Flow<Boolean> = flow { override val canEnrollFingerprints: Flow<Boolean> = flow {
emit( 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 val maxEnrollableFingerprints = flow { emit(maxFingerprints) }
override suspend fun enroll(hardwareAuthToken: ByteArray?, enrollReason: EnrollReason): Flow<FingerEnrollState> = override suspend fun enroll(
fingerprintEnrollStateRepository.enroll(hardwareAuthToken, enrollReason) hardwareAuthToken: ByteArray?,
enrollReason: EnrollReason,
fingerprintEnrollOptions: FingerprintEnrollOptions,
): Flow<FingerEnrollState> =
fingerprintEnrollStateRepository.enroll(
hardwareAuthToken,
enrollReason,
fingerprintEnrollOptions,
)
override suspend fun removeFingerprint(fp: FingerprintData): Boolean = suspendCoroutine { override suspend fun removeFingerprint(fp: FingerprintData): Boolean = suspendCoroutine {
val callback = val callback =
@@ -113,7 +119,7 @@ class FingerprintManagerInteractorImpl(
it.resume(true) it.resume(true)
} }
} }
fingerprintManager.remove( fingerprintManager?.remove(
android.hardware.fingerprint.Fingerprint(fp.name, fp.fingerId, fp.deviceId), android.hardware.fingerprint.Fingerprint(fp.name, fp.fingerId, fp.deviceId),
applicationContext.userId, applicationContext.userId,
callback, callback,
@@ -122,12 +128,12 @@ class FingerprintManagerInteractorImpl(
override suspend fun renameFingerprint(fp: FingerprintData, newName: String) { override suspend fun renameFingerprint(fp: FingerprintData, newName: String) {
withContext(backgroundDispatcher) { withContext(backgroundDispatcher) {
fingerprintManager.rename(fp.fingerId, applicationContext.userId, newName) fingerprintManager?.rename(fp.fingerId, applicationContext.userId, newName)
} }
} }
override suspend fun hasSideFps(): Boolean = suspendCancellableCoroutine { override suspend fun hasSideFps(): Boolean? = suspendCancellableCoroutine {
it.resume(fingerprintManager.isPowerbuttonFps) it.resume(fingerprintManager?.isPowerbuttonFps)
} }
override suspend fun authenticate(): FingerprintAuthAttemptModel = override suspend fun authenticate(): FingerprintAuthAttemptModel =
@@ -156,7 +162,7 @@ class FingerprintManagerInteractorImpl(
val cancellationSignal = CancellationSignal() val cancellationSignal = CancellationSignal()
c.invokeOnCancellation { cancellationSignal.cancel() } c.invokeOnCancellation { cancellationSignal.cancel() }
fingerprintManager.authenticate( fingerprintManager?.authenticate(
null, null,
cancellationSignal, cancellationSignal,
authenticationCallback, authenticationCallback,
@@ -164,5 +170,4 @@ class FingerprintManagerInteractorImpl(
applicationContext.userId, applicationContext.userId,
) )
} }
} }

View File

@@ -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
}

View File

@@ -29,15 +29,12 @@ interface FoldStateInteractor {
val isFolded: Flow<Boolean> val isFolded: Flow<Boolean>
/** /**
* Indicates a configuration change has occurred, and the repo * Indicates a configuration change has occurred, and the repo should update the [isFolded] flow.
* should update the [isFolded] flow.
*/ */
fun onConfigurationChange(newConfig: Configuration) fun onConfigurationChange(newConfig: Configuration)
} }
/** /** Interactor which handles fold state */
* Interactor which handles fold state
*/
class FoldStateInteractorImpl(context: Context) : FoldStateInteractor { class FoldStateInteractorImpl(context: Context) : FoldStateInteractor {
private val screenSizeFoldProvider = ScreenSizeFoldProvider(context) private val screenSizeFoldProvider = ScreenSizeFoldProvider(context)
override val isFolded: Flow<Boolean> = callbackFlow { override val isFolded: Flow<Boolean> = callbackFlow {
@@ -54,5 +51,4 @@ class FoldStateInteractorImpl(context: Context) : FoldStateInteractor {
override fun onConfigurationChange(newConfig: Configuration) { override fun onConfigurationChange(newConfig: Configuration) {
screenSizeFoldProvider.onConfigurationChange(newConfig) screenSizeFoldProvider.onConfigurationChange(newConfig)
} }
} }

View File

@@ -60,10 +60,7 @@ class OrientationInteractorImpl(private val context: Context) : OrientationInter
awaitClose { orientationEventListener.disable() } awaitClose { orientationEventListener.disable() }
} }
override val rotation: Flow<Int> = override val rotation: Flow<Int> = orientation.transform { emit(context.display.rotation) }
orientation.transform {
emit(context.display!!.rotation)
}
override val rotationFromDefault: Flow<Int> = rotation.map { getRotationFromDefault(it) } override val rotationFromDefault: Flow<Int> = rotation.map { getRotationFromDefault(it) }

View File

@@ -38,19 +38,14 @@ class PressToAuthInteractorImpl(
private val backgroundDispatcher: CoroutineDispatcher, private val backgroundDispatcher: CoroutineDispatcher,
) : PressToAuthInteractor { ) : PressToAuthInteractor {
/** /** A flow that contains the status of the press to auth feature. */
* A flow that contains the status of the press to auth feature.
*/
override val isEnabled: Flow<Boolean> = override val isEnabled: Flow<Boolean> =
callbackFlow { callbackFlow {
val callback = val callback =
object : ContentObserver(null) { object : ContentObserver(null) {
override fun onChange(selfChange: Boolean) { override fun onChange(selfChange: Boolean) {
Log.d(TAG, "SFPS_PERFORMANT_AUTH_ENABLED#onchange") Log.d(TAG, "SFPS_PERFORMANT_AUTH_ENABLED#onchange")
trySend( trySend(getPressToAuth())
getPressToAuth(),
)
} }
} }
@@ -58,18 +53,14 @@ class PressToAuthInteractorImpl(
Settings.Secure.getUriFor(Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED), Settings.Secure.getUriFor(Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED),
false, false,
callback, callback,
context.userId context.userId,
) )
trySend(getPressToAuth()) trySend(getPressToAuth())
awaitClose { awaitClose { context.contentResolver.unregisterContentObserver(callback) }
context.contentResolver.unregisterContentObserver(callback)
} }
}.flowOn(backgroundDispatcher) .flowOn(backgroundDispatcher)
/** Returns true if press to auth is enabled */
/**
* Returns true if press to auth is enabled
*/
private fun getPressToAuth(): Boolean { private fun getPressToAuth(): Boolean {
var toReturn: Int = var toReturn: Int =
Settings.Secure.getIntForUser( Settings.Secure.getIntForUser(
@@ -95,7 +86,6 @@ class PressToAuthInteractorImpl(
) )
} }
return toReturn == 1 return toReturn == 1
} }
companion object { companion object {

View File

@@ -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>
}

View File

@@ -16,8 +16,9 @@
package com.android.settings.biometrics.fingerprint2.domain.interactor package com.android.settings.biometrics.fingerprint2.domain.interactor
import android.content.Context
import android.graphics.PointF import android.graphics.PointF
import android.util.Log import android.util.TypedValue
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
@@ -43,13 +44,18 @@ interface UdfpsEnrollInteractor {
/** Keeps track of which guided enrollment point we should be using */ /** Keeps track of which guided enrollment point we should be using */
class UdfpsEnrollInteractorImpl( class UdfpsEnrollInteractorImpl(
pixelsPerMillimeter: Float, applicationContext: Context,
accessibilityInteractor: AccessibilityInteractor, accessibilityInteractor: AccessibilityInteractor,
) : UdfpsEnrollInteractor { ) : UdfpsEnrollInteractor {
private var isGuidedEnrollment = MutableStateFlow(false) private var isGuidedEnrollment = MutableStateFlow(false)
// Number of pixels per mm // 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> = private val guidedEnrollmentPoints: MutableList<PointF> =
mutableListOf( mutableListOf(
PointF(2.00f * px, 0.00f * px), PointF(2.00f * px, 0.00f * px),
@@ -70,7 +76,6 @@ class UdfpsEnrollInteractorImpl(
override fun onEnrollmentStep(stepsRemaining: Int, totalStep: Int) { override fun onEnrollmentStep(stepsRemaining: Int, totalStep: Int) {
val index = (totalStep - stepsRemaining) % guidedEnrollmentPoints.size val index = (totalStep - stepsRemaining) % guidedEnrollmentPoints.size
Log.e("JRM", "guided enroll step $index")
_guidedEnrollment.update { guidedEnrollmentPoints[index] } _guidedEnrollment.update { guidedEnrollmentPoints[index] }
} }

View File

@@ -36,6 +36,7 @@ sealed class FingerprintVibrationEffects {
/** This vibration typically occurs when a help message is shown during UDFPS enrollment */ /** This vibration typically occurs when a help message is shown during UDFPS enrollment */
data object UdfpsHelp : FingerprintVibrationEffects() data object UdfpsHelp : FingerprintVibrationEffects()
} }
/** Interface for sending haptic feedback */ /** Interface for sending haptic feedback */
interface VibrationInteractor { interface VibrationInteractor {
/** This will send a haptic vibration */ /** This will send a haptic vibration */
@@ -43,8 +44,9 @@ interface VibrationInteractor {
} }
/** Implementation of the VibrationInteractor interface */ /** Implementation of the VibrationInteractor interface */
class VibrationInteractorImpl(val vibrator: Vibrator, val applicationContext: Context) : class VibrationInteractorImpl(val applicationContext: Context) : VibrationInteractor {
VibrationInteractor { val vibrator = applicationContext.getSystemService(Vibrator::class.java)!!
override fun vibrate(effect: FingerprintVibrationEffects, caller: String) { override fun vibrate(effect: FingerprintVibrationEffects, caller: String) {
val callerString = "$caller::$effect" val callerString = "$caller::$effect"
val res = val res =

View File

@@ -16,7 +16,7 @@
package com.android.settings.biometrics.fingerprint2.lib.domain.interactor 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.EnrollReason
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel
@@ -32,7 +32,7 @@ import kotlinx.coroutines.flow.Flow
*/ */
interface FingerprintManagerInteractor { interface FingerprintManagerInteractor {
/** Returns the list of current fingerprints. */ /** 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 */ /** Returns the max enrollable fingerprints, note during SUW this might be 1 */
val maxEnrollableFingerprints: Flow<Int> val maxEnrollableFingerprints: Flow<Int>
@@ -62,6 +62,7 @@ interface FingerprintManagerInteractor {
suspend fun enroll( suspend fun enroll(
hardwareAuthToken: ByteArray?, hardwareAuthToken: ByteArray?,
enrollReason: EnrollReason, enrollReason: EnrollReason,
fingerprintEnrollOptions: FingerprintEnrollOptions,
): Flow<FingerEnrollState> ): Flow<FingerEnrollState>
/** /**
@@ -74,5 +75,5 @@ interface FingerprintManagerInteractor {
suspend fun renameFingerprint(fp: FingerprintData, newName: String) suspend fun renameFingerprint(fp: FingerprintData, newName: String)
/** Indicates if the device has side fingerprint */ /** Indicates if the device has side fingerprint */
suspend fun hasSideFps(): Boolean suspend fun hasSideFps(): Boolean?
} }

View File

@@ -24,5 +24,5 @@ enum class EnrollReason {
*/ */
FindSensor, FindSensor,
/** The enroll happens on enrolling screen. */ /** The enroll happens on enrolling screen. */
EnrollEnrolling EnrollEnrolling,
} }

View File

@@ -22,16 +22,12 @@ import android.content.res.Configuration
import android.hardware.fingerprint.FingerprintEnrollOptions import android.hardware.fingerprint.FingerprintEnrollOptions
import android.hardware.fingerprint.FingerprintManager import android.hardware.fingerprint.FingerprintManager
import android.os.Bundle import android.os.Bundle
import android.os.Vibrator
import android.util.Log import android.util.Log
import android.util.TypedValue
import android.view.accessibility.AccessibilityManager
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.android.internal.widget.LockPatternUtils
import com.android.settings.R import com.android.settings.R
import com.android.settings.SetupWizardUtils import com.android.settings.SetupWizardUtils
import com.android.settings.Utils.SETTINGS_PACKAGE_NAME import com.android.settings.Utils.SETTINGS_PACKAGE_NAME
@@ -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.BiometricEnrollBase.RESULT_FINISHED
import com.android.settings.biometrics.BiometricUtils import com.android.settings.biometrics.BiometricUtils
import com.android.settings.biometrics.GatekeeperPasswordProvider 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.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.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.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.lib.model.SetupWizard
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollConfirmationV2Fragment import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollConfirmationV2Fragment
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollEnrollingV2Fragment import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollEnrollingV2Fragment
@@ -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.RfpsEnrollFindSensorFragment
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.education.SfpsEnrollFindSensorFragment 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.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.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.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.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.BackgroundViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintAction 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.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.FingerprintEnrollViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintFlowViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintFlowViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
@@ -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.Introduction
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.TransitionStep 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.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.GatekeeperInfo
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Transition import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Transition
import com.android.settings.flags.Flags import com.android.settings.flags.Flags
@@ -113,23 +84,38 @@ private const val TAG = "FingerprintEnrollmentV2Activity"
* children fragments. * children fragments.
*/ */
class FingerprintEnrollmentV2Activity : FragmentActivity() { class FingerprintEnrollmentV2Activity : FragmentActivity() {
private lateinit var fingerprintEnrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel private val navigationViewModel: FingerprintNavigationViewModel by viewModels {
private lateinit var navigationViewModel: FingerprintNavigationViewModel FingerprintNavigationViewModel.Factory
private lateinit var gatekeeperViewModel: FingerprintGatekeeperViewModel }
private lateinit var fingerprintEnrollViewModel: FingerprintEnrollViewModel private val fingerprintFlowViewModel: FingerprintFlowViewModel by viewModels {
private lateinit var vibrationInteractor: VibrationInteractor 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 foldStateInteractor: FoldStateInteractor
private lateinit var orientationInteractor: OrientationInteractor
private lateinit var displayDensityInteractor: DisplayDensityInteractor 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 private val coroutineDispatcher = Dispatchers.Default
/** Result listener for ChooseLock activity flow. */ /** Result listener for ChooseLock activity flow. */
@@ -172,7 +158,7 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
private fun onConfirmDevice(resultCode: Int, data: Intent?) { private fun onConfirmDevice(resultCode: Int, data: Intent?) {
val wasSuccessful = resultCode == RESULT_FINISHED || resultCode == Activity.RESULT_OK val wasSuccessful = resultCode == RESULT_FINISHED || resultCode == Activity.RESULT_OK
val gateKeeperPasswordHandle = data?.getExtra(EXTRA_KEY_GK_PW_HANDLE) as Long? val gateKeeperPasswordHandle = data?.getExtra(EXTRA_KEY_GK_PW_HANDLE) as Long
lifecycleScope.launch { lifecycleScope.launch {
val confirmDeviceResult = val confirmDeviceResult =
@@ -204,6 +190,15 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
finish() 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)) setTheme(SetupWizardUtils.getTheme(applicationContext, intent))
ThemeHelper.trySetDynamicColor(applicationContext) ThemeHelper.trySetDynamicColor(applicationContext)
@@ -219,31 +214,7 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
Default Default
} }
backgroundViewModel = fingerprintFlowViewModel.updateFlowType(enrollType)
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)
if (intent.getIntExtra(BiometricUtils.EXTRA_ENROLL_REASON, -1) === -1) { if (intent.getIntExtra(BiometricUtils.EXTRA_ENROLL_REASON, -1) === -1) {
val isSuw: Boolean = WizardManagerHelper.isAnySetupWizard(intent) 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? var challenge = intent.getExtra(BiometricEnrollBase.EXTRA_KEY_CHALLENGE) as Long?
val token = intent.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN) val token = intent.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN)
val gatekeeperInfo = FingerprintGatekeeperViewModel.toGateKeeperInfo(challenge, token) val gatekeeperInfo = FingerprintGatekeeperViewModel.toGateKeeperInfo(challenge, token)
val hasConfirmedDeviceCredential = gatekeeperInfo is GatekeeperInfo.GatekeeperPasswordInfo val hasConfirmedDeviceCredential = gatekeeperInfo is GatekeeperInfo.GatekeeperPasswordInfo
navigationViewModel = navigationViewModel.updateFingerprintFlow(enrollType)
ViewModelProvider( navigationViewModel.hasConfirmedDeviceCredential(hasConfirmedDeviceCredential)
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]
lifecycleScope.launch { lifecycleScope.launch {
navigationViewModel.currentStep.collect { step -> navigationViewModel.currentStep.collect { step ->
if (step is Init) { if (step is Init) {
Log.d(TAG, "FingerprintNav.init($step)")
navigationViewModel.update(FingerprintAction.ACTIVITY_CREATED, Init::class, "$TAG#init") navigationViewModel.update(FingerprintAction.ACTIVITY_CREATED, Init::class, "$TAG#init")
} }
} }

View File

@@ -20,8 +20,8 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.annotation.VisibleForTesting
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope 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 * This page will display basic information about what a fingerprint can be used for and acts as the
* final step of enrollment. * final step of enrollment.
*/ */
class FingerprintEnrollConfirmationV2Fragment() : class FingerprintEnrollConfirmationV2Fragment(factory: ViewModelProvider.Factory? = null) :
Fragment(R.layout.fingerprint_enroll_finish_base) { Fragment(R.layout.fingerprint_enroll_finish_base) {
companion object { private val viewModel: FingerprintEnrollConfirmationViewModel by activityViewModels {
const val TAG = "FingerprintEnrollConfirmationV2Fragment" factory ?: FingerprintEnrollConfirmationViewModel.Factory
}
/** 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]
} }
override fun onCreateView( override fun onCreateView(
@@ -106,4 +86,8 @@ class FingerprintEnrollConfirmationV2Fragment() :
private fun onNextButtonClick(view: View?) { private fun onNextButtonClick(view: View?) {
viewModel.onNextButtonClicked() viewModel.onNextButtonClicked()
} }
companion object {
const val TAG = "FingerprintEnrollConfirmationV2Fragment"
}
} }

View File

@@ -30,8 +30,9 @@ import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import android.widget.ScrollView import android.widget.ScrollView
import android.widget.TextView import android.widget.TextView
import androidx.annotation.VisibleForTesting
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.android.settings.R import com.android.settings.R
@@ -74,37 +75,22 @@ private data class TextModel(
* 2. How the data will be stored * 2. How the data will be stored
* 3. How the user can access and remove their data * 3. How the user can access and remove their data
*/ */
class FingerprintEnrollIntroV2Fragment() : Fragment(R.layout.fingerprint_v2_enroll_introduction) { class FingerprintEnrollIntroV2Fragment(testFactory: ViewModelProvider.Factory? = null) :
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())
}
}
private lateinit var footerBarMixin: FooterBarMixin private lateinit var footerBarMixin: FooterBarMixin
private lateinit var textModel: TextModel private lateinit var textModel: TextModel
private val viewModel: FingerprintEnrollIntroViewModel by lazy { private val viewModel: FingerprintEnrollIntroViewModel by activityViewModels {
viewModelProvider[FingerprintEnrollIntroViewModel::class.java] testFactory ?: FingerprintEnrollIntroViewModel.Factory
} }
private val fingerprintScrollViewModel: FingerprintScrollViewModel by lazy { private val fingerprintScrollViewModel: FingerprintScrollViewModel by viewModels {
viewModelProvider[FingerprintScrollViewModel::class.java] testFactory ?: FingerprintScrollViewModel.Factory
} }
private val gateKeeperViewModel: FingerprintGatekeeperViewModel by lazy { private val gateKeeperViewModel: FingerprintGatekeeperViewModel by activityViewModels {
viewModelProvider[FingerprintGatekeeperViewModel::class.java] testFactory ?: FingerprintGatekeeperViewModel.Factory
} }
override fun onCreateView( override fun onCreateView(

View File

@@ -23,11 +23,15 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.android.settings.R import com.android.settings.R
import com.android.settings.biometrics.fingerprint.FingerprintErrorDialog import com.android.settings.biometrics.fingerprint.FingerprintErrorDialog
import com.android.settings.biometrics.fingerprint.FingerprintFindSensorAnimation 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.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollFindSensorViewModel
import com.google.android.setupcompat.template.FooterBarMixin import com.google.android.setupcompat.template.FooterBarMixin
import com.google.android.setupcompat.template.FooterButton import com.google.android.setupcompat.template.FooterButton
@@ -51,18 +55,10 @@ class RfpsEnrollFindSensorFragment() : Fragment() {
factory = theFactory factory = theFactory
} }
private val viewModelProvider: ViewModelProvider by lazy {
if (factory != null) {
ViewModelProvider(requireActivity(), factory!!)
} else {
ViewModelProvider(requireActivity())
}
}
private var animation: FingerprintFindSensorAnimation? = null private var animation: FingerprintFindSensorAnimation? = null
private val viewModel: FingerprintEnrollFindSensorViewModel by lazy { private val viewModel: FingerprintEnrollFindSensorViewModel by activityViewModels {
viewModelProvider[FingerprintEnrollFindSensorViewModel::class.java] factory ?: FingerprintEnrollFindSensorViewModel.Factory
} }
override fun onCreateView( override fun onCreateView(
@@ -78,6 +74,12 @@ class RfpsEnrollFindSensorFragment() : Fragment() {
// Set up footer bar // Set up footer bar
val footerBarMixin = view.getMixin(FooterBarMixin::class.java) val footerBarMixin = view.getMixin(FooterBarMixin::class.java)
setupSecondaryButton(footerBarMixin) setupSecondaryButton(footerBarMixin)
viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
viewModel.enroll(requireActivity().intent.toFingerprintEnrollOptions())
}
}
lifecycleScope.launch { lifecycleScope.launch {
viewModel.showPrimaryButton.collect { setupPrimaryButton(footerBarMixin) } viewModel.showPrimaryButton.collect { setupPrimaryButton(footerBarMixin) }
} }

View File

@@ -24,11 +24,15 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.airbnb.lottie.LottieAnimationView import com.airbnb.lottie.LottieAnimationView
import com.android.settings.R import com.android.settings.R
import com.android.settings.biometrics.fingerprint.FingerprintErrorDialog 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.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollFindSensorViewModel
import com.google.android.setupcompat.template.FooterBarMixin import com.google.android.setupcompat.template.FooterBarMixin
import com.google.android.setupcompat.template.FooterButton import com.google.android.setupcompat.template.FooterButton
@@ -52,16 +56,8 @@ class SfpsEnrollFindSensorFragment() : Fragment() {
factory = theFactory factory = theFactory
} }
private val viewModelProvider: ViewModelProvider by lazy { private val viewModel: FingerprintEnrollFindSensorViewModel by activityViewModels {
if (factory != null) { factory ?: FingerprintEnrollFindSensorViewModel.Factory
ViewModelProvider(requireActivity(), factory!!)
} else {
ViewModelProvider(requireActivity())
}
}
private val viewModel: FingerprintEnrollFindSensorViewModel by lazy {
viewModelProvider[FingerprintEnrollFindSensorViewModel::class.java]
} }
override fun onCreateView( override fun onCreateView(
@@ -78,6 +74,12 @@ class SfpsEnrollFindSensorFragment() : Fragment() {
val footerBarMixin = view.getMixin(FooterBarMixin::class.java) val footerBarMixin = view.getMixin(FooterBarMixin::class.java)
setupSecondaryButton(footerBarMixin) setupSecondaryButton(footerBarMixin)
viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
viewModel.enroll(requireActivity().intent.toFingerprintEnrollOptions())
}
}
// Set up lottie // Set up lottie
lifecycleScope.launch { lifecycleScope.launch {
viewModel.sfpsLottieInfo.collect { (isFolded, rotation) -> viewModel.sfpsLottieInfo.collect { (isFolded, rotation) ->

View File

@@ -24,11 +24,15 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.airbnb.lottie.LottieAnimationView import com.airbnb.lottie.LottieAnimationView
import com.android.settings.R import com.android.settings.R
import com.android.settings.biometrics.fingerprint.FingerprintErrorDialog 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.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollFindSensorViewModel
import com.google.android.setupcompat.template.FooterBarMixin import com.google.android.setupcompat.template.FooterBarMixin
import com.google.android.setupcompat.template.FooterButton import com.google.android.setupcompat.template.FooterButton
@@ -53,16 +57,8 @@ class UdfpsEnrollFindSensorFragment() : Fragment() {
factory = theFactory factory = theFactory
} }
private val viewModelProvider: ViewModelProvider by lazy { private val viewModel: FingerprintEnrollFindSensorViewModel by activityViewModels {
if (factory != null) { factory ?: FingerprintEnrollFindSensorViewModel.Factory
ViewModelProvider(requireActivity(), factory!!)
} else {
ViewModelProvider(requireActivity())
}
}
private val viewModel: FingerprintEnrollFindSensorViewModel by lazy {
viewModelProvider[FingerprintEnrollFindSensorViewModel::class.java]
} }
override fun onCreateView( override fun onCreateView(
@@ -79,6 +75,12 @@ class UdfpsEnrollFindSensorFragment() : Fragment() {
val footerBarMixin = view.getMixin(FooterBarMixin::class.java) val footerBarMixin = view.getMixin(FooterBarMixin::class.java)
setupSecondaryButton(footerBarMixin) setupSecondaryButton(footerBarMixin)
viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
viewModel.enroll(requireActivity().intent.toFingerprintEnrollOptions())
}
}
lifecycleScope.launch { lifecycleScope.launch {
viewModel.showPrimaryButton.collect { setupPrimaryButton(footerBarMixin) } viewModel.showPrimaryButton.collect { setupPrimaryButton(footerBarMixin) }
} }

View File

@@ -28,12 +28,15 @@ import android.view.animation.Interpolator
import android.widget.TextView import android.widget.TextView
import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.repeatOnLifecycle
import com.android.settings.R import com.android.settings.R
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState 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.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.RFPSIconTouchViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.viewmodel.RFPSViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.viewmodel.RFPSViewModel
@@ -62,29 +65,21 @@ class RFPSEnrollFragment() : Fragment(R.layout.fingerprint_v2_rfps_enroll_enroll
factory = theFactory 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 linearOutSlowInInterpolator: Interpolator
private lateinit var fastOutLinearInInterpolator: Interpolator private lateinit var fastOutLinearInInterpolator: Interpolator
private lateinit var textView: TextView private lateinit var textView: TextView
private lateinit var progressBar: RFPSProgressBar private lateinit var progressBar: RFPSProgressBar
private val iconTouchViewModel: RFPSIconTouchViewModel by lazy { private val iconTouchViewModel: RFPSIconTouchViewModel by viewModels {
viewModelProvider[RFPSIconTouchViewModel::class.java] RFPSIconTouchViewModel.Factory
} }
private val rfpsViewModel: RFPSViewModel by lazy { viewModelProvider[RFPSViewModel::class.java] } private val rfpsViewModel: RFPSViewModel by activityViewModels {
factory ?: RFPSViewModel.Factory
private val backgroundViewModel: BackgroundViewModel by lazy {
viewModelProvider[BackgroundViewModel::class.java]
} }
private val backgroundViewModel: BackgroundViewModel by activityViewModels()
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
@@ -131,6 +126,7 @@ class RFPSEnrollFragment() : Fragment(R.layout.fingerprint_v2_rfps_enroll_enroll
viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) { repeatOnLifecycle(Lifecycle.State.RESUMED) {
rfpsViewModel.enroll(requireActivity().intent.toFingerprintEnrollOptions())
// Icon animation update // Icon animation update
viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.lifecycleScope.launch {
// TODO(b/324427704): Fix this delay // TODO(b/324427704): Fix this delay

View File

@@ -19,6 +19,8 @@ package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrol
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
@@ -27,6 +29,7 @@ import kotlinx.coroutines.flow.transform
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
private const val touchesToShowDialog = 3 private const val touchesToShowDialog = 3
/** /**
* This class is responsible for counting the number of touches on the fingerprint icon, and if this * 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 * 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 } _touches.update { _touches.value + 1 }
} }
class RFPSIconTouchViewModelFactory : ViewModelProvider.Factory { companion object {
@Suppress("UNCHECKED_CAST") val Factory: ViewModelProvider.Factory = viewModelFactory {
override fun <T : ViewModel> create(modelClass: Class<T>): T { initializer { RFPSIconTouchViewModel() }
return RFPSIconTouchViewModel() as T
} }
} }
} }

View File

@@ -16,9 +16,14 @@
package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.viewmodel 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.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope 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.domain.interactor.OrientationInteractor
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
@@ -158,27 +163,27 @@ class RFPSViewModel(
enrollFlow = fingerprintEnrollViewModel.enrollFlow enrollFlow = fingerprintEnrollViewModel.enrollFlow
} }
class RFPSViewModelFactory( /** Starts enrollment. */
private val fingerprintEnrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel, fun enroll(enrollOptions: FingerprintEnrollOptions) {
private val navigationViewModel: FingerprintNavigationViewModel, fingerprintEnrollViewModel.enroll(enrollOptions)
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
}
} }
companion object { companion object {
private val navStep = Enrollment::class private val navStep = Enrollment::class
private const val TAG = "RFPSViewModel" 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,
)
}
}
} }
} }

View File

@@ -82,6 +82,7 @@ class RFPSProgressBar : RingProgressBar {
shouldAnimateInternal = shouldAnimate shouldAnimateInternal = shouldAnimate
} }
/** This function should only be called when actual progress has been made. */ /** This function should only be called when actual progress has been made. */
fun updateProgress(percentComplete: Float) { fun updateProgress(percentComplete: Float) {
val progress = maxProgress - (percentComplete.coerceIn(0.0f, 100.0f) * maxProgress).toInt() val progress = maxProgress - (percentComplete.coerceIn(0.0f, 100.0f) * maxProgress).toInt()

View File

@@ -18,8 +18,6 @@ package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrol
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.MotionEvent
import android.view.MotionEvent.ACTION_HOVER_MOVE
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowManager import android.view.WindowManager
@@ -27,6 +25,7 @@ import android.widget.Button
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
@@ -36,6 +35,7 @@ import com.airbnb.lottie.LottieCompositionFactory
import com.android.settings.R import com.android.settings.R
import com.android.settings.biometrics.fingerprint2.data.model.EnrollStageModel import com.android.settings.biometrics.fingerprint2.data.model.EnrollStageModel
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState 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.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.DescriptionText
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.model.HeaderText 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 */ /** Used for testing purposes */
private var factory: ViewModelProvider.Factory? = null private var factory: ViewModelProvider.Factory? = null
private val viewModel: UdfpsViewModel by lazy { viewModelProvider[UdfpsViewModel::class.java] }
private lateinit var udfpsEnrollView: UdfpsEnrollViewV2 private lateinit var udfpsEnrollView: UdfpsEnrollViewV2
private lateinit var lottie: LottieAnimationView private lateinit var lottie: LottieAnimationView
private val viewModelProvider: ViewModelProvider by lazy { private val viewModel: UdfpsViewModel by activityViewModels { factory ?: UdfpsViewModel.Factory }
if (factory != null) {
ViewModelProvider(requireActivity(), factory!!)
} else {
ViewModelProvider(requireActivity())
}
}
@VisibleForTesting @VisibleForTesting
constructor(theFactory: ViewModelProvider.Factory) : this() { constructor(theFactory: ViewModelProvider.Factory) : this() {
@@ -90,6 +83,7 @@ class UdfpsEnrollFragment() : Fragment(R.layout.fingerprint_v2_udfps_enroll_enro
viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) { repeatOnLifecycle(Lifecycle.State.RESUMED) {
viewModel.enroll(requireActivity().intent.toFingerprintEnrollOptions())
launch { launch {
viewModel.sensorLocation.collect { sensor -> viewModel.sensorLocation.collect { sensor ->
udfpsEnrollView.setSensorRect(sensor.sensorBounds, sensor.sensorType) udfpsEnrollView.setSensorRect(sensor.sensorBounds, sensor.sensorType)
@@ -204,12 +198,16 @@ class UdfpsEnrollFragment() : Fragment(R.layout.fingerprint_v2_udfps_enroll_enro
} }
viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.lifecycleScope.launch {
viewModel.touchExplorationDebug.collect { view.setOnTouchListener { _, motionEvent ->
udfpsEnrollView.sendDebugTouchExplorationEvent( viewModel.onTouchEvent(motionEvent)
MotionEvent.obtain(100, 100, ACTION_HOVER_MOVE, it.x.toFloat(), it.y.toFloat(), 0) false
)
} }
} }
viewLifecycleOwner.lifecycleScope.launch {
viewModel.touchEvent.collect { udfpsEnrollView.onTouchEvent(it) }
}
viewModel.readyForEnrollment() viewModel.readyForEnrollment()
} }

View File

@@ -16,9 +16,13 @@
package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel 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.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope 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.FingerprintVibrationEffects
import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractor import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractor
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
@@ -89,14 +93,18 @@ class UdfpsLastStepViewModel(
} }
.filterNotNull() .filterNotNull()
class UdfpsLastStepViewModelFactory( companion object {
private val fingerprintEnrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel, val Factory: ViewModelProvider.Factory = viewModelFactory {
private val vibrationInteractor: VibrationInteractor, initializer {
) : ViewModelProvider.Factory { val settingsApplication =
this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as SettingsApplication
@Suppress("UNCHECKED_CAST") val biometricEnvironment = settingsApplication.biometricEnvironment
override fun <T : ViewModel> create(modelClass: Class<T>): T { val provider = ViewModelProvider(this[VIEW_MODEL_STORE_OWNER_KEY]!!)
return UdfpsLastStepViewModel(fingerprintEnrollEnrollingViewModel, vibrationInteractor) as T UdfpsLastStepViewModel(
provider[FingerprintEnrollEnrollingViewModel::class],
biometricEnvironment!!.vibrationInteractor,
)
}
} }
} }
} }

View File

@@ -16,21 +16,26 @@
package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel
import android.graphics.Point
import android.graphics.PointF import android.graphics.PointF
import android.hardware.fingerprint.FingerprintEnrollOptions
import android.view.MotionEvent
import android.view.Surface import android.view.Surface
import androidx.lifecycle.VIEW_MODEL_STORE_OWNER_KEY
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import 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.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.AccessibilityInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.DebuggingInteractor 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.DisplayDensityInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.EnrollStageInteractor 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.FingerprintVibrationEffects
import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor 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.UdfpsEnrollInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractor import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractor
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
@@ -45,6 +50,7 @@ import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Fing
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.combineTransform import kotlinx.coroutines.flow.combineTransform
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
@@ -60,20 +66,20 @@ import kotlinx.coroutines.launch
/** ViewModel used to drive UDFPS Enrollment through [UdfpsEnrollFragment] */ /** ViewModel used to drive UDFPS Enrollment through [UdfpsEnrollFragment] */
class UdfpsViewModel( class UdfpsViewModel(
val navigationViewModel: FingerprintNavigationViewModel,
val fingerprintEnrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel,
backgroundViewModel: BackgroundViewModel,
val udfpsLastStepViewModel: UdfpsLastStepViewModel,
val vibrationInteractor: VibrationInteractor, val vibrationInteractor: VibrationInteractor,
displayDensityInteractor: DisplayDensityInteractor, displayDensityInteractor: DisplayDensityInteractor,
val navigationViewModel: FingerprintNavigationViewModel,
debuggingInteractor: DebuggingInteractor, debuggingInteractor: DebuggingInteractor,
val fingerprintEnrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel,
simulatedTouchEventsDebugRepository: SimulatedTouchEventsRepository,
enrollStageInteractor: EnrollStageInteractor, enrollStageInteractor: EnrollStageInteractor,
orientationInteractor: OrientationInteractor, orientationInteractor: OrientationInteractor,
backgroundViewModel: BackgroundViewModel,
sensorRepository: FingerprintSensorRepository,
udfpsEnrollInteractor: UdfpsEnrollInteractor, udfpsEnrollInteractor: UdfpsEnrollInteractor,
fingerprintManager: FingerprintManagerInteractor, fingerprintManager: FingerprintManagerInteractor,
val udfpsLastStepViewModel: UdfpsLastStepViewModel,
accessibilityInteractor: AccessibilityInteractor, accessibilityInteractor: AccessibilityInteractor,
sensorRepository: FingerprintSensorInteractor,
touchEventInteractor: TouchEventInteractor,
) : ViewModel() { ) : ViewModel() {
private val isSetupWizard = flowOf(false) private val isSetupWizard = flowOf(false)
@@ -191,15 +197,9 @@ class UdfpsViewModel(
.transform { emit(it == Surface.ROTATION_90) } .transform { emit(it == Surface.ROTATION_90) }
.distinctUntilChanged() .distinctUntilChanged()
/** This sends touch exploration events only used for debugging purposes. */ private val _touchEvent: MutableStateFlow<MotionEvent?> = MutableStateFlow(null)
val touchExplorationDebug: Flow<Point> = val touchEvent =
debuggingInteractor.debuggingEnabled.combineTransform( _touchEvent.asStateFlow().filterNotNull()
simulatedTouchEventsDebugRepository.touchExplorationDebug
) { enabled, point ->
if (enabled) {
emit(point)
}
}
/** Determines the current [EnrollStageModel] enrollment is in */ /** Determines the current [EnrollStageModel] enrollment is in */
private val enrollStage: Flow<EnrollStageModel> = private val enrollStage: Flow<EnrollStageModel> =
@@ -266,6 +266,12 @@ class UdfpsViewModel(
viewModelScope.launch { viewModelScope.launch {
backgroundViewModel.background.filter { it }.collect { didGoToBackground() } backgroundViewModel.background.filter { it }.collect { didGoToBackground() }
} }
viewModelScope.launch {
touchEventInteractor.touchEvent.collect {
_touchEvent.update { it }
}
}
} }
/** Indicates if we should show the lottie. */ /** Indicates if we should show the lottie. */
@@ -393,47 +399,43 @@ class UdfpsViewModel(
) )
} }
class UdfpsEnrollmentFactory( /** Starts enrollment. */
private val vibrationInteractor: VibrationInteractor, fun enroll(enrollOptions: FingerprintEnrollOptions) {
private val displayDensityInteractor: DisplayDensityInteractor, fingerprintEnrollEnrollingViewModel.enroll(enrollOptions)
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 {
@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 { companion object {
private val navStep = FingerprintNavigationStep.Enrollment::class private val navStep = FingerprintNavigationStep.Enrollment::class
private const val TAG = "UDFPSViewModel" 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,
)
}
}
} }
} }

View File

@@ -210,6 +210,7 @@ class UdfpsEnrollProgressBarDrawableV2(private val context: Context, attrs: Attr
override fun getOpacity(): Int { override fun getOpacity(): Int {
return PixelFormat.UNKNOWN return PixelFormat.UNKNOWN
} }
/** /**
* Draws the progress with locations [sensorLocationX] [sensorLocationY], note these must be with * Draws the progress with locations [sensorLocationX] [sensorLocationY], note these must be with
* respect to the parent framelayout. * respect to the parent framelayout.

View File

@@ -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. */ /** Sets the addHoverListener, this should happen when talkback is enabled. */
private fun addHoverListener() { private fun addHoverListener() {
onHoverListener = OnHoverListener { _: View, event: MotionEvent -> onHoverListener = OnHoverListener { _: View, event: MotionEvent ->
sendDebugTouchExplorationEvent(event) touchExplorationAnnouncer.onTouch(event)
false false
} }
this.setOnHoverListener(onHoverListener) this.setOnHoverListener(onHoverListener)

View File

@@ -18,6 +18,8 @@ package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
@@ -39,10 +41,9 @@ class BackgroundViewModel : ViewModel() {
_background.update { false } _background.update { false }
} }
class BackgroundViewModelFactory : ViewModelProvider.Factory { companion object {
@Suppress("UNCHECKED_CAST") val Factory: ViewModelProvider.Factory = viewModelFactory {
override fun <T : ViewModel> create(modelClass: Class<T>): T { initializer { BackgroundViewModel() }
return BackgroundViewModel() as T
} }
} }
} }

View File

@@ -16,14 +16,17 @@
package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel 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.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import com.android.settings.SettingsApplication
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
/** /** Models the UI state for [FingerprintEnrollConfirmationV2Fragment] */
* Models the UI state for [FingerprintEnrollConfirmationV2Fragment]
*/
class FingerprintEnrollConfirmationViewModel( class FingerprintEnrollConfirmationViewModel(
private val navigationViewModel: FingerprintNavigationViewModel, private val navigationViewModel: FingerprintNavigationViewModel,
fingerprintInteractor: FingerprintManagerInteractor, fingerprintInteractor: FingerprintManagerInteractor,
@@ -50,18 +53,20 @@ class FingerprintEnrollConfirmationViewModel(
navigationViewModel.update(FingerprintAction.ADD_ANOTHER, navStep, "onAddAnotherButtonClicked") 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 { companion object {
private const val TAG = "FingerprintEnrollConfirmationViewModel" private const val TAG = "FingerprintEnrollConfirmationViewModel"
private val navStep = FingerprintNavigationStep.Confirmation::class 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,
)
}
}
} }
} }

View File

@@ -16,14 +16,15 @@
package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel 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.ViewModel
import androidx.lifecycle.ViewModelProvider 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.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.transformLatest import kotlinx.coroutines.flow.transformLatest
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
@@ -69,23 +70,24 @@ class FingerprintEnrollEnrollingViewModel(
val enrollFlow = val enrollFlow =
enrollFlowShouldBeRunning.transformLatest { enrollFlowShouldBeRunning.transformLatest {
if (it) { if (it) {
fingerprintEnrollViewModel.enrollFlow.collect { event -> fingerprintEnrollViewModel.enrollFlow.collect { event -> emit(event) }
emit(event) }
} }
} }
class FingerprintEnrollEnrollingViewModelFactory( /** Indicates enrollment to start */
private val fingerprintEnrollViewModel: FingerprintEnrollViewModel, fun enroll(enrollOptions: FingerprintEnrollOptions) {
private val backgroundViewModel: BackgroundViewModel, fingerprintEnrollViewModel.enroll(enrollOptions)
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return FingerprintEnrollEnrollingViewModel(fingerprintEnrollViewModel, backgroundViewModel)
as T
}
} }
companion object { 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],
)
}
}
} }
} }

View File

@@ -16,9 +16,14 @@
package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel 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.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope 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.AccessibilityInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateInteractor import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor
@@ -43,10 +48,10 @@ class FingerprintEnrollFindSensorViewModel(
private val fingerprintEnrollViewModel: FingerprintEnrollViewModel, private val fingerprintEnrollViewModel: FingerprintEnrollViewModel,
private val gatekeeperViewModel: FingerprintGatekeeperViewModel, private val gatekeeperViewModel: FingerprintGatekeeperViewModel,
backgroundViewModel: BackgroundViewModel, backgroundViewModel: BackgroundViewModel,
fingerprintFlowViewModel: FingerprintFlowViewModel,
accessibilityInteractor: AccessibilityInteractor, accessibilityInteractor: AccessibilityInteractor,
foldStateInteractor: FoldStateInteractor, foldStateInteractor: FoldStateInteractor,
orientationInteractor: OrientationInteractor, orientationInteractor: OrientationInteractor,
fingerprintFlowViewModel: FingerprintFlowViewModel,
fingerprintManagerInteractor: FingerprintManagerInteractor, fingerprintManagerInteractor: FingerprintManagerInteractor,
) : ViewModel() { ) : ViewModel() {
@@ -64,6 +69,7 @@ class FingerprintEnrollFindSensorViewModel(
val showPrimaryButton: Flow<Boolean> = _isUdfps.filter { it } val showPrimaryButton: Flow<Boolean> = _isUdfps.filter { it }
private val _showSfpsLottie = _isSfps.filter { it } private val _showSfpsLottie = _isSfps.filter { it }
/** Represents the stream of showing sfps lottie and the information Pair(isFolded, rotation). */ /** Represents the stream of showing sfps lottie and the information Pair(isFolded, rotation). */
val sfpsLottieInfo: Flow<Pair<Boolean, Int>> = val sfpsLottieInfo: Flow<Pair<Boolean, Int>> =
combineTransform( combineTransform(
@@ -75,6 +81,7 @@ class FingerprintEnrollFindSensorViewModel(
} }
private val _showUdfpsLottie = _isUdfps.filter { it } private val _showUdfpsLottie = _isUdfps.filter { it }
/** Represents the stream of showing udfps lottie and whether accessibility is enabled. */ /** Represents the stream of showing udfps lottie and whether accessibility is enabled. */
val udfpsLottieInfo: Flow<Boolean> = val udfpsLottieInfo: Flow<Boolean> =
_showUdfpsLottie.combine(accessibilityInteractor.isAccessibilityEnabled) { _showUdfpsLottie.combine(accessibilityInteractor.isAccessibilityEnabled) {
@@ -87,11 +94,13 @@ class FingerprintEnrollFindSensorViewModel(
val showRfpsAnimation: Flow<Boolean> = _isRearSfps.filter { it } val showRfpsAnimation: Flow<Boolean> = _isRearSfps.filter { it }
private val _showErrorDialog: MutableStateFlow<Pair<Int, Boolean>?> = MutableStateFlow(null) private val _showErrorDialog: MutableStateFlow<Pair<Int, Boolean>?> = MutableStateFlow(null)
/** Represents the stream of showing error dialog. */ /** Represents the stream of showing error dialog. */
val showErrorDialog = _showErrorDialog.filterNotNull() val showErrorDialog = _showErrorDialog.filterNotNull()
private var _didTryEducation = false private var _didTryEducation = false
private var _education: MutableStateFlow<Boolean> = MutableStateFlow(false) private var _education: MutableStateFlow<Boolean> = MutableStateFlow(false)
/** Indicates if the education flow should be running. */ /** Indicates if the education flow should be running. */
private val educationFlowShouldBeRunning: Flow<Boolean> = private val educationFlowShouldBeRunning: Flow<Boolean> =
_education.combine(backgroundViewModel.background) { shouldRunEducation, isInBackground -> _education.combine(backgroundViewModel.background) { shouldRunEducation, isInBackground ->
@@ -167,6 +176,11 @@ class FingerprintEnrollFindSensorViewModel(
_education.update { false } _education.update { false }
} }
/** Indicates enrollment to start */
fun enroll(enrollOptions: FingerprintEnrollOptions) {
fingerprintEnrollViewModel.enroll(enrollOptions)
}
/** Proceed to EnrollEnrolling page. */ /** Proceed to EnrollEnrolling page. */
fun proceedToEnrolling() { fun proceedToEnrolling() {
stopEducation() 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 { companion object {
private const val TAG = "FingerprintEnrollFindSensorViewModel" private const val TAG = "FingerprintEnrollFindSensorViewModel"
private val navStep = Education::class 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,
)
}
}
} }
} }

View File

@@ -16,8 +16,12 @@
package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
import androidx.lifecycle.VIEW_MODEL_STORE_OWNER_KEY
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import com.android.settings.SettingsApplication
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintFlow import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintFlow
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Introduction 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. */ /** A view model for fingerprint enroll introduction. */
class FingerprintEnrollIntroViewModel( class FingerprintEnrollIntroViewModel(
val navigationViewModel: FingerprintNavigationViewModel, val navigationViewModel: FingerprintNavigationViewModel,
private val fingerprintFlowViewModel: FingerprintFlowViewModel, fingerprintFlowViewModel: FingerprintFlowViewModel,
private val fingerprintManagerInteractor: FingerprintManagerInteractor, fingerprintManagerInteractor: FingerprintManagerInteractor,
) : ViewModel() { ) : ViewModel() {
/** Represents a stream of [FingerprintSensor] */ /** 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 { companion object {
val navStep = Introduction::class val navStep = Introduction::class
private const val TAG = "FingerprintEnrollIntroViewModel" 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,
)
}
}
} }
} }

View File

@@ -15,9 +15,15 @@
*/ */
package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel 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.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import com.android.settings.SettingsApplication
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason 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.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.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Enrollment
import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.transformLatest import kotlinx.coroutines.flow.transformLatest
import kotlinx.coroutines.flow.update
/** Represents all of the fingerprint information needed for a fingerprint enrollment process. */ /** Represents all of the fingerprint information needed for a fingerprint enrollment process. */
class FingerprintEnrollViewModel( class FingerprintEnrollViewModel(
@@ -55,6 +63,8 @@ class FingerprintEnrollViewModel(
} }
} }
private val enrollOptions: MutableStateFlow<FingerprintEnrollOptions?> = MutableStateFlow(null)
/** Represents the stream of [FingerprintSensorType] */ /** Represents the stream of [FingerprintSensorType] */
val sensorType: Flow<FingerprintSensorType?> = val sensorType: Flow<FingerprintSensorType?> =
fingerprintManagerInteractor.sensorPropertiesInternal.filterNotNull().map { it.sensorType } fingerprintManagerInteractor.sensorPropertiesInternal.filterNotNull().map { it.sensorType }
@@ -66,16 +76,23 @@ class FingerprintEnrollViewModel(
* This flow should be the only flow which calls enroll(). * This flow should be the only flow which calls enroll().
*/ */
val _enrollFlow: Flow<FingerEnrollState> = val _enrollFlow: Flow<FingerEnrollState> =
combine(gatekeeperViewModel.gatekeeperInfo, _enrollReason) { hardwareAuthToken, enrollReason -> combine(gatekeeperViewModel.gatekeeperInfo, _enrollReason, enrollOptions) {
Pair(hardwareAuthToken, enrollReason) hardwareAuthToken,
enrollReason,
enrollOptions ->
Triple(hardwareAuthToken, enrollReason, enrollOptions)
} }
.transformLatest { .transformLatest {
/** [transformLatest] is used as we want to make sure to cancel previous API call. */ /** [transformLatest] is used as we want to make sure to cancel previous API call. */
(hardwareAuthToken, enrollReason) -> (hardwareAuthToken, enrollReason, enrollOptions) ->
if (hardwareAuthToken is GatekeeperInfo.GatekeeperPasswordInfo && enrollReason != null) { if (
fingerprintManagerInteractor.enroll(hardwareAuthToken.token, enrollReason).collect { hardwareAuthToken is GatekeeperInfo.GatekeeperPasswordInfo &&
emit(it) enrollReason != null &&
} enrollOptions != null
) {
fingerprintManagerInteractor
.enroll(hardwareAuthToken.token, enrollReason, enrollOptions)
.collect { emit(it) }
} }
} }
.shareIn(viewModelScope, SharingStarted.WhileSubscribed(), 0) .shareIn(viewModelScope, SharingStarted.WhileSubscribed(), 0)
@@ -108,14 +125,23 @@ class FingerprintEnrollViewModel(
} }
} }
class FingerprintEnrollViewModelFactory( /** Starts enrollment. */
val interactor: FingerprintManagerInteractor, fun enroll(options: FingerprintEnrollOptions) {
val gatekeeperViewModel: FingerprintGatekeeperViewModel, enrollOptions.update { options }
val navigationViewModel: FingerprintNavigationViewModel, }
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST") companion object {
override fun <T : ViewModel> create(modelClass: Class<T>): T { val Factory: ViewModelProvider.Factory = viewModelFactory {
return FingerprintEnrollViewModel(interactor, gatekeeperViewModel, navigationViewModel) as T 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],
)
}
} }
} }
} }

View File

@@ -19,21 +19,28 @@ package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintFlow import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintFlow
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.update
class FingerprintFlowViewModel(private val fingerprintFlowType: FingerprintFlow) : ViewModel() { class FingerprintFlowViewModel() : ViewModel() {
val fingerprintFlow: Flow<FingerprintFlow> = val _mutableFingerprintFlow: MutableStateFlow<FingerprintFlow?> = MutableStateFlow(null)
flowOf(fingerprintFlowType).shareIn(viewModelScope, SharingStarted.Eagerly, 1) 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") companion object {
override fun <T : ViewModel> create(modelClass: Class<T>): T { val Factory: ViewModelProvider.Factory = viewModelFactory {
return FingerprintFlowViewModel(flowType) as T initializer { FingerprintFlowViewModel() }
} }
} }
} }

View File

@@ -21,6 +21,9 @@ import android.util.Log
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import com.android.settings.SettingsApplication
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@@ -47,12 +50,10 @@ sealed interface GatekeeperInfo {
* in as a parameter to this class. * in as a parameter to this class.
*/ */
class FingerprintGatekeeperViewModel( class FingerprintGatekeeperViewModel(
theGatekeeperInfo: GatekeeperInfo?, private val fingerprintManagerInteractor: FingerprintManagerInteractor
private val fingerprintManagerInteractor: FingerprintManagerInteractor,
) : ViewModel() { ) : ViewModel() {
private var _gatekeeperInfo: MutableStateFlow<GatekeeperInfo?> = private var _gatekeeperInfo: MutableStateFlow<GatekeeperInfo?> = MutableStateFlow(null)
MutableStateFlow(theGatekeeperInfo)
/** The gatekeeper info for fingerprint enrollment. */ /** The gatekeeper info for fingerprint enrollment. */
val gatekeeperInfo: Flow<GatekeeperInfo?> = _gatekeeperInfo.asStateFlow() val gatekeeperInfo: Flow<GatekeeperInfo?> = _gatekeeperInfo.asStateFlow()
@@ -61,29 +62,30 @@ class FingerprintGatekeeperViewModel(
val hasValidGatekeeperInfo: Flow<Boolean> = val hasValidGatekeeperInfo: Flow<Boolean> =
gatekeeperInfo.map { it is GatekeeperInfo.GatekeeperPasswordInfo } gatekeeperInfo.map { it is GatekeeperInfo.GatekeeperPasswordInfo }
private var _credentialConfirmed: MutableStateFlow<Boolean?> = MutableStateFlow(null)
val credentialConfirmed: Flow<Boolean?> = _credentialConfirmed.asStateFlow()
private var countDownTimer: CountDownTimer? = null private var countDownTimer: CountDownTimer? = null
/** Timeout of 15 minutes for a generated challenge */ /** Timeout of 15 minutes for a generated challenge */
private val TIMEOUT: Long = 15 * 60 * 1000 private val TIMEOUT: Long = 15 * 60 * 1000
/** Called after a confirm device credential attempt has been made. */ /** 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) { if (!wasSuccessful) {
Log.d(TAG, "confirmDevice failed") Log.d(TAG, "confirmDevice failed")
_gatekeeperInfo.update { GatekeeperInfo.Invalid } _gatekeeperInfo.update { GatekeeperInfo.Invalid }
_credentialConfirmed.update { false }
} else { } else {
viewModelScope.launch { viewModelScope.launch {
val res = fingerprintManagerInteractor.generateChallenge(theGatekeeperPasswordHandle!!) val res = fingerprintManagerInteractor.generateChallenge(theGatekeeperPasswordHandle!!)
_gatekeeperInfo.update { GatekeeperInfo.GatekeeperPasswordInfo(res.second, res.first) } _gatekeeperInfo.update { GatekeeperInfo.GatekeeperPasswordInfo(res.second, res.first) }
_credentialConfirmed.update { true } if (shouldStartTimer) {
startTimeout() startTimeout()
} }
} }
} }
}
private fun startTimeout() { private fun startTimeout() {
countDownTimer?.cancel() countDownTimer?.cancel()
@@ -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 { companion object {
private const val TAG = "FingerprintGatekeeperViewModel" private const val TAG = "FingerprintGatekeeperViewModel"
/** /**
* A function that checks if the challenge and token are valid, in which case a * A function that checks if the challenge and token are valid, in which case a
* [GatekeeperInfo.GatekeeperPasswordInfo] is provided, else [GatekeeperInfo.Invalid] * [GatekeeperInfo.GatekeeperPasswordInfo] is provided, else [GatekeeperInfo.Invalid]
@@ -121,5 +113,14 @@ class FingerprintGatekeeperViewModel(
} }
return GatekeeperInfo.GatekeeperPasswordInfo(token, challenge) 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)
}
}
} }
} }

View File

@@ -20,7 +20,11 @@ import android.util.Log
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import com.android.settings.SettingsApplication
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.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.Finish
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.TransitionStep import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.TransitionStep
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.UiStep import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.UiStep
@@ -28,39 +32,40 @@ import java.lang.NullPointerException
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.combineTransform import kotlinx.coroutines.flow.combineTransform
import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
/** /**
* This class is essentially a wrapper around [FingerprintNavigationStep] that will be used by * 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 * fragments/viewmodels that want to consume these events. It should provide no additional
* functionality beyond what is available in [FingerprintNavigationStep]. * functionality beyond what is available in [FingerprintNavigationStep].
*/ */
class FingerprintNavigationViewModel( class FingerprintNavigationViewModel(fingerprintManagerInteractor: FingerprintManagerInteractor) :
step: UiStep, ViewModel() {
hasConfirmedDeviceCredential: Boolean,
flowViewModel: FingerprintFlowViewModel,
fingerprintManagerInteractor: FingerprintManagerInteractor,
) : ViewModel() {
private var _navStateInternal: MutableStateFlow<NavigationState?> = MutableStateFlow(null) 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
}
return@combine NavigationState(flow, hasConfirmed, sensorType)
}
.stateIn(viewModelScope, SharingStarted.Eagerly, null)
init { private var _currentStep =
viewModelScope.launch { MutableStateFlow<FingerprintNavigationStep?>(FingerprintNavigationStep.Init)
flowViewModel.fingerprintFlow
.combineTransform(fingerprintManagerInteractor.sensorPropertiesInternal) { flow, props ->
if (props?.sensorId != -1) {
emit(NavigationState(flow, hasConfirmedDeviceCredential, props))
}
}
.collect { navState -> _navStateInternal.update { navState } }
}
}
private var _currentStep = MutableStateFlow<FingerprintNavigationStep?>(step)
private var _navigateTo: MutableStateFlow<UiStep?> = MutableStateFlow(null) private var _navigateTo: MutableStateFlow<UiStep?> = MutableStateFlow(null)
val navigateTo: Flow<UiStep?> = _navigateTo.asStateFlow() val navigateTo: Flow<UiStep?> = _navigateTo.asStateFlow()
@@ -85,6 +90,16 @@ class FingerprintNavigationViewModel(
/** This indicates what screen should currently be presenting to the user. */ /** This indicates what screen should currently be presenting to the user. */
val currentScreen: Flow<UiStep?> = _currentScreen.asStateFlow() 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 */ /** See [updateInternal] for more details */
fun update(action: FingerprintAction, caller: KClass<*>, debugStr: String) { fun update(action: FingerprintAction, caller: KClass<*>, debugStr: String) {
Log.d(TAG, "$caller.update($action) $debugStr") 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 { companion object {
private const val TAG = "FingerprintNavigationViewModel" 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)
}
}
} }
} }

View File

@@ -18,6 +18,8 @@ package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
@@ -36,11 +38,9 @@ class FingerprintScrollViewModel : ViewModel() {
_hasReadConsentScreen.update { true } _hasReadConsentScreen.update { true }
} }
class FingerprintScrollViewModelFactory : ViewModelProvider.Factory { companion object {
val Factory: ViewModelProvider.Factory = viewModelFactory {
@Suppress("UNCHECKED_CAST") initializer { FingerprintScrollViewModel() }
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return FingerprintScrollViewModel() as T
} }
} }
} }

View File

@@ -18,24 +18,15 @@ package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
/** Indicates the type of transitions that can occur between fragments */ /** Indicates the type of transitions that can occur between fragments */
sealed class Transition { 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() 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() 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() 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() data object ExitToRight : Transition()
} }

View File

@@ -54,29 +54,40 @@ object FingerprintSettingsViewBinder {
challenge: Long?, challenge: Long?,
challengeToken: ByteArray?, challengeToken: ByteArray?,
) )
/** Helper to launch an add fingerprint request */ /** Helper to launch an add fingerprint request */
fun launchAddFingerprint(userId: Int, challengeToken: ByteArray?) fun launchAddFingerprint(userId: Int, challengeToken: ByteArray?)
/** /**
* Helper function that will try and launch confirm lock, if that fails we will prompt user to * Helper function that will try and launch confirm lock, if that fails we will prompt user to
* choose a PIN/PATTERN/PASS. * choose a PIN/PATTERN/PASS.
*/ */
fun launchConfirmOrChooseLock(userId: Int) fun launchConfirmOrChooseLock(userId: Int)
/** Used to indicate that FingerprintSettings is finished. */ /** Used to indicate that FingerprintSettings is finished. */
fun finish() fun finish()
/** Indicates what result should be set for the returning callee */ /** Indicates what result should be set for the returning callee */
fun setResultExternal(resultCode: Int) fun setResultExternal(resultCode: Int)
/** Indicates the settings UI should be shown */ /** Indicates the settings UI should be shown */
fun showSettings(enrolledFingerprints: List<FingerprintData>) fun showSettings(enrolledFingerprints: List<FingerprintData>)
/** Updates the add fingerprints preference */ /** Updates the add fingerprints preference */
fun updateAddFingerprintsPreference(canEnroll: Boolean, maxFingerprints: Int) fun updateAddFingerprintsPreference(canEnroll: Boolean, maxFingerprints: Int)
/** Updates the sfps fingerprints preference */ /** Updates the sfps fingerprints preference */
fun updateSfpsPreference(isSfpsPrefVisible: Boolean) fun updateSfpsPreference(isSfpsPrefVisible: Boolean)
/** Indicates that a user has been locked out */ /** Indicates that a user has been locked out */
fun userLockout(authAttemptViewModel: FingerprintAuthAttemptModel.Error) fun userLockout(authAttemptViewModel: FingerprintAuthAttemptModel.Error)
/** Indicates a fingerprint preference should be highlighted */ /** Indicates a fingerprint preference should be highlighted */
suspend fun highlightPref(fingerId: Int) suspend fun highlightPref(fingerId: Int)
/** Indicates a user should be prompted to delete a fingerprint */ /** Indicates a user should be prompted to delete a fingerprint */
suspend fun askUserToDeleteDialog(fingerprintViewModel: FingerprintData): Boolean suspend fun askUserToDeleteDialog(fingerprintViewModel: FingerprintData): Boolean
/** Indicates a user should be asked to renae ma dialog */ /** Indicates a user should be asked to renae ma dialog */
suspend fun askUserToRenameDialog( suspend fun askUserToRenameDialog(
fingerprintViewModel: FingerprintData fingerprintViewModel: FingerprintData

View File

@@ -45,14 +45,13 @@ import com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED
import com.android.settings.biometrics.GatekeeperPasswordProvider import com.android.settings.biometrics.GatekeeperPasswordProvider
import com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling import com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling
import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroductionInternal import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroductionInternal
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintEnrollInteractorImpl
import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepositoryImpl 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.FingerprintManagerInteractorImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.PressToAuthInteractorImpl 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.FingerprintAuthAttemptModel
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData
import com.android.settings.biometrics.fingerprint2.lib.model.Settings 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.binder.FingerprintSettingsViewBinder
import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FingerprintSettingsNavigationViewModel import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FingerprintSettingsNavigationViewModel
import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FingerprintSettingsViewModel import com.android.settings.biometrics.fingerprint2.ui.settings.viewmodel.FingerprintSettingsViewModel
@@ -227,7 +226,6 @@ class FingerprintSettingsV2Fragment :
val fingerprintEnrollStateRepository = val fingerprintEnrollStateRepository =
FingerprintEnrollInteractorImpl( FingerprintEnrollInteractorImpl(
requireContext().applicationContext, requireContext().applicationContext,
intent.toFingerprintEnrollOptions(),
fingerprintManager, fingerprintManager,
Settings, Settings,
) )

View File

@@ -52,7 +52,7 @@ class FingerprintSettingsNavigationViewModel(
_nextStep.update { LaunchConfirmDeviceCredential(userId) } _nextStep.update { LaunchConfirmDeviceCredential(userId) }
} else { } else {
viewModelScope.launch { viewModelScope.launch {
if (fingerprintManagerInteractor.enrolledFingerprints.last().isEmpty()) { if (fingerprintManagerInteractor.enrolledFingerprints.last()?.isEmpty() == true) {
_nextStep.update { EnrollFirstFingerprint(userId, null, challenge, token) } _nextStep.update { EnrollFirstFingerprint(userId, null, challenge, token) }
} else { } else {
showSettingsHelper() showSettingsHelper()
@@ -149,7 +149,7 @@ class FingerprintSettingsNavigationViewModel(
private suspend fun launchEnrollNextStep(gateKeeperPasswordHandle: Long?) { private suspend fun launchEnrollNextStep(gateKeeperPasswordHandle: Long?) {
fingerprintManagerInteractor.enrolledFingerprints.collect { fingerprintManagerInteractor.enrolledFingerprints.collect {
if (it.isEmpty()) { if (it?.isEmpty() == true) {
_nextStep.update { EnrollFirstFingerprint(userId, gateKeeperPasswordHandle, null, null) } _nextStep.update { EnrollFirstFingerprint(userId, gateKeeperPasswordHandle, null, null) }
} else { } else {
viewModelScope.launch(backgroundDispatcher) { viewModelScope.launch(backgroundDispatcher) {

View File

@@ -74,7 +74,7 @@ class FingerprintSettingsViewModel(
/** Represents the stream of visibility of sfps preference. */ /** Represents the stream of visibility of sfps preference. */
val isSfpsPrefVisible: Flow<Boolean> = val isSfpsPrefVisible: Flow<Boolean> =
_enrolledFingerprints.filterOnlyWhenSettingsIsShown().transform { _enrolledFingerprints.filterOnlyWhenSettingsIsShown().transform {
emit(fingerprintManagerInteractor.hasSideFps() && !it.isNullOrEmpty()) emit(fingerprintManagerInteractor.hasSideFps() == true && !it.isNullOrEmpty())
} }
private val _isShowingDialog: MutableStateFlow<PreferenceViewModel?> = MutableStateFlow(null) private val _isShowingDialog: MutableStateFlow<PreferenceViewModel?> = MutableStateFlow(null)

View File

@@ -67,7 +67,6 @@ class FingerprintEnrollIntroFragmentTest {
private val gatekeeperViewModel = private val gatekeeperViewModel =
FingerprintGatekeeperViewModel( FingerprintGatekeeperViewModel(
GatekeeperInfo.GatekeeperPasswordInfo(byteArrayOf(1, 2, 3), 100L),
interactor interactor
) )
private val backgroundDispatcher = StandardTestDispatcher() private val backgroundDispatcher = StandardTestDispatcher()
@@ -86,13 +85,10 @@ class FingerprintEnrollIntroFragmentTest {
.toFingerprintSensor() .toFingerprintSensor()
var enrollFlow = Default var enrollFlow = Default
val flowViewModel = FingerprintFlowViewModel(enrollFlow) val flowViewModel = FingerprintFlowViewModel()
private val navigationViewModel = private val navigationViewModel =
FingerprintNavigationViewModel( FingerprintNavigationViewModel(
Introduction(),
false,
flowViewModel,
interactor interactor
) )
@@ -124,6 +120,11 @@ class FingerprintEnrollIntroFragmentTest {
} }
} }
gatekeeperViewModel.onConfirmDevice(true, 100L, false)
flowViewModel.updateFlowType(enrollFlow)
navigationViewModel.hasConfirmedDeviceCredential(true)
navigationViewModel.updateFingerprintFlow(enrollFlow)
fragmentScenario = fragmentScenario =
launchFragmentInContainer(Bundle(), R.style.SudThemeGlif) { launchFragmentInContainer(Bundle(), R.style.SudThemeGlif) {
FingerprintEnrollIntroV2Fragment(factory) FingerprintEnrollIntroV2Fragment(factory)

View File

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 101 KiB

View File

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 83 KiB

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 148 KiB

View File

@@ -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.FingerprintNavigationStep
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo
import com.android.settings.testutils2.FakeFingerprintManagerInteractor import com.android.settings.testutils2.FakeFingerprintManagerInteractor
import com.android.systemui.biometrics.shared.model.toFingerprintSensor import com.android.systemui.biometrics.shared.model.toFingerprintSensor
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@@ -95,23 +94,27 @@ class Injector(step: FingerprintNavigationStep.UiStep) {
override fun getRotationFromDefault(rotation: Int): Int = rotation override fun getRotationFromDefault(rotation: Int): Int = rotation
} }
var gatekeeperViewModel = var gatekeeperViewModel = FingerprintGatekeeperViewModel(fingerprintManagerInteractor)
FingerprintGatekeeperViewModel(
GatekeeperInfo.GatekeeperPasswordInfo(byteArrayOf(1, 2, 3), 100L),
interactor,
)
val flowViewModel = FingerprintFlowViewModel(enrollFlow) val flowViewModel = FingerprintFlowViewModel()
var navigationViewModel = FingerprintNavigationViewModel(step, true, flowViewModel, interactor) var navigationViewModel = FingerprintNavigationViewModel(fingerprintManagerInteractor)
var fingerprintViewModel = var fingerprintViewModel =
FingerprintEnrollIntroViewModel(navigationViewModel, flowViewModel, interactor) FingerprintEnrollIntroViewModel(
navigationViewModel,
flowViewModel,
fingerprintManagerInteractor,
)
var fingerprintScrollViewModel = FingerprintScrollViewModel() var fingerprintScrollViewModel = FingerprintScrollViewModel()
var backgroundViewModel = BackgroundViewModel() var backgroundViewModel = BackgroundViewModel()
var fingerprintEnrollViewModel = var fingerprintEnrollViewModel =
FingerprintEnrollViewModel(interactor, gatekeeperViewModel, navigationViewModel) FingerprintEnrollViewModel(
fingerprintManagerInteractor,
gatekeeperViewModel,
navigationViewModel,
)
var fingerprintEnrollEnrollingViewModel = var fingerprintEnrollEnrollingViewModel =
FingerprintEnrollEnrollingViewModel(fingerprintEnrollViewModel, backgroundViewModel) FingerprintEnrollEnrollingViewModel(fingerprintEnrollViewModel, backgroundViewModel)
@@ -122,11 +125,11 @@ class Injector(step: FingerprintNavigationStep.UiStep) {
fingerprintEnrollEnrollingViewModel, fingerprintEnrollEnrollingViewModel,
navigationViewModel, navigationViewModel,
orientationInteractor, orientationInteractor,
interactor, fingerprintManagerInteractor,
) )
val fingerprintEnrollConfirmationViewModel = val fingerprintEnrollConfirmationViewModel =
FingerprintEnrollConfirmationViewModel(navigationViewModel, interactor) FingerprintEnrollConfirmationViewModel(navigationViewModel, fingerprintManagerInteractor)
var fingerprintFindSensorViewModel = var fingerprintFindSensorViewModel =
FingerprintEnrollFindSensorViewModel( FingerprintEnrollFindSensorViewModel(
@@ -134,11 +137,11 @@ class Injector(step: FingerprintNavigationStep.UiStep) {
fingerprintEnrollViewModel, fingerprintEnrollViewModel,
gatekeeperViewModel, gatekeeperViewModel,
backgroundViewModel, backgroundViewModel,
flowViewModel,
accessibilityInteractor, accessibilityInteractor,
foldStateInteractor, foldStateInteractor,
orientationInteractor, orientationInteractor,
flowViewModel, fingerprintManagerInteractor,
interactor,
) )
val factory = val factory =
@@ -166,12 +169,16 @@ class Injector(step: FingerprintNavigationStep.UiStep) {
init { init {
fingerprintEnrollViewModel.sensorTypeCached = fingerprintSensor.sensorType fingerprintEnrollViewModel.sensorTypeCached = fingerprintSensor.sensorType
gatekeeperViewModel.onConfirmDevice(true, 100L)
navigationViewModel.updateFingerprintFlow(enrollFlow)
navigationViewModel.hasConfirmedDeviceCredential(true)
flowViewModel.updateFlowType(enrollFlow)
} }
companion object { companion object {
private val Phone = DisplaySpec("phone", width = 1080, height = 2340, densityDpi = 420) private val Phone = DisplaySpec("phone", width = 1080, height = 2340, densityDpi = 420)
private const val screenshotPath = "/settings_screenshots" private const val screenshotPath = "/settings_screenshots"
val interactor = FakeFingerprintManagerInteractor() val fingerprintManagerInteractor = FakeFingerprintManagerInteractor()
fun BiometricFragmentScreenShotRule() = fun BiometricFragmentScreenShotRule() =
FragmentScreenshotTestRule( FragmentScreenshotTestRule(

View File

@@ -17,7 +17,6 @@
package com.android.settings.tests.screenshot.biometrics.fingerprint.fragment package com.android.settings.tests.screenshot.biometrics.fingerprint.fragment
import androidx.test.ext.junit.runners.AndroidJUnit4 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.fragment.FingerprintEnrollConfirmationV2Fragment
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep
import com.android.settings.tests.screenshot.biometrics.fingerprint.Injector import com.android.settings.tests.screenshot.biometrics.fingerprint.Injector
@@ -28,17 +27,15 @@ import platform.test.screenshot.FragmentScreenshotTestRule
import platform.test.screenshot.ViewScreenshotTestRule.Mode import platform.test.screenshot.ViewScreenshotTestRule.Mode
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class FingerprintEnrollConfirmationScreenshotTest { class RfpsEnrollConfirmationScreenshotTest {
private val injector: Injector = Injector(FingerprintNavigationStep.Confirmation) private val injector: Injector = Injector(FingerprintNavigationStep.Confirmation)
@Rule @Rule @JvmField var rule: FragmentScreenshotTestRule = Injector.BiometricFragmentScreenShotRule()
@JvmField
var rule: FragmentScreenshotTestRule = Injector.BiometricFragmentScreenShotRule()
@Test @Test
fun testConfirmation() { fun testConfirmation() {
rule.screenshotTest( rule.screenshotTest(
"fp_enroll_confirmation", "rfps_enroll_confirmation",
Mode.MatchSize, Mode.MatchSize,
FingerprintEnrollConfirmationV2Fragment(injector.factory), FingerprintEnrollConfirmationV2Fragment(injector.factory),
) )

View File

@@ -27,14 +27,14 @@ import platform.test.screenshot.FragmentScreenshotTestRule
import platform.test.screenshot.ViewScreenshotTestRule.Mode import platform.test.screenshot.ViewScreenshotTestRule.Mode
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class FingerprintEnrollEnrollingScreenshotTest { class RfpsEnrollEnrollingScreenshotTest {
private val injector: Injector = private val injector: Injector =
Injector(FingerprintNavigationStep.Enrollment(Injector.interactor.sensorProp)) Injector(FingerprintNavigationStep.Enrollment(Injector.fingerprintManagerInteractor.sensorProp))
@Rule @JvmField var rule: FragmentScreenshotTestRule = BiometricFragmentScreenShotRule() @Rule @JvmField var rule: FragmentScreenshotTestRule = BiometricFragmentScreenShotRule()
@Test @Test
fun testEnrollEnrolling() { fun testEnrollEnrolling() {
rule.screenshotTest("fp_enroll_enrolling", Mode.MatchSize, RFPSEnrollFragment(injector.factory)) rule.screenshotTest("rfps_enroll_enrolling", Mode.MatchSize, RFPSEnrollFragment(injector.factory))
} }
} }

View File

@@ -31,10 +31,6 @@ class RfpsEnrollFindSensorScreenshotTest {
@Test @Test
fun testEnrollFindSensor() { fun testEnrollFindSensor() {
rule.screenshotTest( rule.screenshotTest("rfps_enroll_find_sensor", Mode.MatchSize, RfpsEnrollFindSensorFragment())
"fp_enroll_find_sensor",
Mode.MatchSize,
RfpsEnrollFindSensorFragment(),
)
} }
} }

View File

@@ -27,17 +27,15 @@ import platform.test.screenshot.FragmentScreenshotTestRule
import platform.test.screenshot.ViewScreenshotTestRule.Mode import platform.test.screenshot.ViewScreenshotTestRule.Mode
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class FingerprintEnrollIntroScreenshotTest { class RfpsEnrollIntroScreenshotTest {
private val injector: Injector = Injector(FingerprintNavigationStep.Introduction()) private val injector: Injector = Injector(FingerprintNavigationStep.Introduction())
@Rule @Rule @JvmField var rule: FragmentScreenshotTestRule = Injector.BiometricFragmentScreenShotRule()
@JvmField
var rule: FragmentScreenshotTestRule = Injector.BiometricFragmentScreenShotRule()
@Test @Test
fun testEnrollIntro() { fun testEnrollIntro() {
rule.screenshotTest( rule.screenshotTest(
"fp_enroll_intro", "rfps_enroll_intro",
Mode.MatchSize, Mode.MatchSize,
FingerprintEnrollIntroV2Fragment(injector.factory), FingerprintEnrollIntroV2Fragment(injector.factory),
) )

View File

@@ -19,6 +19,7 @@ package com.android.settings.testutils2
import android.hardware.biometrics.ComponentInfoInternal import android.hardware.biometrics.ComponentInfoInternal
import android.hardware.biometrics.SensorLocationInternal import android.hardware.biometrics.SensorLocationInternal
import android.hardware.biometrics.SensorProperties import android.hardware.biometrics.SensorProperties
import android.hardware.fingerprint.FingerprintEnrollOptions
import android.hardware.fingerprint.FingerprintSensorProperties import android.hardware.fingerprint.FingerprintSensorProperties
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
@@ -78,6 +79,7 @@ class FakeFingerprintManagerInteractor : FingerprintManagerInteractor {
override suspend fun enroll( override suspend fun enroll(
hardwareAuthToken: ByteArray?, hardwareAuthToken: ByteArray?,
enrollReason: EnrollReason, enrollReason: EnrollReason,
fingerprintEnrollOptions: FingerprintEnrollOptions
): Flow<FingerEnrollState> = flowOf(*enrollStateViewModel.toTypedArray()) ): Flow<FingerEnrollState> = flowOf(*enrollStateViewModel.toTypedArray())
override suspend fun removeFingerprint(fp: FingerprintData): Boolean { override suspend fun removeFingerprint(fp: FingerprintData): Boolean {

View File

@@ -109,12 +109,7 @@ class FingerprintManagerInteractorTest {
fingerprintManager, fingerprintManager,
fingerprintSensorRepository, fingerprintSensorRepository,
gateKeeperPasswordProvider, gateKeeperPasswordProvider,
FingerprintEnrollInteractorImpl( FingerprintEnrollInteractorImpl(context, fingerprintManager, Default),
context,
FingerprintEnrollOptions.Builder().build(),
fingerprintManager,
Default,
),
) )
} }
@@ -135,7 +130,7 @@ class FingerprintManagerInteractorTest {
whenever(fingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(fingerprintList) whenever(fingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(fingerprintList)
val list = underTest.enrolledFingerprints.last() val list = underTest.enrolledFingerprints.last()
assertThat(list.size).isEqualTo(fingerprintList.size) assertThat(list!!.size).isEqualTo(fingerprintList.size)
val actual = list[0] val actual = list[0]
assertThat(actual.name).isEqualTo(expected.name) assertThat(actual.name).isEqualTo(expected.name)
assertThat(actual.fingerId).isEqualTo(expected.biometricId) assertThat(actual.fingerId).isEqualTo(expected.biometricId)
@@ -318,7 +313,11 @@ class FingerprintManagerInteractorTest {
testScope.runTest { testScope.runTest {
val token = byteArrayOf(5, 3, 2) val token = byteArrayOf(5, 3, 2)
var result: FingerEnrollState? = null 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() val enrollCallback: ArgumentCaptor<FingerprintManager.EnrollmentCallback> = argumentCaptor()
runCurrent() runCurrent()
@@ -343,7 +342,11 @@ class FingerprintManagerInteractorTest {
testScope.runTest { testScope.runTest {
val token = byteArrayOf(5, 3, 2) val token = byteArrayOf(5, 3, 2)
var result: FingerEnrollState? = null 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() val enrollCallback: ArgumentCaptor<FingerprintManager.EnrollmentCallback> = argumentCaptor()
runCurrent() runCurrent()
@@ -368,7 +371,11 @@ class FingerprintManagerInteractorTest {
testScope.runTest { testScope.runTest {
val token = byteArrayOf(5, 3, 2) val token = byteArrayOf(5, 3, 2)
var result: FingerEnrollState? = null 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() val enrollCallback: ArgumentCaptor<FingerprintManager.EnrollmentCallback> = argumentCaptor()
runCurrent() runCurrent()

View File

@@ -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.FingerprintEnrollViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintFlowViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintFlowViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel
import com.android.settings.testutils2.FakeFingerprintManagerInteractor import com.android.settings.testutils2.FakeFingerprintManagerInteractor
import com.android.systemui.biometrics.shared.model.toFingerprintSensor import com.android.systemui.biometrics.shared.model.toFingerprintSensor
@@ -90,45 +89,20 @@ class FingerprintEnrollFindSensorViewModelV2Test {
Dispatchers.setMain(backgroundDispatcher) Dispatchers.setMain(backgroundDispatcher)
fakeFingerprintManagerInteractor = FakeFingerprintManagerInteractor() fakeFingerprintManagerInteractor = FakeFingerprintManagerInteractor()
gatekeeperViewModel = gatekeeperViewModel = FingerprintGatekeeperViewModel(fakeFingerprintManagerInteractor)
FingerprintGatekeeperViewModel.FingerprintGatekeeperViewModelFactory(
null,
fakeFingerprintManagerInteractor,
)
.create(FingerprintGatekeeperViewModel::class.java)
val sensor = val fingerprintFlowViewModel = FingerprintFlowViewModel()
FingerprintSensorPropertiesInternal( fingerprintFlowViewModel.updateFlowType(Default)
0 /* sensorId */, navigationViewModel = FingerprintNavigationViewModel(fakeFingerprintManagerInteractor)
SensorProperties.STRENGTH_STRONG,
5 /* maxEnrollmentsPerUser */,
listOf<ComponentInfoInternal>(),
FingerprintSensorProperties.TYPE_POWER_BUTTON,
false /* halControlsIllumination */,
true /* resetLockoutRequiresHardwareAuthToken */,
listOf<SensorLocationInternal>(SensorLocationInternal.DEFAULT),
)
.toFingerprintSensor()
val fingerprintFlowViewModel = FingerprintFlowViewModel(Default) backgroundViewModel = BackgroundViewModel()
navigationViewModel =
FingerprintNavigationViewModel(
FingerprintNavigationStep.Education(sensor),
false,
fingerprintFlowViewModel,
fakeFingerprintManagerInteractor,
)
backgroundViewModel =
BackgroundViewModel.BackgroundViewModelFactory().create(BackgroundViewModel::class.java)
backgroundViewModel.inForeground() backgroundViewModel.inForeground()
enrollViewModel = enrollViewModel =
FingerprintEnrollViewModel.FingerprintEnrollViewModelFactory( FingerprintEnrollViewModel(
fakeFingerprintManagerInteractor, fakeFingerprintManagerInteractor,
gatekeeperViewModel, gatekeeperViewModel,
navigationViewModel, navigationViewModel,
) )
.create(FingerprintEnrollViewModel::class.java)
accessibilityInteractor = accessibilityInteractor =
object : AccessibilityInteractor { object : AccessibilityInteractor {
override val isAccessibilityEnabled: Flow<Boolean> = flowOf(false) override val isAccessibilityEnabled: Flow<Boolean> = flowOf(false)
@@ -147,21 +121,21 @@ class FingerprintEnrollFindSensorViewModelV2Test {
override val orientation: Flow<Int> = flowOf(Configuration.ORIENTATION_LANDSCAPE) override val orientation: Flow<Int> = flowOf(Configuration.ORIENTATION_LANDSCAPE)
override val rotation: 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 val rotationFromDefault: Flow<Int> = flowOf(Surface.ROTATION_0)
override fun getRotationFromDefault(rotation: Int): Int = rotation override fun getRotationFromDefault(rotation: Int): Int = rotation
} }
underTest = underTest =
FingerprintEnrollFindSensorViewModel.FingerprintEnrollFindSensorViewModelFactory( FingerprintEnrollFindSensorViewModel(
navigationViewModel, navigationViewModel,
enrollViewModel, enrollViewModel,
gatekeeperViewModel, gatekeeperViewModel,
backgroundViewModel, backgroundViewModel,
fingerprintFlowViewModel,
accessibilityInteractor, accessibilityInteractor,
foldStateInteractor, foldStateInteractor,
orientationInteractor, orientationInteractor,
fingerprintFlowViewModel,
fakeFingerprintManagerInteractor, fakeFingerprintManagerInteractor,
) )
.create(FingerprintEnrollFindSensorViewModel::class.java)
} }
@After @After

View File

@@ -23,22 +23,23 @@ import android.hardware.fingerprint.FingerprintSensorProperties
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.android.settings.biometrics.fingerprint2.lib.model.Default 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.FingerprintEnrollConfirmationViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintFlowViewModel 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.FingerprintNavigationStep
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel
import com.android.settings.testutils2.FakeFingerprintManagerInteractor import com.android.settings.testutils2.FakeFingerprintManagerInteractor
import com.android.systemui.biometrics.shared.model.FingerprintSensor
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.biometrics.shared.model.toFingerprintSensor import com.android.systemui.biometrics.shared.model.toFingerprintSensor
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.setMain
import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@@ -53,28 +54,52 @@ class FingerprintEnrollConfirmationViewModelTest {
@get:Rule val instantTaskRule = InstantTaskExecutorRule() @get:Rule val instantTaskRule = InstantTaskExecutorRule()
private var backgroundDispatcher = StandardTestDispatcher() private var backgroundDispatcher = StandardTestDispatcher()
private var testScope = TestScope(backgroundDispatcher) private var testScope = TestScope(backgroundDispatcher)
val fingerprintFlowViewModel = FingerprintFlowViewModel(Default) val fingerprintFlowViewModel = FingerprintFlowViewModel()
val fakeFingerprintManagerInteractor = FakeFingerprintManagerInteractor() val fakeFingerprintManagerInteractor = FakeFingerprintManagerInteractor()
lateinit var navigationViewModel: FingerprintNavigationViewModel lateinit var navigationViewModel: FingerprintNavigationViewModel
lateinit var underTest: FingerprintEnrollConfirmationViewModel lateinit var underTest: FingerprintEnrollConfirmationViewModel
@Before @Before
fun setup() { fun setup() {
navigationViewModel = Dispatchers.setMain(backgroundDispatcher)
FingerprintNavigationViewModel( fingerprintFlowViewModel.updateFlowType(Default)
FingerprintNavigationStep.Confirmation, navigationViewModel = FingerprintNavigationViewModel(fakeFingerprintManagerInteractor)
false,
fingerprintFlowViewModel,
fakeFingerprintManagerInteractor,
)
underTest = underTest =
FingerprintEnrollConfirmationViewModel(navigationViewModel, fakeFingerprintManagerInteractor) 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 @Test
fun testCanEnrollFingerprints() = fun testCanEnrollFingerprints() =
testScope.runTest { testScope.runTest {
fakeFingerprintManagerInteractor.sensorProp = FingerprintSensorPropertiesInternal( advanceUntilIdle()
bringToConfirmation()
fakeFingerprintManagerInteractor.sensorProp =
FingerprintSensorPropertiesInternal(
0 /* sensorId */, 0 /* sensorId */,
SensorProperties.STRENGTH_STRONG, SensorProperties.STRENGTH_STRONG,
5 /* maxEnrollmentsPerUser */, 5 /* maxEnrollmentsPerUser */,
@@ -90,7 +115,9 @@ class FingerprintEnrollConfirmationViewModelTest {
fakeFingerprintManagerInteractor.enrollableFingerprints = 5 fakeFingerprintManagerInteractor.enrollableFingerprints = 5
var canEnrollFingerprints: Boolean = false var canEnrollFingerprints: Boolean = false
val job = launch { underTest.isAddAnotherButtonVisible.collect { canEnrollFingerprints = it } } val job = launch {
underTest.isAddAnotherButtonVisible.collect { canEnrollFingerprints = it }
}
advanceUntilIdle() advanceUntilIdle()
assertThat(canEnrollFingerprints).isTrue() assertThat(canEnrollFingerprints).isTrue()
@@ -100,12 +127,14 @@ class FingerprintEnrollConfirmationViewModelTest {
@Test @Test
fun testNextButtonSendsNextStep() = fun testNextButtonSendsNextStep() =
testScope.runTest { testScope.runTest {
advanceUntilIdle()
bringToConfirmation()
var step: FingerprintNavigationStep.UiStep? = null var step: FingerprintNavigationStep.UiStep? = null
val job = launch { navigationViewModel.navigateTo.collect { step = it } } val job = launch { navigationViewModel.navigateTo.collect { step = it } }
underTest.onNextButtonClicked() underTest.onNextButtonClicked()
runCurrent() advanceUntilIdle()
assertThat(step).isNull() assertThat(step).isNull()
job.cancel() job.cancel()
@@ -114,14 +143,18 @@ class FingerprintEnrollConfirmationViewModelTest {
@Test @Test
fun testAddAnotherSendsAction() = fun testAddAnotherSendsAction() =
testScope.runTest { testScope.runTest {
advanceUntilIdle()
bringToConfirmation()
advanceUntilIdle()
var step: FingerprintNavigationStep.UiStep? = null var step: FingerprintNavigationStep.UiStep? = null
val job = launch { navigationViewModel.navigateTo.collect { step = it } } val job = launch { navigationViewModel.navigateTo.collect { step = it } }
underTest.onAddAnotherButtonClicked() underTest.onAddAnotherButtonClicked()
runCurrent() advanceUntilIdle()
assertThat(step).isInstanceOf(FingerprintNavigationStep.Enrollment::class.java) assertThat(step).isNull()
job.cancel() job.cancel()
} }
} }

View File

@@ -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.FingerprintEnrollViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintFlowViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintFlowViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Enrollment
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo
import com.android.settings.testutils2.FakeFingerprintManagerInteractor import com.android.settings.testutils2.FakeFingerprintManagerInteractor
import com.android.systemui.biometrics.shared.model.toFingerprintSensor import com.android.systemui.biometrics.shared.model.toFingerprintSensor
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
@@ -61,20 +59,15 @@ class FingerprintEnrollEnrollingViewModelTest {
private lateinit var backgroundViewModel: BackgroundViewModel private lateinit var backgroundViewModel: BackgroundViewModel
private lateinit var gateKeeperViewModel: FingerprintGatekeeperViewModel private lateinit var gateKeeperViewModel: FingerprintGatekeeperViewModel
private lateinit var navigationViewModel: FingerprintNavigationViewModel private lateinit var navigationViewModel: FingerprintNavigationViewModel
private val defaultGatekeeperInfo = GatekeeperInfo.GatekeeperPasswordInfo(byteArrayOf(1, 3), 3)
private var testScope = TestScope(backgroundDispatcher) private var testScope = TestScope(backgroundDispatcher)
private lateinit var fakeFingerprintManagerInteractor: FakeFingerprintManagerInteractor private lateinit var fakeFingerprintManagerInteractor: FakeFingerprintManagerInteractor
private fun initialize(gatekeeperInfo: GatekeeperInfo = defaultGatekeeperInfo) { private fun initialize() {
fakeFingerprintManagerInteractor = FakeFingerprintManagerInteractor() fakeFingerprintManagerInteractor = FakeFingerprintManagerInteractor()
gateKeeperViewModel =
FingerprintGatekeeperViewModel.FingerprintGatekeeperViewModelFactory( gateKeeperViewModel = FingerprintGatekeeperViewModel(fakeFingerprintManagerInteractor)
gatekeeperInfo, fakeFingerprintManagerInteractor.sensorProp =
fakeFingerprintManagerInteractor,
)
.create(FingerprintGatekeeperViewModel::class.java)
val sensor =
FingerprintSensorPropertiesInternal( FingerprintSensorPropertiesInternal(
1 /* sensorId */, 1 /* sensorId */,
SensorProperties.STRENGTH_STRONG, SensorProperties.STRENGTH_STRONG,
@@ -86,32 +79,21 @@ class FingerprintEnrollEnrollingViewModelTest {
listOf<SensorLocationInternal>(SensorLocationInternal.DEFAULT), listOf<SensorLocationInternal>(SensorLocationInternal.DEFAULT),
) )
.toFingerprintSensor() .toFingerprintSensor()
val fingerprintFlowViewModel = FingerprintFlowViewModel(Default) val fingerprintFlowViewModel = FingerprintFlowViewModel()
fingerprintFlowViewModel.updateFlowType(Default)
navigationViewModel = navigationViewModel = FingerprintNavigationViewModel(fakeFingerprintManagerInteractor)
FingerprintNavigationViewModel(
Enrollment(sensor),
false,
fingerprintFlowViewModel,
fakeFingerprintManagerInteractor,
)
backgroundViewModel = backgroundViewModel = BackgroundViewModel()
BackgroundViewModel.BackgroundViewModelFactory().create(BackgroundViewModel::class.java)
backgroundViewModel.inForeground() backgroundViewModel.inForeground()
val fingerprintEnrollViewModel = val fingerprintEnrollViewModel =
FingerprintEnrollViewModel.FingerprintEnrollViewModelFactory( FingerprintEnrollViewModel(
fakeFingerprintManagerInteractor, fakeFingerprintManagerInteractor,
gateKeeperViewModel, gateKeeperViewModel,
navigationViewModel, navigationViewModel,
) )
.create(FingerprintEnrollViewModel::class.java)
enrollEnrollingViewModel = enrollEnrollingViewModel =
FingerprintEnrollEnrollingViewModel.FingerprintEnrollEnrollingViewModelFactory( FingerprintEnrollEnrollingViewModel(fingerprintEnrollViewModel, backgroundViewModel)
fingerprintEnrollViewModel,
backgroundViewModel,
)
.create(FingerprintEnrollEnrollingViewModel::class.java)
} }
@Before @Before
@@ -128,6 +110,7 @@ class FingerprintEnrollEnrollingViewModelTest {
@Test @Test
fun testEnrollShouldBeFalse() = fun testEnrollShouldBeFalse() =
testScope.runTest { testScope.runTest {
gateKeeperViewModel.onConfirmDevice(true, 3L, false)
var shouldEnroll = false var shouldEnroll = false
val job = launch { val job = launch {
@@ -147,6 +130,7 @@ class FingerprintEnrollEnrollingViewModelTest {
@Test @Test
fun testEnrollShouldBeFalseWhenBackground() = fun testEnrollShouldBeFalseWhenBackground() =
testScope.runTest { testScope.runTest {
gateKeeperViewModel.onConfirmDevice(true, 3L, false)
var shouldEnroll = false var shouldEnroll = false
val job = launch { val job = launch {