diff --git a/src/com/android/settings/biometrics/BiometricNavigationUtils.java b/src/com/android/settings/biometrics/BiometricNavigationUtils.java index e4f2b7f3511..b747fafa1da 100644 --- a/src/com/android/settings/biometrics/BiometricNavigationUtils.java +++ b/src/com/android/settings/biometrics/BiometricNavigationUtils.java @@ -19,14 +19,17 @@ package com.android.settings.biometrics; import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME; import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_FROM_SETTINGS_SUMMARY; +import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; -import com.android.settings.Utils; +import com.android.internal.app.UnlaunchableAppActivity; import com.android.settings.core.SettingsBaseActivity; +import com.android.settingslib.RestrictedLockUtils; +import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import com.android.settingslib.transition.SettingsTransitionHelper; /** @@ -41,15 +44,62 @@ public class BiometricNavigationUtils { * for managed profile, otherwise shows a dialog to disable the Quiet Mode. * * @param className The class name of Settings screen to launch. - * @param extras Extras to put into the launching {@link Intent}. + * @param extras Extras to put into the launching {@link Intent}. * @return true if the Settings screen is launching. */ public boolean launchBiometricSettings(Context context, String className, Bundle extras) { - final UserManager userManager = UserManager.get(context); - if (Utils.startQuietModeDialogIfNecessary(context, userManager, mUserId)) { + final Intent quietModeDialogIntent = getQuietModeDialogIntent(context); + if (quietModeDialogIntent != null) { + context.startActivity(quietModeDialogIntent); return false; } + context.startActivity(getSettingsPageIntent(className, extras)); + return true; + } + /** + * Returns {@link Intent} to launch an appropriate Settings screen. + * + *

If the Setting is disabled by admin, returns {@link Intent} to launch an explanation. + * If Quiet Mode is enabled for managed profile, returns {@link Intent} to launch a dialog + * to disable the Quiet Mode. Otherwise, returns {@link Intent} to launch the Settings screen. + * + * @param className The class name of Settings screen to launch. + * @param enforcedAdmin Details of admin account that disables changing the setting. + * @param extras Extras to put into the result {@link Intent}. + */ + public Intent getBiometricSettingsIntent(Context context, String className, + EnforcedAdmin enforcedAdmin, Bundle extras) { + if (enforcedAdmin != null) { + return getRestrictedDialogIntent(context, enforcedAdmin); + } + final Intent quietModeDialogIntent = getQuietModeDialogIntent(context); + return quietModeDialogIntent != null ? quietModeDialogIntent + : getSettingsPageIntent(className, extras); + } + + private Intent getQuietModeDialogIntent(Context context) { + final UserManager userManager = UserManager.get(context); + if (userManager.isQuietModeEnabled(UserHandle.of(mUserId))) { + return UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId); + } + return null; + } + + private Intent getRestrictedDialogIntent(Context context, EnforcedAdmin enforcedAdmin) { + final Intent intent = RestrictedLockUtils + .getShowAdminSupportDetailsIntent(context, enforcedAdmin); + int targetUserId = mUserId; + if (enforcedAdmin.user != null && RestrictedLockUtils + .isCurrentUserOrProfile(context, enforcedAdmin.user.getIdentifier())) { + targetUserId = enforcedAdmin.user.getIdentifier(); + } + intent.putExtra(DevicePolicyManager.EXTRA_RESTRICTION, enforcedAdmin.enforcedRestriction); + intent.putExtra(Intent.EXTRA_USER_ID, targetUserId); + return intent; + } + + private Intent getSettingsPageIntent(String className, Bundle extras) { final Intent intent = new Intent(); intent.setClassName(SETTINGS_PACKAGE_NAME, className); if (!extras.isEmpty()) { @@ -59,7 +109,7 @@ public class BiometricNavigationUtils { intent.putExtra(Intent.EXTRA_USER_ID, mUserId); intent.putExtra(SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE, SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE); - context.startActivity(intent); - return true; + + return intent; } } diff --git a/src/com/android/settings/safetycenter/BiometricsSafetySource.java b/src/com/android/settings/safetycenter/BiometricsSafetySource.java index bfe2fb07d52..6a93bda03c4 100644 --- a/src/com/android/settings/safetycenter/BiometricsSafetySource.java +++ b/src/com/android/settings/safetycenter/BiometricsSafetySource.java @@ -16,14 +16,30 @@ package com.android.settings.safetycenter; +import android.app.PendingIntent; import android.content.Context; +import android.content.Intent; +import android.hardware.face.FaceManager; +import android.hardware.fingerprint.FingerprintManager; +import android.os.Bundle; +import android.safetycenter.SafetySourceData; +import android.safetycenter.SafetySourceStatus; + +import com.android.settings.R; +import com.android.settings.Utils; +import com.android.settings.biometrics.BiometricNavigationUtils; +import com.android.settings.biometrics.combination.CombinedBiometricStatusUtils; +import com.android.settings.biometrics.face.FaceStatusUtils; +import com.android.settings.biometrics.fingerprint.FingerprintStatusUtils; +import com.android.settingslib.RestrictedLockUtils; /** Combined Biometrics Safety Source for Safety Center. */ public final class BiometricsSafetySource { public static final String SAFETY_SOURCE_ID = "Biometrics"; - private BiometricsSafetySource() {} + private BiometricsSafetySource() { + } /** Sends biometric safety data to Safety Center. */ public static void sendSafetyData(Context context) { @@ -31,7 +47,75 @@ public final class BiometricsSafetySource { return; } - // TODO(b/215517420): Send biometric data to Safety Center if there are biometrics available - // on this device. + final BiometricNavigationUtils biometricNavigationUtils = new BiometricNavigationUtils(); + final CombinedBiometricStatusUtils combinedBiometricStatusUtils = + new CombinedBiometricStatusUtils(context); + + if (combinedBiometricStatusUtils.isAvailable()) { + final RestrictedLockUtils.EnforcedAdmin disablingAdmin = + combinedBiometricStatusUtils.getDisablingAdmin(); + sendBiometricSafetySourceData(context, + context.getString(R.string.security_settings_biometric_preference_title), + combinedBiometricStatusUtils.getSummary(), + biometricNavigationUtils.getBiometricSettingsIntent(context, + combinedBiometricStatusUtils.getSettingsClassName(), disablingAdmin, + Bundle.EMPTY), + disablingAdmin == null /* enabled */); + return; + } + + final FaceManager faceManager = Utils.getFaceManagerOrNull(context); + final FaceStatusUtils faceStatusUtils = new FaceStatusUtils(context, faceManager); + + if (faceStatusUtils.isAvailable()) { + final RestrictedLockUtils.EnforcedAdmin disablingAdmin = + faceStatusUtils.getDisablingAdmin(); + sendBiometricSafetySourceData(context, + context.getString(R.string.security_settings_face_preference_title), + faceStatusUtils.getSummary(), + biometricNavigationUtils.getBiometricSettingsIntent(context, + faceStatusUtils.getSettingsClassName(), disablingAdmin, + Bundle.EMPTY), + disablingAdmin == null /* enabled */); + return; + } + + final FingerprintManager fingerprintManager = Utils.getFingerprintManagerOrNull(context); + final FingerprintStatusUtils fingerprintStatusUtils = new FingerprintStatusUtils(context, + fingerprintManager); + + if (fingerprintStatusUtils.isAvailable()) { + final RestrictedLockUtils.EnforcedAdmin disablingAdmin = + fingerprintStatusUtils.getDisablingAdmin(); + sendBiometricSafetySourceData(context, + context.getString(R.string.security_settings_fingerprint_preference_title), + fingerprintStatusUtils.getSummary(), + biometricNavigationUtils.getBiometricSettingsIntent(context, + fingerprintStatusUtils.getSettingsClassName(), disablingAdmin, + Bundle.EMPTY), + disablingAdmin == null /* enabled */); + } + } + + private static void sendBiometricSafetySourceData(Context context, String title, String summary, + Intent clickIntent, boolean enabled) { + final PendingIntent pendingIntent = createPendingIntent(context, clickIntent); + + final SafetySourceStatus status = new SafetySourceStatus.Builder(title, summary, + SafetySourceStatus.STATUS_LEVEL_NONE, pendingIntent) + .setEnabled(enabled).build(); + final SafetySourceData safetySourceData = new SafetySourceData.Builder(SAFETY_SOURCE_ID) + .setStatus(status).build(); + + SafetyCenterManagerWrapper.get().sendSafetyCenterUpdate(context, safetySourceData); + } + + private static PendingIntent createPendingIntent(Context context, Intent intent) { + return PendingIntent + .getActivity( + context, + 0 /* requestCode */, + intent, + PendingIntent.FLAG_IMMUTABLE); } } diff --git a/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java b/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java index 3e6ac093542..c767c32dec6 100644 --- a/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java +++ b/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java @@ -24,14 +24,20 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.admin.DevicePolicyManager; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.os.UserHandle; import android.os.UserManager; +import android.provider.Settings; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -44,6 +50,8 @@ public class BiometricNavigationUtilsTest { private static final String SETTINGS_CLASS_NAME = "SettingsClassName"; private static final String EXTRA_KEY = "EXTRA_KEY"; + private static final ComponentName COMPONENT_NAME = new ComponentName("package", "class"); + private static final int ADMIN_USER_ID = 2; @Mock private UserManager mUserManager; @@ -60,7 +68,7 @@ public class BiometricNavigationUtilsTest { } @Test - public void openBiometricSettings_quietMode_launchesQuiteModeDialog() { + public void launchBiometricSettings_quietMode_launchesQuiteModeDialog() { when(mUserManager.isQuietModeEnabled(any())).thenReturn(true); mBiometricNavigationUtils.launchBiometricSettings(mContext, SETTINGS_CLASS_NAME, @@ -70,7 +78,7 @@ public class BiometricNavigationUtilsTest { } @Test - public void openBiometricSettings_quietMode_returnsFalse() { + public void launchBiometricSettings_quietMode_returnsFalse() { when(mUserManager.isQuietModeEnabled(any())).thenReturn(true); assertThat(mBiometricNavigationUtils.launchBiometricSettings( @@ -78,7 +86,7 @@ public class BiometricNavigationUtilsTest { } @Test - public void openBiometricSettings_noQuietMode_emptyExtras_launchesFragmentWithoutExtras() { + public void launchBiometricSettings_noQuietMode_emptyExtras_launchesFragmentWithoutExtras() { when(mUserManager.isQuietModeEnabled(any())).thenReturn(false); mBiometricNavigationUtils.launchBiometricSettings( @@ -88,7 +96,7 @@ public class BiometricNavigationUtilsTest { } @Test - public void openBiometricSettings_noQuietMode_emptyExtras_returnsTrue() { + public void launchBiometricSettings_noQuietMode_emptyExtras_returnsTrue() { when(mUserManager.isQuietModeEnabled(any())).thenReturn(false); assertThat(mBiometricNavigationUtils.launchBiometricSettings( @@ -96,7 +104,7 @@ public class BiometricNavigationUtilsTest { } @Test - public void openBiometricSettings_noQuietMode_withExtras_launchesFragmentWithExtras() { + public void launchBiometricSettings_noQuietMode_withExtras_launchesFragmentWithExtras() { when(mUserManager.isQuietModeEnabled(any())).thenReturn(false); final Bundle extras = createNotEmptyExtras(); @@ -106,13 +114,79 @@ public class BiometricNavigationUtilsTest { } @Test - public void openBiometricSettings_noQuietMode_withExtras_returnsTrue() { + public void launchBiometricSettings_noQuietMode_withExtras_returnsTrue() { when(mUserManager.isQuietModeEnabled(any())).thenReturn(false); assertThat(mBiometricNavigationUtils.launchBiometricSettings( mContext, SETTINGS_CLASS_NAME, createNotEmptyExtras())).isTrue(); } + @Test + public void getBiometricSettingsIntent_quietMode_returnsQuiteModeDialogIntent() { + when(mUserManager.isQuietModeEnabled(any())).thenReturn(true); + + final Intent intent = mBiometricNavigationUtils.getBiometricSettingsIntent( + mContext, SETTINGS_CLASS_NAME, null /* enforcedAdmin */, Bundle.EMPTY); + + assertQuietModeDialogIntent(intent); + } + + @Test + public void getBiometricSettingsIntent_noQuietMode_emptyExtras_returnsSettingsIntent() { + when(mUserManager.isQuietModeEnabled(any())).thenReturn(false); + + final Intent intent = mBiometricNavigationUtils.getBiometricSettingsIntent( + mContext, SETTINGS_CLASS_NAME, null /* enforcedAdmin */, Bundle.EMPTY); + + assertSettingsPageIntent(intent, false /* shouldContainExtras */); + } + + @Test + public void getBiometricSettingsIntent_noQuietMode_withExtras_returnsSettingsIntent() { + when(mUserManager.isQuietModeEnabled(any())).thenReturn(false); + + final Intent intent = mBiometricNavigationUtils.getBiometricSettingsIntent( + mContext, SETTINGS_CLASS_NAME, null /* enforcedAdmin */, createNotEmptyExtras()); + + assertSettingsPageIntent(intent, true /* shouldContainExtras */); + } + + @Test + public void getBiometricSettingsIntent_whenDisabledByAdmin_quietMode_returnsBlockedIntent() { + when(mUserManager.isQuietModeEnabled(any())).thenReturn(true); + final EnforcedAdmin enforcedAdmin = new EnforcedAdmin( + COMPONENT_NAME, UserHandle.of(ADMIN_USER_ID)); + + final Intent intent = mBiometricNavigationUtils.getBiometricSettingsIntent( + mContext, SETTINGS_CLASS_NAME, enforcedAdmin, Bundle.EMPTY); + + assertBlockedByAdminDialogIntent(intent); + } + + @Test + public void getBiometricSettingsIntent_whenDisabledByAdmin_emptyExtras_returnsBlockedIntent() { + when(mUserManager.isQuietModeEnabled(any())).thenReturn(false); + final EnforcedAdmin enforcedAdmin = new EnforcedAdmin( + COMPONENT_NAME, UserHandle.of(ADMIN_USER_ID)); + + final Intent intent = mBiometricNavigationUtils.getBiometricSettingsIntent( + mContext, SETTINGS_CLASS_NAME, enforcedAdmin, Bundle.EMPTY); + + assertBlockedByAdminDialogIntent(intent); + } + + @Test + public void getBiometricSettingsIntent_whenDisabledByAdmin_withExtras_returnsBlockedIntent() { + when(mUserManager.isQuietModeEnabled(any())).thenReturn(false); + final EnforcedAdmin enforcedAdmin = new EnforcedAdmin( + COMPONENT_NAME, UserHandle.of(ADMIN_USER_ID)); + + final Intent intent = mBiometricNavigationUtils.getBiometricSettingsIntent( + mContext, SETTINGS_CLASS_NAME, enforcedAdmin, Bundle.EMPTY); + + assertBlockedByAdminDialogIntent(intent); + } + private Bundle createNotEmptyExtras() { final Bundle bundle = new Bundle(); bundle.putInt(EXTRA_KEY, 0); @@ -124,17 +198,32 @@ public class BiometricNavigationUtilsTest { verify(mContext).startActivity(intentCaptor.capture()); Intent intent = intentCaptor.getValue(); + assertQuietModeDialogIntent(intent); + } + + private void assertQuietModeDialogIntent(Intent intent) { assertThat(intent.getComponent().getPackageName()) .isEqualTo("android"); assertThat(intent.getComponent().getClassName()) .isEqualTo("com.android.internal.app.UnlaunchableAppActivity"); } + private void assertBlockedByAdminDialogIntent(Intent intent) { + assertThat(intent.getAction()).isEqualTo(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS); + assertThat( + (ComponentName) intent.getParcelableExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN)) + .isEqualTo(COMPONENT_NAME); + } + private void assertSettingsPageLaunchRequested(boolean shouldContainExtras) { ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mContext).startActivity(intentCaptor.capture()); Intent intent = intentCaptor.getValue(); + assertSettingsPageIntent(intent, shouldContainExtras); + } + + private void assertSettingsPageIntent(Intent intent, boolean shouldContainExtras) { assertThat(intent.getComponent().getPackageName()) .isEqualTo("com.android.settings"); assertThat(intent.getComponent().getClassName()) diff --git a/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java b/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java index 2627d245d96..4a91e8faa19 100644 --- a/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java +++ b/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java @@ -16,35 +16,84 @@ package com.android.settings.safetycenter; +import static android.provider.Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS; + +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.admin.DevicePolicyManager; +import android.content.ComponentName; import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.hardware.face.FaceManager; +import android.hardware.fingerprint.Fingerprint; +import android.hardware.fingerprint.FingerprintManager; +import android.os.UserHandle; +import android.safetycenter.SafetySourceData; +import android.safetycenter.SafetySourceStatus; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.android.settings.Settings; +import com.android.settings.biometrics.face.FaceEnrollIntroduction; +import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction; +import com.android.settings.biometrics.fingerprint.FingerprintSettings; +import com.android.settings.testutils.ResourcesUtils; + import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + @RunWith(AndroidJUnit4.class) public class BiometricsSafetySourceTest { + private static final ComponentName COMPONENT_NAME = + new ComponentName("package", "class"); + private static final UserHandle USER_HANDLE = new UserHandle(UserHandle.myUserId()); + private Context mApplicationContext; + @Mock + private PackageManager mPackageManager; + @Mock + private DevicePolicyManager mDevicePolicyManager; + @Mock + private FingerprintManager mFingerprintManager; + @Mock + private FaceManager mFaceManager; @Mock private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper; @Before public void setUp() { MockitoAnnotations.initMocks(this); - mApplicationContext = ApplicationProvider.getApplicationContext(); + mApplicationContext = spy(ApplicationProvider.getApplicationContext()); + when(mApplicationContext.getPackageManager()).thenReturn(mPackageManager); + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)).thenReturn(true); + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true); + when(mDevicePolicyManager.getProfileOwnerOrDeviceOwnerSupervisionComponent(USER_HANDLE)) + .thenReturn(COMPONENT_NAME); + when(mApplicationContext.getSystemService(Context.FINGERPRINT_SERVICE)) + .thenReturn(mFingerprintManager); + when(mApplicationContext.getSystemService(Context.DEVICE_POLICY_SERVICE)) + .thenReturn(mDevicePolicyManager); + when(mApplicationContext.getSystemService(Context.FACE_SERVICE)).thenReturn(mFaceManager); SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper; } @@ -63,12 +112,371 @@ public class BiometricsSafetySourceTest { } @Test - // TODO(b/215517420): Adapt this test when method is implemented. - public void sendSafetyData_whenSafetyCenterIsEnabled_sendsNoData() { - when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); + public void sendSafetyData_whenSafetyCenterIsEnabled_withoutBiometrics_sendsNoData() { + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(false); + when(mFingerprintManager.isHardwareDetected()).thenReturn(false); + when(mFaceManager.isHardwareDetected()).thenReturn(false); BiometricsSafetySource.sendSafetyData(mApplicationContext); verify(mSafetyCenterManagerWrapper, never()).sendSafetyCenterUpdate(any(), any()); } + + @Test + public void sendSafetyData_withFingerprintNotEnrolled_whenDisabledByAdmin_sendsData() { + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(true); + when(mFaceManager.isHardwareDetected()).thenReturn(false); + when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(false); + when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)) + .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT); + + BiometricsSafetySource.sendSafetyData(mApplicationContext); + + assertSafetySourceDisabledDataSentWithSingularSummary( + "security_settings_fingerprint_preference_title", + "security_settings_fingerprint_preference_summary_none"); + } + + @Test + public void sendSafetyData_withFingerprintNotEnrolled_whenNotDisabledByAdmin_sendsData() { + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(true); + when(mFaceManager.isHardwareDetected()).thenReturn(false); + when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(false); + when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0); + + BiometricsSafetySource.sendSafetyData(mApplicationContext); + + assertSafetySourceEnabledDataSentWithSingularSummary( + "security_settings_fingerprint_preference_title", + "security_settings_fingerprint_preference_summary_none", + FingerprintEnrollIntroduction.class.getName()); + } + + @Test + public void sendSafetyData_withFingerprintsEnrolled_whenDisabledByAdmin_sendsData() { + final int enrolledFingerprintsCount = 2; + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(true); + when(mFaceManager.isHardwareDetected()).thenReturn(false); + when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(true); + when(mFingerprintManager.getEnrolledFingerprints(anyInt())) + .thenReturn(createFingerprintList(enrolledFingerprintsCount)); + when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)) + .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT); + + BiometricsSafetySource.sendSafetyData(mApplicationContext); + + assertSafetySourceDisabledDataSentWithPluralSummary( + "security_settings_fingerprint_preference_title", + "security_settings_fingerprint_preference_summary", + enrolledFingerprintsCount); + } + + @Test + public void sendSafetyData_withFingerprintsEnrolled_whenNotDisabledByAdmin_sendsData() { + final int enrolledFingerprintsCount = 2; + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(true); + when(mFaceManager.isHardwareDetected()).thenReturn(false); + when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(true); + when(mFingerprintManager.getEnrolledFingerprints(anyInt())) + .thenReturn(createFingerprintList(enrolledFingerprintsCount)); + when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0); + + BiometricsSafetySource.sendSafetyData(mApplicationContext); + + assertSafetySourceEnabledDataSentWithPluralSummary( + "security_settings_fingerprint_preference_title", + "security_settings_fingerprint_preference_summary", enrolledFingerprintsCount, + FingerprintSettings.class.getName()); + } + + @Test + public void sendSafetyData_withFaceNotEnrolled_whenDisabledByAdmin_sendsData() { + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(false); + when(mFaceManager.isHardwareDetected()).thenReturn(true); + when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false); + when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)) + .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FACE); + + BiometricsSafetySource.sendSafetyData(mApplicationContext); + + assertSafetySourceDisabledDataSentWithSingularSummary( + "security_settings_face_preference_title", + "security_settings_face_preference_summary_none"); + } + + @Test + public void sendSafetyData_withFaceNotEnrolled_whenNotDisabledByAdmin_sendsData() { + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(false); + when(mFaceManager.isHardwareDetected()).thenReturn(true); + when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false); + when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0); + + BiometricsSafetySource.sendSafetyData(mApplicationContext); + + assertSafetySourceEnabledDataSentWithSingularSummary( + "security_settings_face_preference_title", + "security_settings_face_preference_summary_none", + FaceEnrollIntroduction.class.getName()); + } + + @Test + public void sendSafetyData_withFaceEnrolled_whenDisabledByAdmin_sendsData() { + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(false); + when(mFaceManager.isHardwareDetected()).thenReturn(true); + when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true); + when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)) + .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FACE); + + BiometricsSafetySource.sendSafetyData(mApplicationContext); + + assertSafetySourceDisabledDataSentWithSingularSummary( + "security_settings_face_preference_title", + "security_settings_face_preference_summary"); + } + + @Test + public void sendSafetyData_withFaceEnrolled_whenNotDisabledByAdmin_sendsData() { + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(false); + when(mFaceManager.isHardwareDetected()).thenReturn(true); + when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true); + when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0); + + BiometricsSafetySource.sendSafetyData(mApplicationContext); + + assertSafetySourceEnabledDataSentWithSingularSummary( + "security_settings_face_preference_title", + "security_settings_face_preference_summary", + Settings.FaceSettingsActivity.class.getName()); + } + + @Test + public void sandSafetyData_withFaceAndFingerprint_whenBothNotDisabledByAdmin_sendsData() { + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(true); + when(mFaceManager.isHardwareDetected()).thenReturn(true); + when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0); + + BiometricsSafetySource.sendSafetyData(mApplicationContext); + + assertSafetySourceEnabledDataSentWithSingularSummary( + "security_settings_biometric_preference_title", + "security_settings_biometric_preference_summary_none_enrolled", + Settings.CombinedBiometricSettingsActivity.class.getName()); + } + + @Test + public void sandSafetyData_withFaceAndFingerprint_whenFaceDisabledByAdmin_sendsData() { + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(true); + when(mFaceManager.isHardwareDetected()).thenReturn(true); + when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)) + .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FACE); + + BiometricsSafetySource.sendSafetyData(mApplicationContext); + + assertSafetySourceEnabledDataSentWithSingularSummary( + "security_settings_biometric_preference_title", + "security_settings_biometric_preference_summary_none_enrolled", + Settings.CombinedBiometricSettingsActivity.class.getName()); + } + + @Test + public void sandSafetyData_withFaceAndFingerprint_whenFingerprintDisabledByAdmin_sendsData() { + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(true); + when(mFaceManager.isHardwareDetected()).thenReturn(true); + when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)) + .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT); + + BiometricsSafetySource.sendSafetyData(mApplicationContext); + + assertSafetySourceEnabledDataSentWithSingularSummary( + "security_settings_biometric_preference_title", + "security_settings_biometric_preference_summary_none_enrolled", + Settings.CombinedBiometricSettingsActivity.class.getName()); + } + + @Test + public void sandSafetyData_withFaceAndFingerprint_whenBothDisabledByAdmin_sendsData() { + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(true); + when(mFaceManager.isHardwareDetected()).thenReturn(true); + when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)) + .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FACE + | DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT); + + BiometricsSafetySource.sendSafetyData(mApplicationContext); + + assertSafetySourceDisabledDataSentWithSingularSummary( + "security_settings_biometric_preference_title", + "security_settings_biometric_preference_summary_none_enrolled"); + } + + @Test + public void sandSafetyData_withFaceAndFingerprint_whenFaceEnrolled_withMpFingers_sendsData() { + final int enrolledFingerprintsCount = 2; + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(true); + when(mFaceManager.isHardwareDetected()).thenReturn(true); + when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true); + when(mFingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn( + createFingerprintList(enrolledFingerprintsCount)); + + BiometricsSafetySource.sendSafetyData(mApplicationContext); + + assertSafetySourceEnabledDataSentWithSingularSummary( + "security_settings_biometric_preference_title", + "security_settings_biometric_preference_summary_both_fp_multiple", + Settings.CombinedBiometricSettingsActivity.class.getName()); + } + + @Test + public void sandSafetyData_withFaceAndFingerprint_whenFaceEnrolled_withOneFinger_sendsData() { + final int enrolledFingerprintsCount = 1; + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(true); + when(mFaceManager.isHardwareDetected()).thenReturn(true); + when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true); + when(mFingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn( + createFingerprintList(enrolledFingerprintsCount)); + + BiometricsSafetySource.sendSafetyData(mApplicationContext); + + assertSafetySourceEnabledDataSentWithSingularSummary( + "security_settings_biometric_preference_title", + "security_settings_biometric_preference_summary_both_fp_single", + Settings.CombinedBiometricSettingsActivity.class.getName()); + } + + @Test + public void sandSafetyData_withFaceAndFingerprint_whenFaceEnrolled_withNoFingers_sendsData() { + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(true); + when(mFaceManager.isHardwareDetected()).thenReturn(true); + when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true); + when(mFingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn( + Collections.emptyList()); + + BiometricsSafetySource.sendSafetyData(mApplicationContext); + + assertSafetySourceEnabledDataSentWithSingularSummary( + "security_settings_biometric_preference_title", + "security_settings_face_preference_summary", + Settings.CombinedBiometricSettingsActivity.class.getName()); + } + + @Test + public void sandSafetyData_withFaceAndFingerprint_whenNoFaceEnrolled_withFingers_sendsData() { + final int enrolledFingerprintsCount = 1; + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(true); + when(mFaceManager.isHardwareDetected()).thenReturn(true); + when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false); + when(mFingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn( + createFingerprintList(enrolledFingerprintsCount)); + + BiometricsSafetySource.sendSafetyData(mApplicationContext); + + assertSafetySourceEnabledDataSentWithPluralSummary( + "security_settings_biometric_preference_title", + "security_settings_fingerprint_preference_summary", enrolledFingerprintsCount, + Settings.CombinedBiometricSettingsActivity.class.getName()); + } + + private void assertSafetySourceDisabledDataSentWithSingularSummary(String expectedTitleResName, + String expectedSummaryResName) { + assertSafetySourceDisabledDataSent( + ResourcesUtils.getResourcesString(mApplicationContext, expectedTitleResName), + ResourcesUtils.getResourcesString(mApplicationContext, expectedSummaryResName) + ); + } + + private void assertSafetySourceEnabledDataSentWithSingularSummary(String expectedTitleResName, + String expectedSummaryResName, + String expectedSettingsClassName) { + assertSafetySourceEnabledDataSent( + ResourcesUtils.getResourcesString(mApplicationContext, expectedTitleResName), + ResourcesUtils.getResourcesString(mApplicationContext, expectedSummaryResName), + expectedSettingsClassName + ); + } + + private void assertSafetySourceDisabledDataSentWithPluralSummary(String expectedTitleResName, + String expectedSummaryResName, int expectedSummaryQuantity) { + final int stringResId = ResourcesUtils.getResourcesId( + ApplicationProvider.getApplicationContext(), "plurals", + expectedSummaryResName); + assertSafetySourceDisabledDataSent( + ResourcesUtils.getResourcesString(mApplicationContext, expectedTitleResName), + mApplicationContext.getResources().getQuantityString(stringResId, + expectedSummaryQuantity /* quantity */, + expectedSummaryQuantity /* formatArgs */) + ); + } + + private void assertSafetySourceEnabledDataSentWithPluralSummary(String expectedTitleResName, + String expectedSummaryResName, int expectedSummaryQuantity, + String expectedSettingsClassName) { + final int stringResId = ResourcesUtils.getResourcesId( + ApplicationProvider.getApplicationContext(), "plurals", + expectedSummaryResName); + assertSafetySourceEnabledDataSent( + ResourcesUtils.getResourcesString(mApplicationContext, expectedTitleResName), + mApplicationContext.getResources().getQuantityString(stringResId, + expectedSummaryQuantity /* quantity */, + expectedSummaryQuantity /* formatArgs */), + expectedSettingsClassName + ); + } + + private void assertSafetySourceDisabledDataSent(String expectedTitle, String expectedSummary) { + ArgumentCaptor captor = ArgumentCaptor.forClass(SafetySourceData.class); + verify(mSafetyCenterManagerWrapper).sendSafetyCenterUpdate(any(), captor.capture()); + SafetySourceData safetySourceData = captor.getValue(); + SafetySourceStatus safetySourceStatus = safetySourceData.getStatus(); + + assertThat(safetySourceData.getId()).isEqualTo(BiometricsSafetySource.SAFETY_SOURCE_ID); + assertThat(safetySourceStatus.getTitle().toString()).isEqualTo(expectedTitle); + assertThat(safetySourceStatus.getSummary().toString()).isEqualTo(expectedSummary); + assertThat(safetySourceStatus.isEnabled()).isFalse(); + final Intent clickIntent = safetySourceStatus.getPendingIntent().getIntent(); + assertThat(clickIntent).isNotNull(); + assertThat(clickIntent.getAction()).isEqualTo(ACTION_SHOW_ADMIN_SUPPORT_DETAILS); + } + + private void assertSafetySourceEnabledDataSent(String expectedTitle, String expectedSummary, + String expectedSettingsClassName) { + ArgumentCaptor captor = ArgumentCaptor.forClass(SafetySourceData.class); + verify(mSafetyCenterManagerWrapper).sendSafetyCenterUpdate(any(), captor.capture()); + SafetySourceData safetySourceData = captor.getValue(); + SafetySourceStatus safetySourceStatus = safetySourceData.getStatus(); + + assertThat(safetySourceData.getId()).isEqualTo(BiometricsSafetySource.SAFETY_SOURCE_ID); + assertThat(safetySourceStatus.getTitle().toString()).isEqualTo(expectedTitle); + assertThat(safetySourceStatus.getSummary().toString()).isEqualTo(expectedSummary); + assertThat(safetySourceStatus.isEnabled()).isTrue(); + final Intent clickIntent = safetySourceStatus.getPendingIntent().getIntent(); + assertThat(clickIntent).isNotNull(); + assertThat(clickIntent.getComponent().getPackageName()) + .isEqualTo("com.android.settings"); + assertThat(clickIntent.getComponent().getClassName()) + .isEqualTo(expectedSettingsClassName); + } + + + private List createFingerprintList(int size) { + final List fingerprintList = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + fingerprintList.add(new Fingerprint("fingerprint" + i, 0, 0)); + } + return fingerprintList; + } } diff --git a/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java b/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java index f2a28ff04c7..f042c2279fa 100644 --- a/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java +++ b/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java @@ -45,6 +45,8 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.List; + @RunWith(AndroidJUnit4.class) public class SafetySourceBroadcastReceiverTest { @@ -149,9 +151,12 @@ public class SafetySourceBroadcastReceiverTest { new String[]{ BiometricsSafetySource.SAFETY_SOURCE_ID }); new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent); + ArgumentCaptor captor = ArgumentCaptor.forClass(SafetySourceData.class); + verify(mSafetyCenterManagerWrapper, times(1)) + .sendSafetyCenterUpdate(any(), captor.capture()); + SafetySourceData safetySourceData = captor.getValue(); - // TODO(b/215517420): Update this test when BiometricSafetySource is implemented. - verify(mSafetyCenterManagerWrapper, never()).sendSafetyCenterUpdate(any(), any()); + assertThat(safetySourceData.getId()).isEqualTo(BiometricsSafetySource.SAFETY_SOURCE_ID); } @Test @@ -159,14 +164,15 @@ public class SafetySourceBroadcastReceiverTest { when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); Intent intent = new Intent().setAction(Intent.ACTION_BOOT_COMPLETED); - // TODO(b/215517420): Update this test when BiometricSafetySource is implemented to test - // that biometrics data is also sent. new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent); ArgumentCaptor captor = ArgumentCaptor.forClass(SafetySourceData.class); - verify(mSafetyCenterManagerWrapper, times(1)) + verify(mSafetyCenterManagerWrapper, times(2)) .sendSafetyCenterUpdate(any(), captor.capture()); - SafetySourceData safetySourceData = captor.getValue(); + List safetySourceDataList = captor.getAllValues(); - assertThat(safetySourceData.getId()).isEqualTo(LockScreenSafetySource.SAFETY_SOURCE_ID); + assertThat(safetySourceDataList.stream().anyMatch( + data -> data.getId().equals(LockScreenSafetySource.SAFETY_SOURCE_ID))).isTrue(); + assertThat(safetySourceDataList.stream().anyMatch( + data -> data.getId().equals(BiometricsSafetySource.SAFETY_SOURCE_ID))).isTrue(); } }