Added UI tests for FingerprintEnrollIntro
Test: m -j40 RunSettingsRoboTests ROBOTEST_FILTER=FingerprintEnrollmentIntroFragmentTest
Bug: 295206367
Change-Id: I70f6b50dd2604e01805df04ffb1c07a9134ba065
diff --git a/res/layout/fingerprint_v2_enroll_introduction.xml b/res/layout/fingerprint_v2_enroll_introduction.xml
index e9dd08a..2fd1f9c 100644
--- a/res/layout/fingerprint_v2_enroll_introduction.xml
+++ b/res/layout/fingerprint_v2_enroll_introduction.xml
@@ -16,199 +16,210 @@
-->
<com.google.android.setupdesign.GlifLayout
-xmlns:android="http://schemas.android.com/apk/res/android"
-xmlns:app="http://schemas.android.com/apk/res-auto"
-style="?attr/fingerprint_layout_theme"
-android:id="@+id/setup_wizard_layout"
-android:layout_width="match_parent"
-android:layout_height="match_parent">
-
-<LinearLayout
- style="@style/SudContentFrame"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/setup_wizard_layout"
+ style="?attr/fingerprint_layout_theme"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:orientation="vertical">
+ android:layout_height="match_parent">
- <com.google.android.setupdesign.view.RichTextView
- android:id="@+id/error_text"
- style="@style/SudDescription.Glif"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <ImageView
- style="@style/SudContentIllustration"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:contentDescription="@null"
- android:src="@drawable/fingerprint_enroll_introduction" />
-
- </FrameLayout>
-
- <!-- Contains the extra information text at the bottom -->
<LinearLayout
+ style="@style/SudContentFrame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="false"
android:orientation="vertical">
- <!-- How it works -->
- <TextView
+ <com.google.android.setupdesign.view.RichTextView
+ android:id="@+id/error_text"
+ style="@style/SudDescription.Glif"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@style/BiometricEnrollIntroTitle"
- android:text="@string/security_settings_fingerprint_v2_enroll_introduction_footer_title_2" />
+ android:layout_height="wrap_content" />
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <ImageView
+ style="@style/SudContentIllustration"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:contentDescription="@null"
+ android:src="@drawable/fingerprint_enroll_introduction" />
+
+ </FrameLayout>
+
+ <!-- Contains the extra information text at the bottom -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal">
+ android:orientation="vertical">
- <ImageView
- android:id="@+id/icon_fingerprint"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@null"
- android:src="@drawable/ic_fingerprint_24dp"/>
- <Space
- android:layout_width="16dp"
- android:layout_height="wrap_content"/>
+ <!-- How it works -->
<TextView
- android:id="@+id/footer_message_2"
+ style="@style/BiometricEnrollIntroTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- style="@style/BiometricEnrollIntroMessage" />
- </LinearLayout>
+ android:text="@string/security_settings_fingerprint_v2_enroll_introduction_footer_title_2" />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <ImageView
- android:id="@+id/icon_device_locked"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@null"
- android:src="@drawable/ic_lock_24dp"/>
- <Space
- android:layout_width="16dp"
- android:layout_height="wrap_content"/>
- <TextView
- android:id="@+id/footer_message_3"
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- style="@style/BiometricEnrollIntroMessage" />
- </LinearLayout>
+ android:orientation="horizontal">
- <!-- You're in control -->
- <TextView
- android:id="@+id/footer_title_1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@style/BiometricEnrollIntroTitle" />
+ <ImageView
+ android:id="@+id/icon_fingerprint"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@null"
+ android:src="@drawable/ic_fingerprint_24dp" />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
+ <Space
+ android:layout_width="16dp"
+ android:layout_height="wrap_content" />
- <ImageView
- android:id="@+id/icon_trash_can"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@null"
- android:src="@drawable/ic_trash_can"/>
- <Space
- android:layout_width="16dp"
- android:layout_height="wrap_content"/>
- <TextView
- android:id="@+id/footer_message_4"
+ <TextView
+ android:id="@+id/footer_message_2"
+ style="@style/BiometricEnrollIntroMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </LinearLayout>
+
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- style="@style/BiometricEnrollIntroMessage" />
- </LinearLayout>
+ android:orientation="horizontal">
- <!-- Keep in mind -->
- <TextView
- android:id="@+id/footer_title_2"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@style/BiometricEnrollIntroTitle"
- android:text="@string/security_settings_face_enroll_introduction_info_title"/>
+ <ImageView
+ android:id="@+id/icon_device_locked"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@null"
+ android:src="@drawable/ic_lock_24dp" />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
+ <Space
+ android:layout_width="16dp"
+ android:layout_height="wrap_content" />
- <ImageView
- android:id="@+id/icon_info"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@null"
- android:src="@drawable/ic_info_outline_24dp"/>
- <Space
- android:layout_width="16dp"
- android:layout_height="wrap_content"/>
+ <TextView
+ android:id="@+id/footer_message_3"
+ style="@style/BiometricEnrollIntroMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </LinearLayout>
+
+ <!-- You're in control -->
<TextView
- android:id="@+id/footer_message_5"
+ android:id="@+id/footer_title_1"
+ style="@style/BiometricEnrollIntroTitle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- style="@style/BiometricEnrollIntroMessage" />
- </LinearLayout>
+ android:orientation="horizontal">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
+ <ImageView
+ android:id="@+id/icon_trash_can"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@null"
+ android:src="@drawable/ic_trash_can" />
- <ImageView
- android:id="@+id/icon_shield"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@null"
- android:src="@drawable/ic_guarantee"/>
- <Space
- android:layout_width="16dp"
- android:layout_height="wrap_content"/>
+ <Space
+ android:layout_width="16dp"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:id="@+id/footer_message_4"
+ style="@style/BiometricEnrollIntroMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </LinearLayout>
+
+ <!-- Keep in mind -->
<TextView
- android:id="@+id/footer_message_6"
+ android:id="@+id/footer_title_2"
+ style="@style/BiometricEnrollIntroTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- style="@style/BiometricEnrollIntroMessage" />
- </LinearLayout>
+ android:text="@string/security_settings_face_enroll_introduction_info_title" />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <ImageView
- android:id="@+id/icon_link"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@null"
- android:src="@drawable/ic_link_24dp"/>
- <Space
- android:layout_width="16dp"
- android:layout_height="wrap_content"/>
- <TextView
- android:id="@+id/footer_learn_more"
- android:linksClickable="true"
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- style="@style/BiometricEnrollIntroMessage"
- android:paddingBottom="0dp"
- android:text="@string/security_settings_fingerprint_v2_enroll_introduction_message_learn_more" />
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/icon_info"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@null"
+ android:src="@drawable/ic_info_outline_24dp" />
+
+ <Space
+ android:layout_width="16dp"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:id="@+id/footer_message_5"
+ style="@style/BiometricEnrollIntroMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/icon_shield"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@null"
+ android:src="@drawable/ic_guarantee" />
+
+ <Space
+ android:layout_width="16dp"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:id="@+id/footer_message_6"
+ style="@style/BiometricEnrollIntroMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/icon_link"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@null"
+ android:src="@drawable/ic_link_24dp" />
+
+ <Space
+ android:layout_width="16dp"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:id="@+id/footer_learn_more"
+ style="@style/BiometricEnrollIntroMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:linksClickable="true"
+ android:paddingBottom="0dp"
+ android:text="@string/security_settings_fingerprint_v2_enroll_introduction_message_learn_more" />
+ </LinearLayout>
+
</LinearLayout>
</LinearLayout>
-</LinearLayout>
-
</com.google.android.setupdesign.GlifLayout>
\ No newline at end of file
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt
index 31afcb7..2565ab8 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt
@@ -42,6 +42,7 @@
import com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED
import com.android.settings.biometrics.GatekeeperPasswordProvider
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl
+import com.android.settings.biometrics.fingerprint2.shared.model.FingerprintViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollConfirmationV2Fragment
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollEnrollingV2Fragment
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollFindSensorV2Fragment
@@ -82,6 +83,7 @@
private lateinit var accessibilityViewModel: AccessibilityViewModel
private lateinit var foldStateViewModel: FoldStateViewModel
private lateinit var orientationStateViewModel: OrientationStateViewModel
+ private lateinit var fingerprintScrollViewModel: FingerprintScrollViewModel
private val coroutineDispatcher = Dispatchers.Default
/** Result listener for ChooseLock activity flow. */
@@ -210,8 +212,9 @@
)[FingerprintEnrollViewModel::class.java]
// Initialize scroll view model
- ViewModelProvider(this, FingerprintScrollViewModel.FingerprintScrollViewModelFactory())[
- FingerprintScrollViewModel::class.java]
+ fingerprintScrollViewModel =
+ ViewModelProvider(this, FingerprintScrollViewModel.FingerprintScrollViewModelFactory())[
+ FingerprintScrollViewModel::class.java]
// Initialize AccessibilityViewModel
accessibilityViewModel =
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollIntroV2Fragment.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollIntroV2Fragment.kt
index dbf6d12..898b158 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollIntroV2Fragment.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollIntroV2Fragment.kt
@@ -25,10 +25,13 @@
import android.text.Html
import android.text.method.LinkMovementMethod
import android.util.Log
+import android.view.LayoutInflater
import android.view.View
+import android.view.ViewGroup
import android.widget.ImageView
import android.widget.ScrollView
import android.widget.TextView
+import androidx.annotation.VisibleForTesting
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
@@ -72,48 +75,69 @@
* 2. How the data will be stored
* 3. How the user can access and remove their data
*/
-class FingerprintEnrollIntroV2Fragment : Fragment(R.layout.fingerprint_v2_enroll_introduction) {
- private lateinit var footerBarMixin: FooterBarMixin
- private lateinit var textModel: TextModel
- private lateinit var navigationViewModel: FingerprintEnrollNavigationViewModel
- private lateinit var fingerprintEnrollViewModel: FingerprintEnrollViewModel
- private lateinit var fingerprintScrollViewModel: FingerprintScrollViewModel
- private lateinit var gateKeeperViewModel: FingerprintGatekeeperViewModel
+class FingerprintEnrollIntroV2Fragment() : Fragment(R.layout.fingerprint_v2_enroll_introduction) {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- navigationViewModel =
- ViewModelProvider(requireActivity())[FingerprintEnrollNavigationViewModel::class.java]
- fingerprintEnrollViewModel =
- ViewModelProvider(requireActivity())[FingerprintEnrollViewModel::class.java]
- fingerprintScrollViewModel =
- ViewModelProvider(requireActivity())[FingerprintScrollViewModel::class.java]
- gateKeeperViewModel =
- ViewModelProvider(requireActivity())[FingerprintGatekeeperViewModel::class.java]
+ /** Used for testing purposes */
+ private var factory: ViewModelProvider.Factory? = null
+
+ @VisibleForTesting
+ constructor(theFactory: ViewModelProvider.Factory) : this() {
+ factory = theFactory
}
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
+ private val viewModelProvider: ViewModelProvider by lazy {
+ if (factory != null) {
+ ViewModelProvider(requireActivity(), factory!!)
+ } else {
+ ViewModelProvider(requireActivity())
+ }
+ }
- lifecycleScope.launch {
- combine(
- navigationViewModel.enrollType,
- fingerprintEnrollViewModel.sensorType,
- ) { enrollType, sensorType ->
- Pair(enrollType, sensorType)
- }
- .collect { (enrollType, sensorType) ->
- textModel =
- when (enrollType) {
- Unicorn -> getUnicornTextModel()
- else -> getNormalTextModel()
- }
+ private lateinit var footerBarMixin: FooterBarMixin
+ private lateinit var textModel: TextModel
- setupFooterBarAndScrollView(view)
+ // Note that the ViewModels cannot be requested before the onCreate call
+ private val navigationViewModel: FingerprintEnrollNavigationViewModel by lazy {
+ viewModelProvider[FingerprintEnrollNavigationViewModel::class.java]
+ }
+ private val fingerprintViewModel: FingerprintEnrollViewModel by lazy {
+ viewModelProvider[FingerprintEnrollViewModel::class.java]
+ }
+ private val fingerprintScrollViewModel: FingerprintScrollViewModel by lazy {
+ viewModelProvider[FingerprintScrollViewModel::class.java]
+ }
+ private val gateKeeperViewModel: FingerprintGatekeeperViewModel by lazy {
+ viewModelProvider[FingerprintGatekeeperViewModel::class.java]
+ }
- if (savedInstanceState == null) {
- getLayout()?.setHeaderText(textModel.headerText)
- getLayout()?.setDescriptionText(textModel.descriptionText)
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? =
+ super.onCreateView(inflater, container, savedInstanceState).also { theView ->
+ val view = theView!!
+
+ viewLifecycleOwner.lifecycleScope.launch {
+ combine(
+ navigationViewModel.enrollType,
+ fingerprintViewModel.sensorType,
+ ) { enrollType, sensorType ->
+ Pair(enrollType, sensorType)
+ }
+ .collect { (enrollType, sensorType) ->
+ textModel =
+ when (enrollType) {
+ Unicorn -> getUnicornTextModel()
+ else -> getNormalTextModel()
+ }
+
+ setupFooterBarAndScrollView(view)
+
+ val layout = view as GlifLayout
+
+ layout.setHeaderText(textModel.headerText)
+ layout.setDescriptionText(textModel.descriptionText)
// Set color filter for the following icons.
val colorFilter = getIconColorFilter()
@@ -158,9 +182,9 @@
view.requireViewById<TextView?>(R.id.footer_title_1).setText(textModel.footerTitleOne)
view.requireViewById<TextView?>(R.id.footer_title_2).setText(textModel.footerTitleOne)
}
- }
+ }
+ return view
}
- }
private fun setFooterLink(view: View) {
val footerLink: TextView = view.requireViewById(R.id.footer_learn_more)
@@ -185,17 +209,18 @@
navigationViewModel.nextStep()
}
- val layout: GlifLayout = requireActivity().requireViewById(R.id.setup_wizard_layout)
+ val layout: GlifLayout = view.findViewById(R.id.setup_wizard_layout)!!
footerBarMixin = layout.getMixin(FooterBarMixin::class.java)
footerBarMixin.primaryButton =
- FooterButton.Builder(requireActivity())
+ FooterButton.Builder(requireContext())
.setText(R.string.security_settings_face_enroll_introduction_more)
.setListener(onNextButtonClick)
.setButtonType(FooterButton.ButtonType.OPT_IN)
.setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary)
.build()
+
footerBarMixin.setSecondaryButton(
- FooterButton.Builder(requireActivity())
+ FooterButton.Builder(requireContext())
.setText(textModel.negativeButton)
.setListener({ Log.d(TAG, "prevClicked") })
.setButtonType(FooterButton.ButtonType.NEXT)
@@ -211,8 +236,8 @@
val requireScrollMixin = layout.getMixin(RequireScrollMixin::class.java)
requireScrollMixin.requireScrollWithButton(
- requireActivity(),
- footerBarMixin.primaryButton,
+ requireContext(),
+ primaryButton,
R.string.security_settings_face_enroll_introduction_more,
onNextButtonClick
)
@@ -224,7 +249,7 @@
}
}
- lifecycleScope.launch {
+ viewLifecycleOwner.lifecycleScope.launch {
fingerprintScrollViewModel.hasReadConsentScreen.collect { consented ->
if (consented) {
primaryButton.setText(
@@ -244,7 +269,7 @@
// the flow. For instance if someone launches the activity with an invalid challenge, it
// either 1) Fails or 2) Launched confirmDeviceCredential
primaryButton.isEnabled = false
- lifecycleScope.launch {
+ viewLifecycleOwner.lifecycleScope.launch {
gateKeeperViewModel.hasValidGatekeeperInfo.collect { primaryButton.isEnabled = it }
}
}
@@ -284,8 +309,4 @@
PorterDuff.Mode.SRC_IN
)
}
-
- private fun getLayout(): GlifLayout? {
- return requireView().findViewById(R.id.setup_wizard_layout) as GlifLayout?
- }
}
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrolllNavigationViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrolllNavigationViewModel.kt
index d2bb321..97c8271 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrolllNavigationViewModel.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/viewmodel/FingerprintEnrolllNavigationViewModel.kt
@@ -31,11 +31,6 @@
private const val TAG = "FingerprintEnrollNavigationViewModel"
-/** Interface to validate a gatekeeper hat */
-interface Validator {
- fun validateGateKeeper(challenge: Long?): Boolean
-}
-
/**
* The [EnrollType] for fingerprint enrollment indicates information on how the flow should behave.
*/
@@ -56,7 +51,6 @@
*/
class FingerprintEnrollNavigationViewModel(
private val dispatcher: CoroutineDispatcher,
- private val validator: Validator,
private val fingerprintManagerInteractor: FingerprintManagerInteractor,
private val gatekeeperViewModel: FingerprintGatekeeperViewModel,
private val canSkipConfirm: Boolean
@@ -145,11 +139,6 @@
return FingerprintEnrollNavigationViewModel(
backgroundDispatcher,
- object : Validator {
- override fun validateGateKeeper(challenge: Long?): Boolean {
- return challenge != null
- }
- },
fingerprintManagerInteractor,
fingerprintGatekeeperViewModel,
canSkipConfirm,
diff --git a/tests/robotests/Android.bp b/tests/robotests/Android.bp
index fbfd888..1fd4f25 100644
--- a/tests/robotests/Android.bp
+++ b/tests/robotests/Android.bp
@@ -25,6 +25,8 @@
"androidx.fragment_fragment-testing",
"frameworks-base-testutils",
"androidx.fragment_fragment",
+ "androidx.lifecycle_lifecycle-runtime-testing",
+ "kotlinx_coroutines_test",
],
aaptflags: ["--extra-packages com.android.settings"],
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint2/fragment/FingerprintEnrollIntroFragmentTest.kt b/tests/robotests/src/com/android/settings/biometrics/fingerprint2/fragment/FingerprintEnrollIntroFragmentTest.kt
new file mode 100644
index 0000000..cea6676
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint2/fragment/FingerprintEnrollIntroFragmentTest.kt
@@ -0,0 +1,173 @@
+/*
+ * 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.fragment
+
+import android.content.Context
+import android.os.Bundle
+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.espresso.Espresso.onView
+import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
+import androidx.test.espresso.assertion.ViewAssertions.matches
+import androidx.test.espresso.matcher.ViewMatchers.Visibility
+import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
+import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import androidx.test.espresso.matcher.ViewMatchers.withText
+import androidx.test.runner.AndroidJUnit4
+import com.android.settings.R
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollIntroV2Fragment
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollNavigationViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo
+import com.android.settings.testutils2.FakeFingerprintManagerInteractor
+import com.google.android.setupdesign.GlifLayout
+import com.google.android.setupdesign.template.RequireScrollMixin
+import kotlinx.coroutines.test.StandardTestDispatcher
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class FingerprintEnrollIntroFragmentTest {
+ 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 navigationViewModel =
+ FingerprintEnrollNavigationViewModel(
+ backgroundDispatcher,
+ interactor,
+ gatekeeperViewModel,
+ canSkipConfirm = true,
+ )
+ private var fingerprintViewModel = FingerprintEnrollViewModel(interactor, backgroundDispatcher)
+ 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) {
+ FingerprintEnrollViewModel::class.java -> fingerprintViewModel
+ FingerprintScrollViewModel::class.java -> fingerprintScrollViewModel
+ FingerprintEnrollNavigationViewModel::class.java -> navigationViewModel
+ FingerprintGatekeeperViewModel::class.java -> gatekeeperViewModel
+ else -> null
+ }
+ as T
+ }
+ }
+
+ fragmentScenario =
+ launchFragmentInContainer(Bundle(), R.style.SudThemeGlif) {
+ FingerprintEnrollIntroV2Fragment(factory)
+ }
+ }
+
+ @Test
+ fun testScrollToBottomButtonChangesText() {
+ fragmentScenario.onFragment { fragment ->
+ onView(withText("I agree")).check(doesNotExist())
+ val someView = (fragment.requireView().findViewById<GlifLayout>(R.id.setup_wizard_layout))!!
+ val scrollMixin = someView.getMixin(RequireScrollMixin::class.java)!!
+ val listener = scrollMixin.onRequireScrollStateChangedListener
+ // This actually changes the button text
+ listener.onRequireScrollStateChanged(false)
+
+ onView(withText("I agree")).check(matches(isDisplayed()))
+ }
+ }
+
+ @Test
+ fun testBasicTitle() {
+ onView(withText(R.string.security_settings_fingerprint_enroll_introduction_title))
+ .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
+ }
+
+ @Test
+ fun testFooterMessageTwo() {
+ onView(withId(R.id.footer_message_2))
+ .check(
+ matches(
+ withText(
+ context.getString(
+ (R.string.security_settings_fingerprint_v2_enroll_introduction_footer_message_2)
+ )
+ )
+ )
+ )
+ }
+
+ @Test
+ fun testFooterMessageThree() {
+ onView(withId(R.id.footer_message_3))
+ .check(
+ matches(
+ withText(
+ context.getString(
+ (R.string.security_settings_fingerprint_v2_enroll_introduction_footer_message_3)
+ )
+ )
+ )
+ )
+ }
+
+ @Test
+ fun testFooterMessageFour() {
+ onView(withId(R.id.footer_message_4))
+ .check(
+ matches(
+ withText(
+ context.getString(
+ (R.string.security_settings_fingerprint_v2_enroll_introduction_footer_message_4)
+ )
+ )
+ )
+ )
+ }
+
+ @Test
+ fun testFooterMessageFive() {
+ onView(withId(R.id.footer_message_5))
+ .check(
+ matches(
+ withText(
+ context.getString(
+ (R.string.security_settings_fingerprint_v2_enroll_introduction_footer_message_5)
+ )
+ )
+ )
+ )
+ }
+}