Merge Android U (ab/10368041)
Bug: 291102124 Merged-In: I17a6c8a571b4a0b7d943dfd710cde0f18d03da39 Change-Id: I4ed5b2e4c6c59527bb544e8b6dff2b9d4cee9025
This commit is contained in:
@@ -129,6 +129,7 @@ public class BiometricFragment extends InstrumentedFragment {
|
||||
mBiometricPrompt = new BiometricPrompt.Builder(getContext())
|
||||
.setTitle(promptInfo.getTitle())
|
||||
.setUseDefaultTitle() // use default title if title is null/empty
|
||||
.setUseDefaultSubtitle() // use default subtitle if subtitle is null/empty
|
||||
.setDeviceCredentialAllowed(true)
|
||||
.setSubtitle(promptInfo.getSubtitle())
|
||||
.setDescription(promptInfo.getDescription())
|
||||
@@ -140,6 +141,7 @@ public class BiometricFragment extends InstrumentedFragment {
|
||||
.setDisallowBiometricsIfPolicyExists(
|
||||
promptInfo.isDisallowBiometricsIfPolicyExists())
|
||||
.setReceiveSystemEvents(true)
|
||||
.setAllowBackgroundAuthentication(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -54,9 +54,9 @@ import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
@@ -67,7 +67,6 @@ import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.internal.widget.LockscreenCredential;
|
||||
import com.android.settings.EncryptionInterstitial;
|
||||
import com.android.settings.EventLogTags;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
@@ -76,6 +75,7 @@ import com.android.settings.SetupWizardUtils;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.biometrics.BiometricEnrollActivity;
|
||||
import com.android.settings.biometrics.BiometricEnrollBase;
|
||||
import com.android.settings.biometrics.BiometricUtils;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||
import com.android.settings.safetycenter.LockScreenSafetySource;
|
||||
@@ -144,8 +144,6 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
@VisibleForTesting
|
||||
static final int CONFIRM_EXISTING_REQUEST = 100;
|
||||
@VisibleForTesting
|
||||
static final int ENABLE_ENCRYPTION_REQUEST = 101;
|
||||
@VisibleForTesting
|
||||
static final int CHOOSE_LOCK_REQUEST = 102;
|
||||
@VisibleForTesting
|
||||
static final int CHOOSE_LOCK_BEFORE_BIOMETRIC_REQUEST = 103;
|
||||
@@ -157,7 +155,6 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
private boolean mRequestGatekeeperPasswordHandle = false;
|
||||
private boolean mPasswordConfirmed = false;
|
||||
private boolean mWaitingForConfirmation = false;
|
||||
private boolean mForChangeCredRequiredForBoot = false;
|
||||
private LockscreenCredential mUserPassword;
|
||||
private FingerprintManager mFingerprintManager;
|
||||
private FaceManager mFaceManager;
|
||||
@@ -251,8 +248,6 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
|
||||
mIsCallingAppAdmin = intent
|
||||
.getBooleanExtra(EXTRA_KEY_IS_CALLING_APP_ADMIN, /* defValue= */ false);
|
||||
mForChangeCredRequiredForBoot = arguments != null && arguments.getBoolean(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT);
|
||||
mUserManager = UserManager.get(activity);
|
||||
|
||||
if (arguments != null) {
|
||||
@@ -300,10 +295,6 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
|
||||
if (mPasswordConfirmed) {
|
||||
updatePreferencesOrFinish(savedInstanceState != null);
|
||||
if (mForChangeCredRequiredForBoot) {
|
||||
maybeEnableEncryption(mLockPatternUtils.getKeyguardStoredPasswordQuality(
|
||||
mUserId), false);
|
||||
}
|
||||
} else if (!mWaitingForConfirmation) {
|
||||
final ChooseLockSettingsHelper.Builder builder =
|
||||
new ChooseLockSettingsHelper.Builder(activity, this);
|
||||
@@ -451,58 +442,6 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the device has encryption already enabled, then ask the user if they
|
||||
* also want to encrypt the phone with this password.
|
||||
*
|
||||
* @param quality
|
||||
* @param disabled
|
||||
*/
|
||||
// TODO: why does this take disabled, its always called with a quality higher than
|
||||
// what makes sense with disabled == true
|
||||
private void maybeEnableEncryption(int quality, boolean disabled) {
|
||||
DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
|
||||
if (UserManager.get(getActivity()).isAdminUser()
|
||||
&& mUserId == UserHandle.myUserId()
|
||||
&& LockPatternUtils.isDeviceEncryptionEnabled()
|
||||
&& !LockPatternUtils.isFileEncryptionEnabled()
|
||||
&& !dpm.getDoNotAskCredentialsOnBoot()) {
|
||||
// Get the intent that the encryption interstitial should start for creating
|
||||
// the new unlock method.
|
||||
Intent unlockMethodIntent = getIntentForUnlockMethod(quality);
|
||||
unlockMethodIntent.putExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT,
|
||||
mForChangeCredRequiredForBoot);
|
||||
final Context context = getActivity();
|
||||
// If accessibility is enabled and the user hasn't seen this dialog before, set the
|
||||
// default state to agree with that which is compatible with accessibility
|
||||
// (password not required).
|
||||
final boolean accEn = AccessibilityManager.getInstance(context).isEnabled();
|
||||
final boolean required = mLockPatternUtils.isCredentialRequiredToDecrypt(!accEn);
|
||||
Intent intent = getEncryptionInterstitialIntent(context, quality, required,
|
||||
unlockMethodIntent);
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT,
|
||||
mForFingerprint);
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, mForFace);
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, mForBiometrics);
|
||||
// If the caller requested Gatekeeper Password to be returned, we assume it came
|
||||
// from biometric enrollment. This should be cleaned up, since requesting
|
||||
// Gatekeeper Password should not imply it came from biometric setup/settings.
|
||||
startActivityForResult(
|
||||
intent,
|
||||
mIsSetNewPassword && mRequestGatekeeperPasswordHandle
|
||||
? CHOOSE_LOCK_BEFORE_BIOMETRIC_REQUEST
|
||||
: ENABLE_ENCRYPTION_REQUEST);
|
||||
} else {
|
||||
if (mForChangeCredRequiredForBoot) {
|
||||
// Welp, couldn't change it. Oh well.
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
updateUnlockMethodAndFinish(quality, disabled, false /* chooseLockSkipped */);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
@@ -513,17 +452,8 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
? data.getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD)
|
||||
: null;
|
||||
updatePreferencesOrFinish(false /* isRecreatingActivity */);
|
||||
if (mForChangeCredRequiredForBoot) {
|
||||
if (mUserPassword != null && !mUserPassword.isNone()) {
|
||||
maybeEnableEncryption(
|
||||
mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId), false);
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
} else if (requestCode == CHOOSE_LOCK_REQUEST
|
||||
|| requestCode == ENABLE_ENCRYPTION_REQUEST) {
|
||||
if (resultCode != RESULT_CANCELED || mForChangeCredRequiredForBoot) {
|
||||
} else if (requestCode == CHOOSE_LOCK_REQUEST) {
|
||||
if (resultCode != RESULT_CANCELED) {
|
||||
getActivity().setResult(resultCode, data);
|
||||
finish();
|
||||
} else {
|
||||
@@ -563,9 +493,6 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
getActivity().setResult(Activity.RESULT_CANCELED);
|
||||
finish();
|
||||
}
|
||||
if (requestCode == Activity.RESULT_CANCELED && mForChangeCredRequiredForBoot) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
protected Intent getBiometricEnrollIntent(Context context) {
|
||||
@@ -591,11 +518,11 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
void updatePreferencesOrFinish(boolean isRecreatingActivity) {
|
||||
Intent intent = getActivity().getIntent();
|
||||
int quality = -1;
|
||||
if (StorageManager.isFileEncryptedNativeOrEmulated()) {
|
||||
if (StorageManager.isFileEncrypted()) {
|
||||
quality = intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1);
|
||||
} else {
|
||||
// For non-file encrypted devices we need to show encryption interstitial, so always
|
||||
// show the lock type picker and ignore PASSWORD_TYPE_KEY.
|
||||
// For unencrypted devices, always show the lock type picker and ignore
|
||||
// PASSWORD_TYPE_KEY.
|
||||
Log.i(TAG, "Ignoring PASSWORD_TYPE_KEY because device is not file encrypted");
|
||||
}
|
||||
if (quality == -1) {
|
||||
@@ -703,10 +630,11 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
R.string.face_unlock_set_unlock_password);
|
||||
} else if (mForBiometrics) {
|
||||
setPreferenceTitle(ScreenLockType.PATTERN,
|
||||
R.string.biometrics_unlock_set_unlock_pattern);
|
||||
setPreferenceTitle(ScreenLockType.PIN, R.string.biometrics_unlock_set_unlock_pin);
|
||||
getBiometricsPreferenceTitle(ScreenLockType.PATTERN));
|
||||
setPreferenceTitle(ScreenLockType.PIN,
|
||||
getBiometricsPreferenceTitle(ScreenLockType.PIN));
|
||||
setPreferenceTitle(ScreenLockType.PASSWORD,
|
||||
R.string.biometrics_unlock_set_unlock_password);
|
||||
getBiometricsPreferenceTitle(ScreenLockType.PASSWORD));
|
||||
}
|
||||
|
||||
if (mManagedPasswordProvider.isSettingManagedPasswordSupported()) {
|
||||
@@ -727,6 +655,24 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
String getBiometricsPreferenceTitle(@NonNull ScreenLockType secureType) {
|
||||
final boolean hasFingerprint = Utils.hasFingerprintHardware(getContext());
|
||||
final boolean hasFace = Utils.hasFaceHardware(getContext());
|
||||
final boolean isSuw = WizardManagerHelper.isAnySetupWizard(getIntent());
|
||||
final boolean isFaceSupported =
|
||||
hasFace && (!isSuw || BiometricUtils.isFaceSupportedInSuw(getContext()));
|
||||
|
||||
// Assume the flow is "Screen Lock" + "Face" + "Fingerprint"
|
||||
if (mController != null) {
|
||||
return BiometricUtils.getCombinedScreenLockOptions(getContext(),
|
||||
mController.getTitle(secureType), hasFingerprint, isFaceSupported);
|
||||
} else {
|
||||
Log.e(TAG, "ChooseLockGenericController is null!");
|
||||
return getResources().getString(R.string.error_title);
|
||||
}
|
||||
}
|
||||
|
||||
private void setPreferenceTitle(ScreenLockType lock, @StringRes int title) {
|
||||
Preference preference = findPreference(lock.preferenceKey);
|
||||
if (preference != null) {
|
||||
@@ -825,12 +771,6 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
protected Intent getEncryptionInterstitialIntent(Context context, int quality,
|
||||
boolean required, Intent unlockMethodIntent) {
|
||||
return EncryptionInterstitial.createStartIntent(context, quality, required,
|
||||
unlockMethodIntent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes an activity to change the user's pattern, password or PIN based on given quality
|
||||
* and minimum quality specified by DevicePolicyManager. If quality is
|
||||
@@ -896,6 +836,19 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
return intent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
// hasCredential checks to see if user chooses a password for screen lock. If the
|
||||
// screen lock is None or Swipe, we do not want to call getActivity().finish().
|
||||
// Otherwise, bugs would be caused. (e.g. b/278488549, b/278530059)
|
||||
final boolean hasCredential = mLockPatternUtils.isSecure(mUserId);
|
||||
if (!getActivity().isChangingConfigurations()
|
||||
&& !mWaitingForConfirmation && hasCredential) {
|
||||
getActivity().finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
@@ -996,16 +949,14 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
switch (lock) {
|
||||
case NONE:
|
||||
case SWIPE:
|
||||
updateUnlockMethodAndFinish(
|
||||
lock.defaultQuality,
|
||||
lock == ScreenLockType.NONE,
|
||||
false /* chooseLockSkipped */);
|
||||
return true;
|
||||
case PATTERN:
|
||||
case PIN:
|
||||
case PASSWORD:
|
||||
case MANAGED:
|
||||
maybeEnableEncryption(lock.defaultQuality, false);
|
||||
updateUnlockMethodAndFinish(
|
||||
lock.defaultQuality,
|
||||
lock == ScreenLockType.NONE,
|
||||
false /* chooseLockSkipped */);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import static android.app.admin.DevicePolicyResources.Strings.Settings.REENTER_W
|
||||
import static android.app.admin.DevicePolicyResources.Strings.Settings.SET_WORK_PROFILE_PASSWORD_HEADER;
|
||||
import static android.app.admin.DevicePolicyResources.Strings.Settings.SET_WORK_PROFILE_PIN_HEADER;
|
||||
import static android.app.admin.DevicePolicyResources.UNDEFINED;
|
||||
import static android.view.View.ACCESSIBILITY_LIVE_REGION_POLITE;
|
||||
|
||||
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
|
||||
import static com.android.internal.widget.PasswordValidationError.CONTAINS_INVALID_CHARACTERS;
|
||||
@@ -71,6 +72,7 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ImeAwareEditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.TextView.OnEditorActionListener;
|
||||
@@ -86,7 +88,6 @@ import com.android.internal.widget.LockscreenCredential;
|
||||
import com.android.internal.widget.PasswordValidationError;
|
||||
import com.android.internal.widget.TextViewInputDisabler;
|
||||
import com.android.internal.widget.VerifyCredentialResponse;
|
||||
import com.android.settings.EncryptionInterstitial;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.SetupWizardUtils;
|
||||
@@ -102,7 +103,9 @@ import com.google.android.setupdesign.util.ThemeHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ChooseLockPassword extends SettingsActivity {
|
||||
private static final String TAG = "ChooseLockPassword";
|
||||
@@ -124,7 +127,6 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
public IntentBuilder(Context context) {
|
||||
mIntent = new Intent(context, ChooseLockPassword.class);
|
||||
mIntent.putExtra(ChooseLockGeneric.CONFIRM_CREDENTIALS, false);
|
||||
mIntent.putExtra(EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -224,6 +226,10 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
private static final String KEY_UI_STAGE = "ui_stage";
|
||||
private static final String KEY_CURRENT_CREDENTIAL = "current_credential";
|
||||
private static final String FRAGMENT_TAG_SAVE_AND_FINISH = "save_and_finish_worker";
|
||||
private static final String KEY_IS_AUTO_CONFIRM_CHECK_MANUALLY_CHANGED =
|
||||
"auto_confirm_option_set_manually";
|
||||
|
||||
private static final int MIN_AUTO_PIN_REQUIREMENT_LENGTH = 6;
|
||||
|
||||
private LockscreenCredential mCurrentCredential;
|
||||
private LockscreenCredential mChosenPassword;
|
||||
@@ -257,6 +263,9 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
protected FooterButton mSkipOrClearButton;
|
||||
private FooterButton mNextButton;
|
||||
private TextView mMessage;
|
||||
protected CheckBox mAutoPinConfirmOption;
|
||||
protected TextView mAutoConfirmSecurityMessage;
|
||||
protected boolean mIsAutoPinConfirmOptionSetManually;
|
||||
|
||||
private TextChangedHandler mTextChangedHandler;
|
||||
|
||||
@@ -461,21 +470,6 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
mMinMetrics = intent.getParcelableExtra(EXTRA_KEY_MIN_METRICS);
|
||||
if (mMinMetrics == null) mMinMetrics = new PasswordMetrics(CREDENTIAL_TYPE_NONE);
|
||||
|
||||
if (intent.getBooleanExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT, false)) {
|
||||
SaveAndFinishWorker w = new SaveAndFinishWorker();
|
||||
final boolean required = getActivity().getIntent().getBooleanExtra(
|
||||
EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
|
||||
LockscreenCredential currentCredential = intent.getParcelableExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
|
||||
|
||||
final LockPatternUtils utils = new LockPatternUtils(getActivity());
|
||||
|
||||
w.setBlocking(true);
|
||||
w.setListener(this);
|
||||
w.start(utils, required, false /* requestGatekeeperPassword */, currentCredential,
|
||||
currentCredential, mUserId);
|
||||
}
|
||||
mTextChangedHandler = new TextChangedHandler();
|
||||
}
|
||||
|
||||
@@ -532,6 +526,17 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
mPasswordEntry.requestFocus();
|
||||
mPasswordEntryInputDisabler = new TextViewInputDisabler(mPasswordEntry);
|
||||
|
||||
// Fetch the AutoPinConfirmOption
|
||||
mAutoPinConfirmOption = view.findViewById(R.id.auto_pin_confirm_enabler);
|
||||
mAutoConfirmSecurityMessage = view.findViewById(R.id.auto_pin_confirm_security_message);
|
||||
mIsAutoPinConfirmOptionSetManually = false;
|
||||
setOnAutoConfirmOptionClickListener();
|
||||
if (mAutoPinConfirmOption != null) {
|
||||
mAutoPinConfirmOption.setAccessibilityLiveRegion(ACCESSIBILITY_LIVE_REGION_POLITE);
|
||||
mAutoPinConfirmOption.setVisibility(View.GONE);
|
||||
mAutoPinConfirmOption.setChecked(false);
|
||||
}
|
||||
|
||||
final Activity activity = getActivity();
|
||||
|
||||
int currentType = mPasswordEntry.getInputType();
|
||||
@@ -577,6 +582,8 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
mUiStage = Stage.valueOf(state);
|
||||
updateStage(mUiStage);
|
||||
}
|
||||
mIsAutoPinConfirmOptionSetManually =
|
||||
savedInstanceState.getBoolean(KEY_IS_AUTO_CONFIRM_CHECK_MANUALLY_CHANGED);
|
||||
|
||||
mCurrentCredential = savedInstanceState.getParcelable(KEY_CURRENT_CREDENTIAL);
|
||||
|
||||
@@ -659,6 +666,8 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
if (mCurrentCredential != null) {
|
||||
outState.putParcelable(KEY_CURRENT_CREDENTIAL, mCurrentCredential.duplicate());
|
||||
}
|
||||
outState.putBoolean(KEY_IS_AUTO_CONFIRM_CHECK_MANUALLY_CHANGED,
|
||||
mIsAutoPinConfirmOptionSetManually);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -797,46 +806,50 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
messages.add(getString(R.string.lockpassword_illegal_character));
|
||||
break;
|
||||
case NOT_ENOUGH_UPPER_CASE:
|
||||
messages.add(getResources().getQuantityString(
|
||||
R.plurals.lockpassword_password_requires_uppercase,
|
||||
error.requirement, error.requirement));
|
||||
messages.add(StringUtil.getIcuPluralsString(getContext(), error.requirement,
|
||||
R.string.lockpassword_password_requires_uppercase));
|
||||
break;
|
||||
case NOT_ENOUGH_LOWER_CASE:
|
||||
messages.add(getResources().getQuantityString(
|
||||
R.plurals.lockpassword_password_requires_lowercase,
|
||||
error.requirement, error.requirement));
|
||||
messages.add(StringUtil.getIcuPluralsString(getContext(), error.requirement,
|
||||
R.string.lockpassword_password_requires_lowercase));
|
||||
break;
|
||||
case NOT_ENOUGH_LETTERS:
|
||||
messages.add(getResources().getQuantityString(
|
||||
R.plurals.lockpassword_password_requires_letters,
|
||||
error.requirement, error.requirement));
|
||||
messages.add(StringUtil.getIcuPluralsString(getContext(), error.requirement,
|
||||
R.string.lockpassword_password_requires_letters));
|
||||
break;
|
||||
case NOT_ENOUGH_DIGITS:
|
||||
messages.add(getResources().getQuantityString(
|
||||
R.plurals.lockpassword_password_requires_numeric,
|
||||
error.requirement, error.requirement));
|
||||
messages.add(StringUtil.getIcuPluralsString(getContext(), error.requirement,
|
||||
R.string.lockpassword_password_requires_numeric));
|
||||
break;
|
||||
case NOT_ENOUGH_SYMBOLS:
|
||||
messages.add(getResources().getQuantityString(
|
||||
R.plurals.lockpassword_password_requires_symbols,
|
||||
error.requirement, error.requirement));
|
||||
messages.add(StringUtil.getIcuPluralsString(getContext(), error.requirement,
|
||||
R.string.lockpassword_password_requires_symbols));
|
||||
break;
|
||||
case NOT_ENOUGH_NON_LETTER:
|
||||
messages.add(getResources().getQuantityString(
|
||||
R.plurals.lockpassword_password_requires_nonletter,
|
||||
error.requirement, error.requirement));
|
||||
messages.add(StringUtil.getIcuPluralsString(getContext(), error.requirement,
|
||||
R.string.lockpassword_password_requires_nonletter));
|
||||
break;
|
||||
case NOT_ENOUGH_NON_DIGITS:
|
||||
messages.add(getResources().getQuantityString(
|
||||
R.plurals.lockpassword_password_requires_nonnumerical,
|
||||
error.requirement, error.requirement));
|
||||
messages.add(StringUtil.getIcuPluralsString(getContext(), error.requirement,
|
||||
R.string.lockpassword_password_requires_nonnumerical));
|
||||
break;
|
||||
case TOO_SHORT:
|
||||
messages.add(getResources().getQuantityString(
|
||||
String message = StringUtil.getIcuPluralsString(getContext(),
|
||||
error.requirement,
|
||||
mIsAlphaMode
|
||||
? R.plurals.lockpassword_password_too_short
|
||||
: R.plurals.lockpassword_pin_too_short,
|
||||
error.requirement, error.requirement));
|
||||
? R.string.lockpassword_password_too_short
|
||||
: R.string.lockpassword_pin_too_short);
|
||||
if (LockPatternUtils.isAutoPinConfirmFeatureAvailable()
|
||||
&& !mIsAlphaMode
|
||||
&& error.requirement < MIN_AUTO_PIN_REQUIREMENT_LENGTH) {
|
||||
Map<String, Object> arguments = new HashMap<>();
|
||||
arguments.put("count", error.requirement);
|
||||
arguments.put("minAutoConfirmLen", MIN_AUTO_PIN_REQUIREMENT_LENGTH);
|
||||
message = StringUtil.getIcuPluralsString(getContext(),
|
||||
arguments,
|
||||
R.string.lockpassword_pin_too_short_autoConfirm_extra_message);
|
||||
}
|
||||
messages.add(message);
|
||||
break;
|
||||
case TOO_SHORT_WHEN_ALL_NUMERIC:
|
||||
messages.add(
|
||||
@@ -844,11 +857,10 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
R.string.lockpassword_password_too_short_all_numeric));
|
||||
break;
|
||||
case TOO_LONG:
|
||||
messages.add(getResources().getQuantityString(
|
||||
mIsAlphaMode
|
||||
? R.plurals.lockpassword_password_too_long
|
||||
: R.plurals.lockpassword_pin_too_long,
|
||||
error.requirement + 1, error.requirement + 1));
|
||||
messages.add(StringUtil.getIcuPluralsString(getContext(),
|
||||
error.requirement + 1, mIsAlphaMode
|
||||
? R.string.lockpassword_password_too_long
|
||||
: R.string.lockpassword_pin_too_long));
|
||||
break;
|
||||
case CONTAINS_SEQUENCE:
|
||||
messages.add(getString(R.string.lockpassword_pin_no_sequential_digits));
|
||||
@@ -890,6 +902,8 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
String[] messages = convertErrorCodeToMessages();
|
||||
// Update the fulfillment of requirements.
|
||||
mPasswordRequirementAdapter.setRequirements(messages);
|
||||
// set the visibility of pin_auto_confirm option accordingly
|
||||
setAutoPinConfirmOption(passwordCompliant, length);
|
||||
// Enable/Disable the next button accordingly.
|
||||
setNextEnabled(passwordCompliant);
|
||||
} else {
|
||||
@@ -899,6 +913,10 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
mIsManagedProfile));
|
||||
setNextEnabled(canInput && length >= LockPatternUtils.MIN_LOCK_PASSWORD_SIZE);
|
||||
mSkipOrClearButton.setVisibility(toVisibility(canInput && length > 0));
|
||||
|
||||
// Hide the pin_confirm option when we are just asking user to confirm the pwd.
|
||||
mAutoPinConfirmOption.setVisibility(View.GONE);
|
||||
mAutoConfirmSecurityMessage.setVisibility(View.GONE);
|
||||
}
|
||||
final int stage = getStageType();
|
||||
if (getStageType() != Stage.TYPE_NONE) {
|
||||
@@ -922,6 +940,36 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
return visibleOrGone ? View.VISIBLE : View.GONE;
|
||||
}
|
||||
|
||||
private void setAutoPinConfirmOption(boolean enabled, int length) {
|
||||
if (!LockPatternUtils.isAutoPinConfirmFeatureAvailable()
|
||||
|| mAutoPinConfirmOption == null) {
|
||||
return;
|
||||
}
|
||||
if (enabled && !mIsAlphaMode && isAutoPinConfirmPossible(length)) {
|
||||
mAutoPinConfirmOption.setVisibility(View.VISIBLE);
|
||||
mAutoConfirmSecurityMessage.setVisibility(View.VISIBLE);
|
||||
if (!mIsAutoPinConfirmOptionSetManually) {
|
||||
mAutoPinConfirmOption.setChecked(length == MIN_AUTO_PIN_REQUIREMENT_LENGTH);
|
||||
}
|
||||
} else {
|
||||
mAutoPinConfirmOption.setVisibility(View.GONE);
|
||||
mAutoConfirmSecurityMessage.setVisibility(View.GONE);
|
||||
mAutoPinConfirmOption.setChecked(false);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAutoPinConfirmPossible(int currentPinLength) {
|
||||
return currentPinLength >= MIN_AUTO_PIN_REQUIREMENT_LENGTH;
|
||||
}
|
||||
|
||||
private void setOnAutoConfirmOptionClickListener() {
|
||||
if (mAutoPinConfirmOption != null) {
|
||||
mAutoPinConfirmOption.setOnClickListener((v) -> {
|
||||
mIsAutoPinConfirmOptionSetManually = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void setHeaderText(String text) {
|
||||
// Only set the text if it is different than the existing one to avoid announcing again.
|
||||
if (!TextUtils.isEmpty(mLayout.getHeaderText())
|
||||
@@ -954,6 +1002,9 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
return;
|
||||
}
|
||||
|
||||
ConfirmDeviceCredentialUtils.hideImeImmediately(
|
||||
getActivity().getWindow().getDecorView());
|
||||
|
||||
mPasswordEntryInputDisabler.setInputEnabled(false);
|
||||
setNextEnabled(false);
|
||||
|
||||
@@ -965,8 +1016,6 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
getFragmentManager().executePendingTransactions();
|
||||
|
||||
final Intent intent = getActivity().getIntent();
|
||||
final boolean required = intent.getBooleanExtra(
|
||||
EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
|
||||
if (mUnificationProfileId != UserHandle.USER_NULL) {
|
||||
try (LockscreenCredential profileCredential = (LockscreenCredential)
|
||||
intent.getParcelableExtra(EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL)) {
|
||||
@@ -974,7 +1023,13 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
profileCredential);
|
||||
}
|
||||
}
|
||||
mSaveAndFinishWorker.start(mLockPatternUtils, required, mRequestGatekeeperPassword,
|
||||
// update the setting before triggering the password save workflow,
|
||||
// so that pinLength information is stored accordingly when setting is turned on.
|
||||
mLockPatternUtils.setAutoPinConfirm(
|
||||
(mAutoPinConfirmOption != null && mAutoPinConfirmOption.isChecked()),
|
||||
mUserId);
|
||||
|
||||
mSaveAndFinishWorker.start(mLockPatternUtils, mRequestGatekeeperPassword,
|
||||
mChosenPassword, mCurrentCredential, mUserId);
|
||||
}
|
||||
|
||||
@@ -1033,10 +1088,10 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
private LockscreenCredential mChosenPassword;
|
||||
private LockscreenCredential mCurrentCredential;
|
||||
|
||||
public void start(LockPatternUtils utils, boolean required,
|
||||
boolean requestGatekeeperPassword, LockscreenCredential chosenPassword,
|
||||
LockscreenCredential currentCredential, int userId) {
|
||||
prepare(utils, required, requestGatekeeperPassword, userId);
|
||||
public void start(LockPatternUtils utils, boolean requestGatekeeperPassword,
|
||||
LockscreenCredential chosenPassword, LockscreenCredential currentCredential,
|
||||
int userId) {
|
||||
prepare(utils, requestGatekeeperPassword, userId);
|
||||
|
||||
mChosenPassword = chosenPassword;
|
||||
mCurrentCredential = currentCredential != null ? currentCredential
|
||||
|
||||
@@ -54,7 +54,6 @@ import com.android.internal.widget.LockPatternView.Cell;
|
||||
import com.android.internal.widget.LockPatternView.DisplayMode;
|
||||
import com.android.internal.widget.LockscreenCredential;
|
||||
import com.android.internal.widget.VerifyCredentialResponse;
|
||||
import com.android.settings.EncryptionInterstitial;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.SetupWizardUtils;
|
||||
@@ -106,7 +105,6 @@ public class ChooseLockPattern extends SettingsActivity {
|
||||
|
||||
public IntentBuilder(Context context) {
|
||||
mIntent = new Intent(context, ChooseLockPattern.class);
|
||||
mIntent.putExtra(EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, false);
|
||||
mIntent.putExtra(ChooseLockGeneric.CONFIRM_CREDENTIALS, false);
|
||||
}
|
||||
|
||||
@@ -461,18 +459,6 @@ public class ChooseLockPattern extends SettingsActivity {
|
||||
|
||||
mLockPatternUtils = new LockPatternUtils(getActivity());
|
||||
|
||||
if (intent.getBooleanExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT, false)) {
|
||||
SaveAndFinishWorker w = new SaveAndFinishWorker();
|
||||
final boolean required = getActivity().getIntent().getBooleanExtra(
|
||||
EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
|
||||
LockscreenCredential current = intent.getParcelableExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
|
||||
w.setBlocking(true);
|
||||
w.setListener(this);
|
||||
w.start(mLockPatternUtils, required, false /* requestGatekeeperPassword */, current,
|
||||
current, mUserId);
|
||||
}
|
||||
mForFingerprint = intent.getBooleanExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
|
||||
mForFace = intent.getBooleanExtra(
|
||||
@@ -812,7 +798,12 @@ public class ChooseLockPattern extends SettingsActivity {
|
||||
// If the stage changed, announce the header for accessibility. This
|
||||
// is a no-op when accessibility is disabled.
|
||||
if (previousStage != stage || announceAlways) {
|
||||
mHeaderText.announceForAccessibility(mHeaderText.getText());
|
||||
if (stage == Stage.NeedToConfirm) {
|
||||
// If the Stage is NeedToConfirm, move the a11y focus to the header.
|
||||
mHeaderText.requestAccessibilityFocus();
|
||||
} else {
|
||||
mHeaderText.announceForAccessibility(mHeaderText.getText());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -849,8 +840,6 @@ public class ChooseLockPattern extends SettingsActivity {
|
||||
getFragmentManager().executePendingTransactions();
|
||||
|
||||
final Intent intent = getActivity().getIntent();
|
||||
final boolean required = intent.getBooleanExtra(
|
||||
EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
|
||||
if (intent.hasExtra(EXTRA_KEY_UNIFICATION_PROFILE_ID)) {
|
||||
try (LockscreenCredential profileCredential = (LockscreenCredential)
|
||||
intent.getParcelableExtra(EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL)) {
|
||||
@@ -860,8 +849,8 @@ public class ChooseLockPattern extends SettingsActivity {
|
||||
profileCredential);
|
||||
}
|
||||
}
|
||||
mSaveAndFinishWorker.start(mLockPatternUtils, required,
|
||||
mRequestGatekeeperPassword, mChosenPattern, mCurrentCredential, mUserId);
|
||||
mSaveAndFinishWorker.start(mLockPatternUtils, mRequestGatekeeperPassword,
|
||||
mChosenPattern, mCurrentCredential, mUserId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -890,10 +879,10 @@ public class ChooseLockPattern extends SettingsActivity {
|
||||
private LockscreenCredential mChosenPattern;
|
||||
private LockscreenCredential mCurrentCredential;
|
||||
|
||||
public void start(LockPatternUtils utils, boolean credentialRequired,
|
||||
boolean requestGatekeeperPassword, LockscreenCredential chosenPattern,
|
||||
LockscreenCredential currentCredential, int userId) {
|
||||
prepare(utils, credentialRequired, requestGatekeeperPassword, userId);
|
||||
public void start(LockPatternUtils utils, boolean requestGatekeeperPassword,
|
||||
LockscreenCredential chosenPattern, LockscreenCredential currentCredential,
|
||||
int userId) {
|
||||
prepare(utils, requestGatekeeperPassword, userId);
|
||||
|
||||
mCurrentCredential = currentCredential != null ? currentCredential
|
||||
: LockscreenCredential.createNone();
|
||||
|
||||
@@ -21,10 +21,14 @@ import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityOptions;
|
||||
import android.app.KeyguardManager;
|
||||
import android.app.RemoteLockscreenValidationSession;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserManager;
|
||||
import android.util.Log;
|
||||
|
||||
@@ -41,6 +45,8 @@ import com.android.settingslib.transition.SettingsTransitionHelper;
|
||||
|
||||
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public final class ChooseLockSettingsHelper {
|
||||
|
||||
private static final String TAG = "ChooseLockSettingsHelper";
|
||||
@@ -58,7 +64,8 @@ public final class ChooseLockSettingsHelper {
|
||||
public static final String EXTRA_KEY_FOR_FACE = "for_face";
|
||||
// For the paths where multiple biometric sensors exist
|
||||
public static final String EXTRA_KEY_FOR_BIOMETRICS = "for_biometrics";
|
||||
public static final String EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT = "for_cred_req_boot";
|
||||
// For the paths where setup biometrics in suw flow
|
||||
public static final String EXTRA_KEY_IS_SUW = "is_suw";
|
||||
public static final String EXTRA_KEY_FOREGROUND_ONLY = "foreground_only";
|
||||
public static final String EXTRA_KEY_REQUEST_GK_PW_HANDLE = "request_gk_pw_handle";
|
||||
// Gatekeeper password handle, which can subsequently be used to generate Gatekeeper
|
||||
@@ -133,6 +140,7 @@ public final class ChooseLockSettingsHelper {
|
||||
@Nullable private CharSequence mHeader;
|
||||
@Nullable private CharSequence mDescription;
|
||||
@Nullable private CharSequence mAlternateButton;
|
||||
@Nullable private CharSequence mCheckBoxLabel;
|
||||
private boolean mReturnCredentials;
|
||||
private boolean mExternal;
|
||||
private boolean mForegroundOnly;
|
||||
@@ -140,7 +148,11 @@ public final class ChooseLockSettingsHelper {
|
||||
private int mUserId;
|
||||
private boolean mAllowAnyUserId;
|
||||
private boolean mForceVerifyPath;
|
||||
boolean mRequestGatekeeperPasswordHandle;
|
||||
private boolean mRemoteLockscreenValidation;
|
||||
@Nullable private RemoteLockscreenValidationSession mRemoteLockscreenValidationSession;
|
||||
@Nullable private ComponentName mRemoteLockscreenValidationServiceComponent;
|
||||
private boolean mRequestGatekeeperPasswordHandle;
|
||||
private boolean mTaskOverlay;
|
||||
|
||||
public Builder(@NonNull Activity activity) {
|
||||
mActivity = activity;
|
||||
@@ -192,6 +204,15 @@ public final class ChooseLockSettingsHelper {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param checkboxLabel text for the checkbox
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setCheckboxLabel(@Nullable CharSequence checkboxLabel) {
|
||||
mCheckBoxLabel = checkboxLabel;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param returnCredentials if true, puts the following credentials into intent for
|
||||
* onActivityResult with the following keys:
|
||||
@@ -236,6 +257,14 @@ public final class ChooseLockSettingsHelper {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param taskOverlay specifies whether the activity should be launched as a task overlay.
|
||||
*/
|
||||
@NonNull public Builder setTaskOverlay(boolean taskOverlay) {
|
||||
mTaskOverlay = taskOverlay;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param foregroundOnly if true, the confirmation activity will be finished if it loses
|
||||
* foreground.
|
||||
@@ -254,6 +283,42 @@ public final class ChooseLockSettingsHelper {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isRemoteLockscreenValidation if true, remote device validation flow will be
|
||||
* started. {@link #setRemoteLockscreenValidationSession},
|
||||
* {@link #setRemoteLockscreenValidationServiceComponent}
|
||||
* must also be used to set the required data.
|
||||
*/
|
||||
@NonNull public Builder setRemoteLockscreenValidation(
|
||||
boolean isRemoteLockscreenValidation) {
|
||||
mRemoteLockscreenValidation = isRemoteLockscreenValidation;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param remoteLockscreenValidationSession contains information necessary to perform remote
|
||||
* lockscreen validation such as the remote device's
|
||||
* lockscreen type, public key to be used for
|
||||
* encryption, and remaining attempts.
|
||||
*/
|
||||
@NonNull public Builder setRemoteLockscreenValidationSession(
|
||||
RemoteLockscreenValidationSession remoteLockscreenValidationSession) {
|
||||
mRemoteLockscreenValidationSession = remoteLockscreenValidationSession;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param remoteLockscreenValidationServiceComponent the {@link ComponentName} of the
|
||||
* {@link android.service.remotelockscreenvalidation.RemoteLockscreenValidationService}
|
||||
* that will be used to validate the lockscreen guess.
|
||||
*/
|
||||
@NonNull public Builder setRemoteLockscreenValidationServiceComponent(
|
||||
ComponentName remoteLockscreenValidationServiceComponent) {
|
||||
mRemoteLockscreenValidationServiceComponent =
|
||||
remoteLockscreenValidationServiceComponent;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that LockSettingsService return a handle to the Gatekeeper Password (instead of
|
||||
* the Gatekeeper HAT). This allows us to use a single entry of the user's credential
|
||||
@@ -287,7 +352,7 @@ public final class ChooseLockSettingsHelper {
|
||||
Utils.enforceSameOwner(mActivity, mUserId);
|
||||
}
|
||||
|
||||
if (mExternal && mReturnCredentials) {
|
||||
if (mExternal && mReturnCredentials && !mRemoteLockscreenValidation) {
|
||||
throw new IllegalArgumentException("External and ReturnCredentials specified. "
|
||||
+ " External callers should never be allowed to receive credentials in"
|
||||
+ " onActivityResult");
|
||||
@@ -316,49 +381,44 @@ public final class ChooseLockSettingsHelper {
|
||||
return launchConfirmationActivity(mBuilder.mRequestCode, mBuilder.mTitle, mBuilder.mHeader,
|
||||
mBuilder.mDescription, mBuilder.mReturnCredentials, mBuilder.mExternal,
|
||||
mBuilder.mForceVerifyPath, mBuilder.mUserId, mBuilder.mAlternateButton,
|
||||
mBuilder.mAllowAnyUserId, mBuilder.mForegroundOnly,
|
||||
mBuilder.mRequestGatekeeperPasswordHandle);
|
||||
mBuilder.mCheckBoxLabel, mBuilder.mRemoteLockscreenValidation,
|
||||
mBuilder.mRemoteLockscreenValidationSession,
|
||||
mBuilder.mRemoteLockscreenValidationServiceComponent, mBuilder.mAllowAnyUserId,
|
||||
mBuilder.mForegroundOnly, mBuilder.mRequestGatekeeperPasswordHandle,
|
||||
mBuilder.mTaskOverlay);
|
||||
}
|
||||
|
||||
private boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
|
||||
@Nullable CharSequence header, @Nullable CharSequence description,
|
||||
boolean returnCredentials, boolean external, boolean forceVerifyPath,
|
||||
int userId, @Nullable CharSequence alternateButton, boolean allowAnyUser,
|
||||
boolean foregroundOnly, boolean requestGatekeeperPasswordHandle) {
|
||||
final int effectiveUserId = UserManager.get(mActivity).getCredentialOwnerProfile(userId);
|
||||
boolean launched = false;
|
||||
|
||||
switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(effectiveUserId)) {
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
|
||||
launched = launchConfirmationActivity(request, title, header, description,
|
||||
returnCredentials || forceVerifyPath
|
||||
? ConfirmLockPattern.InternalActivity.class
|
||||
: ConfirmLockPattern.class, returnCredentials, external,
|
||||
forceVerifyPath, userId, alternateButton, allowAnyUser,
|
||||
foregroundOnly, requestGatekeeperPasswordHandle);
|
||||
break;
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
|
||||
launched = launchConfirmationActivity(request, title, header, description,
|
||||
returnCredentials || forceVerifyPath
|
||||
? ConfirmLockPassword.InternalActivity.class
|
||||
: ConfirmLockPassword.class, returnCredentials, external,
|
||||
forceVerifyPath, userId, alternateButton, allowAnyUser,
|
||||
foregroundOnly, requestGatekeeperPasswordHandle);
|
||||
break;
|
||||
int userId, @Nullable CharSequence alternateButton,
|
||||
@Nullable CharSequence checkboxLabel, boolean remoteLockscreenValidation,
|
||||
@Nullable RemoteLockscreenValidationSession remoteLockscreenValidationSession,
|
||||
@Nullable ComponentName remoteLockscreenValidationServiceComponent,
|
||||
boolean allowAnyUser, boolean foregroundOnly, boolean requestGatekeeperPasswordHandle,
|
||||
boolean taskOverlay) {
|
||||
Optional<Class<?>> activityClass = determineAppropriateActivityClass(
|
||||
returnCredentials, forceVerifyPath, userId, remoteLockscreenValidationSession);
|
||||
if (activityClass.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return launched;
|
||||
|
||||
return launchConfirmationActivity(request, title, header, description, activityClass.get(),
|
||||
returnCredentials, external, forceVerifyPath, userId, alternateButton,
|
||||
checkboxLabel, remoteLockscreenValidation, remoteLockscreenValidationSession,
|
||||
remoteLockscreenValidationServiceComponent, allowAnyUser, foregroundOnly,
|
||||
requestGatekeeperPasswordHandle, taskOverlay);
|
||||
}
|
||||
|
||||
private boolean launchConfirmationActivity(int request, CharSequence title, CharSequence header,
|
||||
CharSequence message, Class<?> activityClass, boolean returnCredentials,
|
||||
boolean external, boolean forceVerifyPath, int userId,
|
||||
@Nullable CharSequence alternateButton, boolean allowAnyUser,
|
||||
boolean foregroundOnly, boolean requestGatekeeperPasswordHandle) {
|
||||
@Nullable CharSequence alternateButton, @Nullable CharSequence checkbox,
|
||||
boolean remoteLockscreenValidation,
|
||||
@Nullable RemoteLockscreenValidationSession remoteLockscreenValidationSession,
|
||||
@Nullable ComponentName remoteLockscreenValidationServiceComponent,
|
||||
boolean allowAnyUser, boolean foregroundOnly, boolean requestGatekeeperPasswordHandle,
|
||||
boolean taskOverlay) {
|
||||
final Intent intent = new Intent();
|
||||
intent.putExtra(ConfirmDeviceCredentialBaseFragment.TITLE_TEXT, title);
|
||||
intent.putExtra(ConfirmDeviceCredentialBaseFragment.HEADER_TEXT, header);
|
||||
@@ -368,10 +428,16 @@ public final class ChooseLockSettingsHelper {
|
||||
intent.putExtra(ConfirmDeviceCredentialBaseFragment.SHOW_CANCEL_BUTTON, false);
|
||||
intent.putExtra(ConfirmDeviceCredentialBaseFragment.SHOW_WHEN_LOCKED, external);
|
||||
intent.putExtra(ConfirmDeviceCredentialBaseFragment.USE_FADE_ANIMATION, external);
|
||||
intent.putExtra(ConfirmDeviceCredentialBaseFragment.IS_REMOTE_LOCKSCREEN_VALIDATION,
|
||||
remoteLockscreenValidation);
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_RETURN_CREDENTIALS, returnCredentials);
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FORCE_VERIFY, forceVerifyPath);
|
||||
intent.putExtra(Intent.EXTRA_USER_ID, userId);
|
||||
intent.putExtra(KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL, alternateButton);
|
||||
intent.putExtra(KeyguardManager.EXTRA_CHECKBOX_LABEL, checkbox);
|
||||
intent.putExtra(KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION,
|
||||
remoteLockscreenValidationSession);
|
||||
intent.putExtra(Intent.EXTRA_COMPONENT_NAME, remoteLockscreenValidationServiceComponent);
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOREGROUND_ONLY, foregroundOnly);
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_ALLOW_ANY_USER, allowAnyUser);
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE,
|
||||
@@ -384,28 +450,91 @@ public final class ChooseLockSettingsHelper {
|
||||
Intent inIntent = mFragment != null ? mFragment.getActivity().getIntent() :
|
||||
mActivity.getIntent();
|
||||
copyInternalExtras(inIntent, intent);
|
||||
Bundle launchOptions = createLaunchOptions(taskOverlay);
|
||||
if (external) {
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
|
||||
copyOptionalExtras(inIntent, intent);
|
||||
if (mActivityResultLauncher != null) {
|
||||
mActivityResultLauncher.launch(intent);
|
||||
} else if (mFragment != null) {
|
||||
mFragment.startActivity(intent);
|
||||
mFragment.startActivity(intent, launchOptions);
|
||||
} else {
|
||||
mActivity.startActivity(intent);
|
||||
mActivity.startActivity(intent, launchOptions);
|
||||
}
|
||||
} else {
|
||||
if (mActivityResultLauncher != null) {
|
||||
mActivityResultLauncher.launch(intent);
|
||||
} else if (mFragment != null) {
|
||||
mFragment.startActivityForResult(intent, request);
|
||||
mFragment.startActivityForResult(intent, request, launchOptions);
|
||||
} else {
|
||||
mActivity.startActivityForResult(intent, request);
|
||||
mActivity.startActivityForResult(intent, request, launchOptions);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private Bundle createLaunchOptions(boolean taskOverlay) {
|
||||
if (!taskOverlay) {
|
||||
return null;
|
||||
}
|
||||
ActivityOptions options = ActivityOptions.makeBasic();
|
||||
options.setLaunchTaskId(mActivity.getTaskId());
|
||||
options.setTaskOverlay(true /* taskOverlay */, true /* canResume */);
|
||||
return options.toBundle();
|
||||
}
|
||||
|
||||
private Optional<Integer> passwordQualityToLockTypes(int quality) {
|
||||
switch (quality) {
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
|
||||
return Optional.of(KeyguardManager.PATTERN);
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
|
||||
return Optional.of(KeyguardManager.PIN);
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
|
||||
return Optional.of(KeyguardManager.PASSWORD);
|
||||
}
|
||||
Log.e(TAG, String.format(
|
||||
"Cannot determine appropriate activity class for password quality %d",
|
||||
quality));
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private Optional<Class<?>> determineAppropriateActivityClass(boolean returnCredentials,
|
||||
boolean forceVerifyPath, int userId,
|
||||
@Nullable RemoteLockscreenValidationSession remoteLockscreenValidationSession) {
|
||||
int lockType;
|
||||
if (remoteLockscreenValidationSession != null) {
|
||||
lockType = remoteLockscreenValidationSession.getLockType();
|
||||
} else {
|
||||
final int effectiveUserId = UserManager
|
||||
.get(mActivity).getCredentialOwnerProfile(userId);
|
||||
Optional<Integer> lockTypeOptional = passwordQualityToLockTypes(
|
||||
mLockPatternUtils.getKeyguardStoredPasswordQuality(effectiveUserId));
|
||||
if (lockTypeOptional.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
lockType = lockTypeOptional.get();
|
||||
}
|
||||
|
||||
switch (lockType) {
|
||||
case KeyguardManager.PASSWORD:
|
||||
case KeyguardManager.PIN:
|
||||
return Optional.of(returnCredentials || forceVerifyPath
|
||||
? ConfirmLockPassword.InternalActivity.class
|
||||
: ConfirmLockPassword.class);
|
||||
case KeyguardManager.PATTERN:
|
||||
return Optional.of(returnCredentials || forceVerifyPath
|
||||
? ConfirmLockPattern.InternalActivity.class
|
||||
: ConfirmLockPattern.class);
|
||||
}
|
||||
Log.e(TAG, String.format("Cannot determine appropriate activity class for lock type %d",
|
||||
lockType));
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private void copyOptionalExtras(Intent inIntent, Intent outIntent) {
|
||||
IntentSender intentSender = inIntent.getParcelableExtra(Intent.EXTRA_INTENT);
|
||||
if (intentSender != null) {
|
||||
|
||||
@@ -24,12 +24,12 @@ import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROF
|
||||
import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_CONFIRM_PATTERN;
|
||||
import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_CONFIRM_PIN;
|
||||
|
||||
import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.KeyguardManager;
|
||||
import android.app.RemoteLockscreenValidationSession;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.app.trust.TrustManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
@@ -61,13 +61,6 @@ import java.util.concurrent.Executor;
|
||||
public class ConfirmDeviceCredentialActivity extends FragmentActivity {
|
||||
public static final String TAG = ConfirmDeviceCredentialActivity.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* If the intent is sent from {@link com.android.systemui.keyguard.WorkLockActivityController}
|
||||
* then check for device policy management flags.
|
||||
*/
|
||||
public static final String EXTRA_FROM_WORK_LOCK_ACTIVITY_CONTROLLER =
|
||||
"from_work_lock_activity_controller";
|
||||
|
||||
// The normal flow that apps go through
|
||||
private static final int CREDENTIAL_NORMAL = 1;
|
||||
// Unlocks the managed profile when the primary profile is unlocked
|
||||
@@ -78,15 +71,6 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
|
||||
public static class InternalActivity extends ConfirmDeviceCredentialActivity {
|
||||
}
|
||||
|
||||
public static Intent createIntent(CharSequence title, CharSequence details) {
|
||||
Intent intent = new Intent();
|
||||
intent.setClassName(SETTINGS_PACKAGE_NAME,
|
||||
ConfirmDeviceCredentialActivity.class.getName());
|
||||
intent.putExtra(KeyguardManager.EXTRA_TITLE, title);
|
||||
intent.putExtra(KeyguardManager.EXTRA_DESCRIPTION, details);
|
||||
return intent;
|
||||
}
|
||||
|
||||
private BiometricFragment mBiometricFragment;
|
||||
private DevicePolicyManager mDevicePolicyManager;
|
||||
private LockPatternUtils mLockPatternUtils;
|
||||
@@ -95,9 +79,10 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
|
||||
private Handler mHandler = new Handler(Looper.getMainLooper());
|
||||
private Context mContext;
|
||||
private boolean mCheckDevicePolicyManager;
|
||||
private boolean mTaskOverlay;
|
||||
|
||||
private String mTitle;
|
||||
private String mDetails;
|
||||
private CharSequence mDetails;
|
||||
private int mUserId;
|
||||
private int mCredentialMode;
|
||||
private boolean mGoingToBackground;
|
||||
@@ -178,10 +163,14 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
|
||||
mCheckDevicePolicyManager = intent
|
||||
.getBooleanExtra(KeyguardManager.EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS, false);
|
||||
mTitle = intent.getStringExtra(KeyguardManager.EXTRA_TITLE);
|
||||
mDetails = intent.getStringExtra(KeyguardManager.EXTRA_DESCRIPTION);
|
||||
mDetails = intent.getCharSequenceExtra(KeyguardManager.EXTRA_DESCRIPTION);
|
||||
String alternateButton = intent.getStringExtra(
|
||||
KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL);
|
||||
boolean frp = KeyguardManager.ACTION_CONFIRM_FRP_CREDENTIAL.equals(intent.getAction());
|
||||
boolean remoteValidation =
|
||||
KeyguardManager.ACTION_CONFIRM_REMOTE_DEVICE_CREDENTIAL.equals(intent.getAction());
|
||||
mTaskOverlay = isInternalActivity()
|
||||
&& intent.getBooleanExtra(KeyguardManager.EXTRA_FORCE_TASK_OVERLAY, false);
|
||||
|
||||
mUserId = UserHandle.myUserId();
|
||||
if (isInternalActivity()) {
|
||||
@@ -230,6 +219,31 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
|
||||
.setExternal(true)
|
||||
.setUserId(LockPatternUtils.USER_FRP)
|
||||
.show();
|
||||
} else if (remoteValidation) {
|
||||
RemoteLockscreenValidationSession remoteLockscreenValidationSession =
|
||||
intent.getParcelableExtra(
|
||||
KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION,
|
||||
RemoteLockscreenValidationSession.class);
|
||||
ComponentName remoteLockscreenValidationServiceComponent =
|
||||
intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME, ComponentName.class);
|
||||
|
||||
String checkboxLabel = intent.getStringExtra(KeyguardManager.EXTRA_CHECKBOX_LABEL);
|
||||
final ChooseLockSettingsHelper.Builder builder =
|
||||
new ChooseLockSettingsHelper.Builder(this);
|
||||
launchedCDC = builder
|
||||
.setRemoteLockscreenValidation(true)
|
||||
.setRemoteLockscreenValidationSession(remoteLockscreenValidationSession)
|
||||
.setRemoteLockscreenValidationServiceComponent(
|
||||
remoteLockscreenValidationServiceComponent)
|
||||
.setRequestGatekeeperPasswordHandle(true)
|
||||
.setReturnCredentials(true) // returns only password handle.
|
||||
.setHeader(mTitle) // Show the title in the header location
|
||||
.setDescription(mDetails)
|
||||
.setCheckboxLabel(checkboxLabel)
|
||||
.setAlternateButton(alternateButton)
|
||||
.setExternal(true)
|
||||
.show();
|
||||
return;
|
||||
} else if (isEffectiveUserManagedProfile && isInternalActivity()) {
|
||||
mCredentialMode = CREDENTIAL_MANAGED;
|
||||
if (isBiometricAllowed(effectiveUserId, mUserId)) {
|
||||
@@ -391,6 +405,12 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
|
||||
*/
|
||||
private void showConfirmCredentials() {
|
||||
boolean launched = false;
|
||||
ChooseLockSettingsHelper.Builder builder = new ChooseLockSettingsHelper.Builder(this)
|
||||
.setHeader(mTitle)
|
||||
.setDescription(mDetails)
|
||||
.setExternal(true)
|
||||
.setUserId(mUserId)
|
||||
.setTaskOverlay(mTaskOverlay);
|
||||
// The only difference between CREDENTIAL_MANAGED and CREDENTIAL_NORMAL is that for
|
||||
// CREDENTIAL_MANAGED, we launch the real confirm credential activity with an explicit
|
||||
// but fake challenge value (0L). This will result in ConfirmLockPassword calling
|
||||
@@ -403,22 +423,9 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
|
||||
// LockPatternChecker and LockPatternUtils. verifyPassword should be the only API to use,
|
||||
// which optionally accepts a challenge.
|
||||
if (mCredentialMode == CREDENTIAL_MANAGED) {
|
||||
final ChooseLockSettingsHelper.Builder builder =
|
||||
new ChooseLockSettingsHelper.Builder(this);
|
||||
launched = builder.setHeader(mTitle)
|
||||
.setDescription(mDetails)
|
||||
.setExternal(true)
|
||||
.setUserId(mUserId)
|
||||
.setForceVerifyPath(true)
|
||||
.show();
|
||||
launched = builder.setForceVerifyPath(true).show();
|
||||
} else if (mCredentialMode == CREDENTIAL_NORMAL) {
|
||||
final ChooseLockSettingsHelper.Builder builder =
|
||||
new ChooseLockSettingsHelper.Builder(this);
|
||||
launched = builder.setHeader(mTitle) // Show the title string in the header area
|
||||
.setDescription(mDetails)
|
||||
.setExternal(true)
|
||||
.setUserId(mUserId)
|
||||
.show();
|
||||
launched = builder.show();
|
||||
}
|
||||
if (!launched) {
|
||||
Log.d(TAG, "No pin/pattern/pass set");
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
// TODO (b/35202196): move this class out of the root of the package.
|
||||
package com.android.settings.password;
|
||||
|
||||
import static android.app.Activity.RESULT_FIRST_USER;
|
||||
import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LOCK_ATTEMPTS_FAILED;
|
||||
|
||||
import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
|
||||
@@ -24,7 +25,10 @@ import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.Dialog;
|
||||
import android.app.KeyguardManager;
|
||||
import android.app.RemoteLockscreenValidationSession;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.app.admin.ManagedSubscriptionsPolicy;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
@@ -34,10 +38,14 @@ import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.service.remotelockscreenvalidation.RemoteLockscreenValidationClient;
|
||||
import android.telecom.TelecomManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.FeatureFlagUtils;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
@@ -45,10 +53,13 @@ import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.internal.widget.LockscreenCredential;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.core.InstrumentedFragment;
|
||||
|
||||
import com.google.android.setupdesign.GlifLayout;
|
||||
|
||||
/**
|
||||
* Base fragment to be shared for PIN/Pattern/Password confirmation fragments.
|
||||
*/
|
||||
@@ -64,6 +75,8 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
|
||||
SETTINGS_PACKAGE_NAME + ".ConfirmCredentials.showWhenLocked";
|
||||
public static final String USE_FADE_ANIMATION =
|
||||
SETTINGS_PACKAGE_NAME + ".ConfirmCredentials.useFadeAnimation";
|
||||
public static final String IS_REMOTE_LOCKSCREEN_VALIDATION =
|
||||
SETTINGS_PACKAGE_NAME + ".ConfirmCredentials.isRemoteLockscreenValidation";
|
||||
|
||||
protected static final int USER_TYPE_PRIMARY = 1;
|
||||
protected static final int USER_TYPE_MANAGED_PROFILE = 2;
|
||||
@@ -72,9 +85,14 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
|
||||
/** Time we wait before clearing a wrong input attempt (e.g. pattern) and the error message. */
|
||||
protected static final long CLEAR_WRONG_ATTEMPT_TIMEOUT_MS = 3000;
|
||||
|
||||
protected static final String FRAGMENT_TAG_REMOTE_LOCKSCREEN_VALIDATION =
|
||||
"remote_lockscreen_validation";
|
||||
|
||||
protected boolean mReturnCredentials = false;
|
||||
protected boolean mReturnGatekeeperPassword = false;
|
||||
protected boolean mForceVerifyPath = false;
|
||||
protected GlifLayout mGlifLayout;
|
||||
protected CheckBox mCheckBox;
|
||||
protected Button mCancelButton;
|
||||
/** Button allowing managed profile password reset, null when is not shown. */
|
||||
@Nullable protected Button mForgotButton;
|
||||
@@ -86,8 +104,13 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
|
||||
protected TextView mErrorTextView;
|
||||
protected final Handler mHandler = new Handler();
|
||||
protected boolean mFrp;
|
||||
private CharSequence mFrpAlternateButtonText;
|
||||
protected boolean mRemoteValidation;
|
||||
protected CharSequence mAlternateButtonText;
|
||||
protected BiometricManager mBiometricManager;
|
||||
@Nullable protected RemoteLockscreenValidationSession mRemoteLockscreenValidationSession;
|
||||
/** Credential saved so the credential can be set for device if remote validation passes */
|
||||
@Nullable protected RemoteLockscreenValidationClient mRemoteLockscreenValidationClient;
|
||||
protected RemoteLockscreenValidationFragment mRemoteLockscreenValidationFragment;
|
||||
|
||||
private boolean isInternalActivity() {
|
||||
return (getActivity() instanceof ConfirmLockPassword.InternalActivity)
|
||||
@@ -98,7 +121,7 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
final Intent intent = getActivity().getIntent();
|
||||
mFrpAlternateButtonText = intent.getCharSequenceExtra(
|
||||
mAlternateButtonText = intent.getCharSequenceExtra(
|
||||
KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL);
|
||||
mReturnCredentials = intent.getBooleanExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_RETURN_CREDENTIALS, false);
|
||||
@@ -108,6 +131,49 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
|
||||
mForceVerifyPath = intent.getBooleanExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_FORCE_VERIFY, false);
|
||||
|
||||
if (intent.getBooleanExtra(IS_REMOTE_LOCKSCREEN_VALIDATION, false)) {
|
||||
if (FeatureFlagUtils.isEnabled(getContext(),
|
||||
FeatureFlagUtils.SETTINGS_REMOTE_DEVICE_CREDENTIAL_VALIDATION)) {
|
||||
mRemoteValidation = true;
|
||||
} else {
|
||||
onRemoteLockscreenValidationFailure(
|
||||
"Remote lockscreen validation not enabled.");
|
||||
}
|
||||
}
|
||||
if (mRemoteValidation) {
|
||||
mRemoteLockscreenValidationSession = intent.getParcelableExtra(
|
||||
KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION,
|
||||
RemoteLockscreenValidationSession.class);
|
||||
if (mRemoteLockscreenValidationSession == null
|
||||
|| mRemoteLockscreenValidationSession.getRemainingAttempts() == 0) {
|
||||
onRemoteLockscreenValidationFailure("RemoteLockscreenValidationSession is null or "
|
||||
+ "no more attempts for remote lockscreen validation.");
|
||||
}
|
||||
|
||||
ComponentName remoteLockscreenValidationServiceComponent =
|
||||
intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME, ComponentName.class);
|
||||
if (remoteLockscreenValidationServiceComponent == null) {
|
||||
onRemoteLockscreenValidationFailure(
|
||||
"RemoteLockscreenValidationService ComponentName is null");
|
||||
}
|
||||
mRemoteLockscreenValidationClient = RemoteLockscreenValidationClient
|
||||
.create(getContext(), remoteLockscreenValidationServiceComponent);
|
||||
if (!mRemoteLockscreenValidationClient.isServiceAvailable()) {
|
||||
onRemoteLockscreenValidationFailure(String.format(
|
||||
"RemoteLockscreenValidationService at %s is not available",
|
||||
remoteLockscreenValidationServiceComponent.getClassName()));
|
||||
}
|
||||
|
||||
mRemoteLockscreenValidationFragment =
|
||||
(RemoteLockscreenValidationFragment) getFragmentManager()
|
||||
.findFragmentByTag(FRAGMENT_TAG_REMOTE_LOCKSCREEN_VALIDATION);
|
||||
if (mRemoteLockscreenValidationFragment == null) {
|
||||
mRemoteLockscreenValidationFragment = new RemoteLockscreenValidationFragment();
|
||||
getFragmentManager().beginTransaction().add(mRemoteLockscreenValidationFragment,
|
||||
FRAGMENT_TAG_REMOTE_LOCKSCREEN_VALIDATION).commit();
|
||||
}
|
||||
}
|
||||
|
||||
// Only take this argument into account if it belongs to the current profile.
|
||||
mUserId = Utils.getUserIdFromBundle(getActivity(), intent.getExtras(),
|
||||
isInternalActivity());
|
||||
@@ -124,21 +190,54 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
mCancelButton = view.findViewById(R.id.cancelButton);
|
||||
boolean showCancelButton = getActivity().getIntent().getBooleanExtra(
|
||||
boolean showCancelButton = mRemoteValidation || getActivity().getIntent().getBooleanExtra(
|
||||
SHOW_CANCEL_BUTTON, false);
|
||||
boolean hasAlternateButton = mFrp && !TextUtils.isEmpty(mFrpAlternateButtonText);
|
||||
boolean hasAlternateButton = (mFrp || mRemoteValidation) && !TextUtils.isEmpty(
|
||||
mAlternateButtonText);
|
||||
mCancelButton.setVisibility(showCancelButton || hasAlternateButton
|
||||
? View.VISIBLE : View.GONE);
|
||||
if (hasAlternateButton) {
|
||||
mCancelButton.setText(mFrpAlternateButtonText);
|
||||
mCancelButton.setText(mAlternateButtonText);
|
||||
}
|
||||
mCancelButton.setOnClickListener(v -> {
|
||||
if (hasAlternateButton) {
|
||||
getActivity().setResult(KeyguardManager.RESULT_ALTERNATE);
|
||||
getActivity().finish();
|
||||
} else if (mRemoteValidation) {
|
||||
onRemoteLockscreenValidationFailure("Forgot lockscreen credential button pressed.");
|
||||
}
|
||||
getActivity().finish();
|
||||
});
|
||||
setupForgotButtonIfManagedProfile(view);
|
||||
|
||||
mCheckBox = view.findViewById(R.id.checkbox);
|
||||
if (mCheckBox != null && mRemoteValidation) {
|
||||
mCheckBox.setVisibility(View.VISIBLE);
|
||||
}
|
||||
setupEmergencyCallButtonIfManagedSubscription(view);
|
||||
}
|
||||
|
||||
private void setupEmergencyCallButtonIfManagedSubscription(View view) {
|
||||
int policyType = getContext().getSystemService(
|
||||
DevicePolicyManager.class).getManagedSubscriptionsPolicy().getPolicyType();
|
||||
|
||||
if (policyType == ManagedSubscriptionsPolicy.TYPE_ALL_MANAGED_SUBSCRIPTIONS) {
|
||||
Button emergencyCallButton = view.findViewById(R.id.emergencyCallButton);
|
||||
if (emergencyCallButton == null) {
|
||||
Log.wtf(TAG,
|
||||
"Emergency call button not found in managed profile credential dialog");
|
||||
return;
|
||||
}
|
||||
emergencyCallButton.setVisibility(View.VISIBLE);
|
||||
emergencyCallButton.setOnClickListener(v -> {
|
||||
final Intent intent = getActivity()
|
||||
.getSystemService(TelecomManager.class)
|
||||
.createLaunchEmergencyDialerIntent(null)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
getActivity().startActivity(intent);
|
||||
getActivity().finish();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void setupForgotButtonIfManagedProfile(View view) {
|
||||
@@ -205,8 +304,15 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
protected abstract void authenticationSucceeded();
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (mRemoteLockscreenValidationClient != null) {
|
||||
mRemoteLockscreenValidationClient.disconnect();
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
protected abstract void authenticationSucceeded();
|
||||
|
||||
public void prepareEnterAnimation() {
|
||||
}
|
||||
@@ -283,8 +389,8 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
|
||||
case USER_TYPE_MANAGED_PROFILE:
|
||||
return mDevicePolicyManager.getResources().getString(
|
||||
WORK_PROFILE_LOCK_ATTEMPTS_FAILED,
|
||||
() -> getString(com.android.settingslib
|
||||
.R.string.failed_attempts_now_wiping_profile));
|
||||
() -> getString(
|
||||
com.android.settingslib.R.string.failed_attempts_now_wiping_profile));
|
||||
case USER_TYPE_SECONDARY:
|
||||
return getString(com.android.settingslib.R.string.failed_attempts_now_wiping_user);
|
||||
default:
|
||||
@@ -308,6 +414,36 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
|
||||
}
|
||||
}
|
||||
|
||||
protected void validateGuess(LockscreenCredential credentialGuess) {
|
||||
mRemoteLockscreenValidationFragment.validateLockscreenGuess(
|
||||
mRemoteLockscreenValidationClient, credentialGuess,
|
||||
mRemoteLockscreenValidationSession.getSourcePublicKey(), mCheckBox.isChecked());
|
||||
}
|
||||
|
||||
protected void updateRemoteLockscreenValidationViews() {
|
||||
if (!mRemoteValidation || mRemoteLockscreenValidationFragment == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean enable = mRemoteLockscreenValidationFragment.isRemoteValidationInProgress();
|
||||
mGlifLayout.setProgressBarShown(enable);
|
||||
mCheckBox.setEnabled(!enable);
|
||||
mCancelButton.setEnabled(!enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes the activity with result code {@link android.app.Activity#RESULT_FIRST_USER}
|
||||
* after logging the error message.
|
||||
* @param message Optional message to log.
|
||||
*/
|
||||
public void onRemoteLockscreenValidationFailure(String message) {
|
||||
if (!TextUtils.isEmpty(message)) {
|
||||
Log.w(TAG, message);
|
||||
}
|
||||
getActivity().setResult(RESULT_FIRST_USER);
|
||||
getActivity().finish();
|
||||
}
|
||||
|
||||
protected abstract void onShowError();
|
||||
|
||||
protected void showError(int msg, long timeout) {
|
||||
|
||||
@@ -25,6 +25,11 @@ import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserManager;
|
||||
import android.view.View;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.WindowInsetsController;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
|
||||
@@ -47,7 +52,12 @@ public class ConfirmDeviceCredentialUtils {
|
||||
IntentSender intentSender = activity.getIntent().getParcelableExtra(Intent.EXTRA_INTENT);
|
||||
if (intentSender != null) {
|
||||
try {
|
||||
activity.startIntentSenderForResult(intentSender, -1, null, 0, 0, 0);
|
||||
ActivityOptions activityOptions =
|
||||
ActivityOptions.makeBasic()
|
||||
.setPendingIntentBackgroundActivityStartMode(
|
||||
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
|
||||
activity.startIntentSenderForResult(intentSender, -1, null, 0, 0, 0,
|
||||
activityOptions.toBundle());
|
||||
} catch (IntentSender.SendIntentException e) {
|
||||
/* ignore */
|
||||
}
|
||||
@@ -67,4 +77,16 @@ public class ConfirmDeviceCredentialUtils {
|
||||
utils.userPresent(userId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request hiding soft-keyboard before animating away credential UI, in case IME
|
||||
* insets animation get delayed by dismissing animation.
|
||||
* @param view used to get root {@link WindowInsets} and {@link WindowInsetsController}.
|
||||
*/
|
||||
public static void hideImeImmediately(@NonNull View view) {
|
||||
if (view.isAttachedToWindow()
|
||||
&& view.getRootWindowInsets().isVisible(WindowInsets.Type.ime())) {
|
||||
view.getWindowInsetsController().hide(WindowInsets.Type.ime());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,13 @@ import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROF
|
||||
import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_PIN_REQUIRED;
|
||||
import static android.app.admin.DevicePolicyResources.UNDEFINED;
|
||||
|
||||
import static com.android.settings.biometrics.GatekeeperPasswordProvider.containsGatekeeperPasswordHandle;
|
||||
import static com.android.settings.biometrics.GatekeeperPasswordProvider.getGatekeeperPasswordHandle;
|
||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.app.KeyguardManager;
|
||||
import android.app.RemoteLockscreenValidationResult;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
@@ -42,6 +48,7 @@ import android.os.UserManager;
|
||||
import android.text.Editable;
|
||||
import android.text.InputType;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -64,8 +71,6 @@ import com.android.settings.R;
|
||||
import com.android.settingslib.animation.AppearAnimationUtils;
|
||||
import com.android.settingslib.animation.DisappearAnimationUtils;
|
||||
|
||||
import com.google.android.setupdesign.GlifLayout;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
||||
@@ -114,13 +119,14 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.main_content);
|
||||
if (fragment != null && fragment instanceof ConfirmLockPasswordFragment) {
|
||||
((ConfirmLockPasswordFragment)fragment).onWindowFocusChanged(hasFocus);
|
||||
((ConfirmLockPasswordFragment) fragment).onWindowFocusChanged(hasFocus);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConfirmLockPasswordFragment extends ConfirmDeviceCredentialBaseFragment
|
||||
implements OnClickListener, OnEditorActionListener,
|
||||
CredentialCheckResultTracker.Listener {
|
||||
CredentialCheckResultTracker.Listener, SaveChosenLockWorkerBase.Listener,
|
||||
RemoteLockscreenValidationFragment.Listener {
|
||||
private static final String FRAGMENT_TAG_CHECK_LOCK_RESULT = "check_lock_result";
|
||||
private ImeAwareEditText mPasswordEntry;
|
||||
private TextViewInputDisabler mPasswordEntryInputDisabler;
|
||||
@@ -133,7 +139,7 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
||||
private AppearAnimationUtils mAppearAnimationUtils;
|
||||
private DisappearAnimationUtils mDisappearAnimationUtils;
|
||||
private boolean mIsManagedProfile;
|
||||
private GlifLayout mGlifLayout;
|
||||
private CharSequence mCheckBoxLabel;
|
||||
|
||||
// required constructor for fragments
|
||||
public ConfirmLockPasswordFragment() {
|
||||
@@ -160,11 +166,19 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
||||
mPasswordEntry.requestFocus();
|
||||
mPasswordEntryInputDisabler = new TextViewInputDisabler(mPasswordEntry);
|
||||
mErrorTextView = (TextView) view.findViewById(R.id.errorText);
|
||||
mIsAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == storedQuality
|
||||
|| DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == storedQuality
|
||||
|| DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == storedQuality
|
||||
|| DevicePolicyManager.PASSWORD_QUALITY_MANAGED == storedQuality;
|
||||
|
||||
if (mRemoteValidation) {
|
||||
mIsAlpha = mRemoteLockscreenValidationSession.getLockType()
|
||||
== KeyguardManager.PASSWORD;
|
||||
// ProgressBar visibility is set to GONE until interacted with.
|
||||
// Set progress bar to INVISIBLE, so the EditText does not get bumped down later.
|
||||
mGlifLayout.setProgressBarShown(false);
|
||||
} else {
|
||||
mIsAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == storedQuality
|
||||
|| DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == storedQuality
|
||||
|| DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == storedQuality
|
||||
|| DevicePolicyManager.PASSWORD_QUALITY_MANAGED == storedQuality;
|
||||
}
|
||||
mImm = (InputMethodManager) getActivity().getSystemService(
|
||||
Context.INPUT_METHOD_SERVICE);
|
||||
|
||||
@@ -187,6 +201,7 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
||||
}
|
||||
mGlifLayout.setHeaderText(headerMessage);
|
||||
mGlifLayout.setDescriptionText(detailsMessage);
|
||||
mCheckBoxLabel = intent.getCharSequenceExtra(KeyguardManager.EXTRA_CHECKBOX_LABEL);
|
||||
}
|
||||
int currentType = mPasswordEntry.getInputType();
|
||||
if (mIsAlpha) {
|
||||
@@ -227,6 +242,20 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
if (mRemoteValidation) {
|
||||
if (mCheckBox != null) {
|
||||
mCheckBox.setText(TextUtils.isEmpty(mCheckBoxLabel)
|
||||
? getDefaultCheckboxLabel()
|
||||
: mCheckBoxLabel);
|
||||
}
|
||||
if (mCancelButton != null && TextUtils.isEmpty(mAlternateButtonText)) {
|
||||
mCancelButton.setText(mIsAlpha
|
||||
? R.string.lockpassword_forgot_password
|
||||
: R.string.lockpassword_forgot_pin);
|
||||
}
|
||||
updateRemoteLockscreenValidationViews();
|
||||
}
|
||||
|
||||
if (mForgotButton != null) {
|
||||
mForgotButton.setText(mIsAlpha
|
||||
? R.string.lockpassword_forgot_password
|
||||
@@ -237,7 +266,9 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
mPasswordEntry.setText(null);
|
||||
if (mPasswordEntry != null) {
|
||||
mPasswordEntry.setText(null);
|
||||
}
|
||||
// Force a garbage collection to remove remnant of user password shards from memory.
|
||||
// Execute this with a slight delay to allow the activity lifecycle to complete and
|
||||
// the instance to become gc-able.
|
||||
@@ -253,6 +284,9 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
||||
return mIsAlpha ? getString(R.string.lockpassword_confirm_your_password_header_frp)
|
||||
: getString(R.string.lockpassword_confirm_your_pin_header_frp);
|
||||
}
|
||||
if (mRemoteValidation) {
|
||||
return getString(R.string.lockpassword_remote_validation_header);
|
||||
}
|
||||
if (mIsManagedProfile) {
|
||||
if (mIsAlpha) {
|
||||
return mDevicePolicyManager.getResources().getString(
|
||||
@@ -273,6 +307,11 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
||||
return mIsAlpha ? getString(R.string.lockpassword_confirm_your_password_details_frp)
|
||||
: getString(R.string.lockpassword_confirm_your_pin_details_frp);
|
||||
}
|
||||
if (mRemoteValidation) {
|
||||
return getContext().getString(mIsAlpha
|
||||
? R.string.lockpassword_remote_validation_password_details
|
||||
: R.string.lockpassword_remote_validation_pin_details);
|
||||
}
|
||||
boolean isStrongAuthRequired = isStrongAuthRequired();
|
||||
// Map boolean flags to an index by isStrongAuth << 2 + isManagedProfile << 1 + isAlpha.
|
||||
int index = ((isStrongAuthRequired ? 1 : 0) << 2) + ((mIsManagedProfile ? 1 : 0) << 1)
|
||||
@@ -281,6 +320,16 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
||||
DETAIL_TEXT_OVERRIDES[index], () -> getString(DETAIL_TEXTS[index]));
|
||||
}
|
||||
|
||||
private String getDefaultCheckboxLabel() {
|
||||
if (mRemoteValidation) {
|
||||
return getString(mIsAlpha
|
||||
? R.string.lockpassword_remote_validation_set_password_as_screenlock
|
||||
: R.string.lockpassword_remote_validation_set_pin_as_screenlock);
|
||||
}
|
||||
throw new IllegalStateException(
|
||||
"Trying to get default checkbox label for illegal flow");
|
||||
}
|
||||
|
||||
private int getErrorMessage() {
|
||||
return mIsAlpha ? R.string.lockpassword_invalid_password
|
||||
: R.string.lockpassword_invalid_pin;
|
||||
@@ -355,6 +404,9 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
||||
mCountdownTimer = null;
|
||||
}
|
||||
mCredentialCheckResultTracker.setListener(null);
|
||||
if (mRemoteLockscreenValidationFragment != null) {
|
||||
mRemoteLockscreenValidationFragment.setListener(null, /* handler= */ null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -376,6 +428,9 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
||||
mLockPatternUtils.getCurrentFailedPasswordAttempts(mEffectiveUserId));
|
||||
}
|
||||
mCredentialCheckResultTracker.setListener(this);
|
||||
if (mRemoteLockscreenValidationFragment != null) {
|
||||
mRemoteLockscreenValidationFragment.setListener(this, mHandler);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -386,12 +441,17 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
||||
private void updatePasswordEntry() {
|
||||
final boolean isLockedOut =
|
||||
mLockPatternUtils.getLockoutAttemptDeadline(mEffectiveUserId) != 0;
|
||||
mPasswordEntry.setEnabled(!isLockedOut);
|
||||
mPasswordEntryInputDisabler.setInputEnabled(!isLockedOut);
|
||||
if (isLockedOut) {
|
||||
mImm.hideSoftInputFromWindow(mPasswordEntry.getWindowToken(), 0 /*flags*/);
|
||||
} else {
|
||||
final boolean isRemoteLockscreenValidationInProgress =
|
||||
mRemoteLockscreenValidationFragment != null
|
||||
&& mRemoteLockscreenValidationFragment.isRemoteValidationInProgress();
|
||||
boolean shouldEnableInput = !isLockedOut && !isRemoteLockscreenValidationInProgress;
|
||||
mPasswordEntry.setEnabled(shouldEnableInput);
|
||||
mPasswordEntryInputDisabler.setInputEnabled(shouldEnableInput);
|
||||
if (shouldEnableInput) {
|
||||
mPasswordEntry.scheduleShowSoftInput();
|
||||
mPasswordEntry.requestFocus();
|
||||
} else {
|
||||
mImm.hideSoftInputFromWindow(mPasswordEntry.getWindowToken(), /* flags= */0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,12 +473,19 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
||||
if (TextUtils.isEmpty(passwordText)) {
|
||||
return;
|
||||
}
|
||||
final LockscreenCredential credential =
|
||||
mIsAlpha ? LockscreenCredential.createPassword(passwordText)
|
||||
final LockscreenCredential credential = mIsAlpha
|
||||
? LockscreenCredential.createPassword(passwordText)
|
||||
: LockscreenCredential.createPin(passwordText);
|
||||
|
||||
mPasswordEntryInputDisabler.setInputEnabled(false);
|
||||
|
||||
if (mRemoteValidation) {
|
||||
validateGuess(credential);
|
||||
updateRemoteLockscreenValidationViews();
|
||||
updatePasswordEntry();
|
||||
return;
|
||||
}
|
||||
|
||||
Intent intent = new Intent();
|
||||
// TODO(b/161956762): Sanitize this
|
||||
if (mReturnGatekeeperPassword) {
|
||||
@@ -493,6 +560,9 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
||||
}
|
||||
|
||||
private void startDisappearAnimation(final Intent intent) {
|
||||
ConfirmDeviceCredentialUtils.hideImeImmediately(
|
||||
getActivity().getWindow().getDecorView());
|
||||
|
||||
if (mDisappearing) {
|
||||
return;
|
||||
}
|
||||
@@ -543,6 +613,51 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoteLockscreenValidationResult(
|
||||
RemoteLockscreenValidationResult result) {
|
||||
switch (result.getResultCode()) {
|
||||
case RemoteLockscreenValidationResult.RESULT_GUESS_VALID:
|
||||
if (mCheckBox.isChecked() && mRemoteLockscreenValidationFragment
|
||||
.getLockscreenCredential() != null) {
|
||||
Log.i(TAG, "Setting device screen lock to the other device's screen lock.");
|
||||
ChooseLockPassword.SaveAndFinishWorker saveAndFinishWorker =
|
||||
new ChooseLockPassword.SaveAndFinishWorker();
|
||||
getFragmentManager().beginTransaction().add(saveAndFinishWorker, null)
|
||||
.commit();
|
||||
getFragmentManager().executePendingTransactions();
|
||||
saveAndFinishWorker.setListener(this);
|
||||
saveAndFinishWorker.start(
|
||||
mLockPatternUtils,
|
||||
/* requestGatekeeperPassword= */ true,
|
||||
mRemoteLockscreenValidationFragment.getLockscreenCredential(),
|
||||
/* currentCredential= */ null,
|
||||
mEffectiveUserId);
|
||||
} else {
|
||||
mCredentialCheckResultTracker.setResult(/* matched= */ true, new Intent(),
|
||||
/* timeoutMs= */ 0, mEffectiveUserId);
|
||||
}
|
||||
return;
|
||||
case RemoteLockscreenValidationResult.RESULT_GUESS_INVALID:
|
||||
mCredentialCheckResultTracker.setResult(/* matched= */ false, new Intent(),
|
||||
/* timeoutMs= */ 0, mEffectiveUserId);
|
||||
break;
|
||||
case RemoteLockscreenValidationResult.RESULT_LOCKOUT:
|
||||
mCredentialCheckResultTracker.setResult(/* matched= */ false, new Intent(),
|
||||
(int) result.getTimeoutMillis(), mEffectiveUserId);
|
||||
break;
|
||||
case RemoteLockscreenValidationResult.RESULT_NO_REMAINING_ATTEMPTS:
|
||||
case RemoteLockscreenValidationResult.RESULT_SESSION_EXPIRED:
|
||||
onRemoteLockscreenValidationFailure(String.format(
|
||||
"Cannot continue remote lockscreen validation. ResultCode=%d",
|
||||
result.getResultCode()));
|
||||
break;
|
||||
}
|
||||
updateRemoteLockscreenValidationViews();
|
||||
updatePasswordEntry();
|
||||
mRemoteLockscreenValidationFragment.clearLockscreenCredential();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCredentialChecked(boolean matched, Intent intent, int timeoutMs,
|
||||
int effectiveUserId, boolean newResult) {
|
||||
@@ -598,5 +713,22 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for when the current device's lockscreen was set to the guess used for
|
||||
* remote lockscreen validation.
|
||||
*/
|
||||
@Override
|
||||
public void onChosenLockSaveFinished(boolean wasSecureBefore, Intent resultData) {
|
||||
Log.i(TAG, "Device lockscreen has been set to remote device's lockscreen.");
|
||||
mRemoteLockscreenValidationFragment.clearLockscreenCredential();
|
||||
|
||||
Intent result = new Intent();
|
||||
if (mRemoteValidation && containsGatekeeperPasswordHandle(resultData)) {
|
||||
result.putExtra(EXTRA_KEY_GK_PW_HANDLE, getGatekeeperPasswordHandle(resultData));
|
||||
}
|
||||
mCredentialCheckResultTracker.setResult(/* matched= */ true, result,
|
||||
/* timeoutMs= */ 0, mEffectiveUserId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,14 +17,18 @@
|
||||
package com.android.settings.password;
|
||||
|
||||
import static android.app.admin.DevicePolicyResources.Strings.Settings.CONFIRM_WORK_PROFILE_PATTERN_HEADER;
|
||||
import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_CONFIRM_PATTERN;
|
||||
import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LAST_PATTERN_ATTEMPT_BEFORE_WIPE;
|
||||
import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_PATTERN_REQUIRED;
|
||||
import static android.app.admin.DevicePolicyResources.UNDEFINED;
|
||||
|
||||
import static com.android.settings.biometrics.GatekeeperPasswordProvider.containsGatekeeperPasswordHandle;
|
||||
import static com.android.settings.biometrics.GatekeeperPasswordProvider.getGatekeeperPasswordHandle;
|
||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.KeyguardManager;
|
||||
import android.app.RemoteLockscreenValidationResult;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
@@ -33,6 +37,7 @@ import android.os.CountDownTimer;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
@@ -52,8 +57,6 @@ import com.android.settingslib.animation.AppearAnimationCreator;
|
||||
import com.android.settingslib.animation.AppearAnimationUtils;
|
||||
import com.android.settingslib.animation.DisappearAnimationUtils;
|
||||
|
||||
import com.google.android.setupdesign.GlifLayout;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -89,7 +92,8 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
|
||||
}
|
||||
|
||||
public static class ConfirmLockPatternFragment extends ConfirmDeviceCredentialBaseFragment
|
||||
implements AppearAnimationCreator<Object>, CredentialCheckResultTracker.Listener {
|
||||
implements AppearAnimationCreator<Object>, CredentialCheckResultTracker.Listener,
|
||||
SaveChosenLockWorkerBase.Listener, RemoteLockscreenValidationFragment.Listener {
|
||||
|
||||
private static final String FRAGMENT_TAG_CHECK_LOCK_RESULT = "check_lock_result";
|
||||
|
||||
@@ -99,12 +103,12 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
|
||||
private boolean mDisappearing = false;
|
||||
private CountDownTimer mCountdownTimer;
|
||||
|
||||
private GlifLayout mGlifLayout;
|
||||
private View mSudContent;
|
||||
|
||||
// caller-supplied text for various prompts
|
||||
private CharSequence mHeaderText;
|
||||
private CharSequence mDetailsText;
|
||||
private CharSequence mCheckBoxLabel;
|
||||
|
||||
private AppearAnimationUtils mAppearAnimationUtils;
|
||||
private DisappearAnimationUtils mDisappearAnimationUtils;
|
||||
@@ -148,6 +152,7 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
|
||||
ConfirmDeviceCredentialBaseFragment.HEADER_TEXT);
|
||||
mDetailsText = intent.getCharSequenceExtra(
|
||||
ConfirmDeviceCredentialBaseFragment.DETAILS_TEXT);
|
||||
mCheckBoxLabel = intent.getCharSequenceExtra(KeyguardManager.EXTRA_CHECKBOX_LABEL);
|
||||
}
|
||||
if (TextUtils.isEmpty(mHeaderText) && mIsManagedProfile) {
|
||||
mHeaderText = mDevicePolicyManager.getOrganizationNameForUser(mUserId);
|
||||
@@ -174,7 +179,8 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
|
||||
// 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)) {
|
||||
if (!mFrp && !mRemoteValidation
|
||||
&& !mLockPatternUtils.isLockPatternEnabled(mEffectiveUserId)) {
|
||||
getActivity().setResult(Activity.RESULT_OK);
|
||||
getActivity().finish();
|
||||
}
|
||||
@@ -203,12 +209,34 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
|
||||
FRAGMENT_TAG_CHECK_LOCK_RESULT).commit();
|
||||
}
|
||||
|
||||
if (mRemoteValidation) {
|
||||
// ProgressBar visibility is set to GONE until interacted with.
|
||||
// Set progress bar to INVISIBLE, so the pattern does not get bumped down later.
|
||||
mGlifLayout.setProgressBarShown(false);
|
||||
// Lock pattern is generally not visible until the user has set a lockscreen for the
|
||||
// first time. For a new user, this means that the pattern will always be hidden.
|
||||
// Despite this prerequisite, we want to show the pattern anyway for this flow.
|
||||
mLockPatternView.setInStealthMode(false);
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
if (mRemoteValidation) {
|
||||
if (mCheckBox != null) {
|
||||
mCheckBox.setText(TextUtils.isEmpty(mCheckBoxLabel)
|
||||
? getDefaultCheckboxLabel()
|
||||
: mCheckBoxLabel);
|
||||
}
|
||||
if (mCancelButton != null && TextUtils.isEmpty(mAlternateButtonText)) {
|
||||
mCancelButton.setText(R.string.lockpassword_forgot_pattern);
|
||||
}
|
||||
updateRemoteLockscreenValidationViews();
|
||||
}
|
||||
|
||||
if (mForgotButton != null) {
|
||||
mForgotButton.setText(R.string.lockpassword_forgot_pattern);
|
||||
}
|
||||
@@ -227,6 +255,9 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
|
||||
mCountdownTimer.cancel();
|
||||
}
|
||||
mCredentialCheckResultTracker.setListener(null);
|
||||
if (mRemoteLockscreenValidationFragment != null) {
|
||||
mRemoteLockscreenValidationFragment.setListener(null, /* handler= */ null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -249,6 +280,12 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
|
||||
updateStage(Stage.NeedToUnlock);
|
||||
}
|
||||
mCredentialCheckResultTracker.setListener(this);
|
||||
if (mRemoteLockscreenValidationFragment != null) {
|
||||
mRemoteLockscreenValidationFragment.setListener(this, mHandler);
|
||||
if (mRemoteLockscreenValidationFragment.isRemoteValidationInProgress()) {
|
||||
mLockPatternView.setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -271,24 +308,17 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
|
||||
if (mFrp) {
|
||||
return getString(R.string.lockpassword_confirm_your_pattern_details_frp);
|
||||
}
|
||||
if (mRemoteValidation) {
|
||||
return getString(
|
||||
R.string.lockpassword_remote_validation_pattern_details);
|
||||
}
|
||||
final boolean isStrongAuthRequired = isStrongAuthRequired();
|
||||
if (mIsManagedProfile) {
|
||||
if (isStrongAuthRequired) {
|
||||
return mDevicePolicyManager.getResources().getString(
|
||||
WORK_PROFILE_PATTERN_REQUIRED,
|
||||
() -> getString(
|
||||
R.string.lockpassword_strong_auth_required_work_pattern));
|
||||
} else {
|
||||
return mDevicePolicyManager.getResources().getString(
|
||||
WORK_PROFILE_CONFIRM_PATTERN,
|
||||
() -> getString(
|
||||
R.string.lockpassword_confirm_your_pattern_generic_profile));
|
||||
}
|
||||
} else {
|
||||
if (!mIsManagedProfile) {
|
||||
return isStrongAuthRequired
|
||||
? getString(R.string.lockpassword_strong_auth_required_device_pattern)
|
||||
: getString(R.string.lockpassword_confirm_your_pattern_generic);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Object[][] getActiveViews() {
|
||||
@@ -335,11 +365,13 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
|
||||
} else {
|
||||
mGlifLayout.setHeaderText(getDefaultHeader());
|
||||
}
|
||||
if (mDetailsText != null) {
|
||||
mGlifLayout.setDescriptionText(mDetailsText);
|
||||
} else {
|
||||
mGlifLayout.setDescriptionText(getDefaultDetails());
|
||||
|
||||
CharSequence detailsText =
|
||||
mDetailsText == null ? getDefaultDetails() : mDetailsText;
|
||||
if (detailsText != null) {
|
||||
mGlifLayout.setDescriptionText(detailsText);
|
||||
}
|
||||
|
||||
mErrorTextView.setText("");
|
||||
updateErrorMessage(
|
||||
mLockPatternUtils.getCurrentFailedPasswordAttempts(mEffectiveUserId));
|
||||
@@ -371,7 +403,9 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
|
||||
|
||||
private String getDefaultHeader() {
|
||||
if (mFrp) return getString(R.string.lockpassword_confirm_your_pattern_header_frp);
|
||||
|
||||
if (mRemoteValidation) {
|
||||
return getString(R.string.lockpassword_remote_validation_header);
|
||||
}
|
||||
if (mIsManagedProfile) {
|
||||
return mDevicePolicyManager.getResources().getString(
|
||||
CONFIRM_WORK_PROFILE_PATTERN_HEADER,
|
||||
@@ -381,6 +415,14 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
|
||||
return getString(R.string.lockpassword_confirm_your_pattern_header);
|
||||
}
|
||||
|
||||
private String getDefaultCheckboxLabel() {
|
||||
if (mRemoteValidation) {
|
||||
return getString(R.string.lockpassword_remote_validation_set_pattern_as_screenlock);
|
||||
}
|
||||
throw new IllegalStateException(
|
||||
"Trying to get default checkbox label for illegal flow");
|
||||
}
|
||||
|
||||
private Runnable mClearPatternRunnable = new Runnable() {
|
||||
public void run() {
|
||||
mLockPatternView.clearPattern();
|
||||
@@ -431,7 +473,7 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
|
||||
* an existing lock pattern.
|
||||
*/
|
||||
private LockPatternView.OnPatternListener mConfirmExistingLockPatternListener
|
||||
= new LockPatternView.OnPatternListener() {
|
||||
= new LockPatternView.OnPatternListener() {
|
||||
|
||||
public void onPatternStart() {
|
||||
mLockPatternView.removeCallbacks(mClearPatternRunnable);
|
||||
@@ -453,6 +495,13 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
|
||||
mLockPatternView.setEnabled(false);
|
||||
|
||||
final LockscreenCredential credential = LockscreenCredential.createPattern(pattern);
|
||||
|
||||
if (mRemoteValidation) {
|
||||
validateGuess(credential);
|
||||
updateRemoteLockscreenValidationViews();
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(b/161956762): Sanitize this
|
||||
Intent intent = new Intent();
|
||||
if (mReturnGatekeeperPassword) {
|
||||
@@ -563,6 +612,50 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoteLockscreenValidationResult(
|
||||
RemoteLockscreenValidationResult result) {
|
||||
switch (result.getResultCode()) {
|
||||
case RemoteLockscreenValidationResult.RESULT_GUESS_VALID:
|
||||
if (mCheckBox.isChecked() && mRemoteLockscreenValidationFragment
|
||||
.getLockscreenCredential() != null) {
|
||||
Log.i(TAG, "Setting device screen lock to the other device's screen lock.");
|
||||
ChooseLockPattern.SaveAndFinishWorker saveAndFinishWorker =
|
||||
new ChooseLockPattern.SaveAndFinishWorker();
|
||||
getFragmentManager().beginTransaction().add(saveAndFinishWorker, null)
|
||||
.commit();
|
||||
getFragmentManager().executePendingTransactions();
|
||||
saveAndFinishWorker.setListener(this);
|
||||
saveAndFinishWorker.start(
|
||||
mLockPatternUtils,
|
||||
/* requestGatekeeperPassword= */ true,
|
||||
mRemoteLockscreenValidationFragment.getLockscreenCredential(),
|
||||
/* currentCredential= */ null,
|
||||
mEffectiveUserId);
|
||||
} else {
|
||||
mCredentialCheckResultTracker.setResult(/* matched= */ true, new Intent(),
|
||||
/* timeoutMs= */ 0, mEffectiveUserId);
|
||||
}
|
||||
return;
|
||||
case RemoteLockscreenValidationResult.RESULT_GUESS_INVALID:
|
||||
mCredentialCheckResultTracker.setResult(/* matched= */ false, new Intent(),
|
||||
/* timeoutMs= */ 0, mEffectiveUserId);
|
||||
break;
|
||||
case RemoteLockscreenValidationResult.RESULT_LOCKOUT:
|
||||
mCredentialCheckResultTracker.setResult(/* matched= */ false, new Intent(),
|
||||
(int) result.getTimeoutMillis(), mEffectiveUserId);
|
||||
break;
|
||||
case RemoteLockscreenValidationResult.RESULT_NO_REMAINING_ATTEMPTS:
|
||||
case RemoteLockscreenValidationResult.RESULT_SESSION_EXPIRED:
|
||||
onRemoteLockscreenValidationFailure(String.format(
|
||||
"Cannot continue remote lockscreen validation. ResultCode=%d",
|
||||
result.getResultCode()));
|
||||
break;
|
||||
}
|
||||
updateRemoteLockscreenValidationViews();
|
||||
mRemoteLockscreenValidationFragment.clearLockscreenCredential();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCredentialChecked(boolean matched, Intent intent, int timeoutMs,
|
||||
int effectiveUserId, boolean newResult) {
|
||||
@@ -632,5 +725,22 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
|
||||
appearing, interpolator, finishListener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for when the current device's lockscreen to the guess used for
|
||||
* remote lockscreen validation.
|
||||
*/
|
||||
@Override
|
||||
public void onChosenLockSaveFinished(boolean wasSecureBefore, Intent resultData) {
|
||||
Log.i(TAG, "Device lockscreen has been set to remote device's lockscreen.");
|
||||
mRemoteLockscreenValidationFragment.clearLockscreenCredential();
|
||||
|
||||
Intent result = new Intent();
|
||||
if (mRemoteValidation && containsGatekeeperPasswordHandle(resultData)) {
|
||||
result.putExtra(EXTRA_KEY_GK_PW_HANDLE, getGatekeeperPasswordHandle(resultData));
|
||||
}
|
||||
mCredentialCheckResultTracker.setResult(/* matched= */ true, result,
|
||||
/* timeoutMs= */ 0, mEffectiveUserId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ import com.android.settings.R;
|
||||
import com.google.android.setupcompat.template.FooterBarMixin;
|
||||
import com.google.android.setupcompat.template.FooterButton;
|
||||
import com.google.android.setupdesign.GlifLayout;
|
||||
import com.google.android.setupdesign.util.ContentStyler;
|
||||
import com.google.android.setupdesign.util.ThemeHelper;
|
||||
|
||||
/**
|
||||
* An activity that asks the user to contact their admin to get assistance with forgotten password.
|
||||
@@ -65,6 +67,11 @@ public class ForgotPasswordActivity extends Activity {
|
||||
.build()
|
||||
);
|
||||
|
||||
if (ThemeHelper.shouldApplyMaterialYouStyle(this)) {
|
||||
ContentStyler.applyBodyPartnerCustomizationStyle(
|
||||
layout.findViewById(R.id.forgot_password_text));
|
||||
}
|
||||
|
||||
layout.setHeaderText(devicePolicyManager.getResources().getString(
|
||||
FORGOT_PASSWORD_TITLE, () -> getString(R.string.forgot_password_title)));
|
||||
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.password;
|
||||
|
||||
import android.app.RemoteLockscreenValidationResult;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.service.remotelockscreenvalidation.IRemoteLockscreenValidationCallback;
|
||||
import android.service.remotelockscreenvalidation.RemoteLockscreenValidationClient;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.internal.widget.LockscreenCredential;
|
||||
import com.android.security.SecureBox;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PublicKey;
|
||||
|
||||
/**
|
||||
* A fragment used to hold state for remote lockscreen validation.
|
||||
* If the original listener is ever re-created, the new listener must be set again using
|
||||
* {@link #setListener} so that the validation result does not get handled by the old listener.
|
||||
*/
|
||||
public class RemoteLockscreenValidationFragment extends Fragment {
|
||||
|
||||
private static final String TAG = RemoteLockscreenValidationFragment.class.getSimpleName();
|
||||
|
||||
private Listener mListener;
|
||||
private Handler mHandler;
|
||||
private boolean mIsInProgress;
|
||||
private RemoteLockscreenValidationResult mResult;
|
||||
private String mErrorMessage;
|
||||
private LockscreenCredential mLockscreenCredential;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setRetainInstance(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
clearLockscreenCredential();
|
||||
if (mResult != null && mErrorMessage != null) {
|
||||
Log.w(TAG, "Unprocessed remote lockscreen validation result");
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if remote lockscreen guess validation has started or
|
||||
* the validation result has not yet been handled.
|
||||
*/
|
||||
public boolean isRemoteValidationInProgress() {
|
||||
return mIsInProgress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the listener and handler that will handle the result of remote lockscreen validation.
|
||||
* Unprocessed results or failures will be handled after the listener is set.
|
||||
*/
|
||||
public void setListener(Listener listener, Handler handler) {
|
||||
if (mListener == listener) {
|
||||
return;
|
||||
}
|
||||
|
||||
mListener = listener;
|
||||
mHandler = handler;
|
||||
|
||||
if (mResult != null) {
|
||||
handleResult();
|
||||
} else if (mErrorMessage != null) {
|
||||
handleFailure();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link LockscreenCredential} if it was cached in {@link #validateLockscreenGuess}.
|
||||
*/
|
||||
public LockscreenCredential getLockscreenCredential() {
|
||||
return mLockscreenCredential;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the {@link LockscreenCredential} if it was cached in {@link #validateLockscreenGuess}.
|
||||
*/
|
||||
public void clearLockscreenCredential() {
|
||||
if (mLockscreenCredential != null) {
|
||||
mLockscreenCredential.zeroize();
|
||||
mLockscreenCredential = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the lockscreen guess on the remote device.
|
||||
* @param remoteLockscreenValidationClient the client that should be used to send the guess to
|
||||
* for validation
|
||||
* @param guess the {@link LockscreenCredential} guess that the user entered
|
||||
* @param encryptionKey the key that should be used to encrypt the guess before validation
|
||||
* @param shouldCacheGuess whether to cache to guess so it can be used to set the current
|
||||
* device's lockscreen after validation succeeds.
|
||||
*/
|
||||
public void validateLockscreenGuess(
|
||||
RemoteLockscreenValidationClient remoteLockscreenValidationClient,
|
||||
LockscreenCredential guess, byte[] encryptionKey, boolean shouldCacheGuess) {
|
||||
if (shouldCacheGuess) {
|
||||
mLockscreenCredential = guess;
|
||||
}
|
||||
|
||||
remoteLockscreenValidationClient.validateLockscreenGuess(
|
||||
encryptDeviceCredentialGuess(guess.getCredential(), encryptionKey),
|
||||
new IRemoteLockscreenValidationCallback.Stub() {
|
||||
@Override
|
||||
public void onSuccess(RemoteLockscreenValidationResult result) {
|
||||
mResult = result;
|
||||
handleResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(String message) {
|
||||
mErrorMessage = message;
|
||||
handleFailure();
|
||||
}
|
||||
});
|
||||
mIsInProgress = true;
|
||||
}
|
||||
|
||||
private byte[] encryptDeviceCredentialGuess(byte[] guess, byte[] encryptionKey) {
|
||||
try {
|
||||
PublicKey publicKey = SecureBox.decodePublicKey(encryptionKey);
|
||||
return SecureBox.encrypt(
|
||||
publicKey,
|
||||
/* sharedSecret= */ null,
|
||||
LockPatternUtils.ENCRYPTED_REMOTE_CREDENTIALS_HEADER,
|
||||
guess);
|
||||
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
|
||||
Log.w(TAG, "Error encrypting device credential guess. Returning empty byte[].", e);
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
|
||||
private void handleResult() {
|
||||
if (mHandler != null) {
|
||||
mHandler.post(()-> {
|
||||
if (mListener == null || mResult == null) {
|
||||
return;
|
||||
}
|
||||
mIsInProgress = false;
|
||||
mListener.onRemoteLockscreenValidationResult(mResult);
|
||||
mResult = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void handleFailure() {
|
||||
if (mHandler != null) {
|
||||
mHandler.post(()-> {
|
||||
if (mListener == null || mErrorMessage == null) {
|
||||
return;
|
||||
}
|
||||
mIsInProgress = false;
|
||||
mListener.onRemoteLockscreenValidationFailure(
|
||||
String.format("Remote lockscreen validation failed: %s", mErrorMessage));
|
||||
mErrorMessage = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
void onRemoteLockscreenValidationResult(RemoteLockscreenValidationResult result);
|
||||
void onRemoteLockscreenValidationFailure(String message);
|
||||
}
|
||||
}
|
||||
@@ -16,12 +16,10 @@
|
||||
|
||||
package com.android.settings.password;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.util.Pair;
|
||||
import android.widget.Toast;
|
||||
|
||||
@@ -68,21 +66,12 @@ abstract class SaveChosenLockWorkerBase extends Fragment {
|
||||
}
|
||||
}
|
||||
|
||||
protected void prepare(LockPatternUtils utils, boolean credentialRequired,
|
||||
boolean requestGatekeeperPassword, int userId) {
|
||||
protected void prepare(LockPatternUtils utils, boolean requestGatekeeperPassword, int userId) {
|
||||
mUtils = utils;
|
||||
mUserId = userId;
|
||||
mRequestGatekeeperPassword = requestGatekeeperPassword;
|
||||
// This will be a no-op for non managed profiles.
|
||||
mWasSecureBefore = mUtils.isSecure(mUserId);
|
||||
|
||||
Context context = getContext();
|
||||
// If context is null, we're being invoked to change the setCredentialRequiredToDecrypt,
|
||||
// and we made sure that this is the primary user already.
|
||||
if (context == null || UserManager.get(context).getUserInfo(mUserId).isPrimary()) {
|
||||
mUtils.setCredentialRequiredToDecrypt(credentialRequired);
|
||||
}
|
||||
|
||||
mFinished = false;
|
||||
mResultData = null;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.settings.password;
|
||||
import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY;
|
||||
import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY;
|
||||
|
||||
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
|
||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
|
||||
|
||||
import android.app.RemoteServiceException.MissingRequestPasswordComplexityPermissionException;
|
||||
@@ -40,10 +41,10 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SetupEncryptionInterstitial;
|
||||
import com.android.settings.SetupWizardUtils;
|
||||
import com.android.settings.utils.SettingsDividerItemDecoration;
|
||||
|
||||
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||
import com.google.android.setupdesign.GlifPreferenceLayout;
|
||||
import com.google.android.setupdesign.util.ThemeHelper;
|
||||
|
||||
@@ -188,14 +189,14 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric {
|
||||
final String key = preference.getKey();
|
||||
if (KEY_UNLOCK_SET_DO_LATER.equals(key)) {
|
||||
// show warning.
|
||||
final Intent intent = getActivity().getIntent();
|
||||
SetupSkipDialog dialog = SetupSkipDialog.newInstance(
|
||||
getActivity().getIntent()
|
||||
.getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false),
|
||||
/* isPatternMode= */ false,
|
||||
/* isAlphaMode= */ false,
|
||||
CREDENTIAL_TYPE_NONE,
|
||||
intent.getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false),
|
||||
/* forFingerprint= */ false,
|
||||
/* forFace= */ false,
|
||||
/* forBiometrics= */ false
|
||||
/* forBiometrics= */ false,
|
||||
WizardManagerHelper.isAnySetupWizard(intent)
|
||||
);
|
||||
dialog.show(getFragmentManager());
|
||||
return true;
|
||||
@@ -219,15 +220,6 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric {
|
||||
return intent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Intent getEncryptionInterstitialIntent(Context context, int quality,
|
||||
boolean required, Intent unlockMethodIntent) {
|
||||
Intent intent = SetupEncryptionInterstitial.createStartIntent(context, quality,
|
||||
required, unlockMethodIntent);
|
||||
SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent);
|
||||
return intent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Intent getBiometricEnrollIntent(Context context) {
|
||||
final Intent intent = super.getBiometricEnrollIntent(context);
|
||||
|
||||
@@ -16,13 +16,15 @@
|
||||
|
||||
package com.android.settings.password;
|
||||
|
||||
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
|
||||
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -32,6 +34,8 @@ import com.android.settings.R;
|
||||
import com.android.settings.SetupRedactionInterstitial;
|
||||
import com.android.settings.password.ChooseLockTypeDialogFragment.OnLockTypeSelectedListener;
|
||||
|
||||
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||
|
||||
/**
|
||||
* Setup Wizard's version of ChooseLockPassword screen. It inherits the logic and basic structure
|
||||
* from ChooseLockPassword class, and should remain similar to that behaviorally. This class should
|
||||
@@ -114,16 +118,15 @@ public class SetupChooseLockPassword extends ChooseLockPassword {
|
||||
final boolean forBiometrics = intent
|
||||
.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, false);
|
||||
final SetupSkipDialog dialog = SetupSkipDialog.newInstance(
|
||||
mIsAlphaMode ? CREDENTIAL_TYPE_PASSWORD : CREDENTIAL_TYPE_PIN,
|
||||
frpSupported,
|
||||
/* isPatternMode= */ false,
|
||||
mIsAlphaMode,
|
||||
forFingerprint,
|
||||
forFace,
|
||||
forBiometrics);
|
||||
forBiometrics,
|
||||
WizardManagerHelper.isAnySetupWizard(intent));
|
||||
|
||||
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(
|
||||
Context.INPUT_METHOD_SERVICE);
|
||||
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
||||
ConfirmDeviceCredentialUtils.hideImeImmediately(
|
||||
getActivity().getWindow().getDecorView());
|
||||
|
||||
dialog.show(getFragmentManager());
|
||||
return;
|
||||
@@ -172,6 +175,12 @@ public class SetupChooseLockPassword extends ChooseLockPassword {
|
||||
mOptionsButton.setVisibility(
|
||||
mUiStage == Stage.Introduction ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
// Visibility of auto pin confirm opt-in/out option should always be invisible.
|
||||
if (mAutoPinConfirmOption != null) {
|
||||
mAutoPinConfirmOption.setVisibility(View.GONE);
|
||||
mAutoConfirmSecurityMessage.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ package com.android.settings.password;
|
||||
|
||||
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
|
||||
|
||||
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
@@ -32,6 +34,8 @@ import androidx.fragment.app.Fragment;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SetupRedactionInterstitial;
|
||||
|
||||
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||
|
||||
/**
|
||||
* Setup Wizard's version of ChooseLockPattern screen. It inherits the logic and basic structure
|
||||
* from ChooseLockPattern class, and should remain similar to that behaviorally. This class should
|
||||
@@ -101,14 +105,13 @@ public class SetupChooseLockPattern extends ChooseLockPattern {
|
||||
.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
|
||||
final boolean forBiometrics = intent
|
||||
.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, false);
|
||||
|
||||
final SetupSkipDialog dialog = SetupSkipDialog.newInstance(
|
||||
CREDENTIAL_TYPE_PATTERN,
|
||||
frpSupported,
|
||||
/* isPatternMode= */ true,
|
||||
/* isAlphaMode= */ false,
|
||||
forFingerprint,
|
||||
forFace,
|
||||
forBiometrics);
|
||||
forBiometrics,
|
||||
WizardManagerHelper.isAnySetupWizard(intent));
|
||||
dialog.show(getFragmentManager());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,14 @@
|
||||
|
||||
package com.android.settings.password;
|
||||
|
||||
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
|
||||
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
|
||||
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
|
||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS;
|
||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE;
|
||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT;
|
||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_IS_SUW;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
@@ -29,7 +37,10 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.biometrics.BiometricUtils;
|
||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||
|
||||
public class SetupSkipDialog extends InstrumentedDialogFragment
|
||||
@@ -38,24 +49,23 @@ public class SetupSkipDialog extends InstrumentedDialogFragment
|
||||
public static final String EXTRA_FRP_SUPPORTED = ":settings:frp_supported";
|
||||
|
||||
private static final String ARG_FRP_SUPPORTED = "frp_supported";
|
||||
// The key indicates type of lock screen is pattern setup.
|
||||
private static final String ARG_LOCK_TYPE_PATTERN = "lock_type_pattern";
|
||||
// The key indicates type of screen lock credential types(PIN/Pattern/Password)
|
||||
private static final String ARG_LOCK_CREDENTIAL_TYPE = "lock_credential_type";
|
||||
// The key indicates type of lock screen setup is alphanumeric for password setup.
|
||||
private static final String ARG_LOCK_TYPE_ALPHANUMERIC = "lock_type_alphanumeric";
|
||||
private static final String TAG_SKIP_DIALOG = "skip_dialog";
|
||||
public static final int RESULT_SKIP = Activity.RESULT_FIRST_USER + 10;
|
||||
|
||||
public static SetupSkipDialog newInstance(boolean isFrpSupported, boolean isPatternMode,
|
||||
boolean isAlphanumericMode, boolean forFingerprint, boolean forFace,
|
||||
boolean forBiometrics) {
|
||||
public static SetupSkipDialog newInstance(@LockPatternUtils.CredentialType int credentialType,
|
||||
boolean isFrpSupported, boolean forFingerprint, boolean forFace,
|
||||
boolean forBiometrics, boolean isSuw) {
|
||||
SetupSkipDialog dialog = new SetupSkipDialog();
|
||||
Bundle args = new Bundle();
|
||||
args.putInt(ARG_LOCK_CREDENTIAL_TYPE, credentialType);
|
||||
args.putBoolean(ARG_FRP_SUPPORTED, isFrpSupported);
|
||||
args.putBoolean(ARG_LOCK_TYPE_PATTERN, isPatternMode);
|
||||
args.putBoolean(ARG_LOCK_TYPE_ALPHANUMERIC, isAlphanumericMode);
|
||||
args.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, forFingerprint);
|
||||
args.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, forFace);
|
||||
args.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, forBiometrics);
|
||||
args.putBoolean(EXTRA_KEY_FOR_FINGERPRINT, forFingerprint);
|
||||
args.putBoolean(EXTRA_KEY_FOR_FACE, forFace);
|
||||
args.putBoolean(EXTRA_KEY_FOR_BIOMETRICS, forBiometrics);
|
||||
args.putBoolean(EXTRA_KEY_IS_SUW, isSuw);
|
||||
dialog.setArguments(args);
|
||||
return dialog;
|
||||
}
|
||||
@@ -70,59 +80,59 @@ public class SetupSkipDialog extends InstrumentedDialogFragment
|
||||
return onCreateDialogBuilder().create();
|
||||
}
|
||||
|
||||
private AlertDialog.Builder getBiometricsBuilder(
|
||||
@LockPatternUtils.CredentialType int credentialType, boolean isSuw, boolean hasFace,
|
||||
boolean hasFingerprint) {
|
||||
final boolean isFaceSupported = hasFace && (!isSuw || BiometricUtils.isFaceSupportedInSuw(
|
||||
getContext()));
|
||||
final int msgResId;
|
||||
final int screenLockResId;
|
||||
switch (credentialType) {
|
||||
case CREDENTIAL_TYPE_PATTERN:
|
||||
screenLockResId = R.string.unlock_set_unlock_pattern_title;
|
||||
msgResId = getPatternSkipMessageRes(hasFace && isFaceSupported, hasFingerprint);
|
||||
break;
|
||||
case CREDENTIAL_TYPE_PASSWORD:
|
||||
screenLockResId = R.string.unlock_set_unlock_password_title;
|
||||
msgResId = getPasswordSkipMessageRes(hasFace && isFaceSupported, hasFingerprint);
|
||||
break;
|
||||
case CREDENTIAL_TYPE_PIN:
|
||||
default:
|
||||
screenLockResId = R.string.unlock_set_unlock_pin_title;
|
||||
msgResId = getPinSkipMessageRes(hasFace && isFaceSupported, hasFingerprint);
|
||||
break;
|
||||
}
|
||||
return new AlertDialog.Builder(getContext())
|
||||
.setPositiveButton(R.string.skip_lock_screen_dialog_button_label, this)
|
||||
.setNegativeButton(R.string.cancel_lock_screen_dialog_button_label, this)
|
||||
.setTitle(getSkipSetupTitle(screenLockResId, hasFingerprint,
|
||||
hasFace && isFaceSupported))
|
||||
.setMessage(msgResId);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public AlertDialog.Builder onCreateDialogBuilder() {
|
||||
Bundle args = getArguments();
|
||||
final boolean forFace =
|
||||
args.getBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE);
|
||||
final boolean forFingerprint =
|
||||
args.getBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT);
|
||||
final boolean forBiometrics =
|
||||
args.getBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS);
|
||||
final boolean isSuw = args.getBoolean(EXTRA_KEY_IS_SUW);
|
||||
final boolean forBiometrics = args.getBoolean(EXTRA_KEY_FOR_BIOMETRICS);
|
||||
final boolean forFace = args.getBoolean(EXTRA_KEY_FOR_FACE);
|
||||
final boolean forFingerprint = args.getBoolean(EXTRA_KEY_FOR_FINGERPRINT);
|
||||
@LockPatternUtils.CredentialType
|
||||
final int credentialType = args.getInt(ARG_LOCK_CREDENTIAL_TYPE);
|
||||
|
||||
if (forFace || forFingerprint || forBiometrics) {
|
||||
final boolean hasFace = forFace || forBiometrics;
|
||||
final boolean hasFingerprint = forFingerprint || forBiometrics;
|
||||
|
||||
final int titleId;
|
||||
final int msgResId;
|
||||
if (args.getBoolean(ARG_LOCK_TYPE_PATTERN)) {
|
||||
titleId = getPatternSkipTitleRes(hasFace, hasFingerprint);
|
||||
msgResId = getPatternSkipMessageRes(hasFace, hasFingerprint);
|
||||
} else if (args.getBoolean(ARG_LOCK_TYPE_ALPHANUMERIC)) {
|
||||
titleId = getPasswordSkipTitleRes(hasFace, hasFingerprint);
|
||||
msgResId = getPasswordSkipMessageRes(hasFace, hasFingerprint);
|
||||
} else {
|
||||
titleId = getPinSkipTitleRes(hasFace, hasFingerprint);
|
||||
msgResId = getPinSkipMessageRes(hasFace, hasFingerprint);
|
||||
}
|
||||
|
||||
return new AlertDialog.Builder(getContext())
|
||||
.setPositiveButton(R.string.skip_lock_screen_dialog_button_label, this)
|
||||
.setNegativeButton(R.string.cancel_lock_screen_dialog_button_label, this)
|
||||
.setTitle(titleId)
|
||||
.setMessage(msgResId);
|
||||
} else {
|
||||
return new AlertDialog.Builder(getContext())
|
||||
.setPositiveButton(R.string.skip_anyway_button_label, this)
|
||||
.setNegativeButton(R.string.go_back_button_label, this)
|
||||
.setTitle(R.string.lock_screen_intro_skip_title)
|
||||
.setMessage(args.getBoolean(ARG_FRP_SUPPORTED) ?
|
||||
R.string.lock_screen_intro_skip_dialog_text_frp :
|
||||
R.string.lock_screen_intro_skip_dialog_text);
|
||||
final boolean hasFace = Utils.hasFaceHardware(getContext());
|
||||
final boolean hasFingerprint = Utils.hasFingerprintHardware(getContext());
|
||||
return getBiometricsBuilder(credentialType, isSuw, hasFace, hasFingerprint);
|
||||
}
|
||||
}
|
||||
|
||||
@StringRes
|
||||
private int getPatternSkipTitleRes(boolean hasFace, boolean hasFingerprint) {
|
||||
if (hasFace && hasFingerprint) {
|
||||
return R.string.lock_screen_pattern_skip_biometrics_title;
|
||||
} else if (hasFace) {
|
||||
return R.string.lock_screen_pattern_skip_face_title;
|
||||
} else if (hasFingerprint) {
|
||||
return R.string.lock_screen_pattern_skip_fingerprint_title;
|
||||
} else {
|
||||
return R.string.lock_screen_pattern_skip_title;
|
||||
}
|
||||
return new AlertDialog.Builder(getContext())
|
||||
.setPositiveButton(R.string.skip_anyway_button_label, this)
|
||||
.setNegativeButton(R.string.go_back_button_label, this)
|
||||
.setTitle(R.string.lock_screen_intro_skip_title)
|
||||
.setMessage(args.getBoolean(ARG_FRP_SUPPORTED) ?
|
||||
R.string.lock_screen_intro_skip_dialog_text_frp :
|
||||
R.string.lock_screen_intro_skip_dialog_text);
|
||||
}
|
||||
|
||||
@StringRes
|
||||
@@ -138,19 +148,6 @@ public class SetupSkipDialog extends InstrumentedDialogFragment
|
||||
}
|
||||
}
|
||||
|
||||
@StringRes
|
||||
private int getPasswordSkipTitleRes(boolean hasFace, boolean hasFingerprint) {
|
||||
if (hasFace && hasFingerprint) {
|
||||
return R.string.lock_screen_password_skip_biometrics_title;
|
||||
} else if (hasFace) {
|
||||
return R.string.lock_screen_password_skip_face_title;
|
||||
} else if (hasFingerprint) {
|
||||
return R.string.lock_screen_password_skip_fingerprint_title;
|
||||
} else {
|
||||
return R.string.lock_screen_password_skip_title;
|
||||
}
|
||||
}
|
||||
|
||||
@StringRes
|
||||
private int getPasswordSkipMessageRes(boolean hasFace, boolean hasFingerprint) {
|
||||
if (hasFace && hasFingerprint) {
|
||||
@@ -164,19 +161,6 @@ public class SetupSkipDialog extends InstrumentedDialogFragment
|
||||
}
|
||||
}
|
||||
|
||||
@StringRes
|
||||
private int getPinSkipTitleRes(boolean hasFace, boolean hasFingerprint) {
|
||||
if (hasFace && hasFingerprint) {
|
||||
return R.string.lock_screen_pin_skip_biometrics_title;
|
||||
} else if (hasFace) {
|
||||
return R.string.lock_screen_pin_skip_face_title;
|
||||
} else if (hasFingerprint) {
|
||||
return R.string.lock_screen_pin_skip_fingerprint_title;
|
||||
} else {
|
||||
return R.string.lock_screen_pin_skip_title;
|
||||
}
|
||||
}
|
||||
|
||||
@StringRes
|
||||
private int getPinSkipMessageRes(boolean hasFace, boolean hasFingerprint) {
|
||||
if (hasFace && hasFingerprint) {
|
||||
@@ -190,6 +174,13 @@ public class SetupSkipDialog extends InstrumentedDialogFragment
|
||||
}
|
||||
}
|
||||
|
||||
private String getSkipSetupTitle(int screenTypeResId, boolean hasFingerprint,
|
||||
boolean hasFace) {
|
||||
return getString(R.string.lock_screen_skip_setup_title,
|
||||
BiometricUtils.getCombinedScreenLockOptions(getContext(),
|
||||
getString(screenTypeResId), hasFingerprint, hasFace));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int button) {
|
||||
Activity activity = getActivity();
|
||||
|
||||
Reference in New Issue
Block a user