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

@@ -22,7 +22,9 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.KeyguardManager;
import android.app.StartLockscreenValidationRequest;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentSender;
import android.os.UserManager;
@@ -41,6 +43,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";
@@ -132,6 +136,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;
@@ -139,6 +144,9 @@ public final class ChooseLockSettingsHelper {
private int mUserId;
private boolean mAllowAnyUserId;
private boolean mForceVerifyPath;
private boolean mRemoteLockscreenValidation;
@Nullable private StartLockscreenValidationRequest mStartLockscreenValidationRequest;
@Nullable private ComponentName mRemoteLockscreenValidationServiceComponent;
boolean mRequestGatekeeperPasswordHandle;
public Builder(@NonNull Activity activity) {
@@ -191,6 +199,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:
@@ -253,6 +270,42 @@ public final class ChooseLockSettingsHelper {
return this;
}
/**
* @param isRemoteLockscreenValidation if true, remote device validation flow will be
* started. {@link #setStartLockscreenValidationRequest} and
* {@link #setRemoteLockscreenValidationServiceComponent}
* must also be used to set the required data.
*/
@NonNull public Builder setRemoteLockscreenValidation(
boolean isRemoteLockscreenValidation) {
mRemoteLockscreenValidation = isRemoteLockscreenValidation;
return this;
}
/**
* @param startLockScreenValidationRequest 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 setStartLockscreenValidationRequest(
StartLockscreenValidationRequest startLockScreenValidationRequest) {
mStartLockscreenValidationRequest = startLockScreenValidationRequest;
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
@@ -315,49 +368,41 @@ 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.mStartLockscreenValidationRequest,
mBuilder.mRemoteLockscreenValidationServiceComponent, mBuilder.mAllowAnyUserId,
mBuilder.mForegroundOnly, mBuilder.mRequestGatekeeperPasswordHandle);
}
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 StartLockscreenValidationRequest startLockScreenValidationRequest,
@Nullable ComponentName remoteLockscreenValidationServiceComponent,
boolean allowAnyUser, boolean foregroundOnly, boolean requestGatekeeperPasswordHandle) {
Optional<Class<?>> activityClass = determineAppropriateActivityClass(
returnCredentials, forceVerifyPath, userId, startLockScreenValidationRequest);
if (activityClass.isEmpty()) {
return false;
}
return launched;
return launchConfirmationActivity(request, title, header, description, activityClass.get(),
returnCredentials, external, forceVerifyPath, userId, alternateButton,
checkboxLabel, remoteLockscreenValidation, startLockScreenValidationRequest,
remoteLockscreenValidationServiceComponent, allowAnyUser, foregroundOnly,
requestGatekeeperPasswordHandle);
}
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 StartLockscreenValidationRequest startLockScreenValidationRequest,
@Nullable ComponentName remoteLockscreenValidationServiceComponent,
boolean allowAnyUser, boolean foregroundOnly, boolean requestGatekeeperPasswordHandle) {
final Intent intent = new Intent();
intent.putExtra(ConfirmDeviceCredentialBaseFragment.TITLE_TEXT, title);
intent.putExtra(ConfirmDeviceCredentialBaseFragment.HEADER_TEXT, header);
@@ -367,10 +412,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_START_LOCKSCREEN_VALIDATION_REQUEST,
startLockScreenValidationRequest);
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,
@@ -405,6 +456,58 @@ public final class ChooseLockSettingsHelper {
return true;
}
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 StartLockscreenValidationRequest startLockscreenValidationRequest) {
int lockType;
if (startLockscreenValidationRequest != null) {
lockType = startLockscreenValidationRequest.getLockscreenUiType();
} 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) {