Files
packages_apps_Settings/src/com/android/settings/password/ChooseLockSettingsHelper.java
Eric Biggers 5f1d894252 Remove EncryptionInterstitial for Full Disk Encryption
Support for Full Disk Encryption was removed in Android 13, since now
File Based Encryption is always used instead.  It turns out that I
missed a fairly large chunk of obsolete code: EncryptionInterstitial,
which is the screen that asks whether the device will require the
primary user's lockscreen credential when it starts up.  This used to be
shown when setting the primary user's lockscreen credential, to
determine whether the full-disk encryption key would be tied to that
lockscreen credential or not.  But now it's unused code.

This CL removes all this unused code.

This should not change any behavior, with one very minor exception:
Settings will no longer explicitly set the REQUIRE_PASSWORD_TO_DECRYPT
setting to 0 whenever the primary user's lockscreen credential is
changed.  (This happened in SaveChosenLockWorkerBase.)  This setting is
a @SystemApi, but it no longer has any meaning, since it is never set to
1 anymore.  If there is a reason to keep it explicitly set to 0, instead
of unset, we should make LockSettingsService in system_server set it.

Test: Went through SUW, set a PIN, cleared the PIN, set a PIN again (all
      using the UI).  Nothing unusual seen.
Bug: 208476087
Change-Id: I039cc7a284e3f43e1e284970a5869958c909d1b7
2022-12-15 20:47:20 +00:00

435 lines
19 KiB
Java

/*
* Copyright (C) 2010 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 static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.KeyguardManager;
import android.app.admin.DevicePolicyManager;
import android.content.Intent;
import android.content.IntentSender;
import android.os.UserManager;
import android.util.Log;
import androidx.activity.result.ActivityResultLauncher;
import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.Fragment;
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.SetupWizardUtils;
import com.android.settings.Utils;
import com.android.settings.core.SettingsBaseActivity;
import com.android.settings.core.SubSettingLauncher;
import com.android.settingslib.transition.SettingsTransitionHelper;
import com.google.android.setupcompat.util.WizardManagerHelper;
public final class ChooseLockSettingsHelper {
private static final String TAG = "ChooseLockSettingsHelper";
public static final String EXTRA_KEY_PASSWORD = "password";
public static final String EXTRA_KEY_RETURN_CREDENTIALS = "return_credentials";
// Force the verifyCredential path instead of checkCredential path. This will be removed
// after b/161956762 is resolved.
public static final String EXTRA_KEY_FORCE_VERIFY = "force_verify";
// Gatekeeper HardwareAuthToken
public static final String EXTRA_KEY_CHALLENGE_TOKEN = "hw_auth_token";
// For the fingerprint-only path
public static final String EXTRA_KEY_FOR_FINGERPRINT = "for_fingerprint";
// For the face-only path
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_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
// HardwareAuthToken(s) via LockSettingsService#verifyGatekeeperPasswordHandle
public static final String EXTRA_KEY_GK_PW_HANDLE = "gk_pw_handle";
/**
* When EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL and EXTRA_KEY_UNIFICATION_PROFILE_ID are
* provided to ChooseLockGeneric as fragment arguments {@link SubSettingLauncher#setArguments},
* at the end of the password change flow, the supplied profile user
* (EXTRA_KEY_UNIFICATION_PROFILE_ID) will be unified to its parent. The current profile
* password is supplied by EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL.
*/
public static final String EXTRA_KEY_UNIFICATION_PROFILE_ID = "unification_profile_id";
public static final String EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL =
"unification_profile_credential";
/**
* Intent extra for passing the requested min password complexity to later steps in the set new
* screen lock flow.
*/
public static final String EXTRA_KEY_REQUESTED_MIN_COMPLEXITY = "requested_min_complexity";
/**
* Intent extra for passing the label of the calling app to later steps in the set new screen
* lock flow.
*/
public static final String EXTRA_KEY_CALLER_APP_NAME = "caller_app_name";
/**
* Intent extra indicating that the calling app is an admin, such as a Device Adimn, Device
* Owner, or Profile Owner.
*/
public static final String EXTRA_KEY_IS_CALLING_APP_ADMIN = "is_calling_app_admin";
/**
* When invoked via {@link ConfirmLockPassword.InternalActivity}, this flag
* controls if we relax the enforcement of
* {@link Utils#enforceSameOwner(android.content.Context, int)}.
*/
public static final String EXTRA_KEY_ALLOW_ANY_USER = "allow_any_user";
/**
*
*/
public static final String EXTRA_KEY_DEVICE_PASSWORD_REQUIREMENT_ONLY =
"device_password_requirement_only";
@VisibleForTesting @NonNull LockPatternUtils mLockPatternUtils;
@NonNull private final Activity mActivity;
@Nullable private final Fragment mFragment;
@Nullable private final ActivityResultLauncher mActivityResultLauncher;
@NonNull private final Builder mBuilder;
private ChooseLockSettingsHelper(@NonNull Builder builder, @NonNull Activity activity,
@Nullable Fragment fragment,
@Nullable ActivityResultLauncher activityResultLauncher) {
mBuilder = builder;
mActivity = activity;
mFragment = fragment;
mActivityResultLauncher = activityResultLauncher;
mLockPatternUtils = new LockPatternUtils(activity);
}
public static class Builder {
@NonNull private final Activity mActivity;
@Nullable private Fragment mFragment;
@Nullable private ActivityResultLauncher mActivityResultLauncher;
private int mRequestCode;
@Nullable private CharSequence mTitle;
@Nullable private CharSequence mHeader;
@Nullable private CharSequence mDescription;
@Nullable private CharSequence mAlternateButton;
private boolean mReturnCredentials;
private boolean mExternal;
private boolean mForegroundOnly;
// ChooseLockSettingsHelper will determine the caller's userId if none provided.
private int mUserId;
private boolean mAllowAnyUserId;
private boolean mForceVerifyPath;
boolean mRequestGatekeeperPasswordHandle;
public Builder(@NonNull Activity activity) {
mActivity = activity;
mUserId = Utils.getCredentialOwnerUserId(mActivity);
}
public Builder(@NonNull Activity activity, @NonNull Fragment fragment) {
this(activity);
mFragment = fragment;
}
/**
* @param requestCode for onActivityResult
*/
@NonNull public Builder setRequestCode(int requestCode) {
mRequestCode = requestCode;
return this;
}
/**
* @param title of the confirmation screen; shown in the action bar
*/
@NonNull public Builder setTitle(@Nullable CharSequence title) {
mTitle = title;
return this;
}
/**
* @param header of the confirmation screen; shown as large text
*/
@NonNull public Builder setHeader(@Nullable CharSequence header) {
mHeader = header;
return this;
}
/**
* @param description of the confirmation screen
*/
@NonNull public Builder setDescription(@Nullable CharSequence description) {
mDescription = description;
return this;
}
/**
* @param alternateButton text for an alternate button
*/
@NonNull public Builder setAlternateButton(@Nullable CharSequence alternateButton) {
mAlternateButton = alternateButton;
return this;
}
/**
* @param returnCredentials if true, puts the following credentials into intent for
* onActivityResult with the following keys:
* {@link #EXTRA_KEY_PASSWORD},
* {@link #EXTRA_KEY_CHALLENGE_TOKEN},
* {@link #EXTRA_KEY_GK_PW_HANDLE}
* Note that if this is true, this can only be called internally.
*
* This should also generally be set if
* {@link #setRequestGatekeeperPasswordHandle(boolean)} is set.
*/
@NonNull public Builder setReturnCredentials(boolean returnCredentials) {
mReturnCredentials = returnCredentials;
return this;
}
/**
* @param userId for whom the credential should be confirmed.
*/
@NonNull public Builder setUserId(int userId) {
mUserId = userId;
return this;
}
/**
* @param allowAnyUserId Allows the caller to prompt for credentials of any user, including
* those which aren't associated with the current user. As an example,
* this is useful when unlocking the storage for secondary users.
*/
@NonNull public Builder setAllowAnyUserId(boolean allowAnyUserId) {
mAllowAnyUserId = allowAnyUserId;
return this;
}
/**
* @param external specifies whether this activity is launched externally, meaning that it
* will get a dark theme, allow biometric authentication, and it will
* forward the activity result.
*/
@NonNull public Builder setExternal(boolean external) {
mExternal = external;
return this;
}
/**
* @param foregroundOnly if true, the confirmation activity will be finished if it loses
* foreground.
*/
@NonNull public Builder setForegroundOnly(boolean foregroundOnly) {
mForegroundOnly = foregroundOnly;
return this;
}
/**
* @param forceVerifyPath Forces the VerifyCredential path instead of the CheckCredential
* path. This will be removed after b/161956762 is resolved.
*/
@NonNull public Builder setForceVerifyPath(boolean forceVerifyPath) {
mForceVerifyPath = forceVerifyPath;
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
* to create multiple Gatekeeper HATs containing distinct challenges via
* {@link LockPatternUtils#verifyGatekeeperPasswordHandle(long, long, int)}.
*
* Upon confirmation of the user's password, the Gatekeeper Password Handle will be returned
* via onActivityResult with the key being {@link #EXTRA_KEY_GK_PW_HANDLE}.
* @param requestGatekeeperPasswordHandle
*/
@NonNull public Builder setRequestGatekeeperPasswordHandle(
boolean requestGatekeeperPasswordHandle) {
mRequestGatekeeperPasswordHandle = requestGatekeeperPasswordHandle;
return this;
}
/**
* Support of ActivityResultLauncher.
*
* Which allowing the launch operation be controlled externally.
* @param activityResultLauncher a launcher previously prepared.
*/
@NonNull public Builder setActivityResultLauncher(
ActivityResultLauncher activityResultLauncher) {
mActivityResultLauncher = activityResultLauncher;
return this;
}
@NonNull public ChooseLockSettingsHelper build() {
if (!mAllowAnyUserId && mUserId != LockPatternUtils.USER_FRP) {
Utils.enforceSameOwner(mActivity, mUserId);
}
if (mExternal && mReturnCredentials) {
throw new IllegalArgumentException("External and ReturnCredentials specified. "
+ " External callers should never be allowed to receive credentials in"
+ " onActivityResult");
}
if (mRequestGatekeeperPasswordHandle && !mReturnCredentials) {
// HAT containing the signed challenge will not be available to the caller.
Log.w(TAG, "Requested gatekeeper password handle but not requesting"
+ " ReturnCredentials. Are you sure this is what you want?");
}
return new ChooseLockSettingsHelper(this, mActivity, mFragment,
mActivityResultLauncher);
}
public boolean show() {
return build().launch();
}
}
/**
* If a PIN, Pattern, or Password exists, prompt the user to confirm it.
* @return true if the confirmation activity is shown (e.g. user has a credential set up)
*/
public boolean launch() {
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);
}
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;
}
return launched;
}
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) {
final Intent intent = new Intent();
intent.putExtra(ConfirmDeviceCredentialBaseFragment.TITLE_TEXT, title);
intent.putExtra(ConfirmDeviceCredentialBaseFragment.HEADER_TEXT, header);
intent.putExtra(ConfirmDeviceCredentialBaseFragment.DETAILS_TEXT, message);
// TODO: Remove dark theme and show_cancel_button options since they are no longer used
intent.putExtra(ConfirmDeviceCredentialBaseFragment.DARK_THEME, false);
intent.putExtra(ConfirmDeviceCredentialBaseFragment.SHOW_CANCEL_BUTTON, false);
intent.putExtra(ConfirmDeviceCredentialBaseFragment.SHOW_WHEN_LOCKED, external);
intent.putExtra(ConfirmDeviceCredentialBaseFragment.USE_FADE_ANIMATION, external);
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(ChooseLockSettingsHelper.EXTRA_KEY_FOREGROUND_ONLY, foregroundOnly);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_ALLOW_ANY_USER, allowAnyUser);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE,
requestGatekeeperPasswordHandle);
intent.setClassName(SETTINGS_PACKAGE_NAME, activityClass.getName());
intent.putExtra(SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE,
SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE);
Intent inIntent = mFragment != null ? mFragment.getActivity().getIntent() :
mActivity.getIntent();
copyInternalExtras(inIntent, intent);
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);
} else {
mActivity.startActivity(intent);
}
} else {
if (mActivityResultLauncher != null) {
mActivityResultLauncher.launch(intent);
} else if (mFragment != null) {
mFragment.startActivityForResult(intent, request);
} else {
mActivity.startActivityForResult(intent, request);
}
}
return true;
}
private void copyOptionalExtras(Intent inIntent, Intent outIntent) {
IntentSender intentSender = inIntent.getParcelableExtra(Intent.EXTRA_INTENT);
if (intentSender != null) {
outIntent.putExtra(Intent.EXTRA_INTENT, intentSender);
}
int taskId = inIntent.getIntExtra(Intent.EXTRA_TASK_ID, -1);
if (taskId != -1) {
outIntent.putExtra(Intent.EXTRA_TASK_ID, taskId);
}
// If we will launch another activity once credentials are confirmed, exclude from recents.
// This is a workaround to a framework bug where affinity is incorrect for activities
// that are started from a no display activity, as is ConfirmDeviceCredentialActivity.
// TODO: Remove once that bug is fixed.
if (intentSender != null || taskId != -1) {
outIntent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
outIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
}
}
private void copyInternalExtras(Intent inIntent, Intent outIntent) {
SetupWizardUtils.copySetupExtras(inIntent, outIntent);
String theme = inIntent.getStringExtra(WizardManagerHelper.EXTRA_THEME);
if (theme != null) {
outIntent.putExtra(WizardManagerHelper.EXTRA_THEME, theme);
}
}
}