1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.password; 18 19 import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.app.Activity; 24 import android.app.ActivityOptions; 25 import android.app.KeyguardManager; 26 import android.app.RemoteLockscreenValidationSession; 27 import android.app.admin.DevicePolicyManager; 28 import android.content.ComponentName; 29 import android.content.Intent; 30 import android.content.IntentSender; 31 import android.os.Bundle; 32 import android.os.UserManager; 33 import android.util.Log; 34 35 import androidx.activity.result.ActivityResultLauncher; 36 import androidx.annotation.VisibleForTesting; 37 import androidx.fragment.app.Fragment; 38 39 import com.android.internal.widget.LockPatternUtils; 40 import com.android.settings.SetupWizardUtils; 41 import com.android.settings.Utils; 42 import com.android.settings.core.SettingsBaseActivity; 43 import com.android.settings.core.SubSettingLauncher; 44 import com.android.settingslib.transition.SettingsTransitionHelper; 45 46 import com.google.android.setupcompat.util.WizardManagerHelper; 47 48 import java.util.Optional; 49 50 public final class ChooseLockSettingsHelper { 51 52 private static final String TAG = "ChooseLockSettingsHelper"; 53 54 public static final String EXTRA_KEY_PASSWORD = "password"; 55 public static final String EXTRA_KEY_RETURN_CREDENTIALS = "return_credentials"; 56 // Force the verifyCredential path instead of checkCredential path. This will be removed 57 // after b/161956762 is resolved. 58 public static final String EXTRA_KEY_FORCE_VERIFY = "force_verify"; 59 // Gatekeeper HardwareAuthToken 60 public static final String EXTRA_KEY_CHALLENGE_TOKEN = "hw_auth_token"; 61 // For the fingerprint-only path 62 public static final String EXTRA_KEY_FOR_FINGERPRINT = "for_fingerprint"; 63 // For the face-only path 64 public static final String EXTRA_KEY_FOR_FACE = "for_face"; 65 // For the paths where multiple biometric sensors exist 66 public static final String EXTRA_KEY_FOR_BIOMETRICS = "for_biometrics"; 67 // For the paths where setup biometrics in suw flow 68 public static final String EXTRA_KEY_IS_SUW = "is_suw"; 69 public static final String EXTRA_KEY_FOREGROUND_ONLY = "foreground_only"; 70 public static final String EXTRA_KEY_REQUEST_GK_PW_HANDLE = "request_gk_pw_handle"; 71 // Gatekeeper password handle, which can subsequently be used to generate Gatekeeper 72 // HardwareAuthToken(s) via LockSettingsService#verifyGatekeeperPasswordHandle 73 public static final String EXTRA_KEY_GK_PW_HANDLE = "gk_pw_handle"; 74 public static final String EXTRA_KEY_REQUEST_WRITE_REPAIR_MODE_PW = 75 "request_write_repair_mode_pw"; 76 public static final String EXTRA_KEY_WROTE_REPAIR_MODE_CREDENTIAL = 77 "wrote_repair_mode_credential"; 78 79 /** 80 * When EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL and EXTRA_KEY_UNIFICATION_PROFILE_ID are 81 * provided to ChooseLockGeneric as fragment arguments {@link SubSettingLauncher#setArguments}, 82 * at the end of the password change flow, the supplied profile user 83 * (EXTRA_KEY_UNIFICATION_PROFILE_ID) will be unified to its parent. The current profile 84 * password is supplied by EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL. 85 */ 86 public static final String EXTRA_KEY_UNIFICATION_PROFILE_ID = "unification_profile_id"; 87 public static final String EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL = 88 "unification_profile_credential"; 89 90 /** 91 * Intent extra for passing the requested min password complexity to later steps in the set new 92 * screen lock flow. 93 */ 94 public static final String EXTRA_KEY_REQUESTED_MIN_COMPLEXITY = "requested_min_complexity"; 95 96 /** 97 * Intent extra for passing the label of the calling app to later steps in the set new screen 98 * lock flow. 99 */ 100 public static final String EXTRA_KEY_CALLER_APP_NAME = "caller_app_name"; 101 102 /** 103 * Intent extra indicating that the calling app is an admin, such as a Device Adimn, Device 104 * Owner, or Profile Owner. 105 */ 106 public static final String EXTRA_KEY_IS_CALLING_APP_ADMIN = "is_calling_app_admin"; 107 108 /** 109 * When invoked via {@link ConfirmLockPassword.InternalActivity}, this flag 110 * controls if we relax the enforcement of 111 * {@link Utils#enforceSameOwner(android.content.Context, int)}. 112 */ 113 public static final String EXTRA_KEY_ALLOW_ANY_USER = "allow_any_user"; 114 115 /** 116 * 117 */ 118 public static final String EXTRA_KEY_DEVICE_PASSWORD_REQUIREMENT_ONLY = 119 "device_password_requirement_only"; 120 121 @VisibleForTesting @NonNull LockPatternUtils mLockPatternUtils; 122 @NonNull private final Activity mActivity; 123 @Nullable private final Fragment mFragment; 124 @Nullable private final ActivityResultLauncher mActivityResultLauncher; 125 @NonNull private final Builder mBuilder; 126 ChooseLockSettingsHelper(@onNull Builder builder, @NonNull Activity activity, @Nullable Fragment fragment, @Nullable ActivityResultLauncher activityResultLauncher)127 private ChooseLockSettingsHelper(@NonNull Builder builder, @NonNull Activity activity, 128 @Nullable Fragment fragment, 129 @Nullable ActivityResultLauncher activityResultLauncher) { 130 mBuilder = builder; 131 mActivity = activity; 132 mFragment = fragment; 133 mActivityResultLauncher = activityResultLauncher; 134 mLockPatternUtils = new LockPatternUtils(activity); 135 } 136 137 public static class Builder { 138 @NonNull private final Activity mActivity; 139 @Nullable private Fragment mFragment; 140 @Nullable private ActivityResultLauncher mActivityResultLauncher; 141 142 private int mRequestCode; 143 @Nullable private CharSequence mTitle; 144 @Nullable private CharSequence mHeader; 145 @Nullable private CharSequence mDescription; 146 @Nullable private CharSequence mAlternateButton; 147 @Nullable private CharSequence mCheckBoxLabel; 148 private boolean mReturnCredentials; 149 private boolean mExternal; 150 private boolean mForegroundOnly; 151 // ChooseLockSettingsHelper will determine the caller's userId if none provided. 152 private int mUserId; 153 private boolean mAllowAnyUserId; 154 private boolean mForceVerifyPath; 155 private boolean mRemoteLockscreenValidation; 156 @Nullable private RemoteLockscreenValidationSession mRemoteLockscreenValidationSession; 157 @Nullable private ComponentName mRemoteLockscreenValidationServiceComponent; 158 private boolean mRequestGatekeeperPasswordHandle; 159 private boolean mRequestWriteRepairModePassword; 160 private boolean mTaskOverlay; 161 Builder(@onNull Activity activity)162 public Builder(@NonNull Activity activity) { 163 mActivity = activity; 164 mUserId = Utils.getCredentialOwnerUserId(mActivity); 165 } 166 Builder(@onNull Activity activity, @NonNull Fragment fragment)167 public Builder(@NonNull Activity activity, @NonNull Fragment fragment) { 168 this(activity); 169 mFragment = fragment; 170 } 171 172 /** 173 * @param requestCode for onActivityResult 174 */ setRequestCode(int requestCode)175 @NonNull public Builder setRequestCode(int requestCode) { 176 mRequestCode = requestCode; 177 return this; 178 } 179 180 /** 181 * @param title of the confirmation screen; shown in the action bar 182 */ setTitle(@ullable CharSequence title)183 @NonNull public Builder setTitle(@Nullable CharSequence title) { 184 mTitle = title; 185 return this; 186 } 187 188 /** 189 * @param header of the confirmation screen; shown as large text 190 */ setHeader(@ullable CharSequence header)191 @NonNull public Builder setHeader(@Nullable CharSequence header) { 192 mHeader = header; 193 return this; 194 } 195 196 /** 197 * @param description of the confirmation screen 198 */ setDescription(@ullable CharSequence description)199 @NonNull public Builder setDescription(@Nullable CharSequence description) { 200 mDescription = description; 201 return this; 202 } 203 204 /** 205 * @param alternateButton text for an alternate button 206 */ setAlternateButton(@ullable CharSequence alternateButton)207 @NonNull public Builder setAlternateButton(@Nullable CharSequence alternateButton) { 208 mAlternateButton = alternateButton; 209 return this; 210 } 211 212 /** 213 * @param checkboxLabel text for the checkbox 214 */ 215 @NonNull setCheckboxLabel(@ullable CharSequence checkboxLabel)216 public Builder setCheckboxLabel(@Nullable CharSequence checkboxLabel) { 217 mCheckBoxLabel = checkboxLabel; 218 return this; 219 } 220 221 /** 222 * @param returnCredentials if true, puts the following credentials into intent for 223 * onActivityResult with the following keys: 224 * {@link #EXTRA_KEY_PASSWORD}, 225 * {@link #EXTRA_KEY_CHALLENGE_TOKEN}, 226 * {@link #EXTRA_KEY_GK_PW_HANDLE} 227 * Note that if this is true, this can only be called internally. 228 * 229 * This should also generally be set if 230 * {@link #setRequestGatekeeperPasswordHandle(boolean)} is set. 231 */ setReturnCredentials(boolean returnCredentials)232 @NonNull public Builder setReturnCredentials(boolean returnCredentials) { 233 mReturnCredentials = returnCredentials; 234 return this; 235 } 236 237 /** 238 * @param userId for whom the credential should be confirmed. 239 */ setUserId(int userId)240 @NonNull public Builder setUserId(int userId) { 241 mUserId = userId; 242 return this; 243 } 244 245 /** 246 * @param allowAnyUserId Allows the caller to prompt for credentials of any user, including 247 * those which aren't associated with the current user. As an example, 248 * this is useful when unlocking the storage for secondary users. 249 */ setAllowAnyUserId(boolean allowAnyUserId)250 @NonNull public Builder setAllowAnyUserId(boolean allowAnyUserId) { 251 mAllowAnyUserId = allowAnyUserId; 252 return this; 253 } 254 255 /** 256 * @param external specifies whether this activity is launched externally, meaning that it 257 * will get a dark theme, allow biometric authentication, and it will 258 * forward the activity result. 259 */ setExternal(boolean external)260 @NonNull public Builder setExternal(boolean external) { 261 mExternal = external; 262 return this; 263 } 264 265 /** 266 * @param taskOverlay specifies whether the activity should be launched as a task overlay. 267 */ setTaskOverlay(boolean taskOverlay)268 @NonNull public Builder setTaskOverlay(boolean taskOverlay) { 269 mTaskOverlay = taskOverlay; 270 return this; 271 } 272 273 /** 274 * @param foregroundOnly if true, the confirmation activity will be finished if it loses 275 * foreground. 276 */ setForegroundOnly(boolean foregroundOnly)277 @NonNull public Builder setForegroundOnly(boolean foregroundOnly) { 278 mForegroundOnly = foregroundOnly; 279 return this; 280 } 281 282 /** 283 * @param forceVerifyPath Forces the VerifyCredential path instead of the CheckCredential 284 * path. This will be removed after b/161956762 is resolved. 285 */ setForceVerifyPath(boolean forceVerifyPath)286 @NonNull public Builder setForceVerifyPath(boolean forceVerifyPath) { 287 mForceVerifyPath = forceVerifyPath; 288 return this; 289 } 290 291 /** 292 * @param isRemoteLockscreenValidation if true, remote device validation flow will be 293 * started. {@link #setRemoteLockscreenValidationSession}, 294 * {@link #setRemoteLockscreenValidationServiceComponent} 295 * must also be used to set the required data. 296 */ setRemoteLockscreenValidation( boolean isRemoteLockscreenValidation)297 @NonNull public Builder setRemoteLockscreenValidation( 298 boolean isRemoteLockscreenValidation) { 299 mRemoteLockscreenValidation = isRemoteLockscreenValidation; 300 return this; 301 } 302 303 /** 304 * @param remoteLockscreenValidationSession contains information necessary to perform remote 305 * lockscreen validation such as the remote device's 306 * lockscreen type, public key to be used for 307 * encryption, and remaining attempts. 308 */ setRemoteLockscreenValidationSession( RemoteLockscreenValidationSession remoteLockscreenValidationSession)309 @NonNull public Builder setRemoteLockscreenValidationSession( 310 RemoteLockscreenValidationSession remoteLockscreenValidationSession) { 311 mRemoteLockscreenValidationSession = remoteLockscreenValidationSession; 312 return this; 313 } 314 315 /** 316 * @param remoteLockscreenValidationServiceComponent the {@link ComponentName} of the 317 * {@link android.service.remotelockscreenvalidation.RemoteLockscreenValidationService} 318 * that will be used to validate the lockscreen guess. 319 */ setRemoteLockscreenValidationServiceComponent( ComponentName remoteLockscreenValidationServiceComponent)320 @NonNull public Builder setRemoteLockscreenValidationServiceComponent( 321 ComponentName remoteLockscreenValidationServiceComponent) { 322 mRemoteLockscreenValidationServiceComponent = 323 remoteLockscreenValidationServiceComponent; 324 return this; 325 } 326 327 /** 328 * Requests that LockSettingsService return a handle to the Gatekeeper Password (instead of 329 * the Gatekeeper HAT). This allows us to use a single entry of the user's credential 330 * to create multiple Gatekeeper HATs containing distinct challenges via 331 * {@link LockPatternUtils#verifyGatekeeperPasswordHandle(long, long, int)}. 332 * 333 * Upon confirmation of the user's password, the Gatekeeper Password Handle will be returned 334 * via onActivityResult with the key being {@link #EXTRA_KEY_GK_PW_HANDLE}. 335 * @param requestGatekeeperPasswordHandle 336 */ setRequestGatekeeperPasswordHandle( boolean requestGatekeeperPasswordHandle)337 @NonNull public Builder setRequestGatekeeperPasswordHandle( 338 boolean requestGatekeeperPasswordHandle) { 339 mRequestGatekeeperPasswordHandle = requestGatekeeperPasswordHandle; 340 return this; 341 } 342 343 /** 344 * @param requestWriteRepairModePassword Set {@code true} to request that 345 * LockSettingsService writes the password data to the repair mode file after the user 346 * credential is verified successfully. 347 */ setRequestWriteRepairModePassword( boolean requestWriteRepairModePassword)348 @NonNull public Builder setRequestWriteRepairModePassword( 349 boolean requestWriteRepairModePassword) { 350 mRequestWriteRepairModePassword = requestWriteRepairModePassword; 351 return this; 352 } 353 354 /** 355 * Support of ActivityResultLauncher. 356 * 357 * Which allowing the launch operation be controlled externally. 358 * @param activityResultLauncher a launcher previously prepared. 359 */ setActivityResultLauncher( ActivityResultLauncher activityResultLauncher)360 @NonNull public Builder setActivityResultLauncher( 361 ActivityResultLauncher activityResultLauncher) { 362 mActivityResultLauncher = activityResultLauncher; 363 return this; 364 } 365 build()366 @NonNull public ChooseLockSettingsHelper build() { 367 if (!mAllowAnyUserId && mUserId != LockPatternUtils.USER_FRP 368 && mUserId != LockPatternUtils.USER_REPAIR_MODE) { 369 Utils.enforceSameOwner(mActivity, mUserId); 370 } 371 372 if (mExternal && mReturnCredentials && !mRemoteLockscreenValidation) { 373 throw new IllegalArgumentException("External and ReturnCredentials specified. " 374 + " External callers should never be allowed to receive credentials in" 375 + " onActivityResult"); 376 } 377 378 if (mRequestGatekeeperPasswordHandle && !mReturnCredentials) { 379 // HAT containing the signed challenge will not be available to the caller. 380 Log.w(TAG, "Requested gatekeeper password handle but not requesting" 381 + " ReturnCredentials. Are you sure this is what you want?"); 382 } 383 384 return new ChooseLockSettingsHelper(this, mActivity, mFragment, 385 mActivityResultLauncher); 386 } 387 show()388 public boolean show() { 389 return build().launch(); 390 } 391 } 392 393 /** 394 * If a PIN, Pattern, or Password exists, prompt the user to confirm it. 395 * @return true if the confirmation activity is shown (e.g. user has a credential set up) 396 */ launch()397 public boolean launch() { 398 return launchConfirmationActivity(mBuilder.mRequestCode, mBuilder.mTitle, mBuilder.mHeader, 399 mBuilder.mDescription, mBuilder.mReturnCredentials, mBuilder.mExternal, 400 mBuilder.mForceVerifyPath, mBuilder.mUserId, mBuilder.mAlternateButton, 401 mBuilder.mCheckBoxLabel, mBuilder.mRemoteLockscreenValidation, 402 mBuilder.mRemoteLockscreenValidationSession, 403 mBuilder.mRemoteLockscreenValidationServiceComponent, mBuilder.mAllowAnyUserId, 404 mBuilder.mForegroundOnly, mBuilder.mRequestGatekeeperPasswordHandle, 405 mBuilder.mRequestWriteRepairModePassword, mBuilder.mTaskOverlay); 406 } 407 launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, boolean returnCredentials, boolean external, boolean forceVerifyPath, int userId, @Nullable CharSequence alternateButton, @Nullable CharSequence checkboxLabel, boolean remoteLockscreenValidation, @Nullable RemoteLockscreenValidationSession remoteLockscreenValidationSession, @Nullable ComponentName remoteLockscreenValidationServiceComponent, boolean allowAnyUser, boolean foregroundOnly, boolean requestGatekeeperPasswordHandle, boolean requestWriteRepairModePassword, boolean taskOverlay)408 private boolean launchConfirmationActivity(int request, @Nullable CharSequence title, 409 @Nullable CharSequence header, @Nullable CharSequence description, 410 boolean returnCredentials, boolean external, boolean forceVerifyPath, 411 int userId, @Nullable CharSequence alternateButton, 412 @Nullable CharSequence checkboxLabel, boolean remoteLockscreenValidation, 413 @Nullable RemoteLockscreenValidationSession remoteLockscreenValidationSession, 414 @Nullable ComponentName remoteLockscreenValidationServiceComponent, 415 boolean allowAnyUser, boolean foregroundOnly, boolean requestGatekeeperPasswordHandle, 416 boolean requestWriteRepairModePassword, boolean taskOverlay) { 417 Optional<Class<?>> activityClass = determineAppropriateActivityClass( 418 returnCredentials, forceVerifyPath, userId, remoteLockscreenValidationSession); 419 if (activityClass.isEmpty()) { 420 return false; 421 } 422 423 return launchConfirmationActivity(request, title, header, description, activityClass.get(), 424 returnCredentials, external, forceVerifyPath, userId, alternateButton, 425 checkboxLabel, remoteLockscreenValidation, remoteLockscreenValidationSession, 426 remoteLockscreenValidationServiceComponent, allowAnyUser, foregroundOnly, 427 requestGatekeeperPasswordHandle, requestWriteRepairModePassword, taskOverlay); 428 } 429 launchConfirmationActivity(int request, CharSequence title, CharSequence header, CharSequence message, Class<?> activityClass, boolean returnCredentials, boolean external, boolean forceVerifyPath, int userId, @Nullable CharSequence alternateButton, @Nullable CharSequence checkbox, boolean remoteLockscreenValidation, @Nullable RemoteLockscreenValidationSession remoteLockscreenValidationSession, @Nullable ComponentName remoteLockscreenValidationServiceComponent, boolean allowAnyUser, boolean foregroundOnly, boolean requestGatekeeperPasswordHandle, boolean requestWriteRepairModePassword, boolean taskOverlay)430 private boolean launchConfirmationActivity(int request, CharSequence title, CharSequence header, 431 CharSequence message, Class<?> activityClass, boolean returnCredentials, 432 boolean external, boolean forceVerifyPath, int userId, 433 @Nullable CharSequence alternateButton, @Nullable CharSequence checkbox, 434 boolean remoteLockscreenValidation, 435 @Nullable RemoteLockscreenValidationSession remoteLockscreenValidationSession, 436 @Nullable ComponentName remoteLockscreenValidationServiceComponent, 437 boolean allowAnyUser, boolean foregroundOnly, boolean requestGatekeeperPasswordHandle, 438 boolean requestWriteRepairModePassword, boolean taskOverlay) { 439 final Intent intent = new Intent(); 440 intent.putExtra(ConfirmDeviceCredentialBaseFragment.TITLE_TEXT, title); 441 intent.putExtra(ConfirmDeviceCredentialBaseFragment.HEADER_TEXT, header); 442 intent.putExtra(ConfirmDeviceCredentialBaseFragment.DETAILS_TEXT, message); 443 // TODO: Remove dark theme and show_cancel_button options since they are no longer used 444 intent.putExtra(ConfirmDeviceCredentialBaseFragment.DARK_THEME, false); 445 intent.putExtra(ConfirmDeviceCredentialBaseFragment.SHOW_CANCEL_BUTTON, false); 446 intent.putExtra(ConfirmDeviceCredentialBaseFragment.SHOW_WHEN_LOCKED, external); 447 intent.putExtra(ConfirmDeviceCredentialBaseFragment.USE_FADE_ANIMATION, external); 448 intent.putExtra(ConfirmDeviceCredentialBaseFragment.IS_REMOTE_LOCKSCREEN_VALIDATION, 449 remoteLockscreenValidation); 450 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_RETURN_CREDENTIALS, returnCredentials); 451 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FORCE_VERIFY, forceVerifyPath); 452 intent.putExtra(Intent.EXTRA_USER_ID, userId); 453 intent.putExtra(KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL, alternateButton); 454 intent.putExtra(KeyguardManager.EXTRA_CHECKBOX_LABEL, checkbox); 455 intent.putExtra(KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION, 456 remoteLockscreenValidationSession); 457 intent.putExtra(Intent.EXTRA_COMPONENT_NAME, remoteLockscreenValidationServiceComponent); 458 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOREGROUND_ONLY, foregroundOnly); 459 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_ALLOW_ANY_USER, allowAnyUser); 460 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, 461 requestGatekeeperPasswordHandle); 462 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_WRITE_REPAIR_MODE_PW, 463 requestWriteRepairModePassword); 464 465 intent.setClassName(SETTINGS_PACKAGE_NAME, activityClass.getName()); 466 intent.putExtra(SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE, 467 SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE); 468 469 Intent inIntent = mFragment != null ? mFragment.getActivity().getIntent() : 470 mActivity.getIntent(); 471 copyInternalExtras(inIntent, intent); 472 Bundle launchOptions = createLaunchOptions(taskOverlay); 473 if (external) { 474 intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); 475 copyOptionalExtras(inIntent, intent); 476 if (mActivityResultLauncher != null) { 477 mActivityResultLauncher.launch(intent); 478 } else if (mFragment != null) { 479 mFragment.startActivity(intent, launchOptions); 480 } else { 481 mActivity.startActivity(intent, launchOptions); 482 } 483 } else { 484 if (mActivityResultLauncher != null) { 485 mActivityResultLauncher.launch(intent); 486 } else if (mFragment != null) { 487 mFragment.startActivityForResult(intent, request, launchOptions); 488 } else { 489 mActivity.startActivityForResult(intent, request, launchOptions); 490 } 491 } 492 return true; 493 } 494 createLaunchOptions(boolean taskOverlay)495 private Bundle createLaunchOptions(boolean taskOverlay) { 496 if (!taskOverlay) { 497 return null; 498 } 499 ActivityOptions options = ActivityOptions.makeBasic(); 500 options.setLaunchTaskId(mActivity.getTaskId()); 501 options.setTaskOverlay(true /* taskOverlay */, true /* canResume */); 502 return options.toBundle(); 503 } 504 passwordQualityToLockTypes(int quality)505 private Optional<Integer> passwordQualityToLockTypes(int quality) { 506 switch (quality) { 507 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: 508 return Optional.of(KeyguardManager.PATTERN); 509 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: 510 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: 511 return Optional.of(KeyguardManager.PIN); 512 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: 513 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: 514 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: 515 case DevicePolicyManager.PASSWORD_QUALITY_MANAGED: 516 return Optional.of(KeyguardManager.PASSWORD); 517 } 518 Log.e(TAG, String.format( 519 "Cannot determine appropriate activity class for password quality %d", 520 quality)); 521 return Optional.empty(); 522 } 523 determineAppropriateActivityClass(boolean returnCredentials, boolean forceVerifyPath, int userId, @Nullable RemoteLockscreenValidationSession remoteLockscreenValidationSession)524 private Optional<Class<?>> determineAppropriateActivityClass(boolean returnCredentials, 525 boolean forceVerifyPath, int userId, 526 @Nullable RemoteLockscreenValidationSession remoteLockscreenValidationSession) { 527 int lockType; 528 if (remoteLockscreenValidationSession != null) { 529 lockType = remoteLockscreenValidationSession.getLockType(); 530 } else { 531 final int effectiveUserId = UserManager 532 .get(mActivity).getCredentialOwnerProfile(userId); 533 Optional<Integer> lockTypeOptional = passwordQualityToLockTypes( 534 mLockPatternUtils.getKeyguardStoredPasswordQuality(effectiveUserId)); 535 if (lockTypeOptional.isEmpty()) { 536 return Optional.empty(); 537 } 538 lockType = lockTypeOptional.get(); 539 } 540 541 switch (lockType) { 542 case KeyguardManager.PASSWORD: 543 case KeyguardManager.PIN: 544 return Optional.of(returnCredentials || forceVerifyPath 545 ? ConfirmLockPassword.InternalActivity.class 546 : ConfirmLockPassword.class); 547 case KeyguardManager.PATTERN: 548 return Optional.of(returnCredentials || forceVerifyPath 549 ? ConfirmLockPattern.InternalActivity.class 550 : ConfirmLockPattern.class); 551 } 552 Log.e(TAG, String.format("Cannot determine appropriate activity class for lock type %d", 553 lockType)); 554 return Optional.empty(); 555 } 556 copyOptionalExtras(Intent inIntent, Intent outIntent)557 private void copyOptionalExtras(Intent inIntent, Intent outIntent) { 558 IntentSender intentSender = inIntent.getParcelableExtra(Intent.EXTRA_INTENT); 559 if (intentSender != null) { 560 outIntent.putExtra(Intent.EXTRA_INTENT, intentSender); 561 } 562 int taskId = inIntent.getIntExtra(Intent.EXTRA_TASK_ID, -1); 563 if (taskId != -1) { 564 outIntent.putExtra(Intent.EXTRA_TASK_ID, taskId); 565 } 566 // If we will launch another activity once credentials are confirmed, exclude from recents. 567 // This is a workaround to a framework bug where affinity is incorrect for activities 568 // that are started from a no display activity, as is ConfirmDeviceCredentialActivity. 569 // TODO: Remove once that bug is fixed. 570 if (intentSender != null || taskId != -1) { 571 outIntent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 572 outIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); 573 } 574 } 575 copyInternalExtras(Intent inIntent, Intent outIntent)576 private void copyInternalExtras(Intent inIntent, Intent outIntent) { 577 SetupWizardUtils.copySetupExtras(inIntent, outIntent); 578 String theme = inIntent.getStringExtra(WizardManagerHelper.EXTRA_THEME); 579 if (theme != null) { 580 outIntent.putExtra(WizardManagerHelper.EXTRA_THEME, theme); 581 } 582 } 583 } 584