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