Adding more biometric screenshot tests

Test: atest FingerprintEnrollIntroScreenshotTest FingerprintEnrollFindSensorScreenshotTest FingerprintEnrollEnrollingScreenshotTest
Bug: 297083009
Change-Id: I11df6fbaefa9d333dcfe803577947a4be7af9882
This commit is contained in:
Joshua McCloskey
2024-02-13 18:56:07 +00:00
parent 98374376cc
commit d92faeb1cf
35 changed files with 805 additions and 554 deletions

View File

@@ -25,12 +25,12 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:contentDescription="@string/security_settings_fingerprint_enroll_find_sensor_content_description" android:contentDescription="@string/security_settings_fingerprint_enroll_find_sensor_content_description"
android:src="@drawable/fingerprint_sensor_location" android:scaleType="centerInside"
android:scaleType="centerInside"/> android:src="@drawable/fingerprint_sensor_location" />
<com.android.settings.biometrics.fingerprint.FingerprintLocationAnimationView <com.android.settings.biometrics.fingerprint.FingerprintLocationAnimationView
android:id="@+id/fingerprint_sensor_location_animation" android:id="@+id/fingerprint_sensor_location_animation"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"/> android:layout_height="match_parent" />
</FrameLayout> </FrameLayout>

View File

@@ -16,29 +16,30 @@
--> -->
<com.google.android.setupdesign.GlifLayout <com.google.android.setupdesign.GlifLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/setup_wizard_layout" android:id="@+id/setup_wizard_layout"
style="?attr/fingerprint_layout_theme" style="?attr/fingerprint_layout_theme"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent">
android:orientation="vertical"
android:clipToPadding="false"
android:clipChildren="false">
<Space <LinearLayout
android:layout_width="wrap_content" android:id="@+id/content_view"
android:layout_height="0dp"
android:layout_weight="1" />
<include
layout="@layout/fingerprint_enroll_find_sensor_graphic"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:layout_gravity="center_horizontal"/> android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical">
</LinearLayout> <Space
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1" />
<include
layout="@layout/fingerprint_enroll_find_sensor_graphic"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
</LinearLayout>
</com.google.android.setupdesign.GlifLayout> </com.google.android.setupdesign.GlifLayout>

View File

@@ -18,35 +18,35 @@
<com.google.android.setupdesign.GlifLayout <com.google.android.setupdesign.GlifLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
style="?attr/fingerprint_layout_theme"
android:id="@+id/setup_wizard_layout" android:id="@+id/setup_wizard_layout"
style="?attr/fingerprint_layout_theme"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
> >
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/SudContentFrame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical">
<LinearLayout <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/content_view"
style="@style/SudContentFrame"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="match_parent"
android:layout_weight="1" android:clipChildren="false"
android:gravity="center" android:clipToPadding="false"
android:orientation="vertical"> android:orientation="vertical">
<com.google.android.setupdesign.view.FillContentLayout <LinearLayout
android:layout_width="@dimen/fingerprint_progress_bar_max_size" android:layout_width="match_parent"
android:layout_height="@dimen/fingerprint_progress_bar_max_size" android:layout_height="0dp"
android:layout_marginVertical="24dp" android:layout_weight="1"
android:paddingTop="0dp" android:gravity="center"
android:paddingBottom="0dp"> android:orientation="vertical">
<com.google.android.setupdesign.view.FillContentLayout
android:layout_width="@dimen/fingerprint_progress_bar_max_size"
android:layout_height="@dimen/fingerprint_progress_bar_max_size"
android:layout_marginVertical="24dp"
android:paddingTop="0dp"
android:paddingBottom="0dp">
<com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.widget.RFPSProgressBar <com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.widget.RFPSProgressBar
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fingerprint_progress_bar" android:id="@+id/fingerprint_progress_bar"
@@ -54,22 +54,23 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@drawable/fp_illustration" android:background="@drawable/fp_illustration"
android:minHeight="@dimen/fingerprint_progress_bar_min_size" android:minHeight="@dimen/fingerprint_progress_bar_min_size"
android:progress="0" /> android:progress="0"
/>
</com.google.android.setupdesign.view.FillContentLayout> </com.google.android.setupdesign.view.FillContentLayout>
<TextView <TextView
android:id="@+id/text" android:id="@+id/text"
style="@style/TextAppearance.ErrorText" style="@style/TextAppearance.ErrorText"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom" android:layout_gravity="center_horizontal|bottom"
android:accessibilityLiveRegion="polite" android:accessibilityLiveRegion="polite"
android:gravity="center" android:gravity="center"
android:visibility="invisible" /> android:visibility="invisible" />
</LinearLayout>
</LinearLayout> </LinearLayout>
</LinearLayout>
</com.google.android.setupdesign.GlifLayout> </com.google.android.setupdesign.GlifLayout>

View File

@@ -1,3 +1,4 @@
# Owners for Biometric Fingerprint # Owners for Biometric Fingerprint
joshmccloskey@google.com joshmccloskey@google.com
jbolinger@google.com jbolinger@google.com
spdonghao@google.com

View File

@@ -39,16 +39,16 @@ import kotlinx.coroutines.withContext
* *
* TODO(b/313493336): Move this to systemui * TODO(b/313493336): Move this to systemui
*/ */
interface FingerprintSensorRepo { interface FingerprintSensorRepository {
/** Get the [FingerprintSensor] */ /** Get the [FingerprintSensor] */
val fingerprintSensor: Flow<FingerprintSensor> val fingerprintSensor: Flow<FingerprintSensor>
} }
class FingerprintSensorRepoImpl( class FingerprintSensorRepositoryImpl(
fingerprintManager: FingerprintManager, fingerprintManager: FingerprintManager,
backgroundDispatcher: CoroutineDispatcher, backgroundDispatcher: CoroutineDispatcher,
activityScope: CoroutineScope, activityScope: CoroutineScope,
) : FingerprintSensorRepo { ) : FingerprintSensorRepository {
override val fingerprintSensor: Flow<FingerprintSensor> = override val fingerprintSensor: Flow<FingerprintSensor> =
callbackFlow { callbackFlow {

View File

@@ -1,62 +0,0 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.biometrics.fingerprint2.data.repository
import android.content.Context
import android.provider.Settings
/** Interface that indicates if press to auth is on or off. */
interface PressToAuthRepo {
/** Indicates true if the PressToAuth feature is enabled, false otherwise. */
val isEnabled: Boolean
}
/** Indicates whether or not the press to auth feature is enabled. */
class PressToAuthRepoImpl(private val context: Context) : PressToAuthRepo {
/**
* Gets the status of the press to auth feature.
*
* Returns whether or not the press to auth feature is enabled.
*/
override val isEnabled: Boolean
get() {
var toReturn: Int =
Settings.Secure.getIntForUser(
context.contentResolver,
Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED,
-1,
context.userId,
)
if (toReturn == -1) {
toReturn =
if (
context.resources.getBoolean(com.android.internal.R.bool.config_performantAuthDefault)
) {
1
} else {
0
}
Settings.Secure.putIntForUser(
context.contentResolver,
Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED,
toReturn,
context.userId,
)
}
return (toReturn == 1)
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2023 The Android Open Source Project * Copyright (C) 2024 The Android Open Source Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -14,12 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel package com.android.settings.biometrics.fingerprint2.domain.interactor
import android.view.accessibility.AccessibilityManager import android.view.accessibility.AccessibilityManager
import androidx.lifecycle.ViewModel import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
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
@@ -27,28 +25,28 @@ import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
/** Represents all of the information on accessibility state. */ /** Represents all of the information on accessibility state. */
class AccessibilityViewModel(accessibilityManager: AccessibilityManager) : ViewModel() { interface AccessibilityInteractor {
/** A flow that contains whether or not accessibility is enabled */
val isAccessibilityEnabled: Flow<Boolean>
}
class AccessibilityInteractorImpl(
accessibilityManager: AccessibilityManager,
activityScope: LifecycleCoroutineScope
) : AccessibilityInteractor {
/** A flow that contains whether or not accessibility is enabled */ /** A flow that contains whether or not accessibility is enabled */
val isAccessibilityEnabled: Flow<Boolean> = override val isAccessibilityEnabled: Flow<Boolean> =
callbackFlow { callbackFlow {
val listener = val listener =
AccessibilityManager.AccessibilityStateChangeListener { enabled -> trySend(enabled) } AccessibilityManager.AccessibilityStateChangeListener { enabled -> trySend(enabled) }
accessibilityManager.addAccessibilityStateChangeListener(listener) accessibilityManager.addAccessibilityStateChangeListener(listener)
// This clause will be called when no one is listening to the flow // This clause will be called when no one is listening to the flow
awaitClose { accessibilityManager.removeAccessibilityStateChangeListener(listener) } awaitClose { accessibilityManager.removeAccessibilityStateChangeListener(listener) }
}
.stateIn(
viewModelScope, // This is going to tied to the view model scope
SharingStarted.WhileSubscribed(), // When no longer subscribed, we removeTheListener
false,
)
class AccessibilityViewModelFactory(private val accessibilityManager: AccessibilityManager) :
ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return AccessibilityViewModel(accessibilityManager) as T
} }
} .stateIn(
} activityScope, // This is going to tied to the activity scope
SharingStarted.WhileSubscribed(), // When no longer subscribed, we removeTheListener
false
)
}

View File

@@ -26,8 +26,7 @@ import android.util.Log
import com.android.settings.biometrics.GatekeeperPasswordProvider import com.android.settings.biometrics.GatekeeperPasswordProvider
import com.android.settings.biometrics.fingerprint2.conversion.Util.toEnrollError import com.android.settings.biometrics.fingerprint2.conversion.Util.toEnrollError
import com.android.settings.biometrics.fingerprint2.conversion.Util.toOriginalReason import com.android.settings.biometrics.fingerprint2.conversion.Util.toOriginalReason
import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepo import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepository
import com.android.settings.biometrics.fingerprint2.data.repository.PressToAuthRepo
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
@@ -57,9 +56,9 @@ class FingerprintManagerInteractorImpl(
applicationContext: Context, applicationContext: Context,
private val backgroundDispatcher: CoroutineDispatcher, private val backgroundDispatcher: CoroutineDispatcher,
private val fingerprintManager: FingerprintManager, private val fingerprintManager: FingerprintManager,
fingerprintSensorRepo: FingerprintSensorRepo, fingerprintSensorRepository: FingerprintSensorRepository,
private val gatekeeperPasswordProvider: GatekeeperPasswordProvider, private val gatekeeperPasswordProvider: GatekeeperPasswordProvider,
private val pressToAuthRepo: PressToAuthRepo, private val pressToAuthInteractor: PressToAuthInteractor,
private val fingerprintFlow: FingerprintFlow, private val fingerprintFlow: FingerprintFlow,
) : FingerprintManagerInteractor { ) : FingerprintManagerInteractor {
@@ -101,7 +100,7 @@ class FingerprintManagerInteractorImpl(
) )
} }
override val sensorPropertiesInternal = fingerprintSensorRepo.fingerprintSensor override val sensorPropertiesInternal = fingerprintSensorRepository.fingerprintSensor
override val maxEnrollableFingerprints = flow { emit(maxFingerprints) } override val maxEnrollableFingerprints = flow { emit(maxFingerprints) }
@@ -211,10 +210,6 @@ class FingerprintManagerInteractorImpl(
it.resume(fingerprintManager.isPowerbuttonFps) it.resume(fingerprintManager.isPowerbuttonFps)
} }
override suspend fun pressToAuthEnabled(): Boolean = suspendCancellableCoroutine {
it.resume(pressToAuthRepo.isEnabled)
}
override suspend fun authenticate(): FingerprintAuthAttemptModel = override suspend fun authenticate(): FingerprintAuthAttemptModel =
suspendCancellableCoroutine { c: CancellableContinuation<FingerprintAuthAttemptModel> -> suspendCancellableCoroutine { c: CancellableContinuation<FingerprintAuthAttemptModel> ->
val authenticationCallback = val authenticationCallback =

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.biometrics.fingerprint2.domain.interactor
import android.content.Context
import android.content.res.Configuration
import com.android.systemui.unfold.compat.ScreenSizeFoldProvider
import com.android.systemui.unfold.updates.FoldProvider
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
interface FoldStateInteractor {
/** A flow that contains the fold state info */
val isFolded: Flow<Boolean>
/**
* Indicates a configuration change has occurred, and the repo
* should update the [isFolded] flow.
*/
fun onConfigurationChange(newConfig: Configuration)
}
/**
* Interactor which handles fold state
*/
class FoldStateInteractorImpl(context: Context) : FoldStateInteractor {
private val screenSizeFoldProvider = ScreenSizeFoldProvider(context)
override val isFolded: Flow<Boolean> = callbackFlow {
val foldStateListener = FoldProvider.FoldCallback { isFolded -> trySend(isFolded) }
screenSizeFoldProvider.registerCallback(foldStateListener, context.mainExecutor)
awaitClose { screenSizeFoldProvider.unregisterCallback(foldStateListener) }
}
/**
* This function is called by the root activity, indicating an orientation event has occurred.
* When this happens, the [ScreenSizeFoldProvider] is notified and it will re-compute if the
* device is folded or not, and notify the [FoldProvider.FoldCallback]
*/
override fun onConfigurationChange(newConfig: Configuration) {
screenSizeFoldProvider.onConfigurationChange(newConfig)
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2023 The Android Open Source Project * Copyright (C) 2024 The Android Open Source Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -14,25 +14,37 @@
* limitations under the License. * limitations under the License.
*/ */
package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel package com.android.settings.biometrics.fingerprint2.domain.interactor
import android.content.Context import android.content.Context
import android.view.OrientationEventListener import android.view.OrientationEventListener
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.android.internal.R import com.android.internal.R
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
import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
/** Represents all of the information on orientation state and rotation state. */ /**
class OrientationStateViewModel(private val context: Context) : ViewModel() { * Interactor which provides information about orientation
*/
interface OrientationInteractor {
/** A flow that contains the information about the orientation changing */
val orientation: Flow<Int>
/** A flow that contains the rotation info */
val rotation: Flow<Int>
/**
* A Helper function that computes rotation if device is in
* [R.bool.config_reverseDefaultConfigRotation]
*/
fun getRotationFromDefault(rotation: Int): Int
}
/** A flow that contains the orientation info */ class OrientationInteractorImpl(private val context: Context, activityScope: CoroutineScope) :
val orientation: Flow<Int> = callbackFlow { OrientationInteractor {
override val orientation: Flow<Int> = callbackFlow {
val orientationEventListener = val orientationEventListener =
object : OrientationEventListener(context) { object : OrientationEventListener(context) {
override fun onOrientationChanged(orientation: Int) { override fun onOrientationChanged(orientation: Int) {
@@ -43,25 +55,24 @@ class OrientationStateViewModel(private val context: Context) : ViewModel() {
awaitClose { orientationEventListener.disable() } awaitClose { orientationEventListener.disable() }
} }
/** A flow that contains the rotation info */ override val rotation: Flow<Int> =
val rotation: Flow<Int> =
callbackFlow { callbackFlow {
val orientationEventListener = val orientationEventListener =
object : OrientationEventListener(context) { object : OrientationEventListener(context) {
override fun onOrientationChanged(orientation: Int) { override fun onOrientationChanged(orientation: Int) {
trySend(getRotationFromDefault(context.display!!.rotation)) trySend(getRotationFromDefault(context.display!!.rotation))
}
} }
orientationEventListener.enable() }
awaitClose { orientationEventListener.disable() } orientationEventListener.enable()
} awaitClose { orientationEventListener.disable() }
}
.stateIn( .stateIn(
viewModelScope, // This is going to tied to the view model scope activityScope, // This is tied to the activity scope
SharingStarted.WhileSubscribed(), // When no longer subscribed, we removeTheListener SharingStarted.WhileSubscribed(), // When no longer subscribed, we removeTheListener
context.display!!.rotation, context.display!!.rotation,
) )
fun getRotationFromDefault(rotation: Int): Int { override fun getRotationFromDefault(rotation: Int): Int {
val isReverseDefaultRotation = val isReverseDefaultRotation =
context.resources.getBoolean(R.bool.config_reverseDefaultRotation) context.resources.getBoolean(R.bool.config_reverseDefaultRotation)
return if (isReverseDefaultRotation) { return if (isReverseDefaultRotation) {
@@ -70,11 +81,4 @@ class OrientationStateViewModel(private val context: Context) : ViewModel() {
rotation rotation
} }
} }
}
class OrientationViewModelFactory(private val context: Context) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return OrientationStateViewModel(context) as T
}
}
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.biometrics.fingerprint2.domain.interactor
import android.content.Context
import android.database.ContentObserver
import android.provider.Settings
import android.util.Log
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.flowOn
/** Interface that indicates if press to auth is on or off. */
interface PressToAuthInteractor {
/** Indicates true if the PressToAuth feature is enabled, false otherwise. */
val isEnabled: Flow<Boolean>
}
/** Indicates whether or not the press to auth feature is enabled. */
class PressToAuthInteractorImpl(
private val context: Context,
private val backgroundDispatcher: CoroutineDispatcher,
) : PressToAuthInteractor {
/**
* A flow that contains the status of the press to auth feature.
*/
override val isEnabled: Flow<Boolean> =
callbackFlow {
val callback =
object : ContentObserver(null) {
override fun onChange(selfChange: Boolean) {
Log.d(TAG, "SFPS_PERFORMANT_AUTH_ENABLED#onchange")
trySend(
getPressToAuth(),
)
}
}
context.contentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED),
false,
callback,
context.userId
)
trySend(getPressToAuth())
awaitClose {
context.contentResolver.unregisterContentObserver(callback)
}
}.flowOn(backgroundDispatcher)
/**
* Returns true if press to auth is enabled
*/
private fun getPressToAuth(): Boolean {
var toReturn: Int =
Settings.Secure.getIntForUser(
context.contentResolver,
Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED,
-1,
context.userId,
)
if (toReturn == -1) {
toReturn =
if (
context.resources.getBoolean(com.android.internal.R.bool.config_performantAuthDefault)
) {
1
} else {
0
}
Settings.Secure.putIntForUser(
context.contentResolver,
Settings.Secure.SFPS_PERFORMANT_AUTH_ENABLED,
toReturn,
context.userId,
)
}
return toReturn == 1
}
companion object {
const val TAG = "PressToAuthInteractor"
}
}

View File

@@ -75,7 +75,4 @@ interface FingerprintManagerInteractor {
/** Indicates if the device has side fingerprint */ /** Indicates if the device has side fingerprint */
suspend fun hasSideFps(): Boolean suspend fun hasSideFps(): Boolean
/** Indicates if the press to auth feature has been enabled */
suspend fun pressToAuthEnabled(): Boolean
} }

View File

@@ -30,16 +30,20 @@ import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.android.internal.widget.LockPatternUtils import com.android.internal.widget.LockPatternUtils
import com.android.settings.R import com.android.settings.R
import com.android.settings.SettingsApplication
import com.android.settings.SetupWizardUtils import com.android.settings.SetupWizardUtils
import com.android.settings.Utils.SETTINGS_PACKAGE_NAME import com.android.settings.Utils.SETTINGS_PACKAGE_NAME
import com.android.settings.biometrics.BiometricEnrollBase import com.android.settings.biometrics.BiometricEnrollBase
import com.android.settings.biometrics.BiometricEnrollBase.CONFIRM_REQUEST import com.android.settings.biometrics.BiometricEnrollBase.CONFIRM_REQUEST
import com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED import com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED
import com.android.settings.biometrics.GatekeeperPasswordProvider import com.android.settings.biometrics.GatekeeperPasswordProvider
import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepoImpl import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepositoryImpl
import com.android.settings.biometrics.fingerprint2.data.repository.PressToAuthRepoImpl import com.android.settings.biometrics.fingerprint2.domain.interactor.PressToAuthInteractorImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.AccessibilityInteractorImpl
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.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.lib.model.Default import com.android.settings.biometrics.fingerprint2.lib.model.Default
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
@@ -48,7 +52,6 @@ import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.Finge
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollIntroV2Fragment import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollIntroV2Fragment
import com.android.settings.biometrics.fingerprint2.ui.enrollment.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.rfps.ui.viewmodel.RFPSViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.AccessibilityViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintAction import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintAction
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollEnrollingViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollEnrollingViewModel
@@ -66,9 +69,7 @@ import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Fing
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.FingerprintScrollViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FoldStateViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.OrientationStateViewModel
import com.android.settings.password.ChooseLockGeneric import com.android.settings.password.ChooseLockGeneric
import com.android.settings.password.ChooseLockSettingsHelper import com.android.settings.password.ChooseLockSettingsHelper
import com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE import com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE
@@ -90,9 +91,8 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
private lateinit var navigationViewModel: FingerprintNavigationViewModel private lateinit var navigationViewModel: FingerprintNavigationViewModel
private lateinit var gatekeeperViewModel: FingerprintGatekeeperViewModel private lateinit var gatekeeperViewModel: FingerprintGatekeeperViewModel
private lateinit var fingerprintEnrollViewModel: FingerprintEnrollViewModel private lateinit var fingerprintEnrollViewModel: FingerprintEnrollViewModel
private lateinit var accessibilityViewModel: AccessibilityViewModel private lateinit var foldStateInteractor: FoldStateInteractor
private lateinit var foldStateViewModel: FoldStateViewModel private lateinit var orientationInteractor: OrientationInteractor
private lateinit var orientationStateViewModel: OrientationStateViewModel
private lateinit var fingerprintScrollViewModel: FingerprintScrollViewModel private lateinit var fingerprintScrollViewModel: FingerprintScrollViewModel
private lateinit var backgroundViewModel: BackgroundViewModel private lateinit var backgroundViewModel: BackgroundViewModel
private lateinit var fingerprintFlowViewModel: FingerprintFlowViewModel private lateinit var fingerprintFlowViewModel: FingerprintFlowViewModel
@@ -127,7 +127,7 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
override fun onConfigurationChanged(newConfig: Configuration) { override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig) super.onConfigurationChanged(newConfig)
foldStateViewModel.onConfigurationChange(newConfig) foldStateInteractor.onConfigurationChange(newConfig)
} }
private fun onConfirmDevice(resultCode: Int, data: Intent?) { private fun onConfirmDevice(resultCode: Int, data: Intent?) {
@@ -179,7 +179,8 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
FingerprintFlowViewModel::class.java] FingerprintFlowViewModel::class.java]
val fingerprintSensorRepo = val fingerprintSensorRepo =
FingerprintSensorRepoImpl(fingerprintManager, backgroundDispatcher, lifecycleScope) FingerprintSensorRepositoryImpl(fingerprintManager, backgroundDispatcher, lifecycleScope)
val pressToAuthInteractor = PressToAuthInteractorImpl(context, backgroundDispatcher)
val fingerprintManagerInteractor = val fingerprintManagerInteractor =
FingerprintManagerInteractorImpl( FingerprintManagerInteractorImpl(
@@ -188,7 +189,7 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
fingerprintManager, fingerprintManager,
fingerprintSensorRepo, fingerprintSensorRepo,
GatekeeperPasswordProvider(LockPatternUtils(context)), GatekeeperPasswordProvider(LockPatternUtils(context)),
PressToAuthRepoImpl(context), pressToAuthInteractor,
enrollType, enrollType,
) )
@@ -198,6 +199,12 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
val hasConfirmedDeviceCredential = gatekeeperInfo is GatekeeperInfo.GatekeeperPasswordInfo val hasConfirmedDeviceCredential = gatekeeperInfo is GatekeeperInfo.GatekeeperPasswordInfo
val accessibilityInteractor =
AccessibilityInteractorImpl(
getSystemService(AccessibilityManager::class.java)!!,
lifecycleScope,
)
navigationViewModel = navigationViewModel =
ViewModelProvider( ViewModelProvider(
this, this,
@@ -228,10 +235,10 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
)[FingerprintGatekeeperViewModel::class.java] )[FingerprintGatekeeperViewModel::class.java]
// Initialize FoldStateViewModel // Initialize FoldStateViewModel
foldStateViewModel = foldStateInteractor = FoldStateInteractorImpl(context)
ViewModelProvider(this, FoldStateViewModel.FoldStateViewModelFactory(context))[ foldStateInteractor.onConfigurationChange(resources.configuration)
FoldStateViewModel::class.java]
foldStateViewModel.onConfigurationChange(resources.configuration) orientationInteractor = OrientationInteractorImpl(context, lifecycleScope)
// Initialize FingerprintViewModel // Initialize FingerprintViewModel
fingerprintEnrollViewModel = fingerprintEnrollViewModel =
@@ -249,20 +256,6 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
ViewModelProvider(this, FingerprintScrollViewModel.FingerprintScrollViewModelFactory())[ ViewModelProvider(this, FingerprintScrollViewModel.FingerprintScrollViewModelFactory())[
FingerprintScrollViewModel::class.java] FingerprintScrollViewModel::class.java]
// Initialize AccessibilityViewModel
accessibilityViewModel =
ViewModelProvider(
this,
AccessibilityViewModel.AccessibilityViewModelFactory(
getSystemService(AccessibilityManager::class.java)!!
),
)[AccessibilityViewModel::class.java]
// Initialize OrientationViewModel
orientationStateViewModel =
ViewModelProvider(this, OrientationStateViewModel.OrientationViewModelFactory(context))[
OrientationStateViewModel::class.java]
// Initialize FingerprintEnrollEnrollingViewModel // Initialize FingerprintEnrollEnrollingViewModel
fingerprintEnrollEnrollingViewModel = fingerprintEnrollEnrollingViewModel =
ViewModelProvider( ViewModelProvider(
@@ -281,18 +274,24 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
fingerprintEnrollViewModel, fingerprintEnrollViewModel,
gatekeeperViewModel, gatekeeperViewModel,
backgroundViewModel, backgroundViewModel,
accessibilityViewModel, accessibilityInteractor,
foldStateViewModel, foldStateInteractor,
orientationStateViewModel, orientationInteractor,
fingerprintFlowViewModel, fingerprintFlowViewModel,
fingerprintManagerInteractor,
), ),
)[FingerprintEnrollFindSensorViewModel::class.java] )[FingerprintEnrollFindSensorViewModel::class.java]
// Initialize RFPS View Model // Initialize RFPS View Model
ViewModelProvider( ViewModelProvider(
this, this,
RFPSViewModel.RFPSViewModelFactory(fingerprintEnrollEnrollingViewModel, navigationViewModel), RFPSViewModel.RFPSViewModelFactory(
fingerprintEnrollEnrollingViewModel,
navigationViewModel,
orientationInteractor,
),
)[RFPSViewModel::class.java] )[RFPSViewModel::class.java]
lifecycleScope.launch { lifecycleScope.launch {
navigationViewModel.currentStep.collect { step -> navigationViewModel.currentStep.collect { step ->
if (step is Init) { if (step is Init) {

View File

@@ -22,6 +22,7 @@ import android.view.LayoutInflater
import android.view.Surface import android.view.Surface
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.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
@@ -30,7 +31,6 @@ 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.viewmodel.FingerprintEnrollFindSensorViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollFindSensorViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollViewModel
import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.biometrics.shared.model.FingerprintSensorType
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,12 +51,31 @@ private const val TAG = "FingerprintEnrollFindSensorV2Fragment"
* will work. * will work.
*/ */
class FingerprintEnrollFindSensorV2Fragment(val sensorType: FingerprintSensorType) : Fragment() { class FingerprintEnrollFindSensorV2Fragment(val sensorType: FingerprintSensorType) : Fragment() {
/** Used for testing purposes */
private var factory: ViewModelProvider.Factory? = null
@VisibleForTesting
constructor(
sensorType: FingerprintSensorType,
theFactory: ViewModelProvider.Factory,
) : this(sensorType) {
factory = theFactory
}
private val viewModelProvider: ViewModelProvider by lazy {
if (factory != null) {
ViewModelProvider(requireActivity(), factory!!)
} else {
ViewModelProvider(requireActivity())
}
}
// This is only for non-udfps or non-sfps sensor. For udfps and sfps, we show lottie. // This is only for non-udfps or non-sfps sensor. For udfps and sfps, we show lottie.
private var animation: FingerprintFindSensorAnimation? = null private var animation: FingerprintFindSensorAnimation? = null
private var contentLayoutId: Int = -1 private var contentLayoutId: Int = -1
private val viewModel: FingerprintEnrollFindSensorViewModel by lazy { private val viewModel: FingerprintEnrollFindSensorViewModel by lazy {
ViewModelProvider(requireActivity())[FingerprintEnrollFindSensorViewModel::class.java] viewModelProvider[FingerprintEnrollFindSensorViewModel::class.java]
} }
override fun onCreateView( override fun onCreateView(
@@ -65,9 +84,6 @@ class FingerprintEnrollFindSensorV2Fragment(val sensorType: FingerprintSensorTyp
savedInstanceState: Bundle?, savedInstanceState: Bundle?,
): View? { ): View? {
val sensorType =
ViewModelProvider(requireActivity())[FingerprintEnrollViewModel::class.java].sensorTypeCached
contentLayoutId = contentLayoutId =
when (sensorType) { when (sensorType) {
FingerprintSensorType.UDFPS_OPTICAL, FingerprintSensorType.UDFPS_OPTICAL,
@@ -76,46 +92,43 @@ class FingerprintEnrollFindSensorV2Fragment(val sensorType: FingerprintSensorTyp
else -> R.layout.fingerprint_v2_enroll_find_sensor else -> R.layout.fingerprint_v2_enroll_find_sensor
} }
return inflater.inflate(contentLayoutId, container, false).also { it -> val view = inflater.inflate(contentLayoutId, container, false)!! as GlifLayout
val view = it!! as GlifLayout setTexts(sensorType, view)
// Set up header and description // Set up footer bar
lifecycleScope.launch { viewModel.sensorType.collect { setTexts(it, view) } } val footerBarMixin = view.getMixin(FooterBarMixin::class.java)
setupSecondaryButton(footerBarMixin)
lifecycleScope.launch {
viewModel.showPrimaryButton.collect { setupPrimaryButton(footerBarMixin) }
}
// Set up footer bar // Set up lottie or animation
val footerBarMixin = view.getMixin(FooterBarMixin::class.java) lifecycleScope.launch {
setupSecondaryButton(footerBarMixin) viewModel.sfpsLottieInfo.collect { (isFolded, rotation) ->
lifecycleScope.launch { setupLottie(view, getSfpsIllustrationLottieAnimation(isFolded, rotation))
viewModel.showPrimaryButton.collect { setupPrimaryButton(footerBarMixin) }
}
// Set up lottie or animation
lifecycleScope.launch {
viewModel.sfpsLottieInfo.collect { (isFolded, rotation) ->
setupLottie(view, getSfpsIllustrationLottieAnimation(isFolded, rotation))
}
}
lifecycleScope.launch {
viewModel.udfpsLottieInfo.collect { isAccessibilityEnabled ->
val lottieAnimation =
if (isAccessibilityEnabled) R.raw.udfps_edu_a11y_lottie else R.raw.udfps_edu_lottie
setupLottie(view, lottieAnimation) { viewModel.proceedToEnrolling() }
}
}
lifecycleScope.launch {
viewModel.showRfpsAnimation.collect {
animation = view.findViewById(R.id.fingerprint_sensor_location_animation)
animation!!.startAnimation()
}
}
lifecycleScope.launch {
viewModel.showErrorDialog.collect { (errMsgId, isSetup) ->
// TODO: Covert error dialog kotlin as well
FingerprintErrorDialog.showErrorDialog(requireActivity(), errMsgId, isSetup)
}
} }
} }
lifecycleScope.launch {
viewModel.udfpsLottieInfo.collect { isAccessibilityEnabled ->
val lottieAnimation =
if (isAccessibilityEnabled) R.raw.udfps_edu_a11y_lottie else R.raw.udfps_edu_lottie
setupLottie(view, lottieAnimation) { viewModel.proceedToEnrolling() }
}
}
lifecycleScope.launch {
viewModel.showRfpsAnimation.collect {
animation = view.findViewById(R.id.fingerprint_sensor_location_animation)
animation!!.startAnimation()
}
}
lifecycleScope.launch {
viewModel.showErrorDialog.collect { (errMsgId, isSetup) ->
// TODO: Covert error dialog kotlin as well
FingerprintErrorDialog.showErrorDialog(requireActivity(), errMsgId, isSetup)
}
}
return view
} }
override fun onDestroy() { override fun onDestroy() {
@@ -158,7 +171,7 @@ class FingerprintEnrollFindSensorV2Fragment(val sensorType: FingerprintSensorTyp
illustrationLottie?.visibility = View.VISIBLE illustrationLottie?.visibility = View.VISIBLE
} }
private fun setTexts(sensorType: FingerprintSensorType, view: GlifLayout) { private fun setTexts(sensorType: FingerprintSensorType?, view: GlifLayout) {
when (sensorType) { when (sensorType) {
FingerprintSensorType.UDFPS_OPTICAL, FingerprintSensorType.UDFPS_OPTICAL,
FingerprintSensorType.UDFPS_ULTRASONIC -> { FingerprintSensorType.UDFPS_ULTRASONIC -> {

View File

@@ -26,12 +26,14 @@ import android.view.ViewGroup
import android.view.animation.AnimationUtils import android.view.animation.AnimationUtils
import android.view.animation.Interpolator import android.view.animation.Interpolator
import android.widget.TextView import android.widget.TextView
import androidx.annotation.VisibleForTesting
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
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.domain.interactor.OrientationInteractor
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.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
@@ -41,18 +43,34 @@ import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enroll
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.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.OrientationStateViewModel
import com.android.settings.core.instrumentation.InstrumentedDialogFragment import com.android.settings.core.instrumentation.InstrumentedDialogFragment
import com.google.android.setupcompat.template.FooterBarMixin import com.google.android.setupcompat.template.FooterBarMixin
import com.google.android.setupcompat.template.FooterButton import com.google.android.setupcompat.template.FooterButton
import com.google.android.setupdesign.GlifLayout import com.google.android.setupdesign.GlifLayout
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
/** This fragment is responsible for taking care of rear fingerprint enrollment. */ /** This fragment is responsible for taking care of rear fingerprint enrollment. */
class RFPSEnrollFragment : Fragment(R.layout.fingerprint_v2_rfps_enroll_enrolling) { class RFPSEnrollFragment() : Fragment(R.layout.fingerprint_v2_rfps_enroll_enrolling) {
/** 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 linearOutSlowInInterpolator: Interpolator private lateinit var linearOutSlowInInterpolator: Interpolator
private lateinit var fastOutLinearInInterpolator: Interpolator private lateinit var fastOutLinearInInterpolator: Interpolator
@@ -60,24 +78,14 @@ class RFPSEnrollFragment : Fragment(R.layout.fingerprint_v2_rfps_enroll_enrollin
private lateinit var progressBar: RFPSProgressBar private lateinit var progressBar: RFPSProgressBar
private val iconTouchViewModel: RFPSIconTouchViewModel by lazy { private val iconTouchViewModel: RFPSIconTouchViewModel by lazy {
ViewModelProvider(requireActivity())[RFPSIconTouchViewModel::class.java] viewModelProvider[RFPSIconTouchViewModel::class.java]
} }
private val orientationViewModel: OrientationStateViewModel by lazy { private val rfpsViewModel: RFPSViewModel by lazy { viewModelProvider[RFPSViewModel::class.java] }
ViewModelProvider(requireActivity())[OrientationStateViewModel::class.java]
}
private val rfpsViewModel: RFPSViewModel by lazy {
ViewModelProvider(requireActivity())[RFPSViewModel::class.java]
}
private val backgroundViewModel: BackgroundViewModel by lazy { private val backgroundViewModel: BackgroundViewModel by lazy {
ViewModelProvider(requireActivity())[BackgroundViewModel::class.java] viewModelProvider[BackgroundViewModel::class.java]
} }
private val navigationViewModel: FingerprintNavigationViewModel by lazy {
ViewModelProvider(requireActivity())[FingerprintNavigationViewModel::class.java]
}
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
@@ -115,9 +123,8 @@ class RFPSEnrollFragment : Fragment(R.layout.fingerprint_v2_rfps_enroll_enrollin
true true
} }
// On any orientation event, dismiss dialogs.
viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.lifecycleScope.launch {
orientationViewModel.orientation.collect { dismissDialogs() } rfpsViewModel.shouldDismissDialog.collect { dismissDialogs() }
} }
// Signal we are ready for enrollment. // Signal we are ready for enrollment.
@@ -127,6 +134,8 @@ class RFPSEnrollFragment : Fragment(R.layout.fingerprint_v2_rfps_enroll_enrollin
repeatOnLifecycle(Lifecycle.State.RESUMED) { repeatOnLifecycle(Lifecycle.State.RESUMED) {
// Icon animation update // Icon animation update
viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.lifecycleScope.launch {
// TODO(b/324427704): Fix this delay
delay(100)
rfpsViewModel.shouldAnimateIcon.collect { animate -> rfpsViewModel.shouldAnimateIcon.collect { animate ->
progressBar.updateIconAnimation(animate) progressBar.updateIconAnimation(animate)
} }

View File

@@ -19,6 +19,7 @@ package com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrol
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor
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.viewmodel.FingerprintAction import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintAction
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollEnrollingViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollEnrollingViewModel
@@ -39,10 +40,11 @@ import kotlinx.coroutines.flow.update
class RFPSViewModel( class RFPSViewModel(
private val fingerprintEnrollViewModel: FingerprintEnrollEnrollingViewModel, private val fingerprintEnrollViewModel: FingerprintEnrollEnrollingViewModel,
private val navigationViewModel: FingerprintNavigationViewModel, private val navigationViewModel: FingerprintNavigationViewModel,
orientationInteractor: OrientationInteractor,
) : ViewModel() { ) : ViewModel() {
/** Value to indicate if the text view is visible or not */
private val _textViewIsVisible = MutableStateFlow<Boolean>(false) private val _textViewIsVisible = MutableStateFlow<Boolean>(false)
/** Value to indicate if the text view is visible or not */
val textViewIsVisible: Flow<Boolean> = _textViewIsVisible.asStateFlow() val textViewIsVisible: Flow<Boolean> = _textViewIsVisible.asStateFlow()
/** Indicates if the icon should be animating or not */ /** Indicates if the icon should be animating or not */
@@ -78,8 +80,12 @@ class RFPSViewModel(
.filterIsInstance<FingerEnrollState.EnrollError>() .filterIsInstance<FingerEnrollState.EnrollError>()
.shareIn(viewModelScope, SharingStarted.Eagerly, 0) .shareIn(viewModelScope, SharingStarted.Eagerly, 0)
/** Indicates that enrollment was completed. */
val didCompleteEnrollment: Flow<Boolean> = progress.filterNotNull().map { it.remainingSteps == 0 } val didCompleteEnrollment: Flow<Boolean> = progress.filterNotNull().map { it.remainingSteps == 0 }
/** Indicates if the fragment should dismiss a dialog if one was shown. */
val shouldDismissDialog = orientationInteractor.orientation.map { true }
/** Indicates if the consumer is ready for enrollment */ /** Indicates if the consumer is ready for enrollment */
fun readyForEnrollment() { fun readyForEnrollment() {
fingerprintEnrollViewModel.canEnroll() fingerprintEnrollViewModel.canEnroll()
@@ -90,6 +96,7 @@ class RFPSViewModel(
fingerprintEnrollViewModel.stopEnroll() fingerprintEnrollViewModel.stopEnroll()
} }
/** Set the visibility of the text view */
fun setVisibility(isVisible: Boolean) { fun setVisibility(isVisible: Boolean) {
_textViewIsVisible.update { isVisible } _textViewIsVisible.update { isVisible }
} }
@@ -122,6 +129,7 @@ class RFPSViewModel(
) )
} }
/** Indicates that enrollment has been finished and we can proceed to the next step. */
fun finishedSuccessfully() { fun finishedSuccessfully() {
navigationViewModel.update(FingerprintAction.NEXT, navStep, "${TAG}#progressFinished") navigationViewModel.update(FingerprintAction.NEXT, navStep, "${TAG}#progressFinished")
} }
@@ -129,11 +137,17 @@ class RFPSViewModel(
class RFPSViewModelFactory( class RFPSViewModelFactory(
private val fingerprintEnrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel, private val fingerprintEnrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel,
private val navigationViewModel: FingerprintNavigationViewModel, private val navigationViewModel: FingerprintNavigationViewModel,
private val orientationInteractor: OrientationInteractor,
) : ViewModelProvider.Factory { ) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T { override fun <T : ViewModel> create(modelClass: Class<T>): T {
return RFPSViewModel(fingerprintEnrollEnrollingViewModel, navigationViewModel) as T return RFPSViewModel(
fingerprintEnrollEnrollingViewModel,
navigationViewModel,
orientationInteractor,
)
as T
} }
} }

View File

@@ -24,14 +24,14 @@ import android.graphics.drawable.AnimatedVectorDrawable
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable import android.graphics.drawable.LayerDrawable
import android.util.AttributeSet import android.util.AttributeSet
import android.util.Log
import android.view.animation.AnimationUtils import android.view.animation.AnimationUtils
import android.view.animation.Interpolator import android.view.animation.Interpolator
import com.android.settings.R import com.android.settings.R
import com.android.settings.widget.RingProgressBar import com.android.settings.widget.RingProgressBar
/** Progress bar for rear fingerprint enrollment. */ /** Progress bar for rear fingerprint enrollment. */
class RFPSProgressBar(context: Context, attributeSet: AttributeSet) : class RFPSProgressBar : RingProgressBar {
RingProgressBar(context, attributeSet) {
private val fastOutSlowInInterpolator: Interpolator private val fastOutSlowInInterpolator: Interpolator
@@ -42,9 +42,9 @@ class RFPSProgressBar(context: Context, attributeSet: AttributeSet) :
private var progressAnimation: ObjectAnimator? = null private var progressAnimation: ObjectAnimator? = null
private var shouldAnimateInternal: Boolean = true private var shouldAnimateInternal: Boolean = false
init { constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {
val fingerprintDrawable = background as LayerDrawable val fingerprintDrawable = background as LayerDrawable
iconAnimationDrawable = iconAnimationDrawable =
fingerprintDrawable.findDrawableByLayerId(R.id.fingerprint_animation) fingerprintDrawable.findDrawableByLayerId(R.id.fingerprint_animation)
@@ -52,10 +52,8 @@ class RFPSProgressBar(context: Context, attributeSet: AttributeSet) :
iconBackgroundBlinksDrawable = iconBackgroundBlinksDrawable =
fingerprintDrawable.findDrawableByLayerId(R.id.fingerprint_background) fingerprintDrawable.findDrawableByLayerId(R.id.fingerprint_background)
as AnimatedVectorDrawable as AnimatedVectorDrawable
fastOutSlowInInterpolator = fastOutSlowInInterpolator =
AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in) AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in)
iconAnimationDrawable.registerAnimationCallback( iconAnimationDrawable.registerAnimationCallback(
object : Animatable2.AnimationCallback() { object : Animatable2.AnimationCallback() {
override fun onAnimationEnd(drawable: Drawable?) { override fun onAnimationEnd(drawable: Drawable?) {
@@ -66,7 +64,6 @@ class RFPSProgressBar(context: Context, attributeSet: AttributeSet) :
} }
} }
) )
animateIconAnimationInternal()
progressBackgroundTintMode = PorterDuff.Mode.SRC progressBackgroundTintMode = PorterDuff.Mode.SRC
@@ -85,8 +82,8 @@ class RFPSProgressBar(context: Context, attributeSet: AttributeSet) :
} }
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

@@ -19,6 +19,10 @@ package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.android.settings.biometrics.fingerprint2.domain.interactor.AccessibilityInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
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.FingerprintEnrollFindSensorV2Fragment import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollFindSensorV2Fragment
@@ -26,13 +30,11 @@ import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Fing
import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.combineTransform import kotlinx.coroutines.flow.combineTransform
import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter
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.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -42,19 +44,16 @@ class FingerprintEnrollFindSensorViewModel(
private val fingerprintEnrollViewModel: FingerprintEnrollViewModel, private val fingerprintEnrollViewModel: FingerprintEnrollViewModel,
private val gatekeeperViewModel: FingerprintGatekeeperViewModel, private val gatekeeperViewModel: FingerprintGatekeeperViewModel,
backgroundViewModel: BackgroundViewModel, backgroundViewModel: BackgroundViewModel,
accessibilityViewModel: AccessibilityViewModel, accessibilityInteractor: AccessibilityInteractor,
foldStateViewModel: FoldStateViewModel, foldStateInteractor: FoldStateInteractor,
orientationStateViewModel: OrientationStateViewModel, orientationInteractor: OrientationInteractor,
fingerprintFlowViewModel: FingerprintFlowViewModel, fingerprintFlowViewModel: FingerprintFlowViewModel,
fingerprintManagerInteractor: FingerprintManagerInteractor,
) : ViewModel() { ) : ViewModel() {
/** Represents the stream of sensor type. */ /** Represents the stream of sensor type. */
val sensorType: Flow<FingerprintSensorType> = val sensorType: Flow<FingerprintSensorType> =
fingerprintEnrollViewModel.sensorType.shareIn( fingerprintManagerInteractor.sensorPropertiesInternal.filterNotNull().map { it.sensorType }
viewModelScope,
SharingStarted.WhileSubscribed(),
1,
)
private val _isUdfps: Flow<Boolean> = private val _isUdfps: Flow<Boolean> =
sensorType.map { sensorType.map {
it == FingerprintSensorType.UDFPS_OPTICAL || it == FingerprintSensorType.UDFPS_ULTRASONIC it == FingerprintSensorType.UDFPS_OPTICAL || it == FingerprintSensorType.UDFPS_ULTRASONIC
@@ -70,8 +69,8 @@ class FingerprintEnrollFindSensorViewModel(
val sfpsLottieInfo: Flow<Pair<Boolean, Int>> = val sfpsLottieInfo: Flow<Pair<Boolean, Int>> =
combineTransform( combineTransform(
_showSfpsLottie, _showSfpsLottie,
foldStateViewModel.isFolded, foldStateInteractor.isFolded,
orientationStateViewModel.rotation, orientationInteractor.rotation,
) { _, isFolded, rotation -> ) { _, isFolded, rotation ->
emit(Pair(isFolded, rotation)) emit(Pair(isFolded, rotation))
} }
@@ -79,7 +78,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(accessibilityViewModel.isAccessibilityEnabled) { _showUdfpsLottie.combine(accessibilityInteractor.isAccessibilityEnabled) {
_, _,
isAccessibilityEnabled -> isAccessibilityEnabled ->
isAccessibilityEnabled isAccessibilityEnabled
@@ -104,7 +103,7 @@ class FingerprintEnrollFindSensorViewModel(
// Start or end enroll flow // Start or end enroll flow
viewModelScope.launch { viewModelScope.launch {
combine( combine(
fingerprintEnrollViewModel.sensorType, sensorType,
gatekeeperViewModel.hasValidGatekeeperInfo, gatekeeperViewModel.hasValidGatekeeperInfo,
gatekeeperViewModel.gatekeeperInfo, gatekeeperViewModel.gatekeeperInfo,
navigationViewModel.currentScreen, navigationViewModel.currentScreen,
@@ -188,10 +187,11 @@ class FingerprintEnrollFindSensorViewModel(
private val fingerprintEnrollViewModel: FingerprintEnrollViewModel, private val fingerprintEnrollViewModel: FingerprintEnrollViewModel,
private val gatekeeperViewModel: FingerprintGatekeeperViewModel, private val gatekeeperViewModel: FingerprintGatekeeperViewModel,
private val backgroundViewModel: BackgroundViewModel, private val backgroundViewModel: BackgroundViewModel,
private val accessibilityViewModel: AccessibilityViewModel, private val accessibilityInteractor: AccessibilityInteractor,
private val foldStateViewModel: FoldStateViewModel, private val foldStateInteractor: FoldStateInteractor,
private val orientationStateViewModel: OrientationStateViewModel, private val orientationInteractor: OrientationInteractor,
private val fingerprintFlowViewModel: FingerprintFlowViewModel, private val fingerprintFlowViewModel: FingerprintFlowViewModel,
private val fingerprintManagerInteractor: FingerprintManagerInteractor,
) : ViewModelProvider.Factory { ) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T { override fun <T : ViewModel> create(modelClass: Class<T>): T {
@@ -200,10 +200,11 @@ class FingerprintEnrollFindSensorViewModel(
fingerprintEnrollViewModel, fingerprintEnrollViewModel,
gatekeeperViewModel, gatekeeperViewModel,
backgroundViewModel, backgroundViewModel,
accessibilityViewModel, accessibilityInteractor,
foldStateViewModel, foldStateInteractor,
orientationStateViewModel, orientationInteractor,
fingerprintFlowViewModel, fingerprintFlowViewModel,
fingerprintManagerInteractor,
) )
as T as T
} }

View File

@@ -56,7 +56,7 @@ class FingerprintEnrollViewModel(
} }
/** 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 }
/** /**

View File

@@ -1,56 +0,0 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel
import android.content.Context
import android.content.res.Configuration
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.android.systemui.unfold.compat.ScreenSizeFoldProvider
import com.android.systemui.unfold.updates.FoldProvider
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
/** Represents all of the information on fold state. */
class FoldStateViewModel(context: Context) : ViewModel() {
private val screenSizeFoldProvider = ScreenSizeFoldProvider(context)
/** A flow that contains the fold state info */
val isFolded: Flow<Boolean> = callbackFlow {
val foldStateListener =
object : FoldProvider.FoldCallback {
override fun onFoldUpdated(isFolded: Boolean) {
trySend(isFolded)
}
}
screenSizeFoldProvider.registerCallback(foldStateListener, context.mainExecutor)
awaitClose { screenSizeFoldProvider.unregisterCallback(foldStateListener) }
}
fun onConfigurationChange(newConfig: Configuration) {
screenSizeFoldProvider.onConfigurationChange(newConfig)
}
class FoldStateViewModelFactory(private val context: Context) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return FoldStateViewModel(context) as T
}
}
}

View File

@@ -45,8 +45,8 @@ import com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED
import com.android.settings.biometrics.GatekeeperPasswordProvider import com.android.settings.biometrics.GatekeeperPasswordProvider
import com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling import com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling
import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroductionInternal import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroductionInternal
import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepoImpl import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepositoryImpl
import com.android.settings.biometrics.fingerprint2.data.repository.PressToAuthRepoImpl import com.android.settings.biometrics.fingerprint2.domain.interactor.PressToAuthInteractorImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl
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
@@ -220,7 +220,8 @@ class FingerprintSettingsV2Fragment :
toReturn == 1 toReturn == 1
} }
val fingerprintSensorProvider = val fingerprintSensorProvider =
FingerprintSensorRepoImpl(fingerprintManager, backgroundDispatcher, lifecycleScope) FingerprintSensorRepositoryImpl(fingerprintManager, backgroundDispatcher, lifecycleScope)
val pressToAuthInteractor = PressToAuthInteractorImpl(context, backgroundDispatcher)
val interactor = val interactor =
FingerprintManagerInteractorImpl( FingerprintManagerInteractorImpl(
@@ -229,7 +230,7 @@ class FingerprintSettingsV2Fragment :
fingerprintManager, fingerprintManager,
fingerprintSensorProvider, fingerprintSensorProvider,
GatekeeperPasswordProvider(LockPatternUtils(context.applicationContext)), GatekeeperPasswordProvider(LockPatternUtils(context.applicationContext)),
PressToAuthRepoImpl(context), pressToAuthInteractor,
Settings, Settings,
) )

View File

@@ -0,0 +1 @@
include /src/com/android/settings/biometrics/fingerprint2/OWNERS

View File

@@ -23,6 +23,8 @@
<application> <application>
<activity android:name="com.android.settings.test.screenshot.ContainerActivity" android:exported="true" /> <activity android:name="com.android.settings.test.screenshot.ContainerActivity" android:exported="true" />
<activity android:name="platform.test.screenshot.FragmentScreenshotActivity" android:exported="true"
android:theme="@style/GlifTheme.Light" />
</application> </application>
</manifest> </manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 146 KiB

View File

@@ -1,142 +0,0 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.tests.screenshot
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.os.Bundle
import android.view.View
import androidx.fragment.app.testing.FragmentScenario
import androidx.fragment.app.testing.launchFragmentInContainer
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.android.settings.R
import com.android.settings.biometrics.fingerprint2.lib.model.Default
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollIntroV2Fragment
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollIntroViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintFlowViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo
import com.android.settings.testutils2.FakeFingerprintManagerInteractor
import com.android.systemui.biometrics.shared.model.FingerprintSensor
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength
import kotlinx.coroutines.test.StandardTestDispatcher
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import platform.test.screenshot.GoldenImagePathManager
import platform.test.screenshot.ScreenshotTestRule
import platform.test.screenshot.matchers.MSSIMMatcher
@RunWith(AndroidJUnit4::class)
class BasicScreenshotTest {
@Rule
@JvmField
var rule: ScreenshotTestRule =
ScreenshotTestRule(
GoldenImagePathManager(
InstrumentationRegistry.getInstrumentation().getContext(),
InstrumentationRegistry.getInstrumentation()
.getTargetContext()
.getFilesDir()
.getAbsolutePath() + "/settings_screenshots",
)
)
private var context: Context = ApplicationProvider.getApplicationContext()
private var interactor = FakeFingerprintManagerInteractor()
private val gatekeeperViewModel =
FingerprintGatekeeperViewModel(
GatekeeperInfo.GatekeeperPasswordInfo(byteArrayOf(1, 2, 3), 100L),
interactor,
)
private val backgroundDispatcher = StandardTestDispatcher()
private lateinit var fragmentScenario: FragmentScenario<FingerprintEnrollIntroV2Fragment>
private val fingerprintSensor =
FingerprintSensor(1, SensorStrength.STRONG, 5, FingerprintSensorType.POWER_BUTTON)
var enrollFlow = Default
val flowViewModel = FingerprintFlowViewModel(enrollFlow)
private val navigationViewModel =
FingerprintNavigationViewModel(
FingerprintNavigationStep.Introduction,
false,
flowViewModel,
interactor,
)
private var fingerprintViewModel =
FingerprintEnrollIntroViewModel(navigationViewModel, flowViewModel, interactor)
private var fingerprintScrollViewModel = FingerprintScrollViewModel()
@Before
fun setup() {
val factory =
object : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return when (modelClass) {
FingerprintEnrollIntroViewModel::class.java -> fingerprintViewModel
FingerprintScrollViewModel::class.java -> fingerprintScrollViewModel
FingerprintNavigationViewModel::class.java -> navigationViewModel
FingerprintGatekeeperViewModel::class.java -> gatekeeperViewModel
else -> null
}
as T
}
}
fragmentScenario =
launchFragmentInContainer(Bundle(), R.style.SudThemeGlif) {
FingerprintEnrollIntroV2Fragment(factory)
}
}
/** Renders a [view] into a [Bitmap]. */
private fun viewToBitmap(view: View): Bitmap {
val bitmap =
Bitmap.createBitmap(view.measuredWidth, view.measuredHeight, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
view.draw(canvas)
return bitmap
}
@Test
fun testEnrollIntro() {
fragmentScenario.onFragment { fragment ->
val view = fragment.requireView().findViewById<View>(R.id.enroll_intro_content_view)!!
view.setBackgroundColor(Color.BLACK)
}
fragmentScenario.onFragment { fragment ->
val view = fragment.requireView().findViewById<View>(R.id.enroll_intro_content_view)!!
rule.assertBitmapAgainstGolden(viewToBitmap(view), "fp_enroll_intro", MSSIMMatcher())
}
}
}

View File

@@ -0,0 +1,12 @@
# Background info about tests
1. This test is ran in postsubmits at andoid-settings/robo_tests.gcl
2. It is important that this module stays somewhat small, if the test size grows
too large, it will be likely that this suite breaks due to flakiness(which
tends to happen with screenshot tests). In this case investigate splitting
the module.
# Running and updating screenshots.
1. For FingerprintEnrollIntroScreenshotTest.kt#testEnrollIntro
2. atest SettingsScreenshotRNGTests
3. There should be a file like com.android.settings.tests.screenshot.biometrics.fingerprint.fragment.FingerprintEnrollIntroScreenshotTest_testEnrollIntro_actual_robolectric_fp_enroll_intro.png_6245562387930305138.png
4. Place this screenshot in packages/apps/Settings/tests/screenshot/assets/robolectric/fp_enroll_intro.png

View File

@@ -0,0 +1,161 @@
/*
* 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.tests.screenshot.biometrics.fingerprint
import android.content.res.Configuration
import android.view.Surface
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.test.platform.app.InstrumentationRegistry
import com.android.settings.biometrics.fingerprint2.domain.interactor.AccessibilityInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor
import com.android.settings.biometrics.fingerprint2.lib.model.Default
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.viewmodel.BackgroundViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollEnrollingViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollFindSensorViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollIntroViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintFlowViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo
import com.android.settings.testutils2.FakeFingerprintManagerInteractor
import com.android.systemui.biometrics.shared.model.FingerprintSensor
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.update
import platform.test.screenshot.DeviceEmulationSpec
import platform.test.screenshot.DisplaySpec
import platform.test.screenshot.FragmentScreenshotTestRule
import platform.test.screenshot.GoldenImagePathManager
import platform.test.screenshot.matchers.PixelPerfectMatcher
class Injector(step: FingerprintNavigationStep.UiStep) {
var enrollFlow = Default
var fingerprintSensor = FingerprintSensor(1, SensorStrength.STRONG, 5, FingerprintSensorType.REAR)
var accessibilityInteractor =
object : AccessibilityInteractor {
override val isAccessibilityEnabled: Flow<Boolean> = flowOf(true)
}
var foldStateInteractor =
object : FoldStateInteractor {
private val _foldState = MutableStateFlow(false)
override val isFolded: Flow<Boolean> = _foldState.asStateFlow()
override fun onConfigurationChange(newConfig: Configuration) {
_foldState.update { false }
}
}
var orientationInteractor =
object : OrientationInteractor {
override val orientation: Flow<Int> = flowOf(Configuration.ORIENTATION_LANDSCAPE)
override val rotation: Flow<Int> = flowOf(Surface.ROTATION_0)
override fun getRotationFromDefault(rotation: Int): Int = rotation
}
var gatekeeperViewModel =
FingerprintGatekeeperViewModel(
GatekeeperInfo.GatekeeperPasswordInfo(byteArrayOf(1, 2, 3), 100L),
interactor,
)
val flowViewModel = FingerprintFlowViewModel(enrollFlow)
var navigationViewModel = FingerprintNavigationViewModel(step, true, flowViewModel, interactor)
var fingerprintViewModel =
FingerprintEnrollIntroViewModel(navigationViewModel, flowViewModel, interactor)
var fingerprintScrollViewModel = FingerprintScrollViewModel()
var backgroundViewModel = BackgroundViewModel()
var fingerprintEnrollViewModel =
FingerprintEnrollViewModel(interactor, gatekeeperViewModel, navigationViewModel)
var fingerprintEnrollEnrollingViewModel =
FingerprintEnrollEnrollingViewModel(fingerprintEnrollViewModel, backgroundViewModel)
var rfpsIconTouchViewModel = RFPSIconTouchViewModel()
var rfpsViewModel =
RFPSViewModel(fingerprintEnrollEnrollingViewModel, navigationViewModel, orientationInteractor)
var fingerprintFindSensorViewModel =
FingerprintEnrollFindSensorViewModel(
navigationViewModel,
fingerprintEnrollViewModel,
gatekeeperViewModel,
backgroundViewModel,
accessibilityInteractor,
foldStateInteractor,
orientationInteractor,
flowViewModel,
interactor,
)
val factory =
object : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return when (modelClass) {
FingerprintEnrollIntroViewModel::class.java -> fingerprintViewModel
FingerprintScrollViewModel::class.java -> fingerprintScrollViewModel
FingerprintNavigationViewModel::class.java -> navigationViewModel
FingerprintGatekeeperViewModel::class.java -> gatekeeperViewModel
FingerprintEnrollFindSensorViewModel::class.java -> fingerprintFindSensorViewModel
FingerprintEnrollViewModel::class.java -> fingerprintEnrollViewModel
RFPSViewModel::class.java -> rfpsViewModel
BackgroundViewModel::class.java -> backgroundViewModel
RFPSIconTouchViewModel::class.java -> rfpsIconTouchViewModel
FingerprintEnrollEnrollingViewModel::class.java -> fingerprintEnrollEnrollingViewModel
else -> null
}
as T
}
}
init {
fingerprintEnrollViewModel.sensorTypeCached = fingerprintSensor.sensorType
}
companion object {
private val Phone = DisplaySpec("phone", width = 1080, height = 2340, densityDpi = 420)
private const val screenshotPath = "/settings_screenshots"
val interactor = FakeFingerprintManagerInteractor()
fun BiometricFragmentScreenShotRule() =
FragmentScreenshotTestRule(
DeviceEmulationSpec.forDisplays(Phone).first(),
GoldenImagePathManager(
InstrumentationRegistry.getInstrumentation().context,
InstrumentationRegistry.getInstrumentation().targetContext.filesDir.absolutePath +
screenshotPath,
),
PixelPerfectMatcher(),
true,
)
}
}

View File

@@ -0,0 +1,40 @@
/*
* 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.tests.screenshot.biometrics.fingerprint.fragment
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.fragment.RFPSEnrollFragment
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.Companion.BiometricFragmentScreenShotRule
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import platform.test.screenshot.FragmentScreenshotTestRule
import platform.test.screenshot.ViewScreenshotTestRule.Mode
@RunWith(AndroidJUnit4::class)
class FingerprintEnrollEnrollingScreenshotTest {
private val injector: Injector =
Injector(FingerprintNavigationStep.Enrollment(Injector.interactor.sensorProp))
@Rule @JvmField var rule: FragmentScreenshotTestRule = BiometricFragmentScreenShotRule()
@Test
fun testEnrollEnrolling() {
rule.screenshotTest("fp_enroll_enrolling", Mode.MatchSize, RFPSEnrollFragment(injector.factory))
}
}

View File

@@ -0,0 +1,45 @@
package com.android.settings.tests.screenshot.biometrics.fingerprint.fragment
/*
* 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.
*/
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollFindSensorV2Fragment
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.Companion.BiometricFragmentScreenShotRule
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import platform.test.screenshot.FragmentScreenshotTestRule
import platform.test.screenshot.ViewScreenshotTestRule.Mode
@RunWith(AndroidJUnit4::class)
class FingerprintEnrollFindSensorScreenshotTest {
private val injector: Injector =
Injector(FingerprintNavigationStep.Education(Injector.interactor.sensorProp))
@Rule @JvmField var rule: FragmentScreenshotTestRule = BiometricFragmentScreenShotRule()
@Test
fun testEnrollFindSensor() {
rule.screenshotTest(
"fp_enroll_find_sensor",
Mode.MatchSize,
FingerprintEnrollFindSensorV2Fragment(injector.fingerprintSensor.sensorType, injector.factory),
)
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.tests.screenshot.biometrics.fingerprint.fragment
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollIntroV2Fragment
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep
import com.android.settings.tests.screenshot.biometrics.fingerprint.Injector
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import platform.test.screenshot.FragmentScreenshotTestRule
import platform.test.screenshot.ViewScreenshotTestRule.Mode
@RunWith(AndroidJUnit4::class)
class FingerprintEnrollIntroScreenshotTest {
private val injector: Injector = Injector(FingerprintNavigationStep.Introduction)
@Rule
@JvmField
var rule: FragmentScreenshotTestRule = Injector.BiometricFragmentScreenShotRule()
@Test
fun testEnrollIntro() {
rule.screenshotTest(
"fp_enroll_intro",
Mode.MatchSize,
FingerprintEnrollIntroV2Fragment(injector.factory),
)
}
}

View File

@@ -37,7 +37,6 @@ class FakeFingerprintManagerInteractor : FingerprintManagerInteractor {
var authenticateAttempt = FingerprintAuthAttemptModel.Success(1) var authenticateAttempt = FingerprintAuthAttemptModel.Success(1)
var enrollStateViewModel: List<FingerEnrollState> = var enrollStateViewModel: List<FingerEnrollState> =
listOf(FingerEnrollState.EnrollProgress(5, 5)) listOf(FingerEnrollState.EnrollProgress(5, 5))
var pressToAuthEnabled = true
var sensorProp = var sensorProp =
FingerprintSensor( FingerprintSensor(
@@ -86,7 +85,4 @@ class FakeFingerprintManagerInteractor : FingerprintManagerInteractor {
return sensorProp.sensorType == FingerprintSensorType.POWER_BUTTON return sensorProp.sensorType == FingerprintSensorType.POWER_BUTTON
} }
override suspend fun pressToAuthEnabled(): Boolean {
return pressToAuthEnabled
}
} }

View File

@@ -26,9 +26,9 @@ import android.os.CancellationSignal
import android.os.Handler import android.os.Handler
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
import com.android.settings.biometrics.GatekeeperPasswordProvider import com.android.settings.biometrics.GatekeeperPasswordProvider
import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepo import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepository
import com.android.settings.biometrics.fingerprint2.domain.interactor.PressToAuthInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl
import com.android.settings.biometrics.fingerprint2.data.repository.PressToAuthRepo
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.Default import com.android.settings.biometrics.fingerprint2.lib.model.Default
import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason
@@ -77,17 +77,16 @@ class FingerprintManagerInteractorTest {
@Mock private lateinit var gateKeeperPasswordProvider: GatekeeperPasswordProvider @Mock private lateinit var gateKeeperPasswordProvider: GatekeeperPasswordProvider
private var testScope = TestScope(backgroundDispatcher) private var testScope = TestScope(backgroundDispatcher)
private var pressToAuthRepo = private var pressToAuthInteractor =
object : PressToAuthRepo { object : PressToAuthInteractor {
override val isEnabled: Boolean override val isEnabled = flowOf(false)
get() = false
} }
@Before @Before
fun setup() { fun setup() {
val sensor = FingerprintSensor(1, SensorStrength.STRONG, 5, FingerprintSensorType.POWER_BUTTON) val sensor = FingerprintSensor(1, SensorStrength.STRONG, 5, FingerprintSensorType.POWER_BUTTON)
val fingerprintSensorRepo = val fingerprintSensorRepository =
object : FingerprintSensorRepo { object : FingerprintSensorRepository {
override val fingerprintSensor: Flow<FingerprintSensor> = flowOf(sensor) override val fingerprintSensor: Flow<FingerprintSensor> = flowOf(sensor)
} }
@@ -96,9 +95,9 @@ class FingerprintManagerInteractorTest {
context, context,
backgroundDispatcher, backgroundDispatcher,
fingerprintManager, fingerprintManager,
fingerprintSensorRepo, fingerprintSensorRepository,
gateKeeperPasswordProvider, gateKeeperPasswordProvider,
pressToAuthRepo, pressToAuthInteractor,
Default, Default,
) )
} }

View File

@@ -18,27 +18,30 @@ package com.android.settings.fingerprint2.enrollment.viewmodel
import android.content.Context import android.content.Context
import android.content.res.Configuration import android.content.res.Configuration
import android.view.accessibility.AccessibilityManager import android.view.Surface
import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
import com.android.settings.biometrics.fingerprint2.domain.interactor.AccessibilityInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor
import com.android.settings.biometrics.fingerprint2.lib.model.Default import com.android.settings.biometrics.fingerprint2.lib.model.Default
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.AccessibilityViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollFindSensorViewModel import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollFindSensorViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.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.Education 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.FoldStateViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.NavigationState
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.OrientationStateViewModel
import com.android.settings.testutils2.FakeFingerprintManagerInteractor import com.android.settings.testutils2.FakeFingerprintManagerInteractor
import com.android.systemui.biometrics.shared.model.FingerprintSensor import com.android.systemui.biometrics.shared.model.FingerprintSensor
import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength import com.android.systemui.biometrics.shared.model.SensorStrength
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.update
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
@@ -68,14 +71,13 @@ class FingerprintEnrollFindSensorViewModelV2Test {
private lateinit var gatekeeperViewModel: FingerprintGatekeeperViewModel private lateinit var gatekeeperViewModel: FingerprintGatekeeperViewModel
private lateinit var enrollViewModel: FingerprintEnrollViewModel private lateinit var enrollViewModel: FingerprintEnrollViewModel
private lateinit var navigationViewModel: FingerprintNavigationViewModel private lateinit var navigationViewModel: FingerprintNavigationViewModel
private lateinit var accessibilityViewModel: AccessibilityViewModel private lateinit var accessibilityInteractor: AccessibilityInteractor
private lateinit var foldStateViewModel: FoldStateViewModel private lateinit var foldStateInteractor: FoldStateInteractor
private lateinit var orientationStateViewModel: OrientationStateViewModel private lateinit var orientationInteractor: OrientationInteractor
private lateinit var underTest: FingerprintEnrollFindSensorViewModel private lateinit var underTest: FingerprintEnrollFindSensorViewModel
private lateinit var backgroundViewModel: BackgroundViewModel private lateinit var backgroundViewModel: BackgroundViewModel
private val context: Context = ApplicationProvider.getApplicationContext() private val context: Context = ApplicationProvider.getApplicationContext()
private val accessibilityManager: AccessibilityManager = private val foldState = MutableStateFlow(false)
context.getSystemService(AccessibilityManager::class.java)!!
@Before @Before
fun setup() { fun setup() {
@@ -95,7 +97,7 @@ class FingerprintEnrollFindSensorViewModelV2Test {
val fingerprintFlowViewModel = FingerprintFlowViewModel(Default) val fingerprintFlowViewModel = FingerprintFlowViewModel(Default)
navigationViewModel = navigationViewModel =
FingerprintNavigationViewModel( FingerprintNavigationViewModel(
Education(sensor), FingerprintNavigationStep.Education(sensor),
false, false,
fingerprintFlowViewModel, fingerprintFlowViewModel,
fakeFingerprintManagerInteractor, fakeFingerprintManagerInteractor,
@@ -111,24 +113,39 @@ class FingerprintEnrollFindSensorViewModelV2Test {
navigationViewModel, navigationViewModel,
) )
.create(FingerprintEnrollViewModel::class.java) .create(FingerprintEnrollViewModel::class.java)
accessibilityViewModel = accessibilityInteractor =
AccessibilityViewModel.AccessibilityViewModelFactory(accessibilityManager) object : AccessibilityInteractor {
.create(AccessibilityViewModel::class.java) override val isAccessibilityEnabled: Flow<Boolean> = flowOf(false)
foldStateViewModel = }
FoldStateViewModel.FoldStateViewModelFactory(context).create(FoldStateViewModel::class.java) foldStateInteractor =
orientationStateViewModel = object : FoldStateInteractor {
OrientationStateViewModel.OrientationViewModelFactory(context) override val isFolded: Flow<Boolean> = foldState
.create(OrientationStateViewModel::class.java) override fun onConfigurationChange(newConfig: Configuration) {
TODO("Not yet implemented")
}
}
orientationInteractor =
object: OrientationInteractor {
override val orientation: Flow<Int>
get() = TODO("Not yet implemented")
override val rotation: Flow<Int> = flowOf(Surface.ROTATION_0)
override fun getRotationFromDefault(rotation: Int): Int {
TODO("Not yet implemented")
}
}
underTest = underTest =
FingerprintEnrollFindSensorViewModel.FingerprintEnrollFindSensorViewModelFactory( FingerprintEnrollFindSensorViewModel.FingerprintEnrollFindSensorViewModelFactory(
navigationViewModel, navigationViewModel,
enrollViewModel, enrollViewModel,
gatekeeperViewModel, gatekeeperViewModel,
backgroundViewModel, backgroundViewModel,
accessibilityViewModel, accessibilityInteractor,
foldStateViewModel, foldStateInteractor,
orientationStateViewModel, orientationInteractor,
fingerprintFlowViewModel, fingerprintFlowViewModel,
fakeFingerprintManagerInteractor,
) )
.create(FingerprintEnrollFindSensorViewModel::class.java) .create(FingerprintEnrollFindSensorViewModel::class.java)
} }
@@ -171,8 +188,8 @@ class FingerprintEnrollFindSensorViewModelV2Test {
} }
} }
val config = createConfiguration(isFolded = true) foldState.update { true }
foldStateViewModel.onConfigurationChange(config)
advanceUntilIdle() advanceUntilIdle()
assertThat(isFolded).isTrue() assertThat(isFolded).isTrue()
assertThat(rotation).isEqualTo(context.display!!.rotation) assertThat(rotation).isEqualTo(context.display!!.rotation)
@@ -191,8 +208,8 @@ class FingerprintEnrollFindSensorViewModelV2Test {
} }
} }
val config = createConfiguration(isFolded = false) foldState.update { false }
foldStateViewModel.onConfigurationChange(config)
advanceUntilIdle() advanceUntilIdle()
assertThat(isFolded).isFalse() assertThat(isFolded).isFalse()
assertThat(rotation).isEqualTo(context.display!!.rotation) assertThat(rotation).isEqualTo(context.display!!.rotation)