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
This commit is contained in:
MiltonWu
2024-09-04 11:58:56 +00:00
parent 637984a38d
commit 694fe0751a
9 changed files with 233 additions and 16 deletions

View File

@@ -2816,6 +2816,9 @@
<activity android:name=".biometrics.fingerprint.FingerprintEnrollFinish" android:exported="false"/> <activity android:name=".biometrics.fingerprint.FingerprintEnrollFinish" android:exported="false"/>
<activity android:name=".biometrics.fingerprint.FingerprintEnrollParentalConsent" android:exported="false"/> <activity android:name=".biometrics.fingerprint.FingerprintEnrollParentalConsent" android:exported="false"/>
<activity android:name=".biometrics.fingerprint.FingerprintEnrollIntroduction" <activity android:name=".biometrics.fingerprint.FingerprintEnrollIntroduction"
android:exported="false"
android:theme="@style/GlifTheme.Light" />
<activity android:name=".biometrics.fingerprint.FingerprintEnroll"
android:exported="true" android:exported="true"
android:theme="@style/GlifTheme.Light"> android:theme="@style/GlifTheme.Light">
<intent-filter> <intent-filter>
@@ -2826,9 +2829,13 @@
</activity> </activity>
<activity android:name=".biometrics.fingerprint.FingerprintEnrollIntroductionInternal" <activity android:name=".biometrics.fingerprint.FingerprintEnrollIntroductionInternal"
android:exported="false" android:exported="false"
android:theme="@style/GlifTheme.Light" android:theme="@style/GlifTheme.Light"
android:taskAffinity="com.android.settings.root" /> 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" <activity android:name=".biometrics.fingerprint.SetupFingerprintEnrollFindSensor"
android:exported="false" android:exported="false"
@@ -2836,6 +2843,10 @@
<activity android:name=".biometrics.fingerprint.SetupFingerprintEnrollEnrolling" android:exported="false"/> <activity android:name=".biometrics.fingerprint.SetupFingerprintEnrollEnrolling" android:exported="false"/>
<activity android:name=".biometrics.fingerprint.SetupFingerprintEnrollFinish" android:exported="false"/> <activity android:name=".biometrics.fingerprint.SetupFingerprintEnrollFinish" android:exported="false"/>
<activity android:name=".biometrics.fingerprint.SetupFingerprintEnrollIntroduction" <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:exported="true"
android:permission="android.permission.MANAGE_FINGERPRINT" android:permission="android.permission.MANAGE_FINGERPRINT"
android:theme="@style/GlifTheme.Light"> android:theme="@style/GlifTheme.Light">
@@ -2845,7 +2856,6 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name=".biometrics.fingerprint2.ui.enrollment.activity.FingerprintEnrollmentV2Activity" <activity android:name=".biometrics.fingerprint2.ui.enrollment.activity.FingerprintEnrollmentV2Activity"
android:exported="true" android:exported="true"
android:permission="android.permission.MANAGE_FINGERPRINT" android:permission="android.permission.MANAGE_FINGERPRINT"

View File

@@ -40,9 +40,8 @@ import com.android.settings.SettingsActivity;
import com.android.settings.SubSettings; import com.android.settings.SubSettings;
import com.android.settings.biometrics.face.FaceEnrollIntroduction; import com.android.settings.biometrics.face.FaceEnrollIntroduction;
import com.android.settings.biometrics.face.FaceEnrollIntroductionInternal; 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.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.core.FeatureFlags;
import com.android.settings.homepage.DeepLinkHomepageActivity; import com.android.settings.homepage.DeepLinkHomepageActivity;
import com.android.settings.homepage.DeepLinkHomepageActivityInternal; import com.android.settings.homepage.DeepLinkHomepageActivityInternal;
@@ -255,8 +254,12 @@ public class ActivityEmbeddingRulesController {
.buildSearchIntent(mContext, SettingsEnums.SETTINGS_HOMEPAGE); .buildSearchIntent(mContext, SettingsEnums.SETTINGS_HOMEPAGE);
addActivityFilter(activityFilters, searchIntent); addActivityFilter(activityFilters, searchIntent);
} }
addActivityFilter(activityFilters, FingerprintEnrollIntroduction.class); final FingerprintEnrollActivityClassProvider fpClassProvider = FeatureFactory
addActivityFilter(activityFilters, FingerprintEnrollIntroductionInternal.class); .getFeatureFactory()
.getFingerprintFeatureProvider()
.getEnrollActivityClassProvider();
addActivityFilter(activityFilters, fpClassProvider.getDefault());
addActivityFilter(activityFilters, fpClassProvider.getInternal());
addActivityFilter(activityFilters, FingerprintEnrollEnrolling.class); addActivityFilter(activityFilters, FingerprintEnrollEnrolling.class);
addActivityFilter(activityFilters, FaceEnrollIntroductionInternal.class); addActivityFilter(activityFilters, FaceEnrollIntroductionInternal.class);
addActivityFilter(activityFilters, FaceEnrollIntroduction.class); addActivityFilter(activityFilters, FaceEnrollIntroduction.class);

View File

@@ -44,10 +44,9 @@ import com.android.internal.widget.VerifyCredentialResponse;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SetupWizardUtils; import com.android.settings.SetupWizardUtils;
import com.android.settings.biometrics.face.FaceEnrollIntroduction; 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.FingerprintEnrollFindSensor;
import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollFindSensor; import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollFindSensor;
import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollIntroduction;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
import com.android.settings.password.ChooseLockGeneric; import com.android.settings.password.ChooseLockGeneric;
import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settings.password.ChooseLockSettingsHelper;
@@ -262,13 +261,13 @@ public class BiometricUtils {
/** /**
* @param context caller's context * @param context caller's context
* @param activityIntent The intent that started the caller's activity * @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, public static Intent getFingerprintIntroIntent(@NonNull Context context,
@NonNull Intent activityIntent) { @NonNull Intent activityIntent) {
final boolean isSuw = WizardManagerHelper.isAnySetupWizard(activityIntent); final boolean isSuw = WizardManagerHelper.isAnySetupWizard(activityIntent);
final Intent intent = new Intent(context, isSuw final Intent intent = new Intent(context, isSuw
? SetupFingerprintEnrollIntroduction.class : FingerprintEnrollIntroduction.class); ? FingerprintEnroll.SetupActivity.class : FingerprintEnroll.class);
if (isSuw) { if (isSuw) {
WizardManagerHelper.copyWizardManagerExtras(activityIntent, intent); WizardManagerHelper.copyWizardManagerExtras(activityIntent, intent);
} }

View File

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

View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.biometrics.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()
}
}

View File

@@ -33,7 +33,6 @@ public interface FingerprintFeatureProvider {
*/ */
SfpsEnrollmentFeature getSfpsEnrollmentFeature(); SfpsEnrollmentFeature getSfpsEnrollmentFeature();
/** /**
* Gets calibrator for udfps pre-enroll * Gets calibrator for udfps pre-enroll
* @param appContext application context * @param appContext application context
@@ -52,4 +51,13 @@ public interface FingerprintFeatureProvider {
* @return the feature implementation * @return the feature implementation
*/ */
SfpsRestToUnlockFeature getSfpsRestToUnlockFeature(@NonNull Context context); SfpsRestToUnlockFeature getSfpsRestToUnlockFeature(@NonNull Context context);
/**
* Gets the provider for current fingerprint enrollment activity classes
* @return the provider
*/
@NonNull
default FingerprintEnrollActivityClassProvider getEnrollActivityClassProvider() {
return FingerprintEnrollActivityClassProvider.getInstance();
}
} }

View File

@@ -1142,7 +1142,7 @@ public class FingerprintSettings extends SubSettings {
private void addFirstFingerprint(@Nullable Long gkPwHandle) { private void addFirstFingerprint(@Nullable Long gkPwHandle) {
Intent intent = new Intent(); Intent intent = new Intent();
intent.setClassName(SETTINGS_PACKAGE_NAME, intent.setClassName(SETTINGS_PACKAGE_NAME,
FingerprintEnrollIntroductionInternal.class.getName()); FingerprintEnroll.InternalActivity.class.getName());
intent.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, true); intent.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, true);
intent.putExtra(SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE, intent.putExtra(SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE,
SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE); SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE);

View File

@@ -43,7 +43,7 @@ import com.android.settings.biometrics.BiometricEnrollBase.CONFIRM_REQUEST
import com.android.settings.biometrics.BiometricEnrollBase.EXTRA_FROM_SETTINGS_SUMMARY import com.android.settings.biometrics.BiometricEnrollBase.EXTRA_FROM_SETTINGS_SUMMARY
import com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED import com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED
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.FingerprintEnroll.InternalActivity
import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepositoryImpl import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepositoryImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.PressToAuthInteractorImpl import com.android.settings.biometrics.fingerprint2.domain.interactor.PressToAuthInteractorImpl
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel
@@ -514,7 +514,7 @@ class FingerprintSettingsV2Fragment :
val intent = Intent() val intent = Intent()
intent.setClassName( intent.setClassName(
SETTINGS_PACKAGE_NAME, SETTINGS_PACKAGE_NAME,
FingerprintEnrollIntroductionInternal::class.java.name, InternalActivity::class.java.name,
) )
intent.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, true) intent.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, true)
intent.putExtra( intent.putExtra(

View File

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