1 2 /* 3 * Copyright (C) 2014 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.android.settings.password; 19 20 import static android.Manifest.permission.SET_BIOMETRIC_DIALOG_ADVANCED; 21 import static android.app.admin.DevicePolicyResources.Strings.Settings.CONFIRM_WORK_PROFILE_PASSWORD_HEADER; 22 import static android.app.admin.DevicePolicyResources.Strings.Settings.CONFIRM_WORK_PROFILE_PATTERN_HEADER; 23 import static android.app.admin.DevicePolicyResources.Strings.Settings.CONFIRM_WORK_PROFILE_PIN_HEADER; 24 import static android.content.Intent.EXTRA_PACKAGE_NAME; 25 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; 26 27 import static com.android.systemui.biometrics.Utils.toBitmap; 28 29 import android.app.Activity; 30 import android.app.KeyguardManager; 31 import android.app.RemoteLockscreenValidationSession; 32 import android.app.admin.DevicePolicyManager; 33 import android.app.admin.ManagedSubscriptionsPolicy; 34 import android.app.trust.TrustManager; 35 import android.content.ComponentName; 36 import android.content.Context; 37 import android.content.Intent; 38 import android.content.pm.PackageManager; 39 import android.content.pm.UserProperties; 40 import android.content.res.Configuration; 41 import android.graphics.Bitmap; 42 import android.graphics.Color; 43 import android.hardware.biometrics.BiometricConstants; 44 import android.hardware.biometrics.BiometricManager; 45 import android.hardware.biometrics.BiometricPrompt; 46 import android.hardware.biometrics.BiometricPrompt.AuthenticationCallback; 47 import android.hardware.biometrics.Flags; 48 import android.hardware.biometrics.PromptInfo; 49 import android.os.Bundle; 50 import android.os.Handler; 51 import android.os.Looper; 52 import android.os.UserHandle; 53 import android.os.UserManager; 54 import android.os.storage.StorageManager; 55 import android.text.TextUtils; 56 import android.util.Log; 57 import android.view.WindowManager; 58 59 import androidx.annotation.NonNull; 60 import androidx.fragment.app.FragmentActivity; 61 62 import com.android.internal.widget.LockPatternUtils; 63 import com.android.settings.R; 64 import com.android.settings.Utils; 65 66 import java.util.concurrent.Executor; 67 68 /** 69 * Launch this when you want to confirm the user is present by asking them to enter their 70 * PIN/password/pattern. 71 */ 72 public class ConfirmDeviceCredentialActivity extends FragmentActivity { 73 public static final String TAG = ConfirmDeviceCredentialActivity.class.getSimpleName(); 74 75 private static final String TAG_BIOMETRIC_FRAGMENT = "fragment"; 76 77 /** Use this extra value to provide a custom logo for the biometric prompt. **/ 78 public static final String CUSTOM_BIOMETRIC_PROMPT_LOGO_RES_ID_KEY = "custom_logo_res_id"; 79 /** Use this extra value to provide a custom logo description for the biometric prompt. **/ 80 public static final String CUSTOM_BIOMETRIC_PROMPT_LOGO_DESCRIPTION_KEY = 81 "custom_logo_description"; 82 public static final String BIOMETRIC_PROMPT_AUTHENTICATORS = "biometric_prompt_authenticators"; 83 public static final String BIOMETRIC_PROMPT_NEGATIVE_BUTTON_TEXT = 84 "biometric_prompt_negative_button_text"; 85 public static final String BIOMETRIC_PROMPT_HIDE_BACKGROUND = 86 "biometric_prompt_hide_background"; 87 public static final String EXTRA_DATA = "extra_data"; 88 public static final int BIOMETRIC_LOCKOUT_ERROR_RESULT = 100; 89 90 public static class InternalActivity extends ConfirmDeviceCredentialActivity { 91 } 92 93 private BiometricFragment mBiometricFragment; 94 private DevicePolicyManager mDevicePolicyManager; 95 private LockPatternUtils mLockPatternUtils; 96 private UserManager mUserManager; 97 private TrustManager mTrustManager; 98 private Handler mHandler = new Handler(Looper.getMainLooper()); 99 private Context mContext; 100 private boolean mCheckDevicePolicyManager; 101 private boolean mTaskOverlay; 102 103 private String mTitle; 104 private CharSequence mDetails; 105 private int mUserId; 106 // Used to force the verification path required to unlock profile that shares credentials with 107 // with parent 108 private boolean mForceVerifyPath = false; 109 private boolean mGoingToBackground; 110 private boolean mWaitingForBiometricCallback; 111 private int mBiometricsAuthenticators; 112 private Intent mIntentData; 113 114 private Executor mExecutor = (runnable -> { 115 mHandler.post(runnable); 116 }); 117 118 private AuthenticationCallback mAuthenticationCallback = new AuthenticationCallback() { 119 @Override 120 public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) { 121 if (!mGoingToBackground) { 122 mWaitingForBiometricCallback = false; 123 if (errorCode == BiometricPrompt.BIOMETRIC_ERROR_USER_CANCELED 124 || errorCode == BiometricPrompt.BIOMETRIC_ERROR_CANCELED) { 125 finish(); 126 } else if (mUserManager.getUserInfo(mUserId) == null) { 127 // This can happen when profile gets wiped due to too many failed auth attempts. 128 Log.i(TAG, "Finishing, user no longer valid: " + mUserId); 129 finish(); 130 } else { 131 if ((mBiometricsAuthenticators 132 & BiometricManager.Authenticators.DEVICE_CREDENTIAL) != 0) { 133 // All other errors go to some version of CC 134 showConfirmCredentials(); 135 } else { 136 Log.i(TAG, "Finishing, device credential not requested"); 137 if (Flags.mandatoryBiometrics() 138 && errorCode == BiometricPrompt.BIOMETRIC_ERROR_LOCKOUT_PERMANENT) { 139 setResult(BIOMETRIC_LOCKOUT_ERROR_RESULT); 140 } 141 finish(); 142 } 143 } 144 } else if (mWaitingForBiometricCallback) { // mGoingToBackground is true 145 mWaitingForBiometricCallback = false; 146 finish(); 147 } 148 } 149 150 @Override 151 public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) { 152 mWaitingForBiometricCallback = false; 153 mTrustManager.setDeviceLockedForUser(mUserId, false); 154 final boolean isStrongAuth = result.getAuthenticationType() 155 == BiometricPrompt.AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL; 156 ConfirmDeviceCredentialUtils.reportSuccessfulAttempt(mLockPatternUtils, mUserManager, 157 mDevicePolicyManager, mUserId, isStrongAuth); 158 if (isInternalActivity()) { 159 ConfirmDeviceCredentialUtils.checkForPendingIntent( 160 ConfirmDeviceCredentialActivity.this); 161 } 162 163 setResult(Activity.RESULT_OK, mIntentData); 164 finish(); 165 } 166 167 @Override 168 public void onAuthenticationFailed() { 169 mWaitingForBiometricCallback = false; 170 mDevicePolicyManager.reportFailedBiometricAttempt(mUserId); 171 } 172 173 @Override 174 public void onSystemEvent(int event) { 175 Log.d(TAG, "SystemEvent: " + event); 176 switch (event) { 177 case BiometricConstants.BIOMETRIC_SYSTEM_EVENT_EARLY_USER_CANCEL: 178 finish(); 179 break; 180 } 181 } 182 }; 183 184 @Override onCreate(Bundle savedInstanceState)185 protected void onCreate(Bundle savedInstanceState) { 186 super.onCreate(savedInstanceState); 187 188 final Intent intent = getIntent(); 189 if (intent.getBooleanExtra(BIOMETRIC_PROMPT_HIDE_BACKGROUND, false)) { 190 getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); 191 getWindow().setDimAmount(1); 192 intent.removeExtra(BIOMETRIC_PROMPT_HIDE_BACKGROUND); 193 } else { 194 getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 195 getWindow().setStatusBarColor(Color.TRANSPARENT); 196 } 197 198 mDevicePolicyManager = getSystemService(DevicePolicyManager.class); 199 mUserManager = UserManager.get(this); 200 mTrustManager = getSystemService(TrustManager.class); 201 mLockPatternUtils = new LockPatternUtils(this); 202 mContext = this; 203 mCheckDevicePolicyManager = intent 204 .getBooleanExtra(KeyguardManager.EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS, false); 205 mTitle = intent.getStringExtra(KeyguardManager.EXTRA_TITLE); 206 mDetails = intent.getCharSequenceExtra(KeyguardManager.EXTRA_DESCRIPTION); 207 String alternateButton = intent.getStringExtra( 208 KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL); 209 mBiometricsAuthenticators = intent.getIntExtra(BIOMETRIC_PROMPT_AUTHENTICATORS, 210 BiometricManager.Authenticators.DEVICE_CREDENTIAL 211 | BiometricManager.Authenticators.BIOMETRIC_WEAK); 212 mIntentData = intent.getParcelableExtra(EXTRA_DATA, Intent.class); 213 final String negativeButtonText = intent.getStringExtra( 214 BIOMETRIC_PROMPT_NEGATIVE_BUTTON_TEXT); 215 final boolean frp = 216 KeyguardManager.ACTION_CONFIRM_FRP_CREDENTIAL.equals(intent.getAction()); 217 final boolean repairMode = 218 KeyguardManager.ACTION_CONFIRM_REPAIR_MODE_DEVICE_CREDENTIAL 219 .equals(intent.getAction()); 220 final boolean remoteValidation = 221 KeyguardManager.ACTION_CONFIRM_REMOTE_DEVICE_CREDENTIAL.equals(intent.getAction()); 222 mTaskOverlay = isInternalActivity() 223 && intent.getBooleanExtra(KeyguardManager.EXTRA_FORCE_TASK_OVERLAY, false); 224 final boolean prepareRepairMode = 225 KeyguardManager.ACTION_PREPARE_REPAIR_MODE_DEVICE_CREDENTIAL.equals( 226 intent.getAction()); 227 228 mUserId = UserHandle.myUserId(); 229 if (isInternalActivity()) { 230 try { 231 mUserId = Utils.getUserIdFromBundle(this, intent.getExtras()); 232 } catch (SecurityException se) { 233 Log.e(TAG, "Invalid intent extra", se); 234 } 235 } 236 final int effectiveUserId = mUserManager.getCredentialOwnerProfile(mUserId); 237 final boolean isEffectiveUserManagedProfile = 238 mUserManager.isManagedProfile(effectiveUserId); 239 final UserProperties userProperties = 240 mUserManager.getUserProperties(UserHandle.of(mUserId)); 241 // if the client app did not hand in a title and we are about to show the work challenge, 242 // check whether there is a policy setting the organization name and use that as title 243 if ((mTitle == null) && isEffectiveUserManagedProfile) { 244 mTitle = getTitleFromOrganizationName(mUserId); 245 } 246 247 final PromptInfo promptInfo = new PromptInfo(); 248 promptInfo.setTitle(mTitle); 249 promptInfo.setDescription(mDetails); 250 promptInfo.setDisallowBiometricsIfPolicyExists(mCheckDevicePolicyManager); 251 promptInfo.setAuthenticators(mBiometricsAuthenticators); 252 promptInfo.setNegativeButtonText(negativeButtonText); 253 254 final String callerPackageName = intent.getStringExtra(EXTRA_PACKAGE_NAME); 255 if (isInternalActivity() && callerPackageName != null) { 256 promptInfo.setRealCallerForConfirmDeviceCredentialActivity( 257 new ComponentName(callerPackageName, "")); 258 } else { 259 promptInfo.setRealCallerForConfirmDeviceCredentialActivity(getCallingActivity()); 260 } 261 262 if (android.multiuser.Flags.enablePrivateSpaceFeatures() 263 && android.multiuser.Flags.usePrivateSpaceIconInBiometricPrompt() 264 && hasSetBiometricDialogAdvanced(mContext, getLaunchedFromUid()) 265 ) { 266 final int iconResId = intent.getIntExtra(CUSTOM_BIOMETRIC_PROMPT_LOGO_RES_ID_KEY, 0); 267 if (iconResId != 0) { 268 final Bitmap iconBitmap = toBitmap(mContext.getDrawable(iconResId)); 269 promptInfo.setLogo(iconResId, iconBitmap); 270 } 271 String logoDescription = intent.getStringExtra( 272 CUSTOM_BIOMETRIC_PROMPT_LOGO_DESCRIPTION_KEY); 273 if (!TextUtils.isEmpty(logoDescription)) { 274 promptInfo.setLogoDescription(logoDescription); 275 } 276 } 277 278 final int policyType = mDevicePolicyManager.getManagedSubscriptionsPolicy().getPolicyType(); 279 280 if (isEffectiveUserManagedProfile 281 && (policyType == ManagedSubscriptionsPolicy.TYPE_ALL_MANAGED_SUBSCRIPTIONS)) { 282 promptInfo.setShowEmergencyCallButton(true); 283 } 284 285 final @LockPatternUtils.CredentialType int credentialType = Utils.getCredentialType( 286 mContext, effectiveUserId); 287 if (mTitle == null) { 288 promptInfo.setDeviceCredentialTitle( 289 getTitleFromCredentialType(credentialType, isEffectiveUserManagedProfile)); 290 } 291 if (mDetails == null) { 292 promptInfo.setDeviceCredentialSubtitle( 293 Utils.getConfirmCredentialStringForUser(this, mUserId, credentialType)); 294 } 295 296 boolean launchedBiometric = false; 297 boolean launchedCDC = false; 298 // If the target is a managed user and user key not unlocked yet, we will force unlock 299 // tied profile so it will enable work mode and unlock managed profile, when personal 300 // challenge is unlocked. 301 if (frp) { 302 final ChooseLockSettingsHelper.Builder builder = 303 new ChooseLockSettingsHelper.Builder(this); 304 launchedCDC = builder.setHeader(mTitle) // Show the title in the header location 305 .setDescription(mDetails) 306 .setAlternateButton(alternateButton) 307 .setExternal(true) 308 .setUserId(LockPatternUtils.USER_FRP) 309 .show(); 310 } else if (repairMode) { 311 final ChooseLockSettingsHelper.Builder builder = 312 new ChooseLockSettingsHelper.Builder(this); 313 launchedCDC = builder.setHeader(mTitle) 314 .setDescription(mDetails) 315 .setAlternateButton(alternateButton) 316 .setExternal(true) 317 .setUserId(LockPatternUtils.USER_REPAIR_MODE) 318 .show(); 319 } else if (remoteValidation) { 320 RemoteLockscreenValidationSession remoteLockscreenValidationSession = 321 intent.getParcelableExtra( 322 KeyguardManager.EXTRA_REMOTE_LOCKSCREEN_VALIDATION_SESSION, 323 RemoteLockscreenValidationSession.class); 324 ComponentName remoteLockscreenValidationServiceComponent = 325 intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME, ComponentName.class); 326 327 String checkboxLabel = intent.getStringExtra(KeyguardManager.EXTRA_CHECKBOX_LABEL); 328 final ChooseLockSettingsHelper.Builder builder = 329 new ChooseLockSettingsHelper.Builder(this); 330 launchedCDC = builder 331 .setRemoteLockscreenValidation(true) 332 .setRemoteLockscreenValidationSession(remoteLockscreenValidationSession) 333 .setRemoteLockscreenValidationServiceComponent( 334 remoteLockscreenValidationServiceComponent) 335 .setRequestGatekeeperPasswordHandle(true) 336 .setReturnCredentials(true) // returns only password handle. 337 .setHeader(mTitle) // Show the title in the header location 338 .setDescription(mDetails) 339 .setCheckboxLabel(checkboxLabel) 340 .setAlternateButton(alternateButton) 341 .setExternal(true) 342 .show(); 343 return; 344 } else if (prepareRepairMode) { 345 final ChooseLockSettingsHelper.Builder builder = 346 new ChooseLockSettingsHelper.Builder(this); 347 launchedCDC = builder.setHeader(mTitle) 348 .setDescription(mDetails) 349 .setExternal(true) 350 .setUserId(mUserId) 351 .setTaskOverlay(mTaskOverlay) 352 .setRequestWriteRepairModePassword(true) 353 .setForceVerifyPath(true) 354 .show(); 355 } else if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(mUserId) 356 && isInternalActivity()) { 357 // When the mForceVerifyPath is set to true, we launch the real confirm credential 358 // activity with an explicit but fake challenge value (0L). This will result in 359 // ConfirmLockPassword calling verifyTiedProfileChallenge() (if it's a profile with 360 // unified challenge), due to the difference between 361 // ConfirmLockPassword.startVerifyPassword() and 362 // ConfirmLockPassword.startCheckPassword(). Calling verifyTiedProfileChallenge() here 363 // is necessary when this is part of the turning on work profile flow, because it forces 364 // unlocking the work profile even before the profile is running. 365 // TODO: Remove the duplication of checkPassword and verifyPassword in 366 // ConfirmLockPassword, 367 // LockPatternChecker and LockPatternUtils. verifyPassword should be the only API to 368 // use, which optionally accepts a challenge. 369 mForceVerifyPath = true; 370 if (isBiometricAllowed(effectiveUserId, mUserId)) { 371 showBiometricPrompt(promptInfo, mUserId); 372 launchedBiometric = true; 373 } else { 374 showConfirmCredentials(); 375 launchedCDC = true; 376 } 377 } else if (android.os.Flags.allowPrivateProfile() 378 && android.multiuser.Flags.enablePrivateSpaceFeatures() 379 && userProperties != null 380 && userProperties.isAuthAlwaysRequiredToDisableQuietMode() 381 && isInternalActivity()) { 382 // Force verification path is required to be invoked as we might need to verify the 383 // tied profile challenge if the profile is using the unified challenge mode. This 384 // would result in ConfirmLockPassword.startVerifyPassword/ 385 // ConfirmLockPattern.startVerifyPattern being called instead of the 386 // startCheckPassword/startCheckPattern 387 mForceVerifyPath = userProperties.isCredentialShareableWithParent(); 388 if (android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace() 389 && isBiometricAllowed(effectiveUserId, mUserId)) { 390 setBiometricPromptPropertiesForPrivateProfile(promptInfo); 391 showBiometricPrompt(promptInfo, effectiveUserId); 392 launchedBiometric = true; 393 } else if (Flags.privateSpaceBp()) { 394 promptInfo.setAuthenticators(BiometricManager.Authenticators.DEVICE_CREDENTIAL); 395 setBiometricPromptPropertiesForPrivateProfile(promptInfo); 396 showBiometricPrompt(promptInfo, mUserId); 397 launchedBiometric = true; 398 } else { 399 // TODO(b/376328272): Remove custom private space behavior 400 mDetails = Utils.getConfirmCredentialStringForUser(this, mUserId, credentialType); 401 showConfirmCredentials(); 402 launchedCDC = true; 403 } 404 } else { 405 if (isBiometricAllowed(effectiveUserId, mUserId)) { 406 // Don't need to check if biometrics / pin/pattern/pass are enrolled. It will go to 407 // onAuthenticationError and do the right thing automatically. 408 showBiometricPrompt(promptInfo, mUserId); 409 launchedBiometric = true; 410 } else { 411 showConfirmCredentials(); 412 launchedCDC = true; 413 } 414 } 415 416 if (launchedCDC) { 417 finish(); 418 } else if (launchedBiometric) { 419 // Keep this activity alive until BiometricPrompt goes away 420 mWaitingForBiometricCallback = true; 421 } else { 422 Log.d(TAG, "No pattern, password or PIN set."); 423 setResult(Activity.RESULT_OK); 424 finish(); 425 } 426 } 427 setBiometricPromptPropertiesForPrivateProfile(PromptInfo promptInfo)428 private static void setBiometricPromptPropertiesForPrivateProfile(PromptInfo promptInfo) { 429 promptInfo.setUseParentProfileForDeviceCredential(true); 430 promptInfo.setConfirmationRequested(false); 431 } 432 getTitleFromCredentialType(@ockPatternUtils.CredentialType int credentialType, boolean isEffectiveUserManagedProfile)433 private String getTitleFromCredentialType(@LockPatternUtils.CredentialType int credentialType, 434 boolean isEffectiveUserManagedProfile) { 435 switch (credentialType) { 436 case LockPatternUtils.CREDENTIAL_TYPE_PIN: 437 if (isEffectiveUserManagedProfile) { 438 return mDevicePolicyManager.getResources().getString( 439 CONFIRM_WORK_PROFILE_PIN_HEADER, 440 () -> getString(R.string.lockpassword_confirm_your_work_pin_header)); 441 } 442 443 return getString(R.string.lockpassword_confirm_your_pin_header); 444 case LockPatternUtils.CREDENTIAL_TYPE_PATTERN: 445 if (isEffectiveUserManagedProfile) { 446 return mDevicePolicyManager.getResources().getString( 447 CONFIRM_WORK_PROFILE_PATTERN_HEADER, 448 () -> getString( 449 R.string.lockpassword_confirm_your_work_pattern_header)); 450 } 451 452 return getString(R.string.lockpassword_confirm_your_pattern_header); 453 case LockPatternUtils.CREDENTIAL_TYPE_PASSWORD: 454 if (isEffectiveUserManagedProfile) { 455 return mDevicePolicyManager.getResources().getString( 456 CONFIRM_WORK_PROFILE_PASSWORD_HEADER, 457 () -> getString( 458 R.string.lockpassword_confirm_your_work_password_header)); 459 } 460 461 return getString(R.string.lockpassword_confirm_your_password_header); 462 } 463 return null; 464 } 465 466 @Override onStart()467 protected void onStart() { 468 super.onStart(); 469 // Translucent activity that is "visible", so it doesn't complain about finish() 470 // not being called before onResume(). 471 setVisible(true); 472 473 if ((getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) 474 != Configuration.UI_MODE_NIGHT_YES) { 475 getWindow().getInsetsController().setSystemBarsAppearance( 476 APPEARANCE_LIGHT_STATUS_BARS, APPEARANCE_LIGHT_STATUS_BARS); 477 } 478 } 479 480 @Override onPause()481 public void onPause() { 482 super.onPause(); 483 if (!isChangingConfigurations()) { 484 mGoingToBackground = true; 485 if (!mWaitingForBiometricCallback) { 486 finish(); 487 } 488 } else { 489 mGoingToBackground = false; 490 } 491 } 492 493 /** 494 * Checks if the calling uid has the permission to set biometric dialog icon and description. 495 */ hasSetBiometricDialogAdvanced(@onNull Context context, int callingUid)496 private static boolean hasSetBiometricDialogAdvanced(@NonNull Context context, int callingUid) { 497 return context.checkPermission(SET_BIOMETRIC_DIALOG_ADVANCED, /* pid */ -1, callingUid) 498 == PackageManager.PERMISSION_GRANTED; 499 } 500 501 // User could be locked while Effective user is unlocked even though the effective owns the 502 // credential. Otherwise, biometric can't unlock fbe/keystore through 503 // verifyTiedProfileChallenge. In such case, we also wanna show the user message that 504 // biometric is disabled due to device restart. isStrongAuthRequired(int effectiveUserId)505 private boolean isStrongAuthRequired(int effectiveUserId) { 506 return !mLockPatternUtils.isBiometricAllowedForUser(effectiveUserId) 507 || doesUserStateEnforceStrongAuth(mUserId); 508 } 509 doesUserStateEnforceStrongAuth(int userId)510 private boolean doesUserStateEnforceStrongAuth(int userId) { 511 if (android.os.Flags.allowPrivateProfile() 512 && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace() 513 && android.multiuser.Flags.enablePrivateSpaceFeatures()) { 514 // Check if CE storage for user is locked since biometrics can't unlock fbe/keystore of 515 // the profile user using verifyTiedProfileChallenge. Biometrics can still be used if 516 // the user is stopped with delayed locking (i.e., with storage unlocked), so the user 517 // state (whether the user is in the RUNNING_UNLOCKED state) should not be relied upon. 518 return !StorageManager.isCeStorageUnlocked(userId); 519 } 520 return !mUserManager.isUserUnlocked(userId); 521 } 522 isBiometricAllowed(int effectiveUserId, int realUserId)523 private boolean isBiometricAllowed(int effectiveUserId, int realUserId) { 524 return !isStrongAuthRequired(effectiveUserId) && !mLockPatternUtils 525 .hasPendingEscrowToken(realUserId); 526 } 527 showBiometricPrompt(PromptInfo promptInfo, int userId)528 private void showBiometricPrompt(PromptInfo promptInfo, int userId) { 529 mBiometricFragment = (BiometricFragment) getSupportFragmentManager() 530 .findFragmentByTag(TAG_BIOMETRIC_FRAGMENT); 531 boolean newFragment = false; 532 533 if (mBiometricFragment == null) { 534 mBiometricFragment = BiometricFragment.newInstance(promptInfo); 535 newFragment = true; 536 } 537 mBiometricFragment.setCallbacks(mExecutor, mAuthenticationCallback); 538 // TODO(b/315864564): Move the logic of choosing the user id against which the 539 // authentication needs to happen to the BiometricPrompt API 540 mBiometricFragment.setUser(userId); 541 542 if (newFragment) { 543 getSupportFragmentManager().beginTransaction() 544 .add(mBiometricFragment, TAG_BIOMETRIC_FRAGMENT).commit(); 545 } 546 } 547 548 /** 549 * Shows ConfirmDeviceCredentials for normal apps. 550 */ showConfirmCredentials()551 private void showConfirmCredentials() { 552 boolean launched = new ChooseLockSettingsHelper.Builder(this) 553 .setHeader(mTitle) 554 .setDescription(mDetails) 555 .setExternal(true) 556 .setUserId(mUserId) 557 .setTaskOverlay(mTaskOverlay) 558 .setForceVerifyPath(mForceVerifyPath) 559 .show(); 560 561 if (!launched) { 562 Log.d(TAG, "No pin/pattern/pass set"); 563 setResult(Activity.RESULT_OK); 564 } 565 finish(); 566 } 567 isInternalActivity()568 private boolean isInternalActivity() { 569 return this instanceof ConfirmDeviceCredentialActivity.InternalActivity; 570 } 571 getTitleFromOrganizationName(int userId)572 private String getTitleFromOrganizationName(int userId) { 573 DevicePolicyManager dpm = (DevicePolicyManager) getSystemService( 574 Context.DEVICE_POLICY_SERVICE); 575 CharSequence organizationNameForUser = (dpm != null) 576 ? dpm.getOrganizationNameForUser(userId) : null; 577 return organizationNameForUser != null ? organizationNameForUser.toString() : null; 578 } 579 } 580