Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit abc541d5 authored by Yuri Ufimtsev's avatar Yuri Ufimtsev Committed by Android (Google) Code Review
Browse files

Merge "Provide data for BiometricsSafetySource" into tm-dev

parents 530e967a 2b5bf34e
Loading
Loading
Loading
Loading
+56 −6
Original line number Diff line number Diff line
@@ -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;

/**
@@ -45,11 +48,58 @@ public class BiometricNavigationUtils {
     * @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.
     *
     * <p>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;
    }
}
+87 −3
Original line number Diff line number Diff line
@@ -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);
    }
}
+95 −6
Original line number Diff line number Diff line
@@ -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<Intent> 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())
+412 −4

File changed.

Preview size limit exceeded, changes collapsed.

+13 −7
Original line number Diff line number Diff line
@@ -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<SafetySourceData> 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<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
        verify(mSafetyCenterManagerWrapper, times(1))
        verify(mSafetyCenterManagerWrapper, times(2))
                .sendSafetyCenterUpdate(any(), captor.capture());
        SafetySourceData safetySourceData = captor.getValue();
        List<SafetySourceData> 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();
    }
}