diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 0ee20a1afa1..7dd42df3c75 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1499,6 +1499,7 @@ android:theme="@android:style/Theme.NoDisplay"> + diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index 9eeabe860d9..f0d5107bc2d 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -1012,7 +1012,24 @@ public final class Utils extends com.android.settingslib.Utils { return getCredentialOwnerUserId(context); } int userId = bundle.getInt(Intent.EXTRA_USER_ID, UserHandle.myUserId()); - return enforceSameOwner(context, userId); + if (userId == LockPatternUtils.USER_FRP) { + return enforceSystemUser(context, userId); + } else { + return enforceSameOwner(context, userId); + } + } + + /** + * Returns the given user id if the current user is the system user. + * + * @throws SecurityException if the current user is not the system user. + */ + public static int enforceSystemUser(Context context, int userId) { + if (UserHandle.myUserId() == UserHandle.USER_SYSTEM) { + return userId; + } + throw new SecurityException("Given user id " + userId + " must only be used from " + + "USER_SYSTEM, but current user is " + UserHandle.myUserId()); } /** diff --git a/src/com/android/settings/password/ChooseLockSettingsHelper.java b/src/com/android/settings/password/ChooseLockSettingsHelper.java index 8c73355b5ac..95f5a54f9c7 100644 --- a/src/com/android/settings/password/ChooseLockSettingsHelper.java +++ b/src/com/android/settings/password/ChooseLockSettingsHelper.java @@ -19,10 +19,13 @@ package com.android.settings.password; import android.annotation.Nullable; import android.app.Activity; import android.app.Fragment; +import android.app.KeyguardManager; import android.app.admin.DevicePolicyManager; +import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.os.UserManager; +import android.provider.Settings; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.widget.LockPatternUtils; @@ -202,6 +205,21 @@ public final class ChooseLockSettingsHelper { @Nullable CharSequence header, @Nullable CharSequence description, boolean returnCredentials, boolean external, boolean hasChallenge, long challenge, int userId) { + return launchConfirmationActivity(request, title, header, description, returnCredentials, + external, hasChallenge, challenge, userId, null /* alternateButton */); + } + + public boolean launchFrpConfirmationActivity(int request, @Nullable CharSequence header, + @Nullable CharSequence description, @Nullable CharSequence alternateButton) { + return launchConfirmationActivity(request, null /* title */, header, description, + false /* returnCredentials */, true /* external */, false /* hasChallenge */, + 0 /* challenge */, LockPatternUtils.USER_FRP, alternateButton); + } + + private boolean launchConfirmationActivity(int request, @Nullable CharSequence title, + @Nullable CharSequence header, @Nullable CharSequence description, + boolean returnCredentials, boolean external, boolean hasChallenge, + long challenge, int userId, @Nullable CharSequence alternateButton) { final int effectiveUserId = UserManager.get(mActivity).getCredentialOwnerProfile(userId); boolean launched = false; @@ -211,7 +229,7 @@ public final class ChooseLockSettingsHelper { returnCredentials || hasChallenge ? ConfirmLockPattern.InternalActivity.class : ConfirmLockPattern.class, returnCredentials, external, - hasChallenge, challenge, userId); + hasChallenge, challenge, userId, alternateButton); break; case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: @@ -223,7 +241,7 @@ public final class ChooseLockSettingsHelper { returnCredentials || hasChallenge ? ConfirmLockPassword.InternalActivity.class : ConfirmLockPassword.class, returnCredentials, external, - hasChallenge, challenge, userId); + hasChallenge, challenge, userId, alternateButton); break; } return launched; @@ -232,7 +250,7 @@ public final class ChooseLockSettingsHelper { private boolean launchConfirmationActivity(int request, CharSequence title, CharSequence header, CharSequence message, Class activityClass, boolean returnCredentials, boolean external, boolean hasChallenge, long challenge, - int userId) { + int userId, @Nullable CharSequence alternateButton) { final Intent intent = new Intent(); intent.putExtra(ConfirmDeviceCredentialBaseFragment.TITLE_TEXT, title); intent.putExtra(ConfirmDeviceCredentialBaseFragment.HEADER_TEXT, header); @@ -247,6 +265,7 @@ public final class ChooseLockSettingsHelper { // we should never have a drawer when confirming device credentials. intent.putExtra(SettingsActivity.EXTRA_HIDE_DRAWER, true); intent.putExtra(Intent.EXTRA_USER_ID, userId); + intent.putExtra(KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL, alternateButton); intent.setClassName(ConfirmDeviceCredentialBaseFragment.PACKAGE, activityClass.getName()); if (external) { intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java index 38b38fc1a9c..65d72f11bbc 100644 --- a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java +++ b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java @@ -66,6 +66,10 @@ public class ConfirmDeviceCredentialActivity extends Activity { Intent intent = getIntent(); String title = intent.getStringExtra(KeyguardManager.EXTRA_TITLE); String details = intent.getStringExtra(KeyguardManager.EXTRA_DESCRIPTION); + String alternateButton = intent.getStringExtra( + KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL); + boolean frp = KeyguardManager.ACTION_CONFIRM_FRP_CREDENTIAL.equals(intent.getAction()); + int userId = Utils.getCredentialOwnerUserId(this); if (isInternalActivity()) { try { @@ -86,7 +90,9 @@ public class ConfirmDeviceCredentialActivity extends Activity { // If the target is a managed user and user key not unlocked yet, we will force unlock // tied profile so it will enable work mode and unlock managed profile, when personal // challenge is unlocked. - if (isManagedProfile && isInternalActivity() + if (frp) { + launched = helper.launchFrpConfirmationActivity(0, title, details, alternateButton); + } else if (isManagedProfile && isInternalActivity() && !lockPatternUtils.isSeparateProfileChallengeEnabled(userId)) { // We set the challenge as 0L, so it will force to unlock managed profile when it // unlocks primary profile screen lock, by calling verifyTiedProfileChallenge() diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java b/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java index 0c36dba76ad..64f3a6fd04c 100644 --- a/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java +++ b/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java @@ -25,6 +25,7 @@ import android.app.Dialog; import android.app.DialogFragment; import android.app.FragmentManager; import android.app.IActivityManager; +import android.app.KeyguardManager; import android.app.admin.DevicePolicyManager; import android.app.trust.TrustManager; import android.content.Context; @@ -40,6 +41,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.RemoteException; import android.os.UserManager; +import android.text.TextUtils; import android.view.View; import android.view.ViewGroup; import android.widget.Button; @@ -86,15 +88,20 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends OptionsMenuFra protected DevicePolicyManager mDevicePolicyManager; protected TextView mErrorTextView; protected final Handler mHandler = new Handler(); + protected boolean mFrp; + private CharSequence mFrpAlternateButtonText; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); + mFrpAlternateButtonText = getActivity().getIntent().getCharSequenceExtra( + KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL); mReturnCredentials = getActivity().getIntent().getBooleanExtra( ChooseLockSettingsHelper.EXTRA_KEY_RETURN_CREDENTIALS, false); // Only take this argument into account if it belongs to the current profile. Intent intent = getActivity().getIntent(); mUserId = Utils.getUserIdFromBundle(getActivity(), intent.getExtras()); + mFrp = (mUserId == LockPatternUtils.USER_FRP); mUserManager = UserManager.get(getActivity()); mEffectiveUserId = mUserManager.getCredentialOwnerProfile(mUserId); mLockPatternUtils = new LockPatternUtils(getActivity()); @@ -112,10 +119,18 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends OptionsMenuFra (TextView) view.findViewById(R.id.errorText), this, mEffectiveUserId); boolean showCancelButton = getActivity().getIntent().getBooleanExtra( SHOW_CANCEL_BUTTON, false); - mCancelButton.setVisibility(showCancelButton ? View.VISIBLE : View.GONE); + boolean hasAlternateButton = mFrp && !TextUtils.isEmpty(mFrpAlternateButtonText); + mCancelButton.setVisibility(showCancelButton || hasAlternateButton + ? View.VISIBLE : View.GONE); + if (hasAlternateButton) { + mCancelButton.setText(mFrpAlternateButtonText); + } mCancelButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { + if (hasAlternateButton) { + getActivity().setResult(KeyguardManager.RESULT_ALTERNATE); + } getActivity().finish(); } }); @@ -139,15 +154,16 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends OptionsMenuFra // credential. Otherwise, fingerprint can't unlock fbe/keystore through // verifyTiedProfileChallenge. In such case, we also wanna show the user message that // fingerprint is disabled due to device restart. - protected boolean isFingerprintDisallowedByStrongAuth() { - return !(mLockPatternUtils.isFingerprintAllowedForUser(mEffectiveUserId) - && mUserManager.isUserUnlocked(mUserId)); + protected boolean isStrongAuthRequired() { + return mFrp + || !mLockPatternUtils.isFingerprintAllowedForUser(mEffectiveUserId) + || !mUserManager.isUserUnlocked(mUserId); } private boolean isFingerprintAllowed() { return !mReturnCredentials && getActivity().getIntent().getBooleanExtra(ALLOW_FP_AUTHENTICATION, false) - && !isFingerprintDisallowedByStrongAuth() + && !isStrongAuthRequired() && !isFingerprintDisabledByAdmin(); } diff --git a/src/com/android/settings/password/ConfirmLockPassword.java b/src/com/android/settings/password/ConfirmLockPassword.java index a91f572b097..0acdcd8f08b 100644 --- a/src/com/android/settings/password/ConfirmLockPassword.java +++ b/src/com/android/settings/password/ConfirmLockPassword.java @@ -16,7 +16,6 @@ package com.android.settings.password; -import android.app.Activity; import android.app.Fragment; import android.app.admin.DevicePolicyManager; import android.content.Context; @@ -45,7 +44,6 @@ import com.android.internal.widget.LockPatternChecker; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.TextViewInputDisabler; import com.android.settings.R; -import com.android.settings.SettingsActivity; import com.android.settingslib.animation.AppearAnimationUtils; import com.android.settingslib.animation.DisappearAnimationUtils; @@ -197,7 +195,7 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity { } private int getDefaultDetails() { - boolean isStrongAuthRequired = isFingerprintDisallowedByStrongAuth(); + boolean isStrongAuthRequired = isStrongAuthRequired(); boolean isProfile = UserManager.get(getActivity()).isManagedProfile(mEffectiveUserId); // Map boolean flags to an index by isStrongAuth << 2 + isProfile << 1 + isAlpha. int index = ((isStrongAuthRequired ? 1 : 0) << 2) + ((isProfile ? 1 : 0) << 1) diff --git a/src/com/android/settings/password/ConfirmLockPattern.java b/src/com/android/settings/password/ConfirmLockPattern.java index c16b55ab9e5..2931596ec57 100644 --- a/src/com/android/settings/password/ConfirmLockPattern.java +++ b/src/com/android/settings/password/ConfirmLockPattern.java @@ -38,7 +38,6 @@ import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternView; import com.android.internal.widget.LockPatternView.Cell; import com.android.settings.R; -import com.android.settings.SettingsActivity; import com.android.settingslib.animation.AppearAnimationCreator; import com.android.settingslib.animation.AppearAnimationUtils; import com.android.settingslib.animation.DisappearAnimationUtils; @@ -155,7 +154,13 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity { // on first launch, if no lock pattern is set, then finish with // success (don't want user to get stuck confirming something that // doesn't exist). - if (!mLockPatternUtils.isLockPatternEnabled(mEffectiveUserId)) { + // Don't do this check for FRP though, because the pattern is not stored + // in a way that isLockPatternEnabled is aware of for that case. + // TODO(roosa): This block should no longer be needed since we removed the + // ability to disable the pattern in L. Remove this block after + // ensuring it's safe to do so. (Note that ConfirmLockPassword + // doesn't have this). + if (!mFrp && !mLockPatternUtils.isLockPatternEnabled(mEffectiveUserId)) { getActivity().setResult(Activity.RESULT_OK); getActivity().finish(); } @@ -238,7 +243,7 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity { } private int getDefaultDetails() { - boolean isStrongAuthRequired = isFingerprintDisallowedByStrongAuth(); + boolean isStrongAuthRequired = isStrongAuthRequired(); if (UserManager.get(getActivity()).isManagedProfile(mEffectiveUserId)) { return isStrongAuthRequired ? R.string.lockpassword_strong_auth_required_reason_restart_work_pattern