Customize Fingerprint enroll activities

Provide an interface for ODM/OEM to override Fingerprint enrollment
activities.

Bug: 364794493
Flag: EXEMPT can't apply flag for manifest change
Test: atest SettingsRoboTests:FingerprintEnrollTest
Change-Id: Ic519970a3837614b3d4c8cb2f6d75967ae838208
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index d988fea..eebef14 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -2816,6 +2816,9 @@
         <activity android:name=".biometrics.fingerprint.FingerprintEnrollFinish" android:exported="false"/>
         <activity android:name=".biometrics.fingerprint.FingerprintEnrollParentalConsent" android:exported="false"/>
         <activity android:name=".biometrics.fingerprint.FingerprintEnrollIntroduction"
+            android:exported="false"
+            android:theme="@style/GlifTheme.Light" />
+        <activity android:name=".biometrics.fingerprint.FingerprintEnroll"
             android:exported="true"
             android:theme="@style/GlifTheme.Light">
             <intent-filter>
@@ -2826,9 +2829,13 @@
         </activity>
 
         <activity android:name=".biometrics.fingerprint.FingerprintEnrollIntroductionInternal"
-                  android:exported="false"
-                  android:theme="@style/GlifTheme.Light"
-                  android:taskAffinity="com.android.settings.root" />
+              android:exported="false"
+              android:theme="@style/GlifTheme.Light"
+              android:taskAffinity="com.android.settings.root" />
+        <activity android:name=".biometrics.fingerprint.FingerprintEnroll$InternalActivity"
+            android:exported="false"
+            android:theme="@style/GlifTheme.Light"
+            android:taskAffinity="com.android.settings.root" />
 
         <activity android:name=".biometrics.fingerprint.SetupFingerprintEnrollFindSensor"
             android:exported="false"
@@ -2836,6 +2843,10 @@
         <activity android:name=".biometrics.fingerprint.SetupFingerprintEnrollEnrolling" android:exported="false"/>
         <activity android:name=".biometrics.fingerprint.SetupFingerprintEnrollFinish" android:exported="false"/>
         <activity android:name=".biometrics.fingerprint.SetupFingerprintEnrollIntroduction"
+            android:exported="false"
+            android:permission="android.permission.MANAGE_FINGERPRINT"
+            android:theme="@style/GlifTheme.Light" />
+        <activity android:name=".biometrics.fingerprint.FingerprintEnroll$SetupActivity"
             android:exported="true"
             android:permission="android.permission.MANAGE_FINGERPRINT"
             android:theme="@style/GlifTheme.Light">
@@ -2845,7 +2856,6 @@
             </intent-filter>
         </activity>
 
-
         <activity android:name=".biometrics.fingerprint2.ui.enrollment.activity.FingerprintEnrollmentV2Activity"
             android:exported="true"
             android:permission="android.permission.MANAGE_FINGERPRINT"
diff --git a/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java b/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java
index 72a0f08..b38c42c 100644
--- a/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java
+++ b/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java
@@ -40,9 +40,8 @@
 import com.android.settings.SubSettings;
 import com.android.settings.biometrics.face.FaceEnrollIntroduction;
 import com.android.settings.biometrics.face.FaceEnrollIntroductionInternal;
+import com.android.settings.biometrics.fingerprint.FingerprintEnrollActivityClassProvider;
 import com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling;
-import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
-import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroductionInternal;
 import com.android.settings.core.FeatureFlags;
 import com.android.settings.homepage.DeepLinkHomepageActivity;
 import com.android.settings.homepage.DeepLinkHomepageActivityInternal;
@@ -255,8 +254,12 @@
                     .buildSearchIntent(mContext, SettingsEnums.SETTINGS_HOMEPAGE);
             addActivityFilter(activityFilters, searchIntent);
         }
-        addActivityFilter(activityFilters, FingerprintEnrollIntroduction.class);
-        addActivityFilter(activityFilters, FingerprintEnrollIntroductionInternal.class);
+        final FingerprintEnrollActivityClassProvider fpClassProvider = FeatureFactory
+                .getFeatureFactory()
+                .getFingerprintFeatureProvider()
+                .getEnrollActivityClassProvider();
+        addActivityFilter(activityFilters, fpClassProvider.getDefault());
+        addActivityFilter(activityFilters, fpClassProvider.getInternal());
         addActivityFilter(activityFilters, FingerprintEnrollEnrolling.class);
         addActivityFilter(activityFilters, FaceEnrollIntroductionInternal.class);
         addActivityFilter(activityFilters, FaceEnrollIntroduction.class);
diff --git a/src/com/android/settings/biometrics/BiometricUtils.java b/src/com/android/settings/biometrics/BiometricUtils.java
index 09b2dba..2a457f5 100644
--- a/src/com/android/settings/biometrics/BiometricUtils.java
+++ b/src/com/android/settings/biometrics/BiometricUtils.java
@@ -44,10 +44,9 @@
 import com.android.settings.R;
 import com.android.settings.SetupWizardUtils;
 import com.android.settings.biometrics.face.FaceEnrollIntroduction;
+import com.android.settings.biometrics.fingerprint.FingerprintEnroll;
 import com.android.settings.biometrics.fingerprint.FingerprintEnrollFindSensor;
-import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
 import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollFindSensor;
-import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollIntroduction;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.password.ChooseLockGeneric;
 import com.android.settings.password.ChooseLockSettingsHelper;
@@ -262,13 +261,13 @@
     /**
      * @param context caller's context
      * @param activityIntent The intent that started the caller's activity
-     * @return Intent for starting FingerprintEnrollIntroduction
+     * @return Intent for starting FingerprintEnroll
      */
     public static Intent getFingerprintIntroIntent(@NonNull Context context,
             @NonNull Intent activityIntent) {
         final boolean isSuw = WizardManagerHelper.isAnySetupWizard(activityIntent);
         final Intent intent = new Intent(context, isSuw
-                ? SetupFingerprintEnrollIntroduction.class : FingerprintEnrollIntroduction.class);
+                ? FingerprintEnroll.SetupActivity.class : FingerprintEnroll.class);
         if (isSuw) {
             WizardManagerHelper.copyWizardManagerExtras(activityIntent, intent);
         }
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnroll.kt b/src/com/android/settings/biometrics/fingerprint/FingerprintEnroll.kt
new file mode 100644
index 0000000..3d78269
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnroll.kt
@@ -0,0 +1,69 @@
+/*
+ * 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.fingerprint
+
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import androidx.appcompat.app.AppCompatActivity
+import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
+
+/**
+ * Default class for handling fingerprint enrollment, designed to launch a subsequent activity and
+ * forward the result, then finish itself.
+ */
+open class FingerprintEnroll: AppCompatActivity() {
+
+    /** Inner class representing enrolling fingerprint enrollment in SetupWizard environment */
+    class SetupActivity : FingerprintEnroll() {
+        override val nextActivityClass: Class<*>
+            get() = enrollActivityProvider.setup
+    }
+
+    /** Inner class representing enrolling fingerprint enrollment from FingerprintSettings */
+    class InternalActivity : FingerprintEnroll() {
+        override val nextActivityClass: Class<*>
+        get() = enrollActivityProvider.internal
+    }
+
+    /**
+     * The class of the next activity to launch. This is open to allow subclasses to provide their
+     * own behavior. Defaults to the default activity class provided by the
+     * enrollActivityClassProvider.
+     */
+    open val nextActivityClass: Class<*>
+        get() = enrollActivityProvider.default
+
+    protected val enrollActivityProvider: FingerprintEnrollActivityClassProvider
+        get() = featureFactory.fingerprintFeatureProvider.enrollActivityClassProvider
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        /**
+         *  Logs the next activity to be launched, creates an intent for that activity,
+         *  adds flags to forward the result, includes any existing extras from the current intent,
+         *  starts the new activity and then finishes the current one
+         */
+        Log.d("FingerprintEnroll", "forward to $nextActivityClass")
+        val nextIntent = Intent(this, nextActivityClass)
+        nextIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT)
+        nextIntent.putExtras(intent)
+        startActivity(nextIntent)
+        finish()
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollActivityClassProvider.kt b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollActivityClassProvider.kt
new file mode 100644
index 0000000..853a3df
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollActivityClassProvider.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.biometrics.fingerprint
+
+import android.app.Activity
+
+open class FingerprintEnrollActivityClassProvider {
+
+    open val default: Class<out Activity>
+        get() = FingerprintEnrollIntroduction::class.java
+    open val setup: Class<out Activity>
+        get() = SetupFingerprintEnrollIntroduction::class.java
+    open val internal: Class<out Activity>
+        get() = FingerprintEnrollIntroductionInternal::class.java
+
+    companion object {
+        @JvmStatic
+        val instance = FingerprintEnrollActivityClassProvider()
+    }
+}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintFeatureProvider.java b/src/com/android/settings/biometrics/fingerprint/FingerprintFeatureProvider.java
index c1e34a5..baa88b5 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintFeatureProvider.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintFeatureProvider.java
@@ -33,7 +33,6 @@
      */
     SfpsEnrollmentFeature getSfpsEnrollmentFeature();
 
-
     /**
      * Gets calibrator for udfps pre-enroll
      * @param appContext application context
@@ -52,4 +51,13 @@
      * @return the feature implementation
      */
     SfpsRestToUnlockFeature getSfpsRestToUnlockFeature(@NonNull Context context);
+
+    /**
+     * Gets the provider for current fingerprint enrollment activity classes
+     * @return the provider
+     */
+    @NonNull
+    default FingerprintEnrollActivityClassProvider getEnrollActivityClassProvider() {
+        return FingerprintEnrollActivityClassProvider.getInstance();
+    }
 }
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index 125691f..20d453f 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -1142,7 +1142,7 @@
         private void addFirstFingerprint(@Nullable Long gkPwHandle) {
             Intent intent = new Intent();
             intent.setClassName(SETTINGS_PACKAGE_NAME,
-                    FingerprintEnrollIntroductionInternal.class.getName());
+                    FingerprintEnroll.InternalActivity.class.getName());
             intent.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, true);
             intent.putExtra(SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE,
                     SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE);
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/settings/fragment/FingerprintSettingsV2Fragment.kt b/src/com/android/settings/biometrics/fingerprint2/ui/settings/fragment/FingerprintSettingsV2Fragment.kt
index 241eaea..d9289d6 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/settings/fragment/FingerprintSettingsV2Fragment.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/settings/fragment/FingerprintSettingsV2Fragment.kt
@@ -43,7 +43,7 @@
 import com.android.settings.biometrics.BiometricEnrollBase.EXTRA_FROM_SETTINGS_SUMMARY
 import com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED
 import com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling
-import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroductionInternal
+import com.android.settings.biometrics.fingerprint.FingerprintEnroll.InternalActivity
 import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepositoryImpl
 import com.android.settings.biometrics.fingerprint2.domain.interactor.PressToAuthInteractorImpl
 import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel
@@ -514,7 +514,7 @@
     val intent = Intent()
     intent.setClassName(
       SETTINGS_PACKAGE_NAME,
-      FingerprintEnrollIntroductionInternal::class.java.name,
+      InternalActivity::class.java.name,
     )
     intent.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, true)
     intent.putExtra(
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollTest.kt b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollTest.kt
new file mode 100644
index 0000000..07cdffb
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollTest.kt
@@ -0,0 +1,94 @@
+/*
+ * 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.fingerprint
+
+import android.app.Activity
+import android.content.Intent
+import com.android.settings.overlay.FeatureFactory
+import com.android.settings.testutils.FakeFeatureFactory
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.`when`
+import org.robolectric.Robolectric
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.Shadows
+
+@RunWith(RobolectricTestRunner::class)
+class FingerprintEnrollTest {
+
+    private lateinit var featureFactory: FeatureFactory
+
+    private companion object {
+        const val INTENT_KEY = "testKey"
+        const val INTENT_VALUE = "testValue"
+        val INTENT = Intent().apply {
+            putExtra(INTENT_KEY, INTENT_VALUE)
+        }
+    }
+
+    private val activityProvider = FingerprintEnrollActivityClassProvider()
+
+    @Before
+    fun setUp() {
+        featureFactory = FakeFeatureFactory.setupForTest()
+        `when`(featureFactory.fingerprintFeatureProvider.enrollActivityClassProvider)
+            .thenReturn(activityProvider)
+    }
+
+    private fun setupActivity(activityClass: Class<out FingerprintEnroll>): FingerprintEnroll {
+        return Robolectric.buildActivity(activityClass, INTENT).create().get()
+    }
+
+    @Test
+    fun testFinishAndLaunchDefaultActivity() {
+        // Run
+        val activity = setupActivity(FingerprintEnroll::class.java)
+
+        // Verify
+        verifyLaunchNextActivity(activity, activityProvider.default)
+    }
+
+    @Test
+    fun testFinishAndLaunchSetupActivity() {
+        // Run
+        val activity = setupActivity(FingerprintEnroll.SetupActivity::class.java)
+
+        // Verify
+        verifyLaunchNextActivity(activity, activityProvider.setup)
+    }
+
+    @Test
+    fun testFinishAndLaunchInternalActivity() {
+        // Run
+        val activity = setupActivity(FingerprintEnroll.InternalActivity::class.java)
+
+        // Verify
+        verifyLaunchNextActivity(activity, activityProvider.internal)
+    }
+
+    private fun verifyLaunchNextActivity(
+        currentActivityInstance : FingerprintEnroll,
+        nextActivityClass: Class<out Activity>
+    ) {
+        assertThat(currentActivityInstance.isFinishing).isTrue()
+        val nextActivityIntent = Shadows.shadowOf(currentActivityInstance).nextStartedActivity
+        assertThat(nextActivityIntent.component!!.className).isEqualTo(nextActivityClass.name)
+        assertThat(nextActivityIntent.extras!!.size()).isEqualTo(1)
+        assertThat(nextActivityIntent.getStringExtra(INTENT_KEY)).isEqualTo(INTENT_VALUE)
+    }
+}