diff --git a/src/com/android/settings/accounts/AccountTypePreferenceLoader.java b/src/com/android/settings/accounts/AccountTypePreferenceLoader.java index ff2d59167106b0ac869abaeaf44213bb319919da..ded0f872c1126d39b8b85930351f094cd91ed216 100644 --- a/src/com/android/settings/accounts/AccountTypePreferenceLoader.java +++ b/src/com/android/settings/accounts/AccountTypePreferenceLoader.java @@ -270,7 +270,14 @@ public class AccountTypePreferenceLoader { try { // Allows to launch only authenticator owned activities. ApplicationInfo authenticatorAppInf = pm.getApplicationInfo(authDesc.packageName, 0); - return resolvedAppInfo.uid == authenticatorAppInf.uid; + if (resolvedAppInfo.uid == authenticatorAppInf.uid) { + // Explicitly set the component to be same as authenticator to + // prevent launching arbitrary activities. + intent.setComponent(resolvedActivityInfo.getComponentName()); + return true; + } else { + return false; + } } catch (NameNotFoundException e) { Log.e(TAG, "Intent considered unsafe due to exception.", diff --git a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java index 1f7b3e512b2830073337c6ce60793765eff00217..79c7e3a563a25ed8b434953d56627ea339bb23c6 100644 --- a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java @@ -50,6 +50,8 @@ import com.google.android.setupdesign.span.LinkSpan; import com.google.android.setupdesign.template.RequireScrollMixin; import com.google.android.setupdesign.util.DynamicColorPalette; +import java.util.List; + /** * Abstract base class for the intro onboarding activity for biometric enrollment. */ @@ -242,6 +244,19 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase !isScrollNeeded && !enrollmentCompleted ? View.VISIBLE : View.INVISIBLE); } + @Override + protected void onStart() { + super.onStart(); + + if (!getPackageName().equals(getCallingPackage())) { + for (String key : List.of(MultiBiometricEnrollHelper.EXTRA_SKIP_PENDING_ENROLL, + MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FACE, + MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FINGERPRINT)) { + getIntent().removeExtra(key); + } + } + } + @Override protected void onResume() { super.onResume(); @@ -490,14 +505,15 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase getIntent().removeExtra(MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FINGERPRINT); } - protected void removeEnrollNextBiometricIfSkipEnroll(@Nullable Intent data) { + private void removeEnrollNextBiometricIfSkipEnroll(@Nullable Intent data) { if (data != null && data.getBooleanExtra( MultiBiometricEnrollHelper.EXTRA_SKIP_PENDING_ENROLL, false)) { removeEnrollNextBiometric(); } } - protected void handleBiometricResultSkipOrFinished(int resultCode, @Nullable Intent data) { + + private void handleBiometricResultSkipOrFinished(int resultCode, @Nullable Intent data) { removeEnrollNextBiometricIfSkipEnroll(data); if (resultCode == RESULT_SKIP) { onEnrollmentSkipped(data); diff --git a/src/com/android/settings/biometrics/face/FaceSettings.java b/src/com/android/settings/biometrics/face/FaceSettings.java index 5a3949b89234b04475682b90c6b787bc13873713..f69d82526270b035a1cd4c3b76dcf593b2778324 100644 --- a/src/com/android/settings/biometrics/face/FaceSettings.java +++ b/src/com/android/settings/biometrics/face/FaceSettings.java @@ -83,8 +83,8 @@ public class FaceSettings extends DashboardFragment { private FaceManager mFaceManager; private DevicePolicyManager mDevicePolicyManager; private int mUserId; - private int mSensorId; - private long mChallenge; + private int mSensorId = -1; + private long mChallenge = 0; private byte[] mToken; private FaceSettingsAttentionPreferenceController mAttentionController; private FaceSettingsRemoveButtonPreferenceController mRemoveController; @@ -166,12 +166,19 @@ public class FaceSettings extends DashboardFragment { mUserManager = context.getSystemService(UserManager.class); mFaceManager = context.getSystemService(FaceManager.class); mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class); - mToken = getIntent().getByteArrayExtra(KEY_TOKEN); - mSensorId = getIntent().getIntExtra(BiometricEnrollBase.EXTRA_KEY_SENSOR_ID, -1); - mChallenge = getIntent().getLongExtra(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, 0L); - mUserId = getActivity().getIntent().getIntExtra( - Intent.EXTRA_USER_ID, UserHandle.myUserId()); + final SettingsActivity activity = (SettingsActivity) requireActivity(); + final String callingPackage = activity.getInitialCallingPackage(); + if (callingPackage == null || !callingPackage.equals(activity.getPackageName())) { + mUserId = UserHandle.myUserId(); + } else { + // only allow these extras when called internally by Settings + mToken = getIntent().getByteArrayExtra(KEY_TOKEN); + mSensorId = getIntent().getIntExtra(BiometricEnrollBase.EXTRA_KEY_SENSOR_ID, -1); + mChallenge = getIntent().getLongExtra(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, 0L); + mUserId = getIntent().getIntExtra(Intent.EXTRA_USER_ID, UserHandle.myUserId()); + } + mFaceFeatureProvider = FeatureFactory.getFeatureFactory().getFaceFeatureProvider(); if (mUserManager.getUserInfo(mUserId).isManagedProfile()) { diff --git a/src/com/android/settings/notification/history/NotificationHistoryActivity.java b/src/com/android/settings/notification/history/NotificationHistoryActivity.java index 156df96e04e428b1479ff702e9bac0156266900e..701b94c749f6d0bd945da4b4f6594f39a930919f 100644 --- a/src/com/android/settings/notification/history/NotificationHistoryActivity.java +++ b/src/com/android/settings/notification/history/NotificationHistoryActivity.java @@ -16,6 +16,7 @@ package com.android.settings.notification.history; +import static android.provider.Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS; import static android.provider.Settings.Secure.NOTIFICATION_HISTORY_ENABLED; import static androidx.core.view.accessibility.AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUSED; @@ -25,9 +26,11 @@ import android.annotation.ColorInt; import android.app.ActionBar; import android.app.ActivityManager; import android.app.INotificationManager; +import android.app.KeyguardManager; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; +import android.content.pm.UserInfo; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Outline; @@ -58,6 +61,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.UiEventLoggerImpl; +import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.NotificationExpandButton; import com.android.settings.R; import com.android.settings.notification.NotificationBackend; @@ -68,6 +72,7 @@ import com.android.settingslib.widget.MainSwitchBar; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -113,6 +118,9 @@ public class NotificationHistoryActivity extends CollapsingToolbarBaseActivity { }; private UiEventLogger mUiEventLogger = new UiEventLoggerImpl(); + // List of users that have the setting "hide sensitive content" enabled on the lockscreen + private ArrayList mContentRestrictedUsers = new ArrayList<>(); + enum NotificationHistoryEvent implements UiEventLogger.UiEventEnum { @UiEvent(doc = "User turned on notification history") NOTIFICATION_HISTORY_ON(504), @@ -212,14 +220,14 @@ public class NotificationHistoryActivity extends CollapsingToolbarBaseActivity { final NotificationHistoryRecyclerView rv = viewForPackage.findViewById(R.id.notification_list); - rv.setAdapter(new NotificationHistoryAdapter(mNm, rv, + rv.setAdapter(new NotificationHistoryAdapter(NotificationHistoryActivity.this, mNm, rv, newCount -> { count.setText(StringUtil.getIcuPluralsString(this, newCount, R.string.notification_history_count)); if (newCount == 0) { viewForPackage.setVisibility(View.GONE); } - }, mUiEventLogger)); + }, mUiEventLogger, mContentRestrictedUsers)); ((NotificationHistoryAdapter) rv.getAdapter()).onRebuildComplete( new ArrayList<>(nhp.notifications)); @@ -263,6 +271,21 @@ public class NotificationHistoryActivity extends CollapsingToolbarBaseActivity { mPm = getPackageManager(); mUm = getSystemService(UserManager.class); + + mContentRestrictedUsers.clear(); + List users = mUm.getProfiles(getUserId()); + mContentRestrictedUsers.clear(); + for (UserInfo user : users) { + if (Settings.Secure.getIntForUser(getContentResolver(), + LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, user.id) == 0) { + LockPatternUtils lpu = new LockPatternUtils(this); + KeyguardManager km = getSystemService(KeyguardManager.class); + if (lpu.isSecure(user.id) && km.isDeviceLocked(user.id)) { + mContentRestrictedUsers.add(user.id); + } + } + } + // wait for history loading and recent/snooze loading mCountdownLatch = new CountDownLatch(2); @@ -317,6 +340,7 @@ public class NotificationHistoryActivity extends CollapsingToolbarBaseActivity { if (mCountdownFuture != null) { mCountdownFuture.cancel(true); } + mContentRestrictedUsers.clear(); super.onDestroy(); } @@ -406,7 +430,7 @@ public class NotificationHistoryActivity extends CollapsingToolbarBaseActivity { mSnoozedRv.setLayoutManager(lm); mSnoozedRv.setAdapter( new NotificationSbnAdapter(NotificationHistoryActivity.this, mPm, mUm, - true, mUiEventLogger)); + true, mUiEventLogger, mContentRestrictedUsers)); mSnoozedRv.setNestedScrollingEnabled(false); if (snoozed == null || snoozed.length == 0) { @@ -422,7 +446,7 @@ public class NotificationHistoryActivity extends CollapsingToolbarBaseActivity { mDismissedRv.setLayoutManager(dismissLm); mDismissedRv.setAdapter( new NotificationSbnAdapter(NotificationHistoryActivity.this, mPm, mUm, - false, mUiEventLogger)); + false, mUiEventLogger, mContentRestrictedUsers)); mDismissedRv.setNestedScrollingEnabled(false); if (dismissed == null || dismissed.length == 0) { diff --git a/src/com/android/settings/notification/history/NotificationHistoryAdapter.java b/src/com/android/settings/notification/history/NotificationHistoryAdapter.java index 5368f25e76e4b7dc5ddd05625acc3367a210596d..44e15442a1ab37e09a0a3433eef6ac43427c0793 100644 --- a/src/com/android/settings/notification/history/NotificationHistoryAdapter.java +++ b/src/com/android/settings/notification/history/NotificationHistoryAdapter.java @@ -22,6 +22,7 @@ import static android.provider.Settings.EXTRA_CONVERSATION_ID; import android.app.INotificationManager; import android.app.NotificationHistory.HistoricalNotification; +import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.RemoteException; @@ -53,16 +54,23 @@ public class NotificationHistoryAdapter extends private List mValues; private OnItemDeletedListener mListener; private UiEventLogger mUiEventLogger; - public NotificationHistoryAdapter(INotificationManager nm, + private ArrayList mContentRestrictedUsers = new ArrayList<>(); + Context mContext; + + public NotificationHistoryAdapter(Context context, + INotificationManager nm, NotificationHistoryRecyclerView listView, OnItemDeletedListener listener, - UiEventLogger uiEventLogger) { + UiEventLogger uiEventLogger, + ArrayList contentRestrictedUsers) { + mContext = context; mValues = new ArrayList<>(); setHasStableIds(true); listView.setOnItemSwipeDeleteListener(this); mNm = nm; mListener = listener; mUiEventLogger = uiEventLogger; + mContentRestrictedUsers = contentRestrictedUsers; } @Override @@ -81,8 +89,14 @@ public class NotificationHistoryAdapter extends public void onBindViewHolder(final @NonNull NotificationHistoryViewHolder holder, int position) { final HistoricalNotification hn = mValues.get(position); - holder.setTitle(hn.getTitle()); - holder.setSummary(hn.getText()); + // Redact sensitive notification content if needed + if (mContentRestrictedUsers.contains(hn.getUserId())) { + holder.setSummary(mContext.getString( + com.android.internal.R.string.notification_hidden_text)); + } else { + holder.setTitle(hn.getTitle()); + holder.setSummary(hn.getText()); + } holder.setPostedTime(hn.getPostedTimeMs()); final View.OnClickListener onClick = v -> { mUiEventLogger.logWithPosition(NotificationHistoryActivity.NotificationHistoryEvent diff --git a/src/com/android/settings/notification/history/NotificationSbnAdapter.java b/src/com/android/settings/notification/history/NotificationSbnAdapter.java index 0301d7b7fd579fbcb8c6a45b0b5b083fbed739dc..844e9bc980fd74d87c08fa02df9f2f1fcb5cf7eb 100644 --- a/src/com/android/settings/notification/history/NotificationSbnAdapter.java +++ b/src/com/android/settings/notification/history/NotificationSbnAdapter.java @@ -74,9 +74,11 @@ public class NotificationSbnAdapter extends private List mEnabledProfiles = new ArrayList<>(); private boolean mIsSnoozed; private UiEventLogger mUiEventLogger; + private ArrayList mContentRestrictedUsers = new ArrayList<>(); public NotificationSbnAdapter(Context context, PackageManager pm, UserManager um, - boolean isSnoozed, UiEventLogger uiEventLogger) { + boolean isSnoozed, UiEventLogger uiEventLogger, + ArrayList contentRestrictedUsers) { mContext = context; mPm = pm; mUserBadgeCache = new HashMap<>(); @@ -97,6 +99,7 @@ public class NotificationSbnAdapter extends // If true, this is the panel for snoozed notifs, otherwise the one for dismissed notifs. mIsSnoozed = isSnoozed; mUiEventLogger = uiEventLogger; + mContentRestrictedUsers = contentRestrictedUsers; } @Override @@ -114,8 +117,14 @@ public class NotificationSbnAdapter extends holder.setIconBackground(loadBackground(sbn)); holder.setIcon(loadIcon(sbn)); holder.setPackageLabel(loadPackageLabel(sbn.getPackageName()).toString()); - holder.setTitle(getTitleString(sbn.getNotification())); - holder.setSummary(getTextString(mContext, sbn.getNotification())); + // If the notification is from a content restricted user, show generic text. + if (mContentRestrictedUsers.contains(sbn.getNormalizedUserId())) { + holder.setSummary(mContext.getString( + com.android.internal.R.string.notification_hidden_text)); + } else { + holder.setTitle(getTitleString(sbn.getNotification())); + holder.setSummary(getTextString(mContext, sbn.getNotification())); + } holder.setPostedTime(sbn.getPostTime()); holder.setDividerVisible(position < (mValues.size() -1)); int userId = normalizeUserId(sbn); diff --git a/src/com/android/settings/security/ContentProtectionTogglePreferenceController.java b/src/com/android/settings/security/ContentProtectionTogglePreferenceController.java index 69ac6b100be9a9796dc78e62fdcd96ba1d381070..61987cdd8ad1b0d7b64af2302def6a4b057c6fbd 100644 --- a/src/com/android/settings/security/ContentProtectionTogglePreferenceController.java +++ b/src/com/android/settings/security/ContentProtectionTogglePreferenceController.java @@ -132,7 +132,7 @@ public class ContentProtectionTogglePreferenceController extends TogglePreferenc UserManager userManager = mContext.getSystemService(UserManager.class); if (userManager != null - && userManager.isGuestUser() + && !userManager.isAdminUser() && mSwitchBar != null) { mSwitchBar.setEnabled(false); } diff --git a/src/com/android/settings/security/CredentialStorage.java b/src/com/android/settings/security/CredentialStorage.java index b1c65a7c3c0ba086797079684ade6c8cc735b51b..5ea9b7ac21ff3727700c7ce7af9061f09b12f180 100644 --- a/src/com/android/settings/security/CredentialStorage.java +++ b/src/com/android/settings/security/CredentialStorage.java @@ -17,6 +17,7 @@ package com.android.settings.security; import android.app.Activity; +import android.app.ActivityManager; import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.DialogInterface; @@ -322,15 +323,25 @@ public final class CredentialStorage extends FragmentActivity { } } + private String getCallingPackageName() { + try { + return ActivityManager.getService().getLaunchedFromPackage(getActivityToken()); + } catch (RemoteException re) { + // Error talking to ActivityManager, just give up + return null; + } + } + /** * Check that the caller is either certinstaller or Settings running in a profile of this user. */ private boolean checkCallerIsCertInstallerOrSelfInProfile() { - if (TextUtils.equals("com.android.certinstaller", getCallingPackage())) { + String callingPackage = getCallingPackageName(); + if (TextUtils.equals("com.android.certinstaller", callingPackage)) { // CertInstaller is allowed to install credentials if it has the same signature as // Settings package. return getPackageManager().checkSignatures( - getCallingPackage(), getPackageName()) == PackageManager.SIGNATURE_MATCH; + callingPackage, getPackageName()) == PackageManager.SIGNATURE_MATCH; } final int launchedFromUserId; diff --git a/src/com/android/settings/users/AppRestrictionsFragment.java b/src/com/android/settings/users/AppRestrictionsFragment.java index c42e2f57b1dfcf9b085d1bf2dcf2c1a1e486fa5e..5b2a86fff421ce7366afeb7356c5cdaa4db8a3cb 100644 --- a/src/com/android/settings/users/AppRestrictionsFragment.java +++ b/src/com/android/settings/users/AppRestrictionsFragment.java @@ -639,8 +639,11 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen } else if (restrictionsIntent != null) { preference.setRestrictions(restrictions); if (invokeIfCustom && AppRestrictionsFragment.this.isResumed()) { + // We don't necessarily trust the given intent to launch its component. + // We will first check it, and only use parts of it that were indeed checked. + final Intent vettedIntent; try { - assertSafeToStartCustomActivity(restrictionsIntent); + vettedIntent = assertSafeToStartCustomActivity(restrictionsIntent); } catch (ActivityNotFoundException | SecurityException e) { // return without startActivity Log.e(TAG, "Cannot start restrictionsIntent " + e); @@ -651,15 +654,20 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen int requestCode = generateCustomActivityRequestCode( RestrictionsResultReceiver.this.preference); AppRestrictionsFragment.this.startActivityForResult( - new Intent(restrictionsIntent), requestCode); + vettedIntent, requestCode); } } } - private void assertSafeToStartCustomActivity(Intent intent) { + /** + * Checks that it is safe to start the custom activity, and, if so, returns a copy of the + * Intent using its vetted components. + */ + private Intent assertSafeToStartCustomActivity(Intent intent) { EventLog.writeEvent(0x534e4554, "223578534", -1 /* UID */, ""); + final Intent vettedIntent = new Intent(intent); ResolveInfo resolveInfo = mPackageManager.resolveActivity( - intent, PackageManager.MATCH_DEFAULT_ONLY); + vettedIntent, PackageManager.MATCH_DEFAULT_ONLY); if (resolveInfo == null) { throw new ActivityNotFoundException("No result for resolving " + intent); @@ -670,6 +678,12 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen throw new SecurityException("Application " + packageName + " is not allowed to start activity " + intent); } + + // We were able to vet the given intent this time. Make a copy using the components + // that were used to do the vetting, since that's as much as we've verified is safe. + vettedIntent.setComponent(activityInfo.getComponentName()); + vettedIntent.setPackage(activityInfo.packageName); + return vettedIntent; } } diff --git a/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java b/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java index 81a7269459287af0a353930328ea4f98d62a4133..984073f19b53f7ac06c7eddc2d92670438ca2097 100644 --- a/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java +++ b/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java @@ -32,11 +32,13 @@ import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Activity; +import android.app.PendingIntent; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -64,6 +66,7 @@ import com.android.settings.R; import com.android.settings.Settings; import com.android.settings.biometrics.BiometricEnrollBase; import com.android.settings.biometrics.BiometricUtils; +import com.android.settings.biometrics.MultiBiometricEnrollHelper; import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.shadow.SettingsShadowResources; @@ -206,6 +209,12 @@ public class FaceEnrollIntroductionTest { testIntent.putExtra(BiometricUtils.EXTRA_ENROLL_REASON, FaceEnrollOptions.ENROLL_REASON_SETTINGS); + testIntent.putExtra(MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FACE, + mock(PendingIntent.class)); + testIntent.putExtra(MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FINGERPRINT, + mock(PendingIntent.class)); + testIntent.putExtra(MultiBiometricEnrollHelper.EXTRA_SKIP_PENDING_ENROLL, false); + when(mFakeFeatureFactory.mFaceFeatureProvider.getPostureGuidanceIntent(any())).thenReturn( null /* Simulate no posture intent */); mContext = spy(ApplicationProvider.getApplicationContext()); @@ -690,4 +699,16 @@ public class FaceEnrollIntroductionTest { .isEqualTo(FaceEnrollOptions.ENROLL_REASON_SETTINGS); } + @Test + public void drops_pendingIntents() { + setupActivity(); + + mController.start(); + Shadows.shadowOf(Looper.getMainLooper()).idle(); + + final Intent intent = mActivity.getIntent(); + assertThat(intent.hasExtra(MultiBiometricEnrollHelper.EXTRA_SKIP_PENDING_ENROLL)).isFalse(); + assertThat(intent.hasExtra(MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FACE)).isFalse(); + assertThat(intent.hasExtra(MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FINGERPRINT)).isFalse(); + } } diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroductionTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroductionTest.java index edd50a6e6f61e4ba689d5dedd18dcd7adfd58d10..24fb7165fd0c5cf70b138fd601342f4725ff335a 100644 --- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroductionTest.java +++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroductionTest.java @@ -34,6 +34,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.res.Resources; @@ -44,6 +45,7 @@ import android.hardware.fingerprint.FingerprintEnrollOptions; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; +import android.os.Looper; import android.os.UserManager; import android.view.View; @@ -55,6 +57,7 @@ import com.android.internal.widget.VerifyCredentialResponse; import com.android.settings.R; import com.android.settings.biometrics.BiometricUtils; import com.android.settings.biometrics.GatekeeperPasswordProvider; +import com.android.settings.biometrics.MultiBiometricEnrollHelper; import com.google.android.setupcompat.util.WizardManagerHelper; import com.google.android.setupdesign.GlifLayout; @@ -70,6 +73,7 @@ import org.mockito.stubbing.Answer; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import org.robolectric.Shadows; import org.robolectric.android.controller.ActivityController; import java.util.ArrayList; @@ -353,7 +357,19 @@ public class FingerprintEnrollIntroductionTest { false); Assert.assertEquals(View.INVISIBLE, mFingerprintEnrollIntroduction.getSecondaryFooterButton().getVisibility()); + } + + @Test + public void drops_pendingIntents() { + setupFingerprintEnrollIntroWith(newExternalPendingIntent()); + + mController.start(); + Shadows.shadowOf(Looper.getMainLooper()).idle(); + final Intent intent = mFingerprintEnrollIntroduction.getIntent(); + assertThat(intent.hasExtra(MultiBiometricEnrollHelper.EXTRA_SKIP_PENDING_ENROLL)).isFalse(); + assertThat(intent.hasExtra(MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FACE)).isFalse(); + assertThat(intent.hasExtra(MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FINGERPRINT)).isFalse(); } private Intent newTokenOnlyIntent() { @@ -383,6 +399,15 @@ public class FingerprintEnrollIntroductionTest { .putExtra(EXTRA_KEY_GK_PW_HANDLE, 1L); } + private Intent newExternalPendingIntent() { + return newTokenOnlyIntent() + .putExtra(MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FACE, + mock(PendingIntent.class)) + .putExtra(MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FINGERPRINT, + mock(PendingIntent.class)) + .putExtra(MultiBiometricEnrollHelper.EXTRA_SKIP_PENDING_ENROLL, false); + } + private VerifyCredentialResponse newGoodCredential(long gkPwHandle, @NonNull byte[] hat) { return new VerifyCredentialResponse.Builder() .setGatekeeperPasswordHandle(gkPwHandle) diff --git a/tests/robotests/src/com/android/settings/security/ContentProtectionTogglePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/security/ContentProtectionTogglePreferenceControllerTest.java index 6514a4e40431ea7795bb060c3fd764aca878d67b..5f63da19fe6f787d2e72e4335275d116cb5e30db 100644 --- a/tests/robotests/src/com/android/settings/security/ContentProtectionTogglePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/security/ContentProtectionTogglePreferenceControllerTest.java @@ -85,7 +85,7 @@ public class ContentProtectionTogglePreferenceControllerTest { @Before public void setUp() { mShadowUserManager = ShadowUserManager.getShadow(); - mShadowUserManager.setGuestUser(false); + mShadowUserManager.setIsAdminUser(true); mController = new TestContentProtectionTogglePreferenceController(); SettingsMainSwitchPreference switchPreference = new SettingsMainSwitchPreference(mContext); when(mMockPreferenceScreen.findPreference(mController.getPreferenceKey())) @@ -277,8 +277,8 @@ public class ContentProtectionTogglePreferenceControllerTest { } @Test - public void updateState_flagEnabled_noEnforcedAdmin_guestUser_switchBarDisabled() { - mShadowUserManager.setGuestUser(true); + public void updateState_flagEnabled_noEnforcedAdmin_nonAdminUser_switchBarDisabled() { + mShadowUserManager.setIsAdminUser(false); mSetFlagsRule.enableFlags(FLAG_MANAGE_DEVICE_POLICY_ENABLED); mContentProtectionPolicy = DevicePolicyManager.CONTENT_PROTECTION_ENABLED; setupForUpdateState(); @@ -289,13 +289,15 @@ public class ContentProtectionTogglePreferenceControllerTest { } @Test - public void updateState_flagEnabled_noEnforcedAdmin_nonGuestUser_switchBarEnabled() { + public void updateState_flagEnabled_noEnforcedAdmin_adminUser_switchBarEnabled() { + mShadowUserManager.setIsAdminUser(true); mSetFlagsRule.enableFlags(FLAG_MANAGE_DEVICE_POLICY_ENABLED); mContentProtectionPolicy = DevicePolicyManager.CONTENT_PROTECTION_ENABLED; setupForUpdateState(); mController.updateState(mMockSwitchPreference); + // Verify that the switch bar is *not* set to disabled. verify(mMockSwitchPreference, never()).setEnabled(false); }