Add tests for Education
Test: atest FingerprintEnrollFindSensorViewModelV2Test Bug: 295206773 Change-Id: I741ddf49fccae7a301e2fb79194ce8cc6b966070
This commit is contained in:
@@ -34,7 +34,6 @@ import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
||||
import com.google.android.setupcompat.template.FooterBarMixin
|
||||
import com.google.android.setupcompat.template.FooterButton
|
||||
import com.google.android.setupdesign.GlifLayout
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
private const val TAG = "FingerprintEnrollFindSensorV2Fragment"
|
||||
@@ -94,12 +93,12 @@ class FingerprintEnrollFindSensorV2Fragment : Fragment() {
|
||||
|
||||
// Set up lottie or animation
|
||||
lifecycleScope.launch {
|
||||
viewModel.showSfpsLottie.collect { (isFolded, rotation) ->
|
||||
viewModel.sfpsLottieInfo.collect { (isFolded, rotation) ->
|
||||
setupLottie(view, getSfpsIllustrationLottieAnimation(isFolded, rotation))
|
||||
}
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
viewModel.showUdfpsLottie.collect { isAccessibilityEnabled ->
|
||||
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() }
|
||||
|
||||
@@ -26,13 +26,12 @@ import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.combineTransform
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
import kotlinx.coroutines.flow.transform
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -47,41 +46,43 @@ class FingerprintEnrollFindSensorViewModel(
|
||||
) : ViewModel() {
|
||||
/** Represents the stream of sensor type. */
|
||||
val sensorType: Flow<FingerprintSensorType> =
|
||||
fingerprintEnrollViewModel.sensorType
|
||||
.filterWhenEducationIsShown()
|
||||
.shareIn(viewModelScope, SharingStarted.WhileSubscribed(), 1)
|
||||
fingerprintEnrollViewModel.sensorType.shareIn(
|
||||
viewModelScope,
|
||||
SharingStarted.WhileSubscribed(),
|
||||
1
|
||||
)
|
||||
private val _isUdfps: Flow<Boolean> =
|
||||
sensorType.map {
|
||||
it == FingerprintSensorType.UDFPS_OPTICAL || it == FingerprintSensorType.UDFPS_ULTRASONIC
|
||||
}
|
||||
private val _isSfps: Flow<Boolean> = sensorType.map { it == FingerprintSensorType.POWER_BUTTON }
|
||||
private val _isRearSfps: Flow<Boolean> =
|
||||
combineTransform(_isSfps, _isUdfps) { v1, v2 -> !v1 && !v2 }
|
||||
private val _isRearSfps: Flow<Boolean> = sensorType.map { it == FingerprintSensorType.REAR }
|
||||
|
||||
/** Represents the stream of showing primary button. */
|
||||
val showPrimaryButton: Flow<Boolean> = _isUdfps.transform { if (it) emit(true) }
|
||||
val showPrimaryButton: Flow<Boolean> = _isUdfps.filter { it }
|
||||
|
||||
/** Represents the stream of showing sfps lottie, Pair(isFolded, rotation). */
|
||||
val showSfpsLottie: Flow<Pair<Boolean, Int>> =
|
||||
private val _showSfpsLottie = _isSfps.filter { it }
|
||||
/** Represents the stream of showing sfps lottie and the information Pair(isFolded, rotation). */
|
||||
val sfpsLottieInfo: Flow<Pair<Boolean, Int>> =
|
||||
combineTransform(
|
||||
_isSfps,
|
||||
_showSfpsLottie,
|
||||
foldStateViewModel.isFolded,
|
||||
orientationStateViewModel.rotation,
|
||||
) { isSfps, isFolded, rotation ->
|
||||
if (isSfps) emit(Pair(isFolded, rotation))
|
||||
) { _, isFolded, rotation ->
|
||||
emit(Pair(isFolded, rotation))
|
||||
}
|
||||
|
||||
/** Represents the stream of showing udfps lottie. */
|
||||
val showUdfpsLottie: Flow<Boolean> =
|
||||
combineTransform(
|
||||
_isUdfps,
|
||||
accessibilityViewModel.isAccessibilityEnabled,
|
||||
) { isUdfps, isAccessibilityEnabled ->
|
||||
if (isUdfps) emit(isAccessibilityEnabled)
|
||||
private val _showUdfpsLottie = _isUdfps.filter { it }
|
||||
/** Represents the stream of showing udfps lottie and whether accessibility is enabled. */
|
||||
val udfpsLottieInfo: Flow<Boolean> =
|
||||
_showUdfpsLottie.combine(accessibilityViewModel.isAccessibilityEnabled) {
|
||||
_,
|
||||
isAccessibilityEnabled ->
|
||||
isAccessibilityEnabled
|
||||
}
|
||||
|
||||
/** Represents the stream of showing rfps animation. */
|
||||
val showRfpsAnimation: Flow<Boolean> = _isRearSfps.transform { if (it) emit(true) }
|
||||
val showRfpsAnimation: Flow<Boolean> = _isRearSfps.filter { it }
|
||||
|
||||
private val _showErrorDialog: MutableStateFlow<Pair<Int, Boolean>?> = MutableStateFlow(null)
|
||||
/** Represents the stream of showing error dialog. */
|
||||
@@ -145,16 +146,6 @@ class FingerprintEnrollFindSensorViewModel(
|
||||
navigationViewModel.nextStep()
|
||||
}
|
||||
|
||||
// TODO: If we decide to remove previous fragment from activity, then we don't need to check
|
||||
// whether education is shown for the flows that are subscribed by
|
||||
// [FingerprintEnrollFindSensorV2Fragment].
|
||||
private fun <T> Flow<T>.filterWhenEducationIsShown() =
|
||||
combineTransform(navigationViewModel.navigationViewModel) { value, navigationViewModel ->
|
||||
if (navigationViewModel.currStep == Education) {
|
||||
emit(value)
|
||||
}
|
||||
}
|
||||
|
||||
class FingerprintEnrollFindSensorViewModelFactory(
|
||||
private val navigationViewModel: FingerprintEnrollNavigationViewModel,
|
||||
private val fingerprintEnrollViewModel: FingerprintEnrollViewModel,
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* 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.fingerprint2.enrollment.viewmodel
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.view.accessibility.AccessibilityManager
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.AccessibilityViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Education
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollFindSensorViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollNavigationViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FoldStateViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.NextStepViewModel
|
||||
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.OrientationStateViewModel
|
||||
import com.android.settings.testutils2.FakeFingerprintManagerInteractor
|
||||
import com.android.systemui.biometrics.shared.model.FingerprintSensor
|
||||
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
|
||||
import com.android.systemui.biometrics.shared.model.SensorStrength
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.advanceUntilIdle
|
||||
import kotlinx.coroutines.test.resetMain
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.coroutines.test.setMain
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.junit.MockitoJUnit
|
||||
import org.mockito.junit.MockitoJUnitRunner
|
||||
|
||||
/** consistent with [ScreenSizeFoldProvider.INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP] */
|
||||
private const val INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP = 600
|
||||
|
||||
@RunWith(MockitoJUnitRunner::class)
|
||||
class FingerprintEnrollFindSensorViewModelV2Test {
|
||||
@JvmField @Rule var rule = MockitoJUnit.rule()
|
||||
@get:Rule val instantTaskRule = InstantTaskExecutorRule()
|
||||
|
||||
private var backgroundDispatcher = StandardTestDispatcher()
|
||||
private var testScope = TestScope(backgroundDispatcher)
|
||||
private lateinit var fakeFingerprintManagerInteractor: FakeFingerprintManagerInteractor
|
||||
private lateinit var gatekeeperViewModel: FingerprintGatekeeperViewModel
|
||||
private lateinit var enrollViewModel: FingerprintEnrollViewModel
|
||||
private lateinit var navigationViewModel: FingerprintEnrollNavigationViewModel
|
||||
private lateinit var accessibilityViewModel: AccessibilityViewModel
|
||||
private lateinit var foldStateViewModel: FoldStateViewModel
|
||||
private lateinit var orientationStateViewModel: OrientationStateViewModel
|
||||
private lateinit var underTest: FingerprintEnrollFindSensorViewModel
|
||||
private val context: Context = ApplicationProvider.getApplicationContext()
|
||||
private val accessibilityManager: AccessibilityManager =
|
||||
context.getSystemService(AccessibilityManager::class.java)!!
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
backgroundDispatcher = StandardTestDispatcher()
|
||||
testScope = TestScope(backgroundDispatcher)
|
||||
Dispatchers.setMain(backgroundDispatcher)
|
||||
|
||||
fakeFingerprintManagerInteractor = FakeFingerprintManagerInteractor()
|
||||
gatekeeperViewModel =
|
||||
FingerprintGatekeeperViewModel.FingerprintGatekeeperViewModelFactory(
|
||||
null,
|
||||
fakeFingerprintManagerInteractor
|
||||
)
|
||||
.create(FingerprintGatekeeperViewModel::class.java)
|
||||
navigationViewModel =
|
||||
FingerprintEnrollNavigationViewModel.FingerprintEnrollNavigationViewModelFactory(
|
||||
backgroundDispatcher,
|
||||
fakeFingerprintManagerInteractor,
|
||||
gatekeeperViewModel,
|
||||
canSkipConfirm = true,
|
||||
)
|
||||
.create(FingerprintEnrollNavigationViewModel::class.java)
|
||||
enrollViewModel =
|
||||
FingerprintEnrollViewModel.FingerprintEnrollViewModelFactory(
|
||||
fakeFingerprintManagerInteractor,
|
||||
backgroundDispatcher
|
||||
)
|
||||
.create(FingerprintEnrollViewModel::class.java)
|
||||
accessibilityViewModel =
|
||||
AccessibilityViewModel.AccessibilityViewModelFactory(accessibilityManager)
|
||||
.create(AccessibilityViewModel::class.java)
|
||||
foldStateViewModel =
|
||||
FoldStateViewModel.FoldStateViewModelFactory(context).create(FoldStateViewModel::class.java)
|
||||
orientationStateViewModel =
|
||||
OrientationStateViewModel.OrientationViewModelFactory(context)
|
||||
.create(OrientationStateViewModel::class.java)
|
||||
underTest =
|
||||
FingerprintEnrollFindSensorViewModel.FingerprintEnrollFindSensorViewModelFactory(
|
||||
navigationViewModel,
|
||||
enrollViewModel,
|
||||
gatekeeperViewModel,
|
||||
accessibilityViewModel,
|
||||
foldStateViewModel,
|
||||
orientationStateViewModel
|
||||
)
|
||||
.create(FingerprintEnrollFindSensorViewModel::class.java)
|
||||
|
||||
// Navigate to Education page
|
||||
navigationViewModel.nextStep()
|
||||
}
|
||||
@After
|
||||
fun tearDown() {
|
||||
Dispatchers.resetMain()
|
||||
}
|
||||
|
||||
// TODO(b/305094585): test enroll() logic
|
||||
|
||||
@Test
|
||||
fun currentStepIsEducation() =
|
||||
testScope.runTest {
|
||||
var step: NextStepViewModel? = null
|
||||
val job = launch {
|
||||
navigationViewModel.navigationViewModel.collectLatest { step = it.currStep }
|
||||
}
|
||||
advanceUntilIdle()
|
||||
assertThat(step).isEqualTo(Education)
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun udfpsLottieInfo() =
|
||||
testScope.runTest {
|
||||
fakeFingerprintManagerInteractor.sensorProp =
|
||||
FingerprintSensor(
|
||||
0 /* sensorId */,
|
||||
SensorStrength.STRONG,
|
||||
5,
|
||||
FingerprintSensorType.UDFPS_OPTICAL
|
||||
)
|
||||
|
||||
var udfpsLottieInfo: Boolean? = null
|
||||
val job = launch { underTest.udfpsLottieInfo.collect { udfpsLottieInfo = it } }
|
||||
|
||||
advanceUntilIdle()
|
||||
assertThat(udfpsLottieInfo).isNotNull()
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun sfpsLottieInfoWhenFolded() =
|
||||
testScope.runTest {
|
||||
var isFolded = false
|
||||
var rotation: Int = -1
|
||||
val job = launch {
|
||||
underTest.sfpsLottieInfo.collect {
|
||||
isFolded = it.first
|
||||
rotation = it.second
|
||||
}
|
||||
}
|
||||
|
||||
val config = createConfiguration(isFolded = true)
|
||||
foldStateViewModel.onConfigurationChange(config)
|
||||
advanceUntilIdle()
|
||||
assertThat(isFolded).isTrue()
|
||||
assertThat(rotation).isEqualTo(context.display!!.rotation)
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun sfpsLottieInfoWhenUnFolded() =
|
||||
testScope.runTest {
|
||||
var isFolded = false
|
||||
var rotation: Int = -1
|
||||
val job = launch {
|
||||
underTest.sfpsLottieInfo.collect {
|
||||
isFolded = it.first
|
||||
rotation = it.second
|
||||
}
|
||||
}
|
||||
|
||||
val config = createConfiguration(isFolded = false)
|
||||
foldStateViewModel.onConfigurationChange(config)
|
||||
advanceUntilIdle()
|
||||
assertThat(isFolded).isFalse()
|
||||
assertThat(rotation).isEqualTo(context.display!!.rotation)
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun rfpsAnimation() =
|
||||
testScope.runTest {
|
||||
fakeFingerprintManagerInteractor.sensorProp =
|
||||
FingerprintSensor(0 /* sensorId */, SensorStrength.STRONG, 5, FingerprintSensorType.REAR)
|
||||
|
||||
var showRfpsAnimation: Boolean? = null
|
||||
val job = launch { underTest.showRfpsAnimation.collect { showRfpsAnimation = it } }
|
||||
|
||||
advanceUntilIdle()
|
||||
assertThat(showRfpsAnimation).isTrue()
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun showPrimaryButton_ifUdfps() =
|
||||
testScope.runTest {
|
||||
fakeFingerprintManagerInteractor.sensorProp =
|
||||
FingerprintSensor(
|
||||
0 /* sensorId */,
|
||||
SensorStrength.STRONG,
|
||||
5,
|
||||
FingerprintSensorType.UDFPS_OPTICAL
|
||||
)
|
||||
|
||||
var showPrimaryButton: Boolean? = null
|
||||
val job = launch { underTest.showPrimaryButton.collect { showPrimaryButton = it } }
|
||||
|
||||
advanceUntilIdle()
|
||||
assertThat(showPrimaryButton).isTrue()
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun doesNotShowPrimaryButton_ifNonUdfps() =
|
||||
testScope.runTest {
|
||||
var showPrimaryButton: Boolean? = null
|
||||
val job = launch { underTest.showPrimaryButton.collect { showPrimaryButton = it } }
|
||||
|
||||
advanceUntilIdle()
|
||||
assertThat(showPrimaryButton).isNull()
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
private fun createConfiguration(isFolded: Boolean): Configuration {
|
||||
val config = Configuration()
|
||||
config.smallestScreenWidthDp =
|
||||
if (isFolded) INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP - 1
|
||||
else INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP + 1
|
||||
return config
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user