1 /* 2 * Copyright (C) 2014 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.systemui.statusbar; 18 19 import static android.adaptiveauth.Flags.enableAdaptiveAuth; 20 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED; 21 import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_MANAGEMENT_DISCLOSURE; 22 import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_NAMED_MANAGEMENT_DISCLOSURE; 23 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_START; 24 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK; 25 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_TIMEOUT; 26 import static android.hardware.biometrics.BiometricSourceType.FACE; 27 import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT; 28 import static android.view.View.GONE; 29 import static android.view.View.VISIBLE; 30 31 import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_AVAILABLE; 32 import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED; 33 import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED; 34 import static com.android.systemui.DejankUtils.whitelistIpcs; 35 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.IMPORTANT_MSG_MIN_DURATION; 36 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_IS_DISMISSIBLE; 37 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ADAPTIVE_AUTH; 38 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT; 39 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY; 40 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BIOMETRIC_MESSAGE; 41 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP; 42 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_DISCLOSURE; 43 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_LOGOUT; 44 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO; 45 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_PERSISTENT_UNLOCK_MESSAGE; 46 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRUST; 47 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_USER_LOCKED; 48 import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_ON; 49 import static com.android.systemui.log.core.LogLevel.ERROR; 50 import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY; 51 import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow; 52 53 import android.app.AlarmManager; 54 import android.app.admin.DevicePolicyManager; 55 import android.content.BroadcastReceiver; 56 import android.content.Context; 57 import android.content.Intent; 58 import android.content.IntentFilter; 59 import android.content.pm.UserInfo; 60 import android.content.res.ColorStateList; 61 import android.content.res.Resources; 62 import android.graphics.Color; 63 import android.hardware.biometrics.BiometricSourceType; 64 import android.os.BatteryManager; 65 import android.os.Handler; 66 import android.os.Looper; 67 import android.os.Message; 68 import android.os.RemoteException; 69 import android.os.UserHandle; 70 import android.os.UserManager; 71 import android.provider.DeviceConfig; 72 import android.text.TextUtils; 73 import android.text.format.Formatter; 74 import android.util.Pair; 75 import android.view.View; 76 import android.view.ViewGroup; 77 import android.view.accessibility.AccessibilityManager; 78 79 import androidx.annotation.NonNull; 80 import androidx.annotation.Nullable; 81 82 import com.android.internal.annotations.VisibleForTesting; 83 import com.android.internal.app.IBatteryStats; 84 import com.android.internal.widget.LockPatternUtils; 85 import com.android.keyguard.KeyguardUpdateMonitor; 86 import com.android.keyguard.KeyguardUpdateMonitorCallback; 87 import com.android.keyguard.TrustGrantFlags; 88 import com.android.keyguard.logging.KeyguardLogger; 89 import com.android.settingslib.Utils; 90 import com.android.settingslib.fuelgauge.BatteryStatus; 91 import com.android.systemui.Flags; 92 import com.android.systemui.biometrics.AuthController; 93 import com.android.systemui.biometrics.FaceHelpMessageDeferral; 94 import com.android.systemui.biometrics.FaceHelpMessageDeferralFactory; 95 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor; 96 import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor; 97 import com.android.systemui.broadcast.BroadcastDispatcher; 98 import com.android.systemui.dagger.SysUISingleton; 99 import com.android.systemui.dagger.qualifiers.Background; 100 import com.android.systemui.dagger.qualifiers.Main; 101 import com.android.systemui.deviceentry.domain.interactor.BiometricMessageInteractor; 102 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor; 103 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFingerprintAuthInteractor; 104 import com.android.systemui.dock.DockManager; 105 import com.android.systemui.flags.FeatureFlags; 106 import com.android.systemui.keyguard.KeyguardIndication; 107 import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController; 108 import com.android.systemui.keyguard.ScreenLifecycle; 109 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; 110 import com.android.systemui.keyguard.util.IndicationHelper; 111 import com.android.systemui.log.core.LogLevel; 112 import com.android.systemui.plugins.FalsingManager; 113 import com.android.systemui.plugins.statusbar.StatusBarStateController; 114 import com.android.systemui.res.R; 115 import com.android.systemui.settings.UserTracker; 116 import com.android.systemui.statusbar.phone.KeyguardBypassController; 117 import com.android.systemui.statusbar.phone.KeyguardIndicationTextView; 118 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; 119 import com.android.systemui.statusbar.policy.KeyguardStateController; 120 import com.android.systemui.user.domain.interactor.UserLogoutInteractor; 121 import com.android.systemui.util.AlarmTimeout; 122 import com.android.systemui.util.concurrency.DelayableExecutor; 123 import com.android.systemui.util.wakelock.SettableWakeLock; 124 import com.android.systemui.util.wakelock.WakeLock; 125 126 import java.io.PrintWriter; 127 import java.text.NumberFormat; 128 import java.util.Set; 129 import java.util.function.Consumer; 130 131 import javax.inject.Inject; 132 133 /** 134 * Controls the indications and error messages shown on the Keyguard 135 * 136 * On AoD, only one message shows with the following priorities: 137 * 1. Biometric 138 * 2. Transient 139 * 3. Charging alignment 140 * 4. Battery information 141 * 142 * On the lock screen, message rotate through different message types. 143 * See {@link KeyguardIndicationRotateTextViewController.IndicationType} for the list of types. 144 */ 145 @SysUISingleton 146 public class KeyguardIndicationController { 147 148 public static final String TAG = "KeyguardIndication"; 149 private static final boolean DEBUG_CHARGING_SPEED = false; 150 151 private static final int MSG_SHOW_ACTION_TO_UNLOCK = 1; 152 private static final int MSG_RESET_ERROR_MESSAGE_ON_SCREEN_ON = 2; 153 private static final long TRANSIENT_BIOMETRIC_ERROR_TIMEOUT = 1300; 154 public static final long DEFAULT_MESSAGE_TIME = 3500; 155 public static final long DEFAULT_HIDE_DELAY_MS = 156 DEFAULT_MESSAGE_TIME + KeyguardIndicationTextView.Y_IN_DURATION; 157 158 private final Context mContext; 159 private final BroadcastDispatcher mBroadcastDispatcher; 160 private final KeyguardStateController mKeyguardStateController; 161 protected final StatusBarStateController mStatusBarStateController; 162 private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; 163 private final AuthController mAuthController; 164 private final KeyguardLogger mKeyguardLogger; 165 private final UserTracker mUserTracker; 166 private final BouncerMessageInteractor mBouncerMessageInteractor; 167 168 private ViewGroup mIndicationArea; 169 private KeyguardIndicationTextView mTopIndicationView; 170 private KeyguardIndicationTextView mLockScreenIndicationView; 171 private final IBatteryStats mBatteryInfo; 172 private final SettableWakeLock mWakeLock; 173 private final DockManager mDockManager; 174 private final DevicePolicyManager mDevicePolicyManager; 175 private final UserManager mUserManager; 176 protected final @Main DelayableExecutor mExecutor; 177 protected final @Background DelayableExecutor mBackgroundExecutor; 178 private final LockPatternUtils mLockPatternUtils; 179 private final FalsingManager mFalsingManager; 180 private final KeyguardBypassController mKeyguardBypassController; 181 private final AccessibilityManager mAccessibilityManager; 182 private final Handler mHandler; 183 private final AlternateBouncerInteractor mAlternateBouncerInteractor; 184 185 @VisibleForTesting 186 public KeyguardIndicationRotateTextViewController mRotateTextViewController; 187 private BroadcastReceiver mBroadcastReceiver; 188 private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; 189 private KeyguardInteractor mKeyguardInteractor; 190 private final BiometricMessageInteractor mBiometricMessageInteractor; 191 private DeviceEntryFingerprintAuthInteractor mDeviceEntryFingerprintAuthInteractor; 192 private DeviceEntryFaceAuthInteractor mDeviceEntryFaceAuthInteractor; 193 private final UserLogoutInteractor mUserLogoutInteractor; 194 private String mPersistentUnlockMessage; 195 private String mAlignmentIndication; 196 private boolean mForceIsDismissible; 197 private CharSequence mTrustGrantedIndication; 198 private CharSequence mTransientIndication; 199 private CharSequence mTrustAgentErrorMessage; 200 private CharSequence mBiometricMessage; 201 private CharSequence mBiometricMessageFollowUp; 202 private BiometricSourceType mBiometricMessageSource; 203 private ColorStateList mInitialTextColorState; 204 private boolean mVisible; 205 private boolean mOrganizationOwnedDevice; 206 207 // these all assume the device is plugged in (wired/wireless/docked) AND chargingOrFull: 208 protected boolean mPowerPluggedIn; 209 protected boolean mPowerPluggedInWired; 210 protected boolean mPowerPluggedInWireless; 211 protected boolean mPowerPluggedInDock; 212 protected int mChargingSpeed; 213 protected boolean mPowerCharged; 214 protected int mChargingStatus; 215 216 /** Whether the battery defender is triggered. */ 217 private boolean mBatteryDefender; 218 /** Whether the battery defender is triggered with the device plugged. */ 219 private boolean mEnableBatteryDefender; 220 private boolean mIncompatibleCharger; 221 private int mChargingWattage; 222 private int mBatteryLevel = -1; 223 private boolean mBatteryPresent = true; 224 protected long mChargingTimeRemaining; 225 private Pair<String, BiometricSourceType> mBiometricErrorMessageToShowOnScreenOn; 226 private Set<Integer> mCoExFaceAcquisitionMsgIdsToShow; 227 private final FaceHelpMessageDeferral mFaceAcquiredMessageDeferral; 228 private boolean mInited; 229 230 private KeyguardUpdateMonitorCallback mUpdateMonitorCallback; 231 232 private boolean mDozing; 233 private final ScreenLifecycle mScreenLifecycle; 234 @VisibleForTesting 235 final Consumer<Set<Integer>> mCoExAcquisitionMsgIdsToShowCallback = 236 (Set<Integer> coExFaceAcquisitionMsgIdsToShow) -> mCoExFaceAcquisitionMsgIdsToShow = 237 coExFaceAcquisitionMsgIdsToShow; 238 @VisibleForTesting 239 final Consumer<Boolean> mIsFingerprintEngagedCallback = 240 (Boolean isEngaged) -> { 241 if (!isEngaged) { 242 showTrustAgentErrorMessage(mTrustAgentErrorMessage); 243 } 244 }; 245 @VisibleForTesting 246 final Consumer<Boolean> mIsLogoutEnabledCallback = 247 (Boolean isLogoutEnabled) -> { 248 if (mVisible) { 249 updateDeviceEntryIndication(false); 250 } 251 }; 252 private final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() { 253 @Override 254 public void onScreenTurnedOn() { 255 mHandler.removeMessages(MSG_RESET_ERROR_MESSAGE_ON_SCREEN_ON); 256 if (mBiometricErrorMessageToShowOnScreenOn != null) { 257 String followUpMessage = mFaceLockedOutThisAuthSession 258 ? faceLockedOutFollowupMessage() : null; 259 showBiometricMessage( 260 mBiometricErrorMessageToShowOnScreenOn.first, 261 followUpMessage, 262 mBiometricErrorMessageToShowOnScreenOn.second 263 ); 264 // We want to keep this message around in case the screen was off 265 hideBiometricMessageDelayed(DEFAULT_HIDE_DELAY_MS); 266 mBiometricErrorMessageToShowOnScreenOn = null; 267 } 268 } 269 }; 270 private boolean mFaceLockedOutThisAuthSession; 271 272 // Use AlarmTimeouts to guarantee that the events are handled even if scheduled and 273 // triggered while the device is asleep 274 private final AlarmTimeout mHideTransientMessageHandler; 275 private final AlarmTimeout mHideBiometricMessageHandler; 276 private final FeatureFlags mFeatureFlags; 277 private final IndicationHelper mIndicationHelper; 278 279 /** 280 * Creates a new KeyguardIndicationController and registers callbacks. 281 */ 282 @Inject KeyguardIndicationController( Context context, @Main Looper mainLooper, WakeLock.Builder wakeLockBuilder, KeyguardStateController keyguardStateController, StatusBarStateController statusBarStateController, KeyguardUpdateMonitor keyguardUpdateMonitor, DockManager dockManager, BroadcastDispatcher broadcastDispatcher, DevicePolicyManager devicePolicyManager, IBatteryStats iBatteryStats, UserManager userManager, @Main DelayableExecutor executor, @Background DelayableExecutor bgExecutor, FalsingManager falsingManager, AuthController authController, LockPatternUtils lockPatternUtils, ScreenLifecycle screenLifecycle, KeyguardBypassController keyguardBypassController, AccessibilityManager accessibilityManager, FaceHelpMessageDeferralFactory faceHelpMessageDeferral, KeyguardLogger keyguardLogger, AlternateBouncerInteractor alternateBouncerInteractor, AlarmManager alarmManager, UserTracker userTracker, BouncerMessageInteractor bouncerMessageInteractor, FeatureFlags flags, IndicationHelper indicationHelper, KeyguardInteractor keyguardInteractor, BiometricMessageInteractor biometricMessageInteractor, DeviceEntryFingerprintAuthInteractor deviceEntryFingerprintAuthInteractor, DeviceEntryFaceAuthInteractor deviceEntryFaceAuthInteractor, UserLogoutInteractor userLogoutInteractor )283 public KeyguardIndicationController( 284 Context context, 285 @Main Looper mainLooper, 286 WakeLock.Builder wakeLockBuilder, 287 KeyguardStateController keyguardStateController, 288 StatusBarStateController statusBarStateController, 289 KeyguardUpdateMonitor keyguardUpdateMonitor, 290 DockManager dockManager, 291 BroadcastDispatcher broadcastDispatcher, 292 DevicePolicyManager devicePolicyManager, 293 IBatteryStats iBatteryStats, 294 UserManager userManager, 295 @Main DelayableExecutor executor, 296 @Background DelayableExecutor bgExecutor, 297 FalsingManager falsingManager, 298 AuthController authController, 299 LockPatternUtils lockPatternUtils, 300 ScreenLifecycle screenLifecycle, 301 KeyguardBypassController keyguardBypassController, 302 AccessibilityManager accessibilityManager, 303 FaceHelpMessageDeferralFactory faceHelpMessageDeferral, 304 KeyguardLogger keyguardLogger, 305 AlternateBouncerInteractor alternateBouncerInteractor, 306 AlarmManager alarmManager, 307 UserTracker userTracker, 308 BouncerMessageInteractor bouncerMessageInteractor, 309 FeatureFlags flags, 310 IndicationHelper indicationHelper, 311 KeyguardInteractor keyguardInteractor, 312 BiometricMessageInteractor biometricMessageInteractor, 313 DeviceEntryFingerprintAuthInteractor deviceEntryFingerprintAuthInteractor, 314 DeviceEntryFaceAuthInteractor deviceEntryFaceAuthInteractor, 315 UserLogoutInteractor userLogoutInteractor 316 ) { 317 mContext = context; 318 mBroadcastDispatcher = broadcastDispatcher; 319 mDevicePolicyManager = devicePolicyManager; 320 mKeyguardStateController = keyguardStateController; 321 mStatusBarStateController = statusBarStateController; 322 mKeyguardUpdateMonitor = keyguardUpdateMonitor; 323 mDockManager = dockManager; 324 mWakeLock = new SettableWakeLock( 325 wakeLockBuilder.setTag("Doze:KeyguardIndication").build(), TAG); 326 mBatteryInfo = iBatteryStats; 327 mUserManager = userManager; 328 mExecutor = executor; 329 mBackgroundExecutor = bgExecutor; 330 mLockPatternUtils = lockPatternUtils; 331 mAuthController = authController; 332 mFalsingManager = falsingManager; 333 mKeyguardBypassController = keyguardBypassController; 334 mAccessibilityManager = accessibilityManager; 335 mScreenLifecycle = screenLifecycle; 336 mKeyguardLogger = keyguardLogger; 337 mScreenLifecycle.addObserver(mScreenObserver); 338 mAlternateBouncerInteractor = alternateBouncerInteractor; 339 mUserTracker = userTracker; 340 mBouncerMessageInteractor = bouncerMessageInteractor; 341 mFeatureFlags = flags; 342 mIndicationHelper = indicationHelper; 343 mKeyguardInteractor = keyguardInteractor; 344 mBiometricMessageInteractor = biometricMessageInteractor; 345 mDeviceEntryFingerprintAuthInteractor = deviceEntryFingerprintAuthInteractor; 346 mDeviceEntryFaceAuthInteractor = deviceEntryFaceAuthInteractor; 347 mUserLogoutInteractor = userLogoutInteractor; 348 349 350 mFaceAcquiredMessageDeferral = faceHelpMessageDeferral.create(); 351 352 mHandler = new Handler(mainLooper) { 353 @Override 354 public void handleMessage(Message msg) { 355 if (msg.what == MSG_SHOW_ACTION_TO_UNLOCK) { 356 showActionToUnlock(); 357 } else if (msg.what == MSG_RESET_ERROR_MESSAGE_ON_SCREEN_ON) { 358 mBiometricErrorMessageToShowOnScreenOn = null; 359 } 360 } 361 }; 362 363 mHideTransientMessageHandler = new AlarmTimeout( 364 alarmManager, 365 this::hideTransientIndication, 366 TAG, 367 mHandler 368 ); 369 mHideBiometricMessageHandler = new AlarmTimeout( 370 alarmManager, 371 this::hideBiometricMessage, 372 TAG, 373 mHandler 374 ); 375 } 376 377 /** Call this after construction to finish setting up the instance. */ init()378 public void init() { 379 if (mInited) { 380 return; 381 } 382 mInited = true; 383 384 mDockManager.addAlignmentStateListener( 385 alignState -> mHandler.post(() -> handleAlignStateChanged(alignState))); 386 mKeyguardUpdateMonitor.registerCallback(getKeyguardCallback()); 387 mStatusBarStateController.addCallback(mStatusBarStateListener); 388 mKeyguardStateController.addCallback(mKeyguardStateCallback); 389 390 mStatusBarStateListener.onDozingChanged(mStatusBarStateController.isDozing()); 391 } 392 393 @Nullable getIndicationArea()394 public ViewGroup getIndicationArea() { 395 return mIndicationArea; 396 } 397 398 /** 399 * Notify controller about configuration changes. 400 */ onConfigurationChanged()401 public void onConfigurationChanged() { 402 // Get new text color in case theme has changed 403 if (Flags.indicationTextA11yFix()) { 404 setIndicationColorToThemeColor(); 405 } 406 } 407 setIndicationArea(ViewGroup indicationArea)408 public void setIndicationArea(ViewGroup indicationArea) { 409 mIndicationArea = indicationArea; 410 mTopIndicationView = indicationArea.findViewById(R.id.keyguard_indication_text); 411 mLockScreenIndicationView = indicationArea.findViewById( 412 R.id.keyguard_indication_text_bottom); 413 if (Flags.indicationTextA11yFix()) { 414 setIndicationColorToThemeColor(); 415 } else { 416 setIndicationTextColor(mTopIndicationView != null 417 ? mTopIndicationView.getTextColors() : ColorStateList.valueOf(Color.WHITE)); 418 } 419 if (mRotateTextViewController != null) { 420 mRotateTextViewController.destroy(); 421 } 422 mRotateTextViewController = new KeyguardIndicationRotateTextViewController( 423 mLockScreenIndicationView, 424 mExecutor, 425 mStatusBarStateController, 426 mKeyguardLogger, 427 mFeatureFlags 428 ); 429 updateDeviceEntryIndication(false /* animate */); 430 updateOrganizedOwnedDevice(); 431 if (mBroadcastReceiver == null) { 432 // Update the disclosure proactively to avoid IPC on the critical path. 433 mBroadcastReceiver = new BroadcastReceiver() { 434 @Override 435 public void onReceive(Context context, Intent intent) { 436 updateOrganizedOwnedDevice(); 437 } 438 }; 439 IntentFilter intentFilter = new IntentFilter(); 440 intentFilter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); 441 intentFilter.addAction(Intent.ACTION_USER_REMOVED); 442 mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, intentFilter); 443 } 444 445 collectFlow(mIndicationArea, 446 mBiometricMessageInteractor.getCoExFaceAcquisitionMsgIdsToShow(), 447 mCoExAcquisitionMsgIdsToShowCallback); 448 collectFlow(mIndicationArea, mDeviceEntryFingerprintAuthInteractor.isEngaged(), 449 mIsFingerprintEngagedCallback); 450 collectFlow(mIndicationArea, 451 mUserLogoutInteractor.isLogoutEnabled(), 452 mIsLogoutEnabledCallback); 453 } 454 455 @NonNull wallpaperTextColor()456 private ColorStateList wallpaperTextColor() { 457 return ColorStateList.valueOf( 458 Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColor)); 459 } 460 461 /** 462 * Cleanup 463 */ destroy()464 public void destroy() { 465 mHandler.removeCallbacksAndMessages(null); 466 mHideBiometricMessageHandler.cancel(); 467 mHideTransientMessageHandler.cancel(); 468 mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver); 469 } 470 handleAlignStateChanged(int alignState)471 private void handleAlignStateChanged(int alignState) { 472 String alignmentIndication = ""; 473 if (alignState == DockManager.ALIGN_STATE_POOR) { 474 alignmentIndication = 475 mContext.getResources().getString(R.string.dock_alignment_slow_charging); 476 } else if (alignState == DockManager.ALIGN_STATE_TERRIBLE) { 477 alignmentIndication = 478 mContext.getResources().getString(R.string.dock_alignment_not_charging); 479 } 480 if (!alignmentIndication.equals(mAlignmentIndication)) { 481 mAlignmentIndication = alignmentIndication; 482 updateDeviceEntryIndication(false); 483 } 484 } 485 486 /** 487 * Gets the {@link KeyguardUpdateMonitorCallback} instance associated with this 488 * {@link KeyguardIndicationController}. 489 * 490 * <p>Subclasses may override this method to extend or change the callback behavior by extending 491 * the {@link BaseKeyguardCallback}. 492 * 493 * @return A KeyguardUpdateMonitorCallback. Multiple calls to this method <b>must</b> return the 494 * same instance. 495 */ getKeyguardCallback()496 protected KeyguardUpdateMonitorCallback getKeyguardCallback() { 497 if (mUpdateMonitorCallback == null) { 498 mUpdateMonitorCallback = new BaseKeyguardCallback(); 499 } 500 return mUpdateMonitorCallback; 501 } 502 updateLockScreenIndications(boolean animate, int userId)503 private void updateLockScreenIndications(boolean animate, int userId) { 504 // update transient messages: 505 updateBiometricMessage(); 506 updateTransient(); 507 508 // Update persistent messages. The following methods should only be called if we're on the 509 // lock screen: 510 updateForceIsDimissibileChanged(); 511 updateLockScreenDisclosureMsg(); 512 updateLockScreenOwnerInfo(); 513 updateLockScreenBatteryMsg(animate); 514 updateLockScreenUserLockedMsg(userId); 515 updateLockScreenTrustMsg(userId, getTrustGrantedIndication(), getTrustManagedIndication()); 516 updateLockScreenAlignmentMsg(); 517 updateLockScreenLogoutView(); 518 updateLockScreenPersistentUnlockMsg(); 519 if (enableAdaptiveAuth()) { 520 updateLockScreenAdaptiveAuthMsg(userId); 521 } 522 } 523 updateOrganizedOwnedDevice()524 private void updateOrganizedOwnedDevice() { 525 // avoid calling this method since it has an IPC 526 mOrganizationOwnedDevice = whitelistIpcs(this::isOrganizationOwnedDevice); 527 updateDeviceEntryIndication(false); 528 } 529 updateForceIsDimissibileChanged()530 private void updateForceIsDimissibileChanged() { 531 if (mForceIsDismissible) { 532 mRotateTextViewController.updateIndication( 533 INDICATION_IS_DISMISSIBLE, 534 new KeyguardIndication.Builder() 535 .setMessage(mContext.getResources().getString( 536 com.android.systemui.res.R.string.dismissible_keyguard_swipe) 537 ) 538 .setTextColor(getInitialTextColorState()) 539 .build(), 540 /* updateImmediately */ true); 541 } else { 542 mRotateTextViewController.hideIndication(INDICATION_IS_DISMISSIBLE); 543 } 544 } 545 updateLockScreenDisclosureMsg()546 private void updateLockScreenDisclosureMsg() { 547 if (mOrganizationOwnedDevice) { 548 mBackgroundExecutor.execute(() -> { 549 final CharSequence organizationName = getOrganizationOwnedDeviceOrganizationName(); 550 final CharSequence disclosure = getDisclosureText(organizationName); 551 552 mExecutor.execute(() -> { 553 if (mKeyguardStateController.isShowing()) { 554 mRotateTextViewController.updateIndication( 555 INDICATION_TYPE_DISCLOSURE, 556 new KeyguardIndication.Builder() 557 .setMessage(disclosure) 558 .setTextColor(getInitialTextColorState()) 559 .build(), 560 /* updateImmediately */ false); 561 } 562 }); 563 }); 564 } else { 565 mRotateTextViewController.hideIndication(INDICATION_TYPE_DISCLOSURE); 566 } 567 } 568 getDisclosureText(@ullable CharSequence organizationName)569 private CharSequence getDisclosureText(@Nullable CharSequence organizationName) { 570 final Resources packageResources = mContext.getResources(); 571 572 // TODO(b/259908270): remove and inline 573 boolean isFinanced; 574 if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER, 575 DevicePolicyManager.ADD_ISFINANCED_DEVICE_FLAG, 576 DevicePolicyManager.ADD_ISFINANCED_FEVICE_DEFAULT)) { 577 isFinanced = mDevicePolicyManager.isFinancedDevice(); 578 } else { 579 isFinanced = mDevicePolicyManager.isDeviceManaged() 580 && mDevicePolicyManager.getDeviceOwnerType( 581 mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()) 582 == DEVICE_OWNER_TYPE_FINANCED; 583 } 584 585 if (organizationName == null) { 586 return mDevicePolicyManager.getResources().getString( 587 KEYGUARD_MANAGEMENT_DISCLOSURE, 588 () -> packageResources.getString(R.string.do_disclosure_generic)); 589 } else if (isFinanced) { 590 return packageResources.getString(R.string.do_financed_disclosure_with_name, 591 organizationName); 592 } else { 593 return mDevicePolicyManager.getResources().getString( 594 KEYGUARD_NAMED_MANAGEMENT_DISCLOSURE, 595 () -> packageResources.getString( 596 R.string.do_disclosure_with_name, organizationName), 597 organizationName); 598 } 599 } 600 getCurrentUser()601 private int getCurrentUser() { 602 return mUserTracker.getUserId(); 603 } 604 updateLockScreenOwnerInfo()605 private void updateLockScreenOwnerInfo() { 606 // Check device owner info on a bg thread. 607 // It makes multiple IPCs that could block the thread it's run on. 608 mBackgroundExecutor.execute(() -> { 609 String info = mLockPatternUtils.getDeviceOwnerInfo(); 610 if (info == null) { 611 // Use the current user owner information if enabled. 612 final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled( 613 getCurrentUser()); 614 if (ownerInfoEnabled) { 615 info = mLockPatternUtils.getOwnerInfo(getCurrentUser()); 616 } 617 } 618 619 // Update the UI on the main thread. 620 final String finalInfo = info; 621 mExecutor.execute(() -> { 622 if (!TextUtils.isEmpty(finalInfo) && mKeyguardStateController.isShowing()) { 623 mRotateTextViewController.updateIndication( 624 INDICATION_TYPE_OWNER_INFO, 625 new KeyguardIndication.Builder() 626 .setMessage(finalInfo) 627 .setTextColor(getInitialTextColorState()) 628 .build(), 629 false); 630 } else { 631 mRotateTextViewController.hideIndication(INDICATION_TYPE_OWNER_INFO); 632 } 633 }); 634 }); 635 } 636 updateLockScreenBatteryMsg(boolean animate)637 private void updateLockScreenBatteryMsg(boolean animate) { 638 if (mPowerPluggedIn || mEnableBatteryDefender) { 639 String powerIndication = computePowerIndication(); 640 if (DEBUG_CHARGING_SPEED) { 641 powerIndication += ", " + (mChargingWattage / 1000) + " mW"; 642 } 643 644 mKeyguardLogger.logUpdateBatteryIndication(powerIndication, mPowerPluggedIn); 645 mRotateTextViewController.updateIndication( 646 INDICATION_TYPE_BATTERY, 647 new KeyguardIndication.Builder() 648 .setMessage(powerIndication) 649 .setTextColor(getInitialTextColorState()) 650 .build(), 651 animate); 652 } else { 653 mKeyguardLogger.log(TAG, LogLevel.DEBUG, "hide battery indication"); 654 // don't show the charging information if device isn't plugged in 655 mRotateTextViewController.hideIndication(INDICATION_TYPE_BATTERY); 656 } 657 } 658 updateLockScreenUserLockedMsg(int userId)659 private void updateLockScreenUserLockedMsg(int userId) { 660 boolean userStorageUnlocked = mKeyguardUpdateMonitor.isUserUnlocked(userId); 661 boolean encryptedOrLockdown = mKeyguardUpdateMonitor.isEncryptedOrLockdown(userId); 662 mKeyguardLogger.logUpdateLockScreenUserLockedMsg(userId, userStorageUnlocked, 663 encryptedOrLockdown); 664 if (!userStorageUnlocked || encryptedOrLockdown) { 665 mRotateTextViewController.updateIndication( 666 INDICATION_TYPE_USER_LOCKED, 667 new KeyguardIndication.Builder() 668 .setMessage(mContext.getResources().getText( 669 com.android.internal.R.string.lockscreen_storage_locked)) 670 .setTextColor(getInitialTextColorState()) 671 .build(), 672 false); 673 } else { 674 mRotateTextViewController.hideIndication(INDICATION_TYPE_USER_LOCKED); 675 } 676 } 677 updateBiometricMessage()678 private void updateBiometricMessage() { 679 if (mDozing) { 680 updateDeviceEntryIndication(false); 681 return; 682 } 683 684 if (!TextUtils.isEmpty(mBiometricMessage)) { 685 mRotateTextViewController.updateIndication( 686 INDICATION_TYPE_BIOMETRIC_MESSAGE, 687 new KeyguardIndication.Builder() 688 .setMessage(mBiometricMessage) 689 .setForceAccessibilityLiveRegionAssertive() 690 .setMinVisibilityMillis(IMPORTANT_MSG_MIN_DURATION) 691 .setTextColor(getInitialTextColorState()) 692 .build(), 693 true 694 ); 695 } else { 696 mRotateTextViewController.hideIndication( 697 INDICATION_TYPE_BIOMETRIC_MESSAGE); 698 } 699 if (!TextUtils.isEmpty(mBiometricMessageFollowUp)) { 700 mRotateTextViewController.updateIndication( 701 INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP, 702 new KeyguardIndication.Builder() 703 .setMessage(mBiometricMessageFollowUp) 704 .setMinVisibilityMillis(IMPORTANT_MSG_MIN_DURATION) 705 .setTextColor(getInitialTextColorState()) 706 .build(), 707 true 708 ); 709 } else { 710 mRotateTextViewController.hideIndication( 711 INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP); 712 } 713 } 714 updateTransient()715 private void updateTransient() { 716 if (mDozing) { 717 updateDeviceEntryIndication(false); 718 return; 719 } 720 721 if (!TextUtils.isEmpty(mTransientIndication)) { 722 mRotateTextViewController.showTransient(mTransientIndication); 723 } else { 724 mRotateTextViewController.hideTransient(); 725 } 726 } 727 updateLockScreenTrustMsg(int userId, CharSequence trustGrantedIndication, CharSequence trustManagedIndication)728 private void updateLockScreenTrustMsg(int userId, CharSequence trustGrantedIndication, 729 CharSequence trustManagedIndication) { 730 final boolean userHasTrust = mKeyguardUpdateMonitor.getUserHasTrust(userId); 731 if (!TextUtils.isEmpty(trustGrantedIndication) && userHasTrust) { 732 mRotateTextViewController.updateIndication( 733 INDICATION_TYPE_TRUST, 734 new KeyguardIndication.Builder() 735 .setMessage(trustGrantedIndication) 736 .setTextColor(getInitialTextColorState()) 737 .build(), 738 true); 739 hideBiometricMessage(); 740 } else if (!TextUtils.isEmpty(trustManagedIndication) 741 && mKeyguardUpdateMonitor.getUserTrustIsManaged(userId) 742 && !userHasTrust) { 743 mRotateTextViewController.updateIndication( 744 INDICATION_TYPE_TRUST, 745 new KeyguardIndication.Builder() 746 .setMessage(trustManagedIndication) 747 .setTextColor(getInitialTextColorState()) 748 .build(), 749 false); 750 } else { 751 mRotateTextViewController.hideIndication(INDICATION_TYPE_TRUST); 752 } 753 } 754 updateLockScreenAlignmentMsg()755 private void updateLockScreenAlignmentMsg() { 756 if (!TextUtils.isEmpty(mAlignmentIndication)) { 757 mRotateTextViewController.updateIndication( 758 INDICATION_TYPE_ALIGNMENT, 759 new KeyguardIndication.Builder() 760 .setMessage(mAlignmentIndication) 761 .setTextColor(ColorStateList.valueOf( 762 mContext.getColor(R.color.misalignment_text_color))) 763 .build(), 764 true); 765 } else { 766 mRotateTextViewController.hideIndication(INDICATION_TYPE_ALIGNMENT); 767 } 768 } 769 updateLockScreenPersistentUnlockMsg()770 private void updateLockScreenPersistentUnlockMsg() { 771 if (!TextUtils.isEmpty(mPersistentUnlockMessage)) { 772 mRotateTextViewController.updateIndication( 773 INDICATION_TYPE_PERSISTENT_UNLOCK_MESSAGE, 774 new KeyguardIndication.Builder() 775 .setMessage(mPersistentUnlockMessage) 776 .setTextColor(getInitialTextColorState()) 777 .build(), 778 true); 779 } else { 780 mRotateTextViewController.hideIndication(INDICATION_TYPE_PERSISTENT_UNLOCK_MESSAGE); 781 } 782 } 783 updateLockScreenLogoutView()784 private void updateLockScreenLogoutView() { 785 if (mUserLogoutInteractor.isLogoutEnabled().getValue()) { 786 mRotateTextViewController.updateIndication( 787 INDICATION_TYPE_LOGOUT, 788 new KeyguardIndication.Builder() 789 .setMessage(mContext.getResources().getString( 790 com.android.internal.R.string.global_action_logout)) 791 .setTextColor(Utils.getColorAttr( 792 mContext, com.android.internal.R.attr.textColorOnAccent)) 793 .setBackground(mContext.getDrawable( 794 com.android.systemui.res.R.drawable.logout_button_background)) 795 .setClickListener((view) -> { 796 if (mFalsingManager.isFalseTap(LOW_PENALTY)) { 797 return; 798 } 799 mUserLogoutInteractor.logOut(); 800 }) 801 .build(), 802 false); 803 } else { 804 mRotateTextViewController.hideIndication(INDICATION_TYPE_LOGOUT); 805 } 806 } 807 updateLockScreenAdaptiveAuthMsg(int userId)808 private void updateLockScreenAdaptiveAuthMsg(int userId) { 809 final boolean deviceLocked = mKeyguardUpdateMonitor.isDeviceLockedByAdaptiveAuth(userId); 810 final boolean canSkipBouncer = mKeyguardUpdateMonitor.getUserCanSkipBouncer(userId); 811 if (deviceLocked && !canSkipBouncer) { 812 mRotateTextViewController.updateIndication( 813 INDICATION_TYPE_ADAPTIVE_AUTH, 814 new KeyguardIndication.Builder() 815 .setMessage(mContext.getString( 816 R.string.keyguard_indication_after_adaptive_auth_lock)) 817 .setTextColor(getInitialTextColorState()) 818 .build(), 819 true); 820 } else { 821 mRotateTextViewController.hideIndication(INDICATION_TYPE_ADAPTIVE_AUTH); 822 } 823 } 824 isOrganizationOwnedDevice()825 private boolean isOrganizationOwnedDevice() { 826 return mDevicePolicyManager.isDeviceManaged() 827 || mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile(); 828 } 829 830 @Nullable getOrganizationOwnedDeviceOrganizationName()831 private CharSequence getOrganizationOwnedDeviceOrganizationName() { 832 if (mDevicePolicyManager.isDeviceManaged()) { 833 return mDevicePolicyManager.getDeviceOwnerOrganizationName(); 834 } else if (mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()) { 835 return getWorkProfileOrganizationName(); 836 } 837 return null; 838 } 839 getWorkProfileOrganizationName()840 private CharSequence getWorkProfileOrganizationName() { 841 final int profileId = getWorkProfileUserId(UserHandle.myUserId()); 842 if (profileId == UserHandle.USER_NULL) { 843 return null; 844 } 845 return mDevicePolicyManager.getOrganizationNameForUser(profileId); 846 } 847 getWorkProfileUserId(int userId)848 private int getWorkProfileUserId(int userId) { 849 for (final UserInfo userInfo : mUserManager.getProfiles(userId)) { 850 if (userInfo.isManagedProfile()) { 851 return userInfo.id; 852 } 853 } 854 return UserHandle.USER_NULL; 855 } 856 857 /** 858 * Sets the visibility of keyguard bottom area, and if the indications are updatable. 859 * 860 * @param visible true to make the area visible and update the indication, false otherwise. 861 */ setVisible(boolean visible)862 public void setVisible(boolean visible) { 863 mVisible = visible; 864 mIndicationArea.setVisibility(visible ? VISIBLE : GONE); 865 if (visible) { 866 // If this is called after an error message was already shown, we should not clear it. 867 // Otherwise the error message won't be shown 868 if (!mHideTransientMessageHandler.isScheduled()) { 869 hideTransientIndication(); 870 } 871 updateDeviceEntryIndication(false); 872 } else { 873 // If we unlock and return to keyguard quickly, previous error should not be shown 874 hideTransientIndication(); 875 } 876 } 877 setPersistentUnlockMessage(String persistentUnlockMessage)878 private void setPersistentUnlockMessage(String persistentUnlockMessage) { 879 mPersistentUnlockMessage = persistentUnlockMessage; 880 updateDeviceEntryIndication(false); 881 } 882 883 /** 884 * Returns the indication text indicating that trust has been granted. 885 * 886 * @return an empty string if a trust indication text should not be shown. 887 */ 888 @VisibleForTesting getTrustGrantedIndication()889 String getTrustGrantedIndication() { 890 return mTrustGrantedIndication == null 891 ? mContext.getString(R.string.keyguard_indication_trust_unlocked) 892 : mTrustGrantedIndication.toString(); 893 } 894 895 /** 896 * Sets if the device is plugged in 897 */ 898 @VisibleForTesting setPowerPluggedIn(boolean plugged)899 void setPowerPluggedIn(boolean plugged) { 900 mPowerPluggedIn = plugged; 901 } 902 903 /** 904 * Returns the indication text indicating that trust is currently being managed. 905 * 906 * @return {@code null} or an empty string if a trust managed text should not be shown. 907 */ getTrustManagedIndication()908 private String getTrustManagedIndication() { 909 return null; 910 } 911 912 /** 913 * Hides transient indication in {@param delayMs}. 914 */ hideTransientIndicationDelayed(long delayMs)915 public void hideTransientIndicationDelayed(long delayMs) { 916 mHideTransientMessageHandler.schedule(delayMs, AlarmTimeout.MODE_RESCHEDULE_IF_SCHEDULED); 917 } 918 919 /** 920 * Hides biometric indication in {@param delayMs}. 921 */ hideBiometricMessageDelayed(long delayMs)922 public void hideBiometricMessageDelayed(long delayMs) { 923 mHideBiometricMessageHandler.schedule(delayMs, AlarmTimeout.MODE_RESCHEDULE_IF_SCHEDULED); 924 } 925 926 /** 927 * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}. 928 */ showTransientIndication(int transientIndication)929 public void showTransientIndication(int transientIndication) { 930 showTransientIndication(mContext.getResources().getString(transientIndication)); 931 } 932 933 /** 934 * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}. 935 */ showTransientIndication(CharSequence transientIndication)936 private void showTransientIndication(CharSequence transientIndication) { 937 mTransientIndication = transientIndication; 938 hideTransientIndicationDelayed(DEFAULT_HIDE_DELAY_MS); 939 940 updateTransient(); 941 } 942 showSuccessBiometricMessage( CharSequence biometricMessage, @Nullable CharSequence biometricMessageFollowUp, BiometricSourceType biometricSourceType )943 private void showSuccessBiometricMessage( 944 CharSequence biometricMessage, 945 @Nullable CharSequence biometricMessageFollowUp, 946 BiometricSourceType biometricSourceType 947 ) { 948 showBiometricMessage(biometricMessage, biometricMessageFollowUp, biometricSourceType, true); 949 } 950 showSuccessBiometricMessage(CharSequence biometricMessage, BiometricSourceType biometricSourceType)951 private void showSuccessBiometricMessage(CharSequence biometricMessage, 952 BiometricSourceType biometricSourceType) { 953 showSuccessBiometricMessage(biometricMessage, null, biometricSourceType); 954 } 955 showBiometricMessage(CharSequence biometricMessage, BiometricSourceType biometricSourceType)956 private void showBiometricMessage(CharSequence biometricMessage, 957 BiometricSourceType biometricSourceType) { 958 showBiometricMessage(biometricMessage, null, biometricSourceType, false); 959 } 960 showBiometricMessage( CharSequence biometricMessage, @Nullable CharSequence biometricMessageFollowUp, BiometricSourceType biometricSourceType )961 private void showBiometricMessage( 962 CharSequence biometricMessage, 963 @Nullable CharSequence biometricMessageFollowUp, 964 BiometricSourceType biometricSourceType 965 ) { 966 showBiometricMessage( 967 biometricMessage, 968 biometricMessageFollowUp, 969 biometricSourceType, 970 false 971 ); 972 } 973 974 /** 975 * Shows {@param biometricMessage} and {@param biometricMessageFollowUp} 976 * until they are hidden by {@link #hideBiometricMessage}. Messages are rotated through 977 * by {@link KeyguardIndicationRotateTextViewController}, see class for rotating message 978 * logic. 979 */ showBiometricMessage( CharSequence biometricMessage, @Nullable CharSequence biometricMessageFollowUp, BiometricSourceType biometricSourceType, boolean isSuccessMessage )980 private void showBiometricMessage( 981 CharSequence biometricMessage, 982 @Nullable CharSequence biometricMessageFollowUp, 983 BiometricSourceType biometricSourceType, 984 boolean isSuccessMessage 985 ) { 986 if (TextUtils.equals(biometricMessage, mBiometricMessage) 987 && biometricSourceType == mBiometricMessageSource 988 && TextUtils.equals(biometricMessageFollowUp, mBiometricMessageFollowUp)) { 989 return; 990 } 991 992 if (!isSuccessMessage 993 && mBiometricMessageSource == FINGERPRINT 994 && biometricSourceType == FACE) { 995 // drop any face messages if there's a fingerprint message showing 996 mKeyguardLogger.logDropFaceMessage( 997 biometricMessage, 998 biometricMessageFollowUp 999 ); 1000 return; 1001 } 1002 1003 if (mBiometricMessageSource != null && biometricSourceType == null) { 1004 // If there's a current biometric message showing and a non-biometric message 1005 // arrives, update the followup message with the non-biometric message. 1006 // Keep the biometricMessage and biometricMessageSource the same. 1007 mBiometricMessageFollowUp = biometricMessage; 1008 } else { 1009 mBiometricMessage = biometricMessage; 1010 mBiometricMessageFollowUp = biometricMessageFollowUp; 1011 mBiometricMessageSource = biometricSourceType; 1012 } 1013 1014 mHandler.removeMessages(MSG_SHOW_ACTION_TO_UNLOCK); 1015 hideBiometricMessageDelayed( 1016 !TextUtils.isEmpty(mBiometricMessage) 1017 && !TextUtils.isEmpty(mBiometricMessageFollowUp) 1018 ? IMPORTANT_MSG_MIN_DURATION * 2 1019 : DEFAULT_HIDE_DELAY_MS 1020 ); 1021 1022 updateBiometricMessage(); 1023 } 1024 hideBiometricMessage()1025 private void hideBiometricMessage() { 1026 if (mBiometricMessage != null || mBiometricMessageFollowUp != null) { 1027 mBiometricMessage = null; 1028 mBiometricMessageFollowUp = null; 1029 mBiometricMessageSource = null; 1030 mHideBiometricMessageHandler.cancel(); 1031 updateBiometricMessage(); 1032 } 1033 } 1034 1035 /** 1036 * Hides transient indication. 1037 */ hideTransientIndication()1038 public void hideTransientIndication() { 1039 if (mTransientIndication != null) { 1040 mTransientIndication = null; 1041 mHideTransientMessageHandler.cancel(); 1042 updateTransient(); 1043 } 1044 } 1045 1046 /** 1047 * Updates message shown to the user. If the device is dozing, a single message with the highest 1048 * precedence is shown. If the device is not dozing (on the lock screen), then several messages 1049 * may continuously be cycled through. 1050 */ updateDeviceEntryIndication(boolean animate)1051 protected final void updateDeviceEntryIndication(boolean animate) { 1052 mKeyguardLogger.logUpdateDeviceEntryIndication(animate, mVisible, mDozing); 1053 if (!mVisible) { 1054 return; 1055 } 1056 1057 // A few places might need to hide the indication, so always start by making it visible 1058 mIndicationArea.setVisibility(VISIBLE); 1059 1060 // Walk down a precedence-ordered list of what indication 1061 // should be shown based on device state 1062 if (mDozing) { 1063 boolean useMisalignmentColor = false; 1064 mLockScreenIndicationView.setVisibility(View.GONE); 1065 mTopIndicationView.setVisibility(VISIBLE); 1066 CharSequence newIndication; 1067 if (!TextUtils.isEmpty(mBiometricMessage)) { 1068 newIndication = mBiometricMessage; // note: doesn't show mBiometricMessageFollowUp 1069 } else if (!TextUtils.isEmpty(mTransientIndication)) { 1070 newIndication = mTransientIndication; 1071 } else if (!mBatteryPresent) { 1072 // If there is no battery detected, hide the indication area and bail 1073 mIndicationArea.setVisibility(GONE); 1074 return; 1075 } else if (!TextUtils.isEmpty(mAlignmentIndication)) { 1076 useMisalignmentColor = true; 1077 newIndication = mAlignmentIndication; 1078 } else if (mBatteryLevel == -1) { 1079 // If the battery level is not initialized, hide the indication area 1080 mIndicationArea.setVisibility(GONE); 1081 return; 1082 } else if (mPowerPluggedIn || mEnableBatteryDefender) { 1083 newIndication = computePowerIndication(); 1084 } else { 1085 newIndication = NumberFormat.getPercentInstance() 1086 .format(mBatteryLevel / 100f); 1087 } 1088 1089 if (!TextUtils.equals(mTopIndicationView.getText(), newIndication)) { 1090 mWakeLock.setAcquired(true); 1091 final KeyguardIndication.Builder builder = new KeyguardIndication.Builder() 1092 .setMessage(newIndication) 1093 .setTextColor(ColorStateList.valueOf( 1094 useMisalignmentColor 1095 ? mContext.getColor(R.color.misalignment_text_color) 1096 : Color.WHITE)); 1097 if (mBiometricMessage != null && newIndication == mBiometricMessage) { 1098 builder.setForceAccessibilityLiveRegionAssertive(); 1099 } 1100 1101 mTopIndicationView.switchIndication(newIndication, 1102 builder.build(), 1103 true, () -> mWakeLock.setAcquired(false)); 1104 } 1105 return; 1106 } 1107 1108 // LOCK SCREEN 1109 mTopIndicationView.setVisibility(GONE); 1110 mTopIndicationView.setText(null); 1111 mLockScreenIndicationView.setVisibility(View.VISIBLE); 1112 updateLockScreenIndications(animate, getCurrentUser()); 1113 } 1114 1115 /** 1116 * Assumption: device is charging 1117 */ computePowerIndication()1118 protected String computePowerIndication() { 1119 if (mBatteryDefender) { 1120 String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f); 1121 return mContext.getResources().getString( 1122 R.string.keyguard_plugged_in_charging_limited, percentage); 1123 } else if (mPowerPluggedIn && mIncompatibleCharger) { 1124 String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f); 1125 return mContext.getResources().getString( 1126 R.string.keyguard_plugged_in_incompatible_charger, percentage); 1127 } 1128 1129 return computePowerChargingStringIndication(); 1130 } 1131 computePowerChargingStringIndication()1132 protected String computePowerChargingStringIndication() { 1133 if (mPowerCharged) { 1134 return mContext.getResources().getString(R.string.keyguard_charged); 1135 } 1136 final boolean hasChargingTime = mChargingTimeRemaining > 0; 1137 int chargingId; 1138 if (mPowerPluggedInWired) { 1139 switch (mChargingSpeed) { 1140 case BatteryStatus.CHARGING_FAST: 1141 chargingId = hasChargingTime 1142 ? R.string.keyguard_indication_charging_time_fast 1143 : R.string.keyguard_plugged_in_charging_fast; 1144 break; 1145 case BatteryStatus.CHARGING_SLOWLY: 1146 chargingId = hasChargingTime 1147 ? R.string.keyguard_indication_charging_time_slowly 1148 : R.string.keyguard_plugged_in_charging_slowly; 1149 break; 1150 default: 1151 chargingId = hasChargingTime 1152 ? R.string.keyguard_indication_charging_time 1153 : R.string.keyguard_plugged_in; 1154 break; 1155 } 1156 } else if (mPowerPluggedInWireless) { 1157 chargingId = hasChargingTime 1158 ? R.string.keyguard_indication_charging_time_wireless 1159 : R.string.keyguard_plugged_in_wireless; 1160 } else if (mPowerPluggedInDock) { 1161 chargingId = hasChargingTime 1162 ? R.string.keyguard_indication_charging_time_dock 1163 : R.string.keyguard_plugged_in_dock; 1164 } else { 1165 chargingId = hasChargingTime 1166 ? R.string.keyguard_indication_charging_time 1167 : R.string.keyguard_plugged_in; 1168 } 1169 1170 String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f); 1171 if (hasChargingTime) { 1172 String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes( 1173 mContext, mChargingTimeRemaining); 1174 return mContext.getResources().getString(chargingId, chargingTimeFormatted, 1175 percentage); 1176 } else { 1177 return mContext.getResources().getString(chargingId, percentage); 1178 } 1179 } 1180 setStatusBarKeyguardViewManager( StatusBarKeyguardViewManager statusBarKeyguardViewManager)1181 public void setStatusBarKeyguardViewManager( 1182 StatusBarKeyguardViewManager statusBarKeyguardViewManager) { 1183 mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; 1184 } 1185 1186 /** 1187 * Show message on the keyguard for how the user can unlock/enter their device. 1188 */ showActionToUnlock()1189 public void showActionToUnlock() { 1190 if (mDozing 1191 && !mKeyguardUpdateMonitor.getUserCanSkipBouncer( 1192 getCurrentUser())) { 1193 return; 1194 } 1195 1196 if (mStatusBarKeyguardViewManager.isBouncerShowing()) { 1197 if (mAlternateBouncerInteractor.isVisibleState()) { 1198 return; // udfps affordance is highlighted, no need to show action to unlock 1199 } else if (mKeyguardUpdateMonitor.isFaceEnabledAndEnrolled() 1200 && !mKeyguardUpdateMonitor.getIsFaceAuthenticated()) { 1201 String message; 1202 if (mAccessibilityManager.isEnabled() 1203 || mAccessibilityManager.isTouchExplorationEnabled()) { 1204 message = mContext.getString(R.string.accesssibility_keyguard_retry); 1205 } else { 1206 message = mContext.getString(R.string.keyguard_retry); 1207 } 1208 mStatusBarKeyguardViewManager.setKeyguardMessage(message, 1209 getInitialTextColorState(), 1210 null); 1211 } 1212 } else { 1213 final boolean canSkipBouncer = mKeyguardUpdateMonitor.getUserCanSkipBouncer( 1214 getCurrentUser()); 1215 if (canSkipBouncer) { 1216 final boolean faceAuthenticated = mKeyguardUpdateMonitor.getIsFaceAuthenticated(); 1217 final boolean udfpsSupported = mKeyguardUpdateMonitor.isUdfpsSupported(); 1218 final boolean a11yEnabled = mAccessibilityManager.isEnabled() 1219 || mAccessibilityManager.isTouchExplorationEnabled(); 1220 if (udfpsSupported && faceAuthenticated) { // co-ex 1221 if (a11yEnabled) { 1222 showSuccessBiometricMessage( 1223 mContext.getString(R.string.keyguard_face_successful_unlock), 1224 mContext.getString(R.string.keyguard_unlock), 1225 FACE 1226 ); 1227 } else { 1228 showSuccessBiometricMessage( 1229 mContext.getString(R.string.keyguard_face_successful_unlock), 1230 mContext.getString(R.string.keyguard_unlock_press), 1231 FACE 1232 ); 1233 } 1234 } else if (faceAuthenticated) { // face-only 1235 showSuccessBiometricMessage( 1236 mContext.getString(R.string.keyguard_face_successful_unlock), 1237 mContext.getString(R.string.keyguard_unlock), 1238 FACE 1239 ); 1240 } else if (udfpsSupported) { // udfps-only 1241 if (a11yEnabled) { 1242 showSuccessBiometricMessage( 1243 mContext.getString(R.string.keyguard_unlock), 1244 null 1245 ); 1246 } else { 1247 showSuccessBiometricMessage(mContext.getString( 1248 R.string.keyguard_unlock_press), null); 1249 } 1250 } else { // no security or unlocked by a trust agent 1251 showSuccessBiometricMessage(mContext.getString(R.string.keyguard_unlock), null); 1252 } 1253 } else { 1254 // suggest swiping up for the primary authentication bouncer 1255 showBiometricMessage(mContext.getString(R.string.keyguard_unlock), null); 1256 } 1257 } 1258 } 1259 dump(PrintWriter pw, String[] args)1260 public void dump(PrintWriter pw, String[] args) { 1261 pw.println("KeyguardIndicationController:"); 1262 pw.println(" mInitialTextColorState: " + getInitialTextColorState()); 1263 pw.println(" mPowerPluggedInWired: " + mPowerPluggedInWired); 1264 pw.println(" mPowerPluggedIn: " + mPowerPluggedIn); 1265 pw.println(" mPowerCharged: " + mPowerCharged); 1266 pw.println(" mChargingSpeed: " + mChargingSpeed); 1267 pw.println(" mChargingWattage: " + mChargingWattage); 1268 pw.println(" mChargingStatus: " + mChargingStatus); 1269 pw.println(" mMessageToShowOnScreenOn: " + mBiometricErrorMessageToShowOnScreenOn); 1270 pw.println(" mDozing: " + mDozing); 1271 pw.println(" mTransientIndication: " + mTransientIndication); 1272 pw.println(" mBiometricMessage: " + mBiometricMessage); 1273 pw.println(" mBiometricMessageFollowUp: " + mBiometricMessageFollowUp); 1274 pw.println(" mBatteryLevel: " + mBatteryLevel); 1275 pw.println(" mBatteryPresent: " + mBatteryPresent); 1276 pw.println(" AOD text: " + ( 1277 mTopIndicationView == null ? null : mTopIndicationView.getText())); 1278 pw.println(" computePowerIndication(): " + computePowerIndication()); 1279 pw.println(" trustGrantedIndication: " + getTrustGrantedIndication()); 1280 pw.println(" mCoExFaceHelpMsgIdsToShow=" + mCoExFaceAcquisitionMsgIdsToShow); 1281 mRotateTextViewController.dump(pw, args); 1282 } 1283 getInitialTextColorState()1284 protected ColorStateList getInitialTextColorState() { 1285 return mInitialTextColorState; 1286 } 1287 setIndicationColorToThemeColor()1288 private void setIndicationColorToThemeColor() { 1289 mInitialTextColorState = wallpaperTextColor(); 1290 } 1291 1292 /** 1293 * @deprecated Use {@link #setIndicationColorToThemeColor} 1294 */ 1295 @Deprecated setIndicationTextColor(ColorStateList color)1296 private void setIndicationTextColor(ColorStateList color) { 1297 mInitialTextColorState = color; 1298 } 1299 1300 protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback { 1301 @Override onTimeChanged()1302 public void onTimeChanged() { 1303 if (mVisible) { 1304 updateDeviceEntryIndication(false /* animate */); 1305 } 1306 } 1307 1308 /** 1309 * KeyguardUpdateMonitor only sends "interesting" battery updates 1310 * {@link KeyguardUpdateMonitor#isBatteryUpdateInteresting}. 1311 * Therefore, make sure to always check plugged in state along with any charging status 1312 * change, or else we could end up with stale state. 1313 */ 1314 @Override onRefreshBatteryInfo(BatteryStatus status)1315 public void onRefreshBatteryInfo(BatteryStatus status) { 1316 boolean isChargingOrFull = status.status == BatteryManager.BATTERY_STATUS_CHARGING 1317 || status.isCharged(); 1318 boolean wasPluggedIn = mPowerPluggedIn; 1319 mPowerPluggedInWired = status.isPluggedInWired() && isChargingOrFull; 1320 mPowerPluggedInWireless = status.isPluggedInWireless() && isChargingOrFull; 1321 mPowerPluggedInDock = status.isPluggedInDock() && isChargingOrFull; 1322 mPowerPluggedIn = isPowerPluggedIn(status, isChargingOrFull); 1323 mPowerCharged = status.isCharged(); 1324 mChargingWattage = status.maxChargingWattage; 1325 mChargingSpeed = status.getChargingSpeed(mContext); 1326 mChargingStatus = status.chargingStatus; 1327 mBatteryLevel = status.level; 1328 mBatteryPresent = status.present; 1329 mBatteryDefender = isBatteryDefender(status); 1330 // when the battery is overheated, device doesn't charge so only guard on pluggedIn: 1331 mEnableBatteryDefender = mBatteryDefender && status.isPluggedIn(); 1332 mIncompatibleCharger = status.incompatibleCharger.orElse(false); 1333 try { 1334 mChargingTimeRemaining = mPowerPluggedIn 1335 ? mBatteryInfo.computeChargeTimeRemaining() : -1; 1336 } catch (RemoteException e) { 1337 mKeyguardLogger.log(TAG, ERROR, "Error calling IBatteryStats", e); 1338 mChargingTimeRemaining = -1; 1339 } 1340 1341 mKeyguardLogger.logRefreshBatteryInfo(isChargingOrFull, mPowerPluggedIn, mBatteryLevel, 1342 mBatteryDefender); 1343 updateDeviceEntryIndication(!wasPluggedIn && mPowerPluggedInWired); 1344 } 1345 1346 @Override onBiometricAcquired(BiometricSourceType biometricSourceType, int acquireInfo)1347 public void onBiometricAcquired(BiometricSourceType biometricSourceType, int acquireInfo) { 1348 if (biometricSourceType == FACE) { 1349 if (acquireInfo == FACE_ACQUIRED_START) { 1350 // Let's hide any previous messages when authentication starts, otherwise 1351 // multiple auth attempts would overlap. 1352 hideBiometricMessage(); 1353 mBiometricErrorMessageToShowOnScreenOn = null; 1354 } 1355 mFaceAcquiredMessageDeferral.processFrame(acquireInfo); 1356 } 1357 } 1358 1359 @Override onBiometricHelp(int msgId, String helpString, BiometricSourceType biometricSourceType)1360 public void onBiometricHelp(int msgId, String helpString, 1361 BiometricSourceType biometricSourceType) { 1362 if (biometricSourceType == FACE) { 1363 mFaceAcquiredMessageDeferral.updateMessage(msgId, helpString); 1364 if (mFaceAcquiredMessageDeferral.shouldDefer(msgId)) { 1365 return; 1366 } 1367 } 1368 1369 final boolean faceAuthUnavailable = biometricSourceType == FACE 1370 && msgId == BIOMETRIC_HELP_FACE_NOT_AVAILABLE; 1371 1372 if (isPrimaryAuthRequired() 1373 && !faceAuthUnavailable) { 1374 return; 1375 } 1376 1377 final boolean faceAuthSoftError = biometricSourceType == FACE 1378 && msgId != BIOMETRIC_HELP_FACE_NOT_RECOGNIZED 1379 && msgId != BIOMETRIC_HELP_FACE_NOT_AVAILABLE; 1380 final boolean faceAuthFailed = biometricSourceType == FACE 1381 && msgId == BIOMETRIC_HELP_FACE_NOT_RECOGNIZED; // ran through matcher & failed 1382 if (faceAuthFailed && mFaceLockedOutThisAuthSession) { 1383 mKeyguardLogger.logBiometricMessage( 1384 "skipped showing faceAuthFailed message due to lockout", 1385 msgId, 1386 helpString); 1387 return; 1388 } 1389 final boolean fpAuthFailed = biometricSourceType == FINGERPRINT 1390 && msgId == BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED; // ran matcher & failed 1391 final boolean isUnlockWithFingerprintPossible = canUnlockWithFingerprint(); 1392 final boolean isCoExFaceAcquisitionMessage = 1393 faceAuthSoftError && isUnlockWithFingerprintPossible; 1394 if (isCoExFaceAcquisitionMessage && !mCoExFaceAcquisitionMsgIdsToShow.contains(msgId)) { 1395 mKeyguardLogger.logBiometricMessage( 1396 "skipped showing help message due to co-ex logic", 1397 msgId, 1398 helpString); 1399 } else if (mStatusBarKeyguardViewManager.isBouncerShowing()) { 1400 if (biometricSourceType == FINGERPRINT && !fpAuthFailed) { 1401 mBouncerMessageInteractor.setFingerprintAcquisitionMessage(helpString); 1402 } else if (faceAuthSoftError) { 1403 mBouncerMessageInteractor.setFaceAcquisitionMessage(helpString); 1404 } 1405 mStatusBarKeyguardViewManager.setKeyguardMessage(helpString, 1406 getInitialTextColorState(), biometricSourceType); 1407 } else if (mScreenLifecycle.getScreenState() == SCREEN_ON) { 1408 if (isCoExFaceAcquisitionMessage && msgId == FACE_ACQUIRED_TOO_DARK) { 1409 showBiometricMessage( 1410 helpString, 1411 mContext.getString(R.string.keyguard_suggest_fingerprint), 1412 biometricSourceType 1413 ); 1414 } else if (faceAuthFailed && isUnlockWithFingerprintPossible) { 1415 showBiometricMessage( 1416 mContext.getString(R.string.keyguard_face_failed), 1417 mContext.getString(R.string.keyguard_suggest_fingerprint), 1418 biometricSourceType 1419 ); 1420 } else if (fpAuthFailed 1421 && mKeyguardUpdateMonitor.isCurrentUserUnlockedWithFace()) { 1422 // face had already previously unlocked the device, so instead of showing a 1423 // fingerprint error, tell them they have already unlocked with face auth 1424 // and how to enter their device 1425 showSuccessBiometricMessage( 1426 mContext.getString(R.string.keyguard_face_successful_unlock), 1427 mContext.getString(R.string.keyguard_unlock), 1428 null 1429 ); 1430 } else if (fpAuthFailed 1431 && mKeyguardUpdateMonitor.getUserHasTrust(getCurrentUser())) { 1432 showSuccessBiometricMessage( 1433 getTrustGrantedIndication(), 1434 mContext.getString(R.string.keyguard_unlock), 1435 null 1436 ); 1437 } else if (faceAuthUnavailable) { 1438 showBiometricMessage( 1439 helpString, 1440 isUnlockWithFingerprintPossible 1441 ? mContext.getString(R.string.keyguard_suggest_fingerprint) 1442 : mContext.getString(R.string.keyguard_unlock), 1443 biometricSourceType 1444 ); 1445 } else { 1446 showBiometricMessage(helpString, biometricSourceType); 1447 } 1448 } else if (faceAuthFailed) { 1449 // show action to unlock 1450 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SHOW_ACTION_TO_UNLOCK), 1451 TRANSIENT_BIOMETRIC_ERROR_TIMEOUT); 1452 } else { 1453 mBiometricErrorMessageToShowOnScreenOn = 1454 new Pair<>(helpString, biometricSourceType); 1455 mHandler.sendMessageDelayed( 1456 mHandler.obtainMessage(MSG_RESET_ERROR_MESSAGE_ON_SCREEN_ON), 1457 1000); 1458 } 1459 } 1460 1461 @Override onBiometricAuthFailed(BiometricSourceType biometricSourceType)1462 public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) { 1463 if (biometricSourceType == FACE) { 1464 mFaceAcquiredMessageDeferral.reset(); 1465 } 1466 } 1467 1468 @Override onLockedOutStateChanged(BiometricSourceType biometricSourceType)1469 public void onLockedOutStateChanged(BiometricSourceType biometricSourceType) { 1470 if (biometricSourceType == FACE && !mKeyguardUpdateMonitor.isFaceLockedOut()) { 1471 mFaceLockedOutThisAuthSession = false; 1472 } else if (biometricSourceType == FINGERPRINT) { 1473 setPersistentUnlockMessage(mKeyguardUpdateMonitor.isFingerprintLockedOut() 1474 ? mContext.getString(R.string.keyguard_unlock) : ""); 1475 } 1476 } 1477 1478 @Override onBiometricError(int msgId, String errString, BiometricSourceType biometricSourceType)1479 public void onBiometricError(int msgId, String errString, 1480 BiometricSourceType biometricSourceType) { 1481 if (biometricSourceType == FACE) { 1482 onFaceAuthError(msgId, errString); 1483 } else if (biometricSourceType == FINGERPRINT) { 1484 onFingerprintAuthError(msgId, errString); 1485 } 1486 } 1487 onFaceAuthError(int msgId, String errString)1488 private void onFaceAuthError(int msgId, String errString) { 1489 CharSequence deferredFaceMessage = mFaceAcquiredMessageDeferral.getDeferredMessage(); 1490 mFaceAcquiredMessageDeferral.reset(); 1491 if (mIndicationHelper.shouldSuppressErrorMsg(FACE, msgId)) { 1492 mKeyguardLogger.logBiometricMessage("KIC suppressingFaceError", msgId, errString); 1493 return; 1494 } 1495 if (msgId == FACE_ERROR_TIMEOUT) { 1496 handleFaceAuthTimeoutError(deferredFaceMessage); 1497 } else if (mIndicationHelper.isFaceLockoutErrorMsg(msgId)) { 1498 handleFaceLockoutError(errString); 1499 } else { 1500 showErrorMessageNowOrLater(errString, null, FACE); 1501 } 1502 } 1503 onFingerprintAuthError(int msgId, String errString)1504 private void onFingerprintAuthError(int msgId, String errString) { 1505 if (mIndicationHelper.shouldSuppressErrorMsg(FINGERPRINT, msgId)) { 1506 mKeyguardLogger.logBiometricMessage("KIC suppressingFingerprintError", 1507 msgId, 1508 errString); 1509 } else { 1510 showErrorMessageNowOrLater(errString, null, FINGERPRINT); 1511 } 1512 } 1513 1514 @Override onTrustChanged(int userId)1515 public void onTrustChanged(int userId) { 1516 if (!isCurrentUser(userId)) return; 1517 updateDeviceEntryIndication(false); 1518 } 1519 1520 @Override onForceIsDismissibleChanged(boolean forceIsDismissible)1521 public void onForceIsDismissibleChanged(boolean forceIsDismissible) { 1522 mForceIsDismissible = forceIsDismissible; 1523 updateDeviceEntryIndication(false); 1524 } 1525 1526 @Override onTrustGrantedForCurrentUser( boolean dismissKeyguard, boolean newlyUnlocked, @NonNull TrustGrantFlags flags, @Nullable String message )1527 public void onTrustGrantedForCurrentUser( 1528 boolean dismissKeyguard, 1529 boolean newlyUnlocked, 1530 @NonNull TrustGrantFlags flags, 1531 @Nullable String message 1532 ) { 1533 showTrustGrantedMessage(dismissKeyguard, message); 1534 } 1535 1536 @Override onTrustAgentErrorMessage(CharSequence message)1537 public void onTrustAgentErrorMessage(CharSequence message) { 1538 showTrustAgentErrorMessage(message); 1539 } 1540 1541 @Override onBiometricRunningStateChanged(boolean running, BiometricSourceType biometricSourceType)1542 public void onBiometricRunningStateChanged(boolean running, 1543 BiometricSourceType biometricSourceType) { 1544 if (!running && biometricSourceType == FACE) { 1545 showTrustAgentErrorMessage(mTrustAgentErrorMessage); 1546 } 1547 } 1548 1549 @Override onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType, boolean isStrongBiometric)1550 public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType, 1551 boolean isStrongBiometric) { 1552 super.onBiometricAuthenticated(userId, biometricSourceType, isStrongBiometric); 1553 hideBiometricMessage(); 1554 if (biometricSourceType == FACE) { 1555 mFaceAcquiredMessageDeferral.reset(); 1556 if (!mKeyguardBypassController.canBypass()) { 1557 showActionToUnlock(); 1558 } 1559 } 1560 } 1561 1562 @Override onUserSwitchComplete(int userId)1563 public void onUserSwitchComplete(int userId) { 1564 if (mVisible) { 1565 updateDeviceEntryIndication(false); 1566 } 1567 } 1568 1569 @Override onUserUnlocked()1570 public void onUserUnlocked() { 1571 if (mVisible) { 1572 updateDeviceEntryIndication(false); 1573 } 1574 } 1575 1576 @Override onRequireUnlockForNfc()1577 public void onRequireUnlockForNfc() { 1578 showTransientIndication(mContext.getString(R.string.require_unlock_for_nfc)); 1579 hideTransientIndicationDelayed(DEFAULT_HIDE_DELAY_MS); 1580 } 1581 } 1582 isPrimaryAuthRequired()1583 private boolean isPrimaryAuthRequired() { 1584 // Only checking if unlocking with Biometric is allowed (no matter strong or non-strong 1585 // as long as primary auth, i.e. PIN/pattern/password, is required), so it's ok to 1586 // pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the 1587 // check of whether non-strong biometric is allowed since strong biometrics can still be 1588 // used. 1589 return !mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed( 1590 true /* isStrongBiometric */); 1591 } 1592 isPluggedInAndCharging()1593 protected boolean isPluggedInAndCharging() { 1594 return mPowerPluggedIn; 1595 } 1596 1597 /** Return true if the device is under the battery defender mode. */ isBatteryDefender(BatteryStatus status)1598 protected boolean isBatteryDefender(BatteryStatus status) { 1599 return status.isBatteryDefender(); 1600 } 1601 1602 /** Return true if the device has power plugged in. */ isPowerPluggedIn(BatteryStatus status, boolean isChargingOrFull)1603 protected boolean isPowerPluggedIn(BatteryStatus status, boolean isChargingOrFull) { 1604 return status.isPluggedIn() && isChargingOrFull; 1605 } 1606 isCurrentUser(int userId)1607 private boolean isCurrentUser(int userId) { 1608 return getCurrentUser() == userId; 1609 } 1610 1611 /** 1612 * Only show trust agent messages after biometrics are no longer active. 1613 */ showTrustAgentErrorMessage(CharSequence message)1614 private void showTrustAgentErrorMessage(CharSequence message) { 1615 if (message == null) { 1616 mTrustAgentErrorMessage = null; 1617 return; 1618 } 1619 boolean fpEngaged = mDeviceEntryFingerprintAuthInteractor.isEngaged().getValue(); 1620 boolean faceRunning = mDeviceEntryFaceAuthInteractor.isRunning(); 1621 if (fpEngaged || faceRunning) { 1622 mKeyguardLogger.delayShowingTrustAgentError(message, fpEngaged, faceRunning); 1623 mTrustAgentErrorMessage = message; 1624 } else { 1625 mTrustAgentErrorMessage = null; 1626 showBiometricMessage(message, null); 1627 } 1628 } 1629 showTrustGrantedMessage(boolean dismissKeyguard, @Nullable String message)1630 protected void showTrustGrantedMessage(boolean dismissKeyguard, @Nullable String message) { 1631 mTrustGrantedIndication = message; 1632 updateDeviceEntryIndication(false); 1633 } 1634 handleFaceLockoutError(String errString)1635 private void handleFaceLockoutError(String errString) { 1636 String followupMessage = faceLockedOutFollowupMessage(); 1637 // Lockout error can happen multiple times in a session because we trigger face auth 1638 // even when it is locked out so that the user is aware that face unlock would have 1639 // triggered but didn't because it is locked out. 1640 1641 // On first lockout we show the error message from FaceManager, which tells the user they 1642 // had too many unsuccessful attempts. 1643 if (!mFaceLockedOutThisAuthSession) { 1644 mFaceLockedOutThisAuthSession = true; 1645 showErrorMessageNowOrLater(errString, followupMessage, FACE); 1646 } else if (!mAuthController.isUdfpsFingerDown()) { 1647 // On subsequent lockouts, we show a more generic locked out message. 1648 showErrorMessageNowOrLater( 1649 mContext.getString(R.string.keyguard_face_unlock_unavailable), 1650 followupMessage, 1651 FACE); 1652 } 1653 } 1654 faceLockedOutFollowupMessage()1655 private String faceLockedOutFollowupMessage() { 1656 int followupMsgId = canUnlockWithFingerprint() ? R.string.keyguard_suggest_fingerprint 1657 : R.string.keyguard_unlock; 1658 return mContext.getString(followupMsgId); 1659 } 1660 handleFaceAuthTimeoutError(@ullable CharSequence deferredFaceMessage)1661 private void handleFaceAuthTimeoutError(@Nullable CharSequence deferredFaceMessage) { 1662 mKeyguardLogger.logBiometricMessage("deferred message after face auth timeout", 1663 null, String.valueOf(deferredFaceMessage)); 1664 if (canUnlockWithFingerprint()) { 1665 // Co-ex: show deferred message OR nothing 1666 // if we're on the lock screen (bouncer isn't showing), show the deferred msg 1667 if (deferredFaceMessage != null 1668 && !mStatusBarKeyguardViewManager.isBouncerShowing()) { 1669 showBiometricMessage( 1670 deferredFaceMessage, 1671 mContext.getString(R.string.keyguard_suggest_fingerprint), 1672 FACE 1673 ); 1674 } else { 1675 // otherwise, don't show any message 1676 mKeyguardLogger.logBiometricMessage( 1677 "skip showing FACE_ERROR_TIMEOUT due to co-ex logic"); 1678 } 1679 } else if (deferredFaceMessage != null) { 1680 mBouncerMessageInteractor.setFaceAcquisitionMessage(deferredFaceMessage.toString()); 1681 // Face-only: The face timeout message is not very actionable, let's ask the 1682 // user to manually retry. 1683 showBiometricMessage( 1684 deferredFaceMessage, 1685 mContext.getString(R.string.keyguard_unlock), 1686 FACE 1687 ); 1688 } else { 1689 // Face-only 1690 // suggest swiping up to unlock (try face auth again or swipe up to bouncer) 1691 showActionToUnlock(); 1692 } 1693 } 1694 canUnlockWithFingerprint()1695 private boolean canUnlockWithFingerprint() { 1696 return mKeyguardUpdateMonitor.isUnlockWithFingerprintPossible( 1697 getCurrentUser()) && mKeyguardUpdateMonitor.isUnlockingWithFingerprintAllowed(); 1698 } 1699 showErrorMessageNowOrLater(String errString, @Nullable String followUpMsg, BiometricSourceType biometricSourceType)1700 private void showErrorMessageNowOrLater(String errString, @Nullable String followUpMsg, 1701 BiometricSourceType biometricSourceType) { 1702 if (mStatusBarKeyguardViewManager.isBouncerShowing()) { 1703 mStatusBarKeyguardViewManager.setKeyguardMessage(errString, getInitialTextColorState(), 1704 biometricSourceType); 1705 } else if (mScreenLifecycle.getScreenState() == SCREEN_ON) { 1706 showBiometricMessage(errString, followUpMsg, biometricSourceType); 1707 } else { 1708 mBiometricErrorMessageToShowOnScreenOn = new Pair<>(errString, biometricSourceType); 1709 } 1710 } 1711 1712 private final StatusBarStateController.StateListener mStatusBarStateListener = 1713 new StatusBarStateController.StateListener() { 1714 @Override 1715 public void onDozingChanged(boolean dozing) { 1716 if (mDozing == dozing) { 1717 return; 1718 } 1719 mDozing = dozing; 1720 1721 if (mDozing) { 1722 hideBiometricMessage(); 1723 } 1724 updateDeviceEntryIndication(false); 1725 } 1726 }; 1727 1728 private final KeyguardStateController.Callback mKeyguardStateCallback = 1729 new KeyguardStateController.Callback() { 1730 @Override 1731 public void onUnlockedChanged() { 1732 mTrustAgentErrorMessage = null; 1733 updateDeviceEntryIndication(false); 1734 } 1735 1736 @Override 1737 public void onKeyguardShowingChanged() { 1738 // All transient messages are gone the next time keyguard is shown 1739 if (!mKeyguardStateController.isShowing()) { 1740 mKeyguardLogger.log(TAG, LogLevel.DEBUG, "clear messages"); 1741 mTopIndicationView.clearMessages(); 1742 mRotateTextViewController.clearMessages(); 1743 mTrustAgentErrorMessage = null; 1744 } else { 1745 updateDeviceEntryIndication(false); 1746 } 1747 } 1748 }; 1749 } 1750