diff --git a/AndroidManifest.xml b/AndroidManifest.xml index ff30f954944afb9ca5eb84976d7c91a3b8c863cc..ec5d134752c7d893e2de373d13d82ed0d2c9f715 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2500,7 +2500,7 @@ android:name="Settings$AppUsageAccessSettingsActivity" android:exported="true" android:label="@string/usage_access_title"> - + diff --git a/src/com/android/settings/applications/AppInfoBase.java b/src/com/android/settings/applications/AppInfoBase.java index 02237b886d979656f4cb6370afb2fd17f1a8d2e1..14e54eb5b03cfb9ae5e9755f647eef922a1154e0 100644 --- a/src/com/android/settings/applications/AppInfoBase.java +++ b/src/com/android/settings/applications/AppInfoBase.java @@ -49,6 +49,7 @@ import androidx.fragment.app.Fragment; import com.android.settings.SettingsActivity; import com.android.settings.SettingsPreferenceFragment; +import com.android.settings.activityembedding.ActivityEmbeddingUtils; import com.android.settings.applications.manageapplications.ManageApplications; import com.android.settings.core.SubSettingLauncher; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; @@ -178,6 +179,25 @@ public abstract class AppInfoBase extends SettingsPreferenceFragment if (!(activity instanceof SettingsActivity)) { return false; } + // Check the permission of the calling package if the device supports multi-pane. + if (ActivityEmbeddingUtils.isEmbeddingActivityEnabled(activity)) { + final String callingPackageName = + ((SettingsActivity) activity).getInitialCallingPackage(); + + if (TextUtils.isEmpty(callingPackageName)) { + Log.w(TAG, "Not able to get calling package name for permission check"); + return false; + } + if (mPm.checkPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, + callingPackageName) + != PackageManager.PERMISSION_GRANTED) { + Log.w(TAG, "Package " + callingPackageName + " does not have required permission " + + Manifest.permission.INTERACT_ACROSS_USERS_FULL); + return false; + } + return true; + } + try { int callerUid = ActivityManager.getService().getLaunchedFromUid( activity.getActivityToken()); diff --git a/src/com/android/settings/biometrics/face/FaceEnroll.kt b/src/com/android/settings/biometrics/face/FaceEnroll.kt index 48ea527c0325b8131600cbbeee540749e25bb1bd..40d3f08e76e8e4f4fed9be2bc73f033c5af15ae3 100644 --- a/src/com/android/settings/biometrics/face/FaceEnroll.kt +++ b/src/com/android/settings/biometrics/face/FaceEnroll.kt @@ -23,10 +23,11 @@ import android.util.Log import androidx.annotation.VisibleForTesting import androidx.appcompat.app.AppCompatActivity import com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED +import com.android.settings.biometrics.MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FACE import com.android.settings.biometrics.combination.CombinedBiometricStatusUtils import com.android.settings.overlay.FeatureFactory.Companion.featureFactory -class FaceEnroll: AppCompatActivity() { +class FaceEnroll : AppCompatActivity() { /** * The class of the next activity to launch. This is open to allow subclasses to provide their @@ -39,8 +40,7 @@ class FaceEnroll: AppCompatActivity() { private val enrollActivityProvider: FaceEnrollActivityClassProvider get() = featureFactory.faceFeatureProvider.enrollActivityClassProvider - @VisibleForTesting - var launchedFromProvider: () -> String? = { launchedFromPackage } + @VisibleForTesting var launchedFromProvider: () -> String? = { launchedFromPackage } private var isLaunched = false @@ -53,9 +53,9 @@ class FaceEnroll: AppCompatActivity() { if (!isLaunched) { /** - * 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 + * 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("FaceEnroll", "forward to $nextActivityClass") val nextIntent = Intent(this, nextActivityClass) @@ -63,6 +63,7 @@ class FaceEnroll: AppCompatActivity() { // drop extras that are not allowed from external packages before launching if (launchedFromProvider() != packageName) { + nextIntent.removeExtra(EXTRA_ENROLL_AFTER_FACE) nextIntent.removeExtra(Intent.EXTRA_USER_ID) } startActivityForResult(nextIntent, 0) @@ -80,13 +81,16 @@ class FaceEnroll: AppCompatActivity() { requestCode: Int, resultCode: Int, data: Intent?, - caller: ComponentCaller + caller: ComponentCaller, ) { super.onActivityResult(requestCode, resultCode, data, caller) isLaunched = false - if (intent.getBooleanExtra( - CombinedBiometricStatusUtils.EXTRA_LAUNCH_FROM_SAFETY_SOURCE_ISSUE, false) - && resultCode != RESULT_FINISHED) { + if ( + intent.getBooleanExtra( + CombinedBiometricStatusUtils.EXTRA_LAUNCH_FROM_SAFETY_SOURCE_ISSUE, + false, + ) && resultCode != RESULT_FINISHED + ) { featureFactory.biometricsFeatureProvider.notifySafetyIssueActionLaunched() } setResult(resultCode, data) diff --git a/src/com/android/settings/biometrics/face/FaceSettingsAppsPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsAppsPreferenceController.java index 9500c25a8ec2ed8ad19012a5030ac3042201173b..78d9ffaf7c431404332bba5fe12b94107e1b3b80 100644 --- a/src/com/android/settings/biometrics/face/FaceSettingsAppsPreferenceController.java +++ b/src/com/android/settings/biometrics/face/FaceSettingsAppsPreferenceController.java @@ -16,6 +16,7 @@ package com.android.settings.biometrics.face; +import static android.provider.Settings.Secure.BIOMETRIC_APP_ENABLED; import static android.provider.Settings.Secure.FACE_APP_ENABLED; import android.app.settings.SettingsEnums; @@ -31,6 +32,7 @@ import com.android.settings.biometrics.activeunlock.ActiveUnlockStatusUtils; public class FaceSettingsAppsPreferenceController extends FaceSettingsPreferenceController { + private static final int NOT_SET = -1; private static final int ON = 1; private static final int OFF = 0; private static final int DEFAULT = ON; @@ -40,12 +42,23 @@ public class FaceSettingsAppsPreferenceController extends public FaceSettingsAppsPreferenceController(@NonNull Context context, @NonNull String key) { super(context, key); mFaceManager = Utils.getFaceManagerOrNull(context); + + // For OTA case: if FACE_APP_ENABLED is not set and BIOMETRIC_APP_ENABLED is set, set the + // default value of the former to that of the latter. + final int defValue = Settings.Secure.getIntForUser(mContext.getContentResolver(), + FACE_APP_ENABLED, NOT_SET, getUserId()); + final int oldDefValue = Settings.Secure.getIntForUser(mContext.getContentResolver(), + BIOMETRIC_APP_ENABLED, NOT_SET, getUserId()); + if (defValue == NOT_SET && oldDefValue != NOT_SET) { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + FACE_APP_ENABLED, oldDefValue, getUserId()); + } } @Override public boolean isChecked() { - return Settings.Secure.getIntForUser(mContext.getContentResolver(), FACE_APP_ENABLED, - DEFAULT, getUserId()) == ON; + return Settings.Secure.getIntForUser(mContext.getContentResolver(), + FACE_APP_ENABLED, DEFAULT, getUserId()) == ON; } @Override diff --git a/src/com/android/settings/biometrics/face/FaceSettingsKeyguardUnlockPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsKeyguardUnlockPreferenceController.java index 5ff15232a026e8338ceb2bcf72b6b367b6687c62..46731b9445159c7a64bd9e7ad658dc7139943748 100644 --- a/src/com/android/settings/biometrics/face/FaceSettingsKeyguardUnlockPreferenceController.java +++ b/src/com/android/settings/biometrics/face/FaceSettingsKeyguardUnlockPreferenceController.java @@ -16,6 +16,7 @@ package com.android.settings.biometrics.face; +import static android.provider.Settings.Secure.BIOMETRIC_KEYGUARD_ENABLED; import static android.provider.Settings.Secure.FACE_KEYGUARD_ENABLED; import android.app.settings.SettingsEnums; @@ -31,6 +32,7 @@ import com.android.settings.biometrics.activeunlock.ActiveUnlockStatusUtils; public class FaceSettingsKeyguardUnlockPreferenceController extends FaceSettingsPreferenceController { + private static final int NOT_SET = -1; private static final int ON = 1; private static final int OFF = 0; private static final int DEFAULT = ON; @@ -41,6 +43,17 @@ public class FaceSettingsKeyguardUnlockPreferenceController extends @NonNull Context context, @NonNull String key) { super(context, key); mFaceManager = Utils.getFaceManagerOrNull(context); + + // For OTA case: if FACE_KEYGUARD_ENABLED is not set and BIOMETRIC_KEYGUARD_ENABLED is set, + // set the default value of the former to that of the latter. + final int defValue = Settings.Secure.getIntForUser(mContext.getContentResolver(), + FACE_KEYGUARD_ENABLED, NOT_SET, getUserId()); + final int oldDefValue = Settings.Secure.getIntForUser(mContext.getContentResolver(), + BIOMETRIC_KEYGUARD_ENABLED, NOT_SET, getUserId()); + if (defValue == NOT_SET && oldDefValue != NOT_SET) { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + FACE_KEYGUARD_ENABLED, oldDefValue, getUserId()); + } } @Override diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsAppsPreferenceController.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsAppsPreferenceController.java index 63fc3dcef230068300af208af23677577549b3fe..574d406e3821a07c6765a2375f47e999b69ce4d8 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsAppsPreferenceController.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsAppsPreferenceController.java @@ -16,6 +16,7 @@ package com.android.settings.biometrics.fingerprint; +import static android.provider.Settings.Secure.BIOMETRIC_APP_ENABLED; import static android.provider.Settings.Secure.FINGERPRINT_APP_ENABLED; import android.app.settings.SettingsEnums; @@ -31,6 +32,7 @@ import com.android.settings.biometrics.activeunlock.ActiveUnlockStatusUtils; public class FingerprintSettingsAppsPreferenceController extends FingerprintSettingsPreferenceController { + private static final int NOT_SET = -1; private static final int ON = 1; private static final int OFF = 0; private static final int DEFAULT = ON; @@ -41,12 +43,23 @@ public class FingerprintSettingsAppsPreferenceController @NonNull Context context, @NonNull String key) { super(context, key); mFingerprintManager = Utils.getFingerprintManagerOrNull(context); + + // For OTA case: if FINGERPRINT_APP_ENABLED is not set and BIOMETRIC_APP_ENABLED is set, + // set the default value of the former to that of the latter. + final int defValue = Settings.Secure.getIntForUser(mContext.getContentResolver(), + FINGERPRINT_APP_ENABLED, NOT_SET, getUserId()); + final int oldDefValue = Settings.Secure.getIntForUser(mContext.getContentResolver(), + BIOMETRIC_APP_ENABLED, NOT_SET, getUserId()); + if (defValue == NOT_SET && oldDefValue != NOT_SET) { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + FINGERPRINT_APP_ENABLED, oldDefValue, getUserId()); + } } @Override public boolean isChecked() { - return Settings.Secure.getIntForUser(mContext.getContentResolver(), FINGERPRINT_APP_ENABLED, - DEFAULT, getUserId()) == ON; + return Settings.Secure.getIntForUser(mContext.getContentResolver(), + FINGERPRINT_APP_ENABLED, DEFAULT, getUserId()) == ON; } @Override diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsKeyguardUnlockPreferenceController.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsKeyguardUnlockPreferenceController.java index 56ef2c3db8be545794e3d445cb1e9a3ce80d56b6..89bea9b5fdeb3564069c31a2bb8dbd4c9eca1b38 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsKeyguardUnlockPreferenceController.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsKeyguardUnlockPreferenceController.java @@ -16,6 +16,7 @@ package com.android.settings.biometrics.fingerprint; +import static android.provider.Settings.Secure.BIOMETRIC_KEYGUARD_ENABLED; import static android.provider.Settings.Secure.FINGERPRINT_KEYGUARD_ENABLED; import android.app.settings.SettingsEnums; @@ -32,6 +33,7 @@ import com.android.settings.biometrics.activeunlock.ActiveUnlockStatusUtils; public class FingerprintSettingsKeyguardUnlockPreferenceController extends FingerprintSettingsPreferenceController { + private static final int NOT_SET = -1; private static final int ON = 1; private static final int OFF = 0; private static final int DEFAULT = ON; @@ -42,6 +44,17 @@ public class FingerprintSettingsKeyguardUnlockPreferenceController @NonNull Context context, @NonNull String key) { super(context, key); mFingerprintManager = Utils.getFingerprintManagerOrNull(context); + + // For OTA case: if FINGERPRINT_KEYGUARD_ENABLED is not set and BIOMETRIC_KEYGUARD_ENABLED + // is set, set the default value of the former to that of the latter. + final int defValue = Settings.Secure.getIntForUser(mContext.getContentResolver(), + FINGERPRINT_KEYGUARD_ENABLED, NOT_SET, getUserId()); + final int oldDefValue = Settings.Secure.getIntForUser(mContext.getContentResolver(), + BIOMETRIC_KEYGUARD_ENABLED, NOT_SET, getUserId()); + if (defValue == NOT_SET && oldDefValue != NOT_SET) { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + FINGERPRINT_KEYGUARD_ENABLED, oldDefValue, getUserId()); + } } @Override diff --git a/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollTest.kt b/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollTest.kt index ad4605aff98dc454afc51b8d3c7a80cc43f71029..b5ea747862fdb5abe97205528fbda87fb01246b1 100644 --- a/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollTest.kt +++ b/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollTest.kt @@ -17,14 +17,17 @@ package com.android.settings.biometrics.face import android.app.Activity +import android.app.PendingIntent import android.content.Intent +import androidx.test.core.app.ApplicationProvider +import com.android.settings.biometrics.MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FACE 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` as whenever +import org.mockito.kotlin.whenever import org.robolectric.Robolectric import org.robolectric.RobolectricTestRunner import org.robolectric.Shadows @@ -36,10 +39,6 @@ class FaceEnrollTest { private companion object { const val INTENT_KEY = "testKey" const val INTENT_VALUE = "testValue" - val INTENT = Intent().apply { - putExtra(INTENT_KEY, INTENT_VALUE) - putExtra(Intent.EXTRA_USER_ID, 11) - } } private val activityProvider = FaceEnrollActivityClassProvider() @@ -55,7 +54,21 @@ class FaceEnrollTest { activityClass: Class, launchedFrom: String? = null, ): FaceEnroll { - val activityController = Robolectric.buildActivity(activityClass, INTENT) + val activityIntent = + Intent().apply { + putExtra(INTENT_KEY, INTENT_VALUE) + putExtra(Intent.EXTRA_USER_ID, 11) + putExtra( + EXTRA_ENROLL_AFTER_FACE, + PendingIntent.getActivity( + ApplicationProvider.getApplicationContext()!!, + 1, + Intent(), + 0, + ), + ) + } + val activityController = Robolectric.buildActivity(activityClass, activityIntent) activityController.get().launchedFromProvider = { launchedFrom ?: activityController.get().packageName } @@ -68,23 +81,22 @@ class FaceEnrollTest { val nextActivityIntent = activity.asShadow().nextStartedActivity assertThat(nextActivityIntent.component!!.className).isEqualTo(activityProvider.next.name) - assertThat(nextActivityIntent.extras!!.size()).isEqualTo(2) + assertThat(nextActivityIntent.extras!!.size()).isEqualTo(3) assertThat(nextActivityIntent.getStringExtra(INTENT_KEY)).isEqualTo(INTENT_VALUE) assertThat(nextActivityIntent.hasExtra(Intent.EXTRA_USER_ID)).isTrue() + assertThat(nextActivityIntent.hasExtra(EXTRA_ENROLL_AFTER_FACE)).isTrue() } @Test - fun testFinishAndLaunchDefaultActivity_fromExternal_dropUser() { - val activity = setupActivity( - FaceEnroll::class.java, - launchedFrom = "com.foo.bar" - ) + fun testFinishAndLaunchDefaultActivity_fromExternal_dropUserAndDropEnrollAfterFace() { + val activity = setupActivity(FaceEnroll::class.java, launchedFrom = "com.foo.bar") val nextActivityIntent = activity.asShadow().nextStartedActivity assertThat(nextActivityIntent.component!!.className).isEqualTo(activityProvider.next.name) assertThat(nextActivityIntent.extras!!.size()).isEqualTo(1) assertThat(nextActivityIntent.getStringExtra(INTENT_KEY)).isEqualTo(INTENT_VALUE) assertThat(nextActivityIntent.hasExtra(Intent.EXTRA_USER_ID)).isFalse() + assertThat(nextActivityIntent.hasExtra(EXTRA_ENROLL_AFTER_FACE)).isFalse() } } diff --git a/tests/robotests/src/com/android/settings/biometrics/face/FaceSettingsAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/biometrics/face/FaceSettingsAppsPreferenceControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..676031c4951e3a5bcbaa2fe8ae73c5fc458f84f8 --- /dev/null +++ b/tests/robotests/src/com/android/settings/biometrics/face/FaceSettingsAppsPreferenceControllerTest.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2025 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.face; + +import static android.provider.Settings.Secure.BIOMETRIC_APP_ENABLED; +import static android.provider.Settings.Secure.FACE_APP_ENABLED; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.hardware.biometrics.ComponentInfoInternal; +import android.hardware.biometrics.SensorProperties; +import android.hardware.face.FaceManager; +import android.hardware.face.FaceSensorProperties; +import android.hardware.face.FaceSensorPropertiesInternal; +import android.provider.Settings; + +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.testutils.shadow.ShadowSecureSettings; +import com.android.settings.testutils.shadow.ShadowUtils; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import java.util.ArrayList; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowSecureSettings.class}) +public class FaceSettingsAppsPreferenceControllerTest { + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + @Spy + private Context mContext = ApplicationProvider.getApplicationContext(); + @Mock + private FaceManager mFaceManager; + private FaceSettingsAppsPreferenceController mController; + + private FaceSensorPropertiesInternal mConvenienceSensorProperty = + new FaceSensorPropertiesInternal( + 0 /* sensorId */, + SensorProperties.STRENGTH_CONVENIENCE, + 1 /* maxEnrollmentsPerUser */, + new ArrayList(), + FaceSensorProperties.TYPE_UNKNOWN, + true /* supportsFaceDetection */, + true /* supportsSelfIllumination */, + true /* resetLockoutRequiresChallenge */); + private FakeFeatureFactory mFeatureFactory; + + @Before + public void setUp() { + when(mContext.getSystemService(Context.FACE_SERVICE)).thenReturn(mFaceManager); + final ArrayList list = new ArrayList<>(); + list.add(mConvenienceSensorProperty); + when(mFaceManager.getSensorPropertiesInternal()).thenReturn(list); + mFeatureFactory = FakeFeatureFactory.setupForTest(); + } + + @After + public void tearDown() { + ShadowUtils.reset(); + } + + @Test + public void isChecked_BiometricAppEnableOff_FaceAppEnabledNotSet_returnFalse() { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + BIOMETRIC_APP_ENABLED, 0, mContext.getUserId()); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + FACE_APP_ENABLED, -1, mContext.getUserId()); + + mController = new FaceSettingsAppsPreferenceController( + mContext, "biometric_settings_face_app"); + + assertThat(mController.isChecked()).isFalse(); + } + + @Test + public void isChecked_BiometricAppEnableOff_FaceAppEnabledOn_returnTrue() { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + BIOMETRIC_APP_ENABLED, 0, mContext.getUserId()); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + FACE_APP_ENABLED, 1, mContext.getUserId()); + + mController = new FaceSettingsAppsPreferenceController( + mContext, "biometric_settings_face_app"); + + assertThat(mController.isChecked()).isTrue(); + } +} diff --git a/tests/robotests/src/com/android/settings/biometrics/face/FaceSettingsKeyguardUnlockPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/biometrics/face/FaceSettingsKeyguardUnlockPreferenceControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..837f31e3bd6f1e654e8797727364a13e718b88c3 --- /dev/null +++ b/tests/robotests/src/com/android/settings/biometrics/face/FaceSettingsKeyguardUnlockPreferenceControllerTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2025 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.face; + +import static android.provider.Settings.Secure.BIOMETRIC_KEYGUARD_ENABLED; +import static android.provider.Settings.Secure.FACE_KEYGUARD_ENABLED; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.os.UserManager; +import android.provider.Settings; + +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.testutils.shadow.ShadowSecureSettings; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowSecureSettings.class}) +public class FaceSettingsKeyguardUnlockPreferenceControllerTest { + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + @Spy + Context mContext = ApplicationProvider.getApplicationContext(); + private FaceSettingsKeyguardUnlockPreferenceController mController; + private FakeFeatureFactory mFeatureFactory; + @Mock + private UserManager mUserManager; + + @Before + public void setUp() { + + mFeatureFactory = FakeFeatureFactory.setupForTest(); + when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager); + } + + @Test + public void isChecked_BiometricKeyguardEnabledOff_FaceKeyguardEnabledNotSet_returnFalse() { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + BIOMETRIC_KEYGUARD_ENABLED, 0, mContext.getUserId()); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + FACE_KEYGUARD_ENABLED, -1, mContext.getUserId()); + + mController = new FaceSettingsKeyguardUnlockPreferenceController( + mContext, "biometric_settings_face_keyguard"); + + assertThat(mController.isChecked()).isFalse(); + } + + @Test + public void isChecked_BiometricKeyguardEnabledOff_FaceKeyguardEnabledOn_returnTrue() { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + BIOMETRIC_KEYGUARD_ENABLED, 0, mContext.getUserId()); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + FACE_KEYGUARD_ENABLED, 1, mContext.getUserId()); + + mController = new FaceSettingsKeyguardUnlockPreferenceController( + mContext, "biometric_settings_face_keyguard"); + + assertThat(mController.isChecked()).isTrue(); + } +} diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsAppsPreferenceControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..841cec2f3de6ac13af3b3860cbb03230b07afaa4 --- /dev/null +++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsAppsPreferenceControllerTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2025 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 static android.provider.Settings.Secure.BIOMETRIC_APP_ENABLED; +import static android.provider.Settings.Secure.FINGERPRINT_APP_ENABLED; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.provider.Settings; + +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.testutils.shadow.ShadowSecureSettings; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowSecureSettings.class}) +public class FingerprintSettingsAppsPreferenceControllerTest { + private Context mContext; + private FingerprintSettingsAppsPreferenceController mController; + private FakeFeatureFactory mFeatureFactory; + + @Before + public void setUp() { + mContext = ApplicationProvider.getApplicationContext(); + mFeatureFactory = FakeFeatureFactory.setupForTest(); + } + + @Test + public void isChecked_BiometricAppEnableOff_FingerprintAppEnabledNotSet_returnFalse() { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + BIOMETRIC_APP_ENABLED, 0, mContext.getUserId()); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + FINGERPRINT_APP_ENABLED, -1, mContext.getUserId()); + + mController = new FingerprintSettingsAppsPreferenceController( + mContext, "biometric_settings_fingerprint_app"); + + assertThat(mController.isChecked()).isFalse(); + } + + @Test + public void isChecked_BiometricAppEnableOff_FingerprintAppEnabledOn_returnTrue() { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + BIOMETRIC_APP_ENABLED, 0, mContext.getUserId()); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + FINGERPRINT_APP_ENABLED, 1, mContext.getUserId()); + + mController = new FingerprintSettingsAppsPreferenceController( + mContext, "biometric_settings_fingerprint_app"); + + assertThat(mController.isChecked()).isTrue(); + } +} diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsKeyguardUnlockPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsKeyguardUnlockPreferenceControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..119fda8bbf2825ac30444d691c10766471737291 --- /dev/null +++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsKeyguardUnlockPreferenceControllerTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2025 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 static android.provider.Settings.Secure.BIOMETRIC_KEYGUARD_ENABLED; +import static android.provider.Settings.Secure.FINGERPRINT_KEYGUARD_ENABLED; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.os.UserManager; +import android.provider.Settings; + +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.testutils.shadow.ShadowSecureSettings; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowSecureSettings.class}) +public class FingerprintSettingsKeyguardUnlockPreferenceControllerTest { + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + @Spy + Context mContext = ApplicationProvider.getApplicationContext(); + private FingerprintSettingsKeyguardUnlockPreferenceController mController; + private FakeFeatureFactory mFeatureFactory; + @Mock + private UserManager mUserManager; + + @Before + public void setUp() { + mFeatureFactory = FakeFeatureFactory.setupForTest(); + when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager); + } + + @Test + public void + isChecked_BiometricKeyguardEnabledOff_FingerprintKeyguardEnabledNotSet_returnFalse() { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + BIOMETRIC_KEYGUARD_ENABLED, 0, mContext.getUserId()); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + FINGERPRINT_KEYGUARD_ENABLED, -1, mContext.getUserId()); + + mController = new FingerprintSettingsKeyguardUnlockPreferenceController( + mContext, "biometric_settings_fingerprint_keyguard"); + + assertThat(mController.isChecked()).isFalse(); + } + + @Test + public void isChecked_BiometricKeyguardEnabledOff_FingerprintKeyguardEnabledOn_returnTrue() { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + BIOMETRIC_KEYGUARD_ENABLED, 0, mContext.getUserId()); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + FINGERPRINT_KEYGUARD_ENABLED, 1, mContext.getUserId()); + + mController = new FingerprintSettingsKeyguardUnlockPreferenceController( + mContext, "biometric_settings_fingerprint_keyguard"); + + assertThat(mController.isChecked()).isTrue(); + } +}