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