Support remote device credentials validation in UI.

Test: m RunSettingsRoboTests -j ROBOTEST_FILTER=com.android.settings.password
Test: Manual
Bug: 258505917

Change-Id: Ifb9f15728eb8396b34c844d28f71a8e6e1aad837
This commit is contained in:
Brian Lee
2022-12-05 15:58:01 -08:00
parent dff3e4ed74
commit d4f8e5802e
18 changed files with 1582 additions and 71 deletions

View File

@@ -27,6 +27,8 @@ import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROF
import static android.app.admin.DevicePolicyResources.UNDEFINED;
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 +44,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;
@@ -114,13 +117,13 @@ 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 {
private static final String FRAGMENT_TAG_CHECK_LOCK_RESULT = "check_lock_result";
private ImeAwareEditText mPasswordEntry;
private TextViewInputDisabler mPasswordEntryInputDisabler;
@@ -134,6 +137,7 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
private DisappearAnimationUtils mDisappearAnimationUtils;
private boolean mIsManagedProfile;
private GlifLayout mGlifLayout;
private CharSequence mCheckBoxLabel;
// required constructor for fragments
public ConfirmLockPasswordFragment() {
@@ -160,11 +164,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 = mStartLockscreenValidationRequest.getLockscreenUiType()
== 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 +199,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 +240,19 @@ 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);
}
}
if (mForgotButton != null) {
mForgotButton.setText(mIsAlpha
? R.string.lockpassword_forgot_password
@@ -237,7 +263,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 +281,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 +304,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 +317,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;
@@ -392,6 +438,7 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
mImm.hideSoftInputFromWindow(mPasswordEntry.getWindowToken(), 0 /*flags*/);
} else {
mPasswordEntry.scheduleShowSoftInput();
mPasswordEntry.requestFocus();
}
}
@@ -413,12 +460,18 @@ 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);
mGlifLayout.setProgressBarShown(true);
return;
}
Intent intent = new Intent();
// TODO(b/161956762): Sanitize this
if (mReturnGatekeeperPassword) {
@@ -546,6 +599,44 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
}
}
@Override
protected void onRemoteDeviceCredentialValidationResult(
RemoteLockscreenValidationResult result) {
switch (result.getResultCode()) {
case RemoteLockscreenValidationResult.RESULT_GUESS_VALID:
if (mCheckBox.isChecked()) {
ChooseLockPassword.SaveAndFinishWorker saveAndFinishWorker =
new ChooseLockPassword.SaveAndFinishWorker();
Log.i(TAG, "Setting device screen lock to the other device's screen lock.");
getFragmentManager().beginTransaction().add(saveAndFinishWorker, null)
.commit();
getFragmentManager().executePendingTransactions();
saveAndFinishWorker.setListener(this);
saveAndFinishWorker.start(
mLockPatternUtils,
/* requestGatekeeperPassword= */ false,
mDeviceCredentialGuess,
/* currentCredential= */ null,
mEffectiveUserId);
return;
}
mCredentialCheckResultTracker.setResult(/* matched= */ true, new Intent(),
/* timeoutMs= */ 0, mEffectiveUserId);
break;
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:
getActivity().finish();
}
mGlifLayout.setProgressBarShown(false);
}
@Override
public void onCredentialChecked(boolean matched, Intent intent, int timeoutMs,
int effectiveUserId, boolean newResult) {
@@ -601,5 +692,19 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
}
return false;
}
/**
* Callback for when the device credential guess used for remote validation was set as the
* current device's device credential.
*/
@Override
public void onChosenLockSaveFinished(boolean wasSecureBefore, Intent resultData) {
if (mDeviceCredentialGuess != null) {
mDeviceCredentialGuess.zeroize();
}
mGlifLayout.setProgressBarShown(false);
mCredentialCheckResultTracker.setResult(/* matched= */ true, new Intent(),
/* timeoutMs= */ 0, mEffectiveUserId);
}
}
}