1 /* 2 * Copyright (C) 2020 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.biometrics; 18 19 import static android.app.StatusBarManager.SESSION_BIOMETRIC_PROMPT; 20 import static android.app.StatusBarManager.SESSION_KEYGUARD; 21 import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD; 22 import static android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP; 23 import static android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD; 24 import static android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING; 25 import static android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR; 26 27 import static com.android.internal.util.Preconditions.checkNotNull; 28 import static com.android.systemui.classifier.Classifier.UDFPS_AUTHENTICATION; 29 import static com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION; 30 31 import android.content.BroadcastReceiver; 32 import android.content.Context; 33 import android.content.Intent; 34 import android.content.IntentFilter; 35 import android.graphics.Point; 36 import android.graphics.Rect; 37 import android.hardware.biometrics.BiometricFingerprintConstants; 38 import android.hardware.biometrics.SensorProperties; 39 import android.hardware.display.DisplayManager; 40 import android.hardware.fingerprint.FingerprintManager; 41 import android.hardware.fingerprint.FingerprintSensorProperties; 42 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; 43 import android.hardware.fingerprint.IUdfpsOverlayController; 44 import android.hardware.fingerprint.IUdfpsOverlayControllerCallback; 45 import android.hardware.input.InputManager; 46 import android.os.Build; 47 import android.os.Handler; 48 import android.os.PowerManager; 49 import android.os.Process; 50 import android.os.Trace; 51 import android.os.VibrationAttributes; 52 import android.os.VibrationEffect; 53 import android.util.Log; 54 import android.view.HapticFeedbackConstants; 55 import android.view.LayoutInflater; 56 import android.view.MotionEvent; 57 import android.view.VelocityTracker; 58 import android.view.WindowManager; 59 import android.view.accessibility.AccessibilityManager; 60 61 import androidx.annotation.NonNull; 62 import androidx.annotation.Nullable; 63 64 import com.android.internal.R; 65 import com.android.internal.annotations.VisibleForTesting; 66 import com.android.internal.logging.InstanceId; 67 import com.android.internal.util.LatencyTracker; 68 import com.android.keyguard.FaceAuthApiRequestReason; 69 import com.android.keyguard.KeyguardUpdateMonitor; 70 import com.android.settingslib.udfps.UdfpsOverlayParams; 71 import com.android.settingslib.udfps.UdfpsUtils; 72 import com.android.systemui.Dumpable; 73 import com.android.systemui.animation.ActivityLaunchAnimator; 74 import com.android.systemui.biometrics.dagger.BiometricsBackground; 75 import com.android.systemui.biometrics.udfps.InteractionEvent; 76 import com.android.systemui.biometrics.udfps.NormalizedTouchData; 77 import com.android.systemui.biometrics.udfps.SinglePointerTouchProcessor; 78 import com.android.systemui.biometrics.udfps.TouchProcessor; 79 import com.android.systemui.biometrics.udfps.TouchProcessorResult; 80 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor; 81 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor; 82 import com.android.systemui.dagger.SysUISingleton; 83 import com.android.systemui.dagger.qualifiers.Main; 84 import com.android.systemui.doze.DozeReceiver; 85 import com.android.systemui.dump.DumpManager; 86 import com.android.systemui.flags.FeatureFlags; 87 import com.android.systemui.flags.Flags; 88 import com.android.systemui.keyguard.ScreenLifecycle; 89 import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor; 90 import com.android.systemui.keyguard.ui.adapter.UdfpsKeyguardViewControllerAdapter; 91 import com.android.systemui.keyguard.ui.viewmodel.UdfpsKeyguardViewModels; 92 import com.android.systemui.log.SessionTracker; 93 import com.android.systemui.plugins.FalsingManager; 94 import com.android.systemui.plugins.statusbar.StatusBarStateController; 95 import com.android.systemui.shade.ShadeExpansionStateManager; 96 import com.android.systemui.shared.system.SysUiStatsLog; 97 import com.android.systemui.statusbar.LockscreenShadeTransitionController; 98 import com.android.systemui.statusbar.VibratorHelper; 99 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; 100 import com.android.systemui.statusbar.phone.SystemUIDialogManager; 101 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; 102 import com.android.systemui.statusbar.policy.ConfigurationController; 103 import com.android.systemui.statusbar.policy.KeyguardStateController; 104 import com.android.systemui.util.concurrency.DelayableExecutor; 105 import com.android.systemui.util.concurrency.Execution; 106 import com.android.systemui.util.settings.SecureSettings; 107 import com.android.systemui.util.time.SystemClock; 108 109 import kotlin.Unit; 110 111 import java.io.PrintWriter; 112 import java.util.ArrayList; 113 import java.util.HashSet; 114 import java.util.Optional; 115 import java.util.Set; 116 import java.util.concurrent.Executor; 117 118 import javax.inject.Inject; 119 import javax.inject.Provider; 120 121 /** 122 * Shows and hides the under-display fingerprint sensor (UDFPS) overlay, handles UDFPS touch events, 123 * and toggles the UDFPS display mode. 124 * 125 * Note that the current architecture is designed so that a single {@link UdfpsController} 126 * controls/manages all UDFPS sensors. In other words, a single controller is registered with 127 * {@link com.android.server.biometrics.sensors.fingerprint.FingerprintService}, and interfaces such 128 * as {@link FingerprintManager#onPointerDown(long, int, int, int, float, float)} or 129 * {@link IUdfpsOverlayController#showUdfpsOverlay} should all have 130 * {@code sensorId} parameters. 131 */ 132 @SuppressWarnings("deprecation") 133 @SysUISingleton 134 public class UdfpsController implements DozeReceiver, Dumpable { 135 private static final String TAG = "UdfpsController"; 136 private static final long AOD_SEND_FINGER_UP_DELAY_MILLIS = 1000; 137 138 // Minimum required delay between consecutive touch logs in milliseconds. 139 private static final long MIN_TOUCH_LOG_INTERVAL = 50; 140 private static final long MIN_UNCHANGED_INTERACTION_LOG_INTERVAL = 50; 141 142 // This algorithm checks whether the touch is within the sensor's bounding box. 143 private static final int BOUNDING_BOX_TOUCH_CONFIG_ID = 0; 144 145 private final Context mContext; 146 private final Execution mExecution; 147 private final FingerprintManager mFingerprintManager; 148 @NonNull private final LayoutInflater mInflater; 149 private final WindowManager mWindowManager; 150 private final DelayableExecutor mFgExecutor; 151 @NonNull private final Executor mBiometricExecutor; 152 @NonNull private final ShadeExpansionStateManager mShadeExpansionStateManager; 153 @NonNull private final StatusBarStateController mStatusBarStateController; 154 @NonNull private final KeyguardStateController mKeyguardStateController; 155 @NonNull private final StatusBarKeyguardViewManager mKeyguardViewManager; 156 @NonNull private final DumpManager mDumpManager; 157 @NonNull private final SystemUIDialogManager mDialogManager; 158 @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; 159 @NonNull private final KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor; 160 @NonNull private final Provider<UdfpsKeyguardViewModels> mUdfpsKeyguardViewModels; 161 @NonNull private final VibratorHelper mVibrator; 162 @NonNull private final FeatureFlags mFeatureFlags; 163 @NonNull private final FalsingManager mFalsingManager; 164 @NonNull private final PowerManager mPowerManager; 165 @NonNull private final AccessibilityManager mAccessibilityManager; 166 @NonNull private final LockscreenShadeTransitionController mLockscreenShadeTransitionController; 167 @NonNull private final ConfigurationController mConfigurationController; 168 @NonNull private final SystemClock mSystemClock; 169 @NonNull private final UnlockedScreenOffAnimationController 170 mUnlockedScreenOffAnimationController; 171 @NonNull private final LatencyTracker mLatencyTracker; 172 @VisibleForTesting @NonNull final BiometricDisplayListener mOrientationListener; 173 @NonNull private final ActivityLaunchAnimator mActivityLaunchAnimator; 174 @NonNull private final PrimaryBouncerInteractor mPrimaryBouncerInteractor; 175 @Nullable private final TouchProcessor mTouchProcessor; 176 @NonNull private final SessionTracker mSessionTracker; 177 @NonNull private final AlternateBouncerInteractor mAlternateBouncerInteractor; 178 @NonNull private final SecureSettings mSecureSettings; 179 @NonNull private final UdfpsUtils mUdfpsUtils; 180 @NonNull private final InputManager mInputManager; 181 @NonNull private final UdfpsKeyguardAccessibilityDelegate mUdfpsKeyguardAccessibilityDelegate; 182 private final boolean mIgnoreRefreshRate; 183 184 // Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple 185 // sensors, this, in addition to a lot of the code here, will be updated. 186 @VisibleForTesting @NonNull FingerprintSensorPropertiesInternal mSensorProps; 187 @VisibleForTesting @NonNull UdfpsOverlayParams mOverlayParams = new UdfpsOverlayParams(); 188 // TODO(b/229290039): UDFPS controller should manage its dimensions on its own. Remove this. 189 @Nullable private Runnable mAuthControllerUpdateUdfpsLocation; 190 @Nullable private final AlternateUdfpsTouchProvider mAlternateTouchProvider; 191 @Nullable private UdfpsDisplayModeProvider mUdfpsDisplayMode; 192 193 // Tracks the velocity of a touch to help filter out the touches that move too fast. 194 @Nullable private VelocityTracker mVelocityTracker; 195 // The ID of the pointer for which ACTION_DOWN has occurred. -1 means no pointer is active. 196 private int mActivePointerId = -1; 197 // Whether a pointer has been pilfered for current gesture 198 private boolean mPointerPilfered = false; 199 // The timestamp of the most recent touch log. 200 private long mTouchLogTime; 201 // The timestamp of the most recent log of a touch InteractionEvent. 202 private long mLastTouchInteractionTime; 203 // Sensor has a capture (good or bad) for this touch. No need to enable the UDFPS display mode 204 // anymore for this particular touch event. In other words, do not enable the UDFPS mode until 205 // the user touches the sensor area again. 206 private boolean mAcquiredReceived; 207 208 // The current request from FingerprintService. Null if no current request. 209 @Nullable UdfpsControllerOverlay mOverlay; 210 211 // The fingerprint AOD trigger doesn't provide an ACTION_UP/ACTION_CANCEL event to tell us when 212 // to turn off high brightness mode. To get around this limitation, the state of the AOD 213 // interrupt is being tracked and a timeout is used as a last resort to turn off high brightness 214 // mode. 215 private boolean mIsAodInterruptActive; 216 @Nullable private Runnable mCancelAodFingerUpAction; 217 private boolean mScreenOn; 218 private Runnable mAodInterruptRunnable; 219 private boolean mOnFingerDown; 220 private boolean mAttemptedToDismissKeyguard; 221 private final Set<Callback> mCallbacks = new HashSet<>(); 222 223 @VisibleForTesting 224 public static final VibrationAttributes UDFPS_VIBRATION_ATTRIBUTES = 225 new VibrationAttributes.Builder() 226 // vibration will bypass battery saver mode: 227 .setUsage(VibrationAttributes.USAGE_COMMUNICATION_REQUEST) 228 .build(); 229 @VisibleForTesting 230 public static final VibrationAttributes LOCK_ICON_VIBRATION_ATTRIBUTES = 231 new VibrationAttributes.Builder() 232 .setUsage(VibrationAttributes.USAGE_TOUCH) 233 .build(); 234 235 // haptic to use for successful device entry 236 public static final VibrationEffect EFFECT_CLICK = 237 VibrationEffect.get(VibrationEffect.EFFECT_CLICK); 238 239 public static final int LONG_PRESS = HapticFeedbackConstants.LONG_PRESS; 240 241 private final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() { 242 @Override 243 public void onScreenTurnedOn() { 244 mScreenOn = true; 245 if (mAodInterruptRunnable != null) { 246 mAodInterruptRunnable.run(); 247 mAodInterruptRunnable = null; 248 } 249 } 250 251 @Override 252 public void onScreenTurnedOff() { 253 mScreenOn = false; 254 } 255 }; 256 257 @Override dump(@onNull PrintWriter pw, @NonNull String[] args)258 public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { 259 pw.println("mSensorProps=(" + mSensorProps + ")"); 260 pw.println("Using new touch detection framework: " + mFeatureFlags.isEnabled( 261 Flags.UDFPS_NEW_TOUCH_DETECTION)); 262 pw.println("Using ellipse touch detection: " + mFeatureFlags.isEnabled( 263 Flags.UDFPS_ELLIPSE_DETECTION)); 264 } 265 266 public class UdfpsOverlayController extends IUdfpsOverlayController.Stub { 267 @Override showUdfpsOverlay(long requestId, int sensorId, int reason, @NonNull IUdfpsOverlayControllerCallback callback)268 public void showUdfpsOverlay(long requestId, int sensorId, int reason, 269 @NonNull IUdfpsOverlayControllerCallback callback) { 270 mFgExecutor.execute(() -> UdfpsController.this.showUdfpsOverlay( 271 new UdfpsControllerOverlay(mContext, mFingerprintManager, mInflater, 272 mWindowManager, mAccessibilityManager, mStatusBarStateController, 273 mShadeExpansionStateManager, mKeyguardViewManager, 274 mKeyguardUpdateMonitor, mDialogManager, mDumpManager, 275 mLockscreenShadeTransitionController, mConfigurationController, 276 mKeyguardStateController, 277 mUnlockedScreenOffAnimationController, 278 mUdfpsDisplayMode, mSecureSettings, requestId, reason, callback, 279 (view, event, fromUdfpsView) -> onTouch(requestId, event, 280 fromUdfpsView), mActivityLaunchAnimator, mFeatureFlags, 281 mPrimaryBouncerInteractor, mAlternateBouncerInteractor, mUdfpsUtils, 282 mUdfpsKeyguardAccessibilityDelegate, 283 mUdfpsKeyguardViewModels))); 284 } 285 286 @Override hideUdfpsOverlay(int sensorId)287 public void hideUdfpsOverlay(int sensorId) { 288 mFgExecutor.execute(() -> { 289 if (mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) { 290 // if we get here, we expect keyguardUpdateMonitor's fingerprintRunningState 291 // to be updated shortly afterwards 292 Log.d(TAG, "hiding udfps overlay when " 293 + "mKeyguardUpdateMonitor.isFingerprintDetectionRunning()=true"); 294 } 295 296 UdfpsController.this.hideUdfpsOverlay(); 297 }); 298 } 299 300 @Override onAcquired( int sensorId, @BiometricFingerprintConstants.FingerprintAcquired int acquiredInfo )301 public void onAcquired( 302 int sensorId, 303 @BiometricFingerprintConstants.FingerprintAcquired int acquiredInfo 304 ) { 305 if (BiometricFingerprintConstants.shouldDisableUdfpsDisplayMode(acquiredInfo)) { 306 boolean acquiredGood = acquiredInfo == FINGERPRINT_ACQUIRED_GOOD; 307 mFgExecutor.execute(() -> { 308 if (mOverlay == null) { 309 Log.e(TAG, "Null request when onAcquired for sensorId: " + sensorId 310 + " acquiredInfo=" + acquiredInfo); 311 return; 312 } 313 mAcquiredReceived = true; 314 final UdfpsView view = mOverlay.getOverlayView(); 315 if (view != null && isOptical()) { 316 unconfigureDisplay(view); 317 } 318 tryAodSendFingerUp(); 319 }); 320 } 321 } 322 323 @Override onEnrollmentProgress(int sensorId, int remaining)324 public void onEnrollmentProgress(int sensorId, int remaining) { } 325 326 @Override onEnrollmentHelp(int sensorId)327 public void onEnrollmentHelp(int sensorId) { } 328 329 @Override setDebugMessage(int sensorId, String message)330 public void setDebugMessage(int sensorId, String message) { 331 mFgExecutor.execute(() -> { 332 if (mOverlay == null || mOverlay.isHiding()) { 333 return; 334 } 335 mOverlay.getOverlayView().setDebugMessage(message); 336 }); 337 } 338 getSensorBounds()339 public Rect getSensorBounds() { 340 return mOverlayParams.getSensorBounds(); 341 } 342 343 /** 344 * Passes a mocked MotionEvent to OnTouch. 345 * 346 * @param event MotionEvent to simulate in onTouch 347 */ debugOnTouch(MotionEvent event)348 public void debugOnTouch(MotionEvent event) { 349 final long requestId = (mOverlay != null) ? mOverlay.getRequestId() : 0L; 350 UdfpsController.this.onTouch(requestId, event, true); 351 } 352 353 /** 354 * Debug to run onUiReady 355 */ debugOnUiReady(int sensorId)356 public void debugOnUiReady(int sensorId) { 357 if (UdfpsController.this.mAlternateTouchProvider != null) { 358 UdfpsController.this.mAlternateTouchProvider.onUiReady(); 359 } else { 360 final long requestId = (mOverlay != null) ? mOverlay.getRequestId() : 0L; 361 UdfpsController.this.mFingerprintManager.onUdfpsUiEvent( 362 FingerprintManager.UDFPS_UI_READY, requestId, sensorId); 363 } 364 } 365 } 366 367 /** 368 * Updates the overlay parameters and reconstructs or redraws the overlay, if necessary. 369 * 370 * @param sensorProps sensor for which the overlay is getting updated. 371 * @param overlayParams See {@link UdfpsOverlayParams}. 372 */ updateOverlayParams(@onNull FingerprintSensorPropertiesInternal sensorProps, @NonNull UdfpsOverlayParams overlayParams)373 public void updateOverlayParams(@NonNull FingerprintSensorPropertiesInternal sensorProps, 374 @NonNull UdfpsOverlayParams overlayParams) { 375 if (mSensorProps.sensorId != sensorProps.sensorId) { 376 mSensorProps = sensorProps; 377 Log.w(TAG, "updateUdfpsParams | sensorId has changed"); 378 } 379 380 if (!mOverlayParams.equals(overlayParams)) { 381 mOverlayParams = overlayParams; 382 383 final boolean wasShowingAlternateBouncer = mAlternateBouncerInteractor.isVisibleState(); 384 385 // When the bounds change it's always necessary to re-create the overlay's window with 386 // new LayoutParams. If the overlay needs to be shown, this will re-create and show the 387 // overlay with the updated LayoutParams. Otherwise, the overlay will remain hidden. 388 redrawOverlay(); 389 if (wasShowingAlternateBouncer) { 390 mKeyguardViewManager.showBouncer(true); 391 } 392 } 393 } 394 395 // TODO(b/229290039): UDFPS controller should manage its dimensions on its own. Remove this. setAuthControllerUpdateUdfpsLocation(@ullable Runnable r)396 public void setAuthControllerUpdateUdfpsLocation(@Nullable Runnable r) { 397 mAuthControllerUpdateUdfpsLocation = r; 398 } 399 setUdfpsDisplayMode(@onNull UdfpsDisplayModeProvider udfpsDisplayMode)400 public void setUdfpsDisplayMode(@NonNull UdfpsDisplayModeProvider udfpsDisplayMode) { 401 mUdfpsDisplayMode = udfpsDisplayMode; 402 } 403 404 /** 405 * Calculate the pointer speed given a velocity tracker and the pointer id. 406 * This assumes that the velocity tracker has already been passed all relevant motion events. 407 */ computePointerSpeed(@onNull VelocityTracker tracker, int pointerId)408 public static float computePointerSpeed(@NonNull VelocityTracker tracker, int pointerId) { 409 final float vx = tracker.getXVelocity(pointerId); 410 final float vy = tracker.getYVelocity(pointerId); 411 return (float) Math.sqrt(Math.pow(vx, 2.0) + Math.pow(vy, 2.0)); 412 } 413 414 /** 415 * Whether the velocity exceeds the acceptable UDFPS debouncing threshold. 416 */ exceedsVelocityThreshold(float velocity)417 public static boolean exceedsVelocityThreshold(float velocity) { 418 return velocity > 750f; 419 } 420 421 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 422 @Override 423 public void onReceive(Context context, Intent intent) { 424 if (mOverlay != null 425 && mOverlay.getRequestReason() != REASON_AUTH_KEYGUARD 426 && Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) { 427 String reason = intent.getStringExtra("reason"); 428 reason = (reason != null) ? reason : "unknown"; 429 Log.d(TAG, "ACTION_CLOSE_SYSTEM_DIALOGS received, reason: " + reason 430 + ", mRequestReason: " + mOverlay.getRequestReason()); 431 432 mOverlay.cancel(); 433 hideUdfpsOverlay(); 434 } 435 } 436 }; 437 438 /** 439 * Forwards touches to the udfps controller / view 440 */ onTouch(MotionEvent event)441 public boolean onTouch(MotionEvent event) { 442 if (mOverlay == null || mOverlay.isHiding()) { 443 return false; 444 } 445 // TODO(b/225068271): may not be correct but no way to get the id yet 446 return onTouch(mOverlay.getRequestId(), event, false); 447 } 448 449 /** 450 * @param x coordinate 451 * @param y coordinate 452 * @param relativeToUdfpsView true if the coordinates are relative to the udfps view; else, 453 * calculate from the display dimensions in portrait orientation 454 */ isWithinSensorArea(UdfpsView udfpsView, float x, float y, boolean relativeToUdfpsView)455 private boolean isWithinSensorArea(UdfpsView udfpsView, float x, float y, 456 boolean relativeToUdfpsView) { 457 if (relativeToUdfpsView) { 458 // TODO: move isWithinSensorArea to UdfpsController. 459 return udfpsView.isWithinSensorArea(x, y); 460 } 461 462 if (mOverlay == null || mOverlay.getAnimationViewController() == null) { 463 return false; 464 } 465 466 return !mOverlay.getAnimationViewController().shouldPauseAuth() 467 && mOverlayParams.getSensorBounds().contains((int) x, (int) y); 468 } 469 tryDismissingKeyguard()470 private void tryDismissingKeyguard() { 471 if (!mOnFingerDown) { 472 playStartHaptic(); 473 } 474 mKeyguardViewManager.notifyKeyguardAuthenticated(false /* primaryAuth */); 475 mAttemptedToDismissKeyguard = true; 476 } 477 478 @VisibleForTesting onTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView)479 boolean onTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) { 480 if (mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) { 481 return newOnTouch(requestId, event, fromUdfpsView); 482 } else { 483 return oldOnTouch(requestId, event, fromUdfpsView); 484 } 485 } 486 getBiometricSessionType()487 private int getBiometricSessionType() { 488 if (mOverlay == null) { 489 return -1; 490 } 491 switch (mOverlay.getRequestReason()) { 492 case REASON_AUTH_KEYGUARD: 493 return SESSION_KEYGUARD; 494 case REASON_AUTH_BP: 495 return SESSION_BIOMETRIC_PROMPT; 496 case REASON_ENROLL_FIND_SENSOR: 497 case REASON_ENROLL_ENROLLING: 498 // TODO(b/255634916): create a reason for enrollment (or an "unknown" reason). 499 return SESSION_BIOMETRIC_PROMPT << 1; 500 default: 501 return -1; 502 } 503 } 504 toBiometricTouchReportedTouchType(InteractionEvent event)505 private static int toBiometricTouchReportedTouchType(InteractionEvent event) { 506 switch (event) { 507 case DOWN: 508 return SysUiStatsLog.BIOMETRIC_TOUCH_REPORTED__TOUCH_TYPE__TOUCH_TYPE_DOWN; 509 case UP: 510 return SysUiStatsLog.BIOMETRIC_TOUCH_REPORTED__TOUCH_TYPE__TOUCH_TYPE_UP; 511 case CANCEL: 512 return SysUiStatsLog.BIOMETRIC_TOUCH_REPORTED__TOUCH_TYPE__TOUCH_TYPE_CANCEL; 513 default: 514 return SysUiStatsLog.BIOMETRIC_TOUCH_REPORTED__TOUCH_TYPE__TOUCH_TYPE_UNCHANGED; 515 } 516 } 517 logBiometricTouch(InteractionEvent event, NormalizedTouchData data)518 private void logBiometricTouch(InteractionEvent event, NormalizedTouchData data) { 519 if (event == InteractionEvent.UNCHANGED) { 520 long sinceLastLog = mSystemClock.elapsedRealtime() - mLastTouchInteractionTime; 521 if (sinceLastLog < MIN_UNCHANGED_INTERACTION_LOG_INTERVAL) { 522 return; 523 } 524 } 525 mLastTouchInteractionTime = mSystemClock.elapsedRealtime(); 526 527 final int biometricTouchReportedTouchType = toBiometricTouchReportedTouchType(event); 528 final InstanceId sessionIdProvider = mSessionTracker.getSessionId( 529 getBiometricSessionType()); 530 final int sessionId = (sessionIdProvider != null) ? sessionIdProvider.getId() : -1; 531 final int touchConfigId = mContext.getResources().getInteger( 532 com.android.internal.R.integer.config_selected_udfps_touch_detection); 533 534 SysUiStatsLog.write(SysUiStatsLog.BIOMETRIC_TOUCH_REPORTED, biometricTouchReportedTouchType, 535 touchConfigId, sessionId, data.getX(), data.getY(), data.getMinor(), 536 data.getMajor(), data.getOrientation(), data.getTime(), data.getGestureStart(), 537 mStatusBarStateController.isDozing()); 538 539 if (Build.isDebuggable()) { 540 Log.d(TAG, data.toPrettyString(event.toString())); 541 Log.d(TAG, "sessionId: " + sessionId 542 + ", isAod: " + mStatusBarStateController.isDozing() 543 + ", touchConfigId: " + touchConfigId); 544 } 545 } 546 newOnTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView)547 private boolean newOnTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) { 548 if (!fromUdfpsView) { 549 Log.e(TAG, "ignoring the touch injected from outside of UdfpsView"); 550 return false; 551 } 552 if (mOverlay == null || mOverlay.getAnimationViewController() == null) { 553 Log.w(TAG, "ignoring onTouch with null overlay or animation view controller"); 554 return false; 555 } 556 if (mOverlay.getAnimationViewController().shouldPauseAuth()) { 557 Log.w(TAG, "ignoring onTouch with shouldPauseAuth = true"); 558 return false; 559 } 560 if (!mOverlay.matchesRequestId(requestId)) { 561 Log.w(TAG, "ignoring stale touch event: " + requestId + " current: " 562 + mOverlay.getRequestId()); 563 return false; 564 } 565 566 if ((mLockscreenShadeTransitionController.getQSDragProgress() != 0f 567 && !mAlternateBouncerInteractor.isVisibleState()) 568 || mPrimaryBouncerInteractor.isInTransit()) { 569 return false; 570 } 571 if (event.getAction() == MotionEvent.ACTION_DOWN 572 || event.getAction() == MotionEvent.ACTION_HOVER_ENTER) { 573 // Reset on ACTION_DOWN, start of new gesture 574 mPointerPilfered = false; 575 } 576 577 final TouchProcessorResult result = mTouchProcessor.processTouch(event, mActivePointerId, 578 mOverlayParams); 579 if (result instanceof TouchProcessorResult.Failure) { 580 Log.w(TAG, ((TouchProcessorResult.Failure) result).getReason()); 581 return false; 582 } 583 584 final TouchProcessorResult.ProcessedTouch processedTouch = 585 (TouchProcessorResult.ProcessedTouch) result; 586 final NormalizedTouchData data = processedTouch.getTouchData(); 587 588 boolean shouldPilfer = false; 589 mActivePointerId = processedTouch.getPointerOnSensorId(); 590 switch (processedTouch.getEvent()) { 591 case DOWN: 592 if (shouldTryToDismissKeyguard()) { 593 tryDismissingKeyguard(); 594 } 595 if (!mOnFingerDown) { 596 onFingerDown(requestId, 597 data.getPointerId(), 598 data.getX(), 599 data.getY(), 600 data.getMinor(), 601 data.getMajor(), 602 data.getOrientation(), 603 data.getTime(), 604 data.getGestureStart(), 605 mStatusBarStateController.isDozing()); 606 } 607 608 // Pilfer if valid overlap, don't allow following events to reach keyguard 609 shouldPilfer = true; 610 611 // Touch is a valid UDFPS touch. Inform the falsing manager so that the touch 612 // isn't counted against the falsing algorithm as an accidental touch. 613 // We do this on the DOWN event instead of CANCEL/UP because the CANCEL/UP events 614 // get sent too late to this receiver (after the actual cancel/up motions occur), 615 // and therefore wouldn't end up being used as part of the falsing algo. 616 mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION); 617 break; 618 619 case UP: 620 case CANCEL: 621 if (InteractionEvent.CANCEL.equals(processedTouch.getEvent())) { 622 Log.w(TAG, "This is a CANCEL event that's reported as an UP event!"); 623 } 624 mAttemptedToDismissKeyguard = false; 625 onFingerUp(requestId, 626 mOverlay.getOverlayView(), 627 data.getPointerId(), 628 data.getX(), 629 data.getY(), 630 data.getMinor(), 631 data.getMajor(), 632 data.getOrientation(), 633 data.getTime(), 634 data.getGestureStart(), 635 mStatusBarStateController.isDozing()); 636 break; 637 638 case UNCHANGED: 639 if (!isWithinSensorArea(mOverlay.getOverlayView(), event.getRawX(), event.getRawY(), 640 true) && mActivePointerId == MotionEvent.INVALID_POINTER_ID 641 && mAlternateBouncerInteractor.isVisibleState()) { 642 // No pointer on sensor, forward to keyguard if alternateBouncer is visible 643 mKeyguardViewManager.onTouch(event); 644 } 645 646 default: 647 break; 648 } 649 logBiometricTouch(processedTouch.getEvent(), data); 650 651 // Always pilfer pointers that are within sensor area or when alternate bouncer is showing 652 if (isWithinSensorArea(mOverlay.getOverlayView(), event.getRawX(), event.getRawY(), true) 653 || mAlternateBouncerInteractor.isVisibleState()) { 654 shouldPilfer = true; 655 } 656 657 // Pilfer only once per gesture, don't pilfer for BP 658 if (shouldPilfer && !mPointerPilfered 659 && getBiometricSessionType() != SESSION_BIOMETRIC_PROMPT) { 660 mInputManager.pilferPointers( 661 mOverlay.getOverlayView().getViewRootImpl().getInputToken()); 662 mPointerPilfered = true; 663 } 664 665 return processedTouch.getTouchData().isWithinBounds(mOverlayParams.getNativeSensorBounds()); 666 } 667 oldOnTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView)668 private boolean oldOnTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) { 669 if (mOverlay == null) { 670 Log.w(TAG, "ignoring onTouch with null overlay"); 671 return false; 672 } 673 if (!mOverlay.matchesRequestId(requestId)) { 674 Log.w(TAG, "ignoring stale touch event: " + requestId + " current: " 675 + mOverlay.getRequestId()); 676 return false; 677 } 678 679 final UdfpsView udfpsView = mOverlay.getOverlayView(); 680 boolean handled = false; 681 switch (event.getActionMasked()) { 682 case MotionEvent.ACTION_DOWN: 683 case MotionEvent.ACTION_HOVER_ENTER: 684 Trace.beginSection("UdfpsController.onTouch.ACTION_DOWN"); 685 // To simplify the lifecycle of the velocity tracker, make sure it's never null 686 // after ACTION_DOWN, and always null after ACTION_CANCEL or ACTION_UP. 687 if (mVelocityTracker == null) { 688 mVelocityTracker = VelocityTracker.obtain(); 689 } else { 690 // ACTION_UP or ACTION_CANCEL is not guaranteed to be called before a new 691 // ACTION_DOWN, in that case we should just reuse the old instance. 692 mVelocityTracker.clear(); 693 } 694 695 final boolean withinSensorArea = 696 isWithinSensorArea(udfpsView, event.getX(), event.getY(), fromUdfpsView); 697 if (withinSensorArea) { 698 Trace.beginAsyncSection("UdfpsController.e2e.onPointerDown", 0); 699 Log.v(TAG, "onTouch | action down"); 700 // The pointer that causes ACTION_DOWN is always at index 0. 701 // We need to persist its ID to track it during ACTION_MOVE that could include 702 // data for many other pointers because of multi-touch support. 703 mActivePointerId = event.getPointerId(0); 704 mVelocityTracker.addMovement(event); 705 handled = true; 706 mAcquiredReceived = false; 707 } 708 if ((withinSensorArea || fromUdfpsView) && shouldTryToDismissKeyguard()) { 709 Log.v(TAG, "onTouch | dismiss keyguard ACTION_DOWN"); 710 tryDismissingKeyguard(); 711 } 712 713 Trace.endSection(); 714 break; 715 716 case MotionEvent.ACTION_MOVE: 717 case MotionEvent.ACTION_HOVER_MOVE: 718 Trace.beginSection("UdfpsController.onTouch.ACTION_MOVE"); 719 final int idx = mActivePointerId == -1 720 ? event.getPointerId(0) 721 : event.findPointerIndex(mActivePointerId); 722 if (idx == event.getActionIndex()) { 723 final boolean actionMoveWithinSensorArea = 724 isWithinSensorArea(udfpsView, event.getX(idx), event.getY(idx), 725 fromUdfpsView); 726 if ((fromUdfpsView || actionMoveWithinSensorArea) 727 && shouldTryToDismissKeyguard()) { 728 Log.v(TAG, "onTouch | dismiss keyguard ACTION_MOVE"); 729 tryDismissingKeyguard(); 730 break; 731 } 732 // Map the touch to portrait mode if the device is in landscape mode. 733 final Point scaledTouch = mUdfpsUtils.getTouchInNativeCoordinates( 734 idx, event, mOverlayParams); 735 if (actionMoveWithinSensorArea) { 736 if (mVelocityTracker == null) { 737 // touches could be injected, so the velocity tracker may not have 738 // been initialized (via ACTION_DOWN). 739 mVelocityTracker = VelocityTracker.obtain(); 740 } 741 mVelocityTracker.addMovement(event); 742 // Compute pointer velocity in pixels per second. 743 mVelocityTracker.computeCurrentVelocity(1000); 744 // Compute pointer speed from X and Y velocities. 745 final float v = computePointerSpeed(mVelocityTracker, mActivePointerId); 746 final float minor = event.getTouchMinor(idx); 747 final float major = event.getTouchMajor(idx); 748 final boolean exceedsVelocityThreshold = exceedsVelocityThreshold(v); 749 final String touchInfo = String.format( 750 "minor: %.1f, major: %.1f, v: %.1f, exceedsVelocityThreshold: %b", 751 minor, major, v, exceedsVelocityThreshold); 752 final long sinceLastLog = mSystemClock.elapsedRealtime() - mTouchLogTime; 753 754 if (!mOnFingerDown && !mAcquiredReceived && !exceedsVelocityThreshold) { 755 final float scale = mOverlayParams.getScaleFactor(); 756 float scaledMinor = minor / scale; 757 float scaledMajor = major / scale; 758 onFingerDown(requestId, scaledTouch.x, scaledTouch.y, scaledMinor, 759 scaledMajor); 760 761 Log.v(TAG, "onTouch | finger down: " + touchInfo); 762 mTouchLogTime = mSystemClock.elapsedRealtime(); 763 handled = true; 764 } else if (sinceLastLog >= MIN_TOUCH_LOG_INTERVAL) { 765 Log.v(TAG, "onTouch | finger move: " + touchInfo); 766 mTouchLogTime = mSystemClock.elapsedRealtime(); 767 } 768 } else { 769 Log.v(TAG, "onTouch | finger outside"); 770 onFingerUp(requestId, udfpsView); 771 // Maybe announce for accessibility. 772 mFgExecutor.execute(() -> { 773 if (mOverlay == null) { 774 Log.e(TAG, "touch outside sensor area received" 775 + "but serverRequest is null"); 776 return; 777 } 778 mOverlay.onTouchOutsideOfSensorArea(scaledTouch); 779 }); 780 } 781 } 782 Trace.endSection(); 783 break; 784 785 case MotionEvent.ACTION_UP: 786 case MotionEvent.ACTION_CANCEL: 787 case MotionEvent.ACTION_HOVER_EXIT: 788 Trace.beginSection("UdfpsController.onTouch.ACTION_UP"); 789 mActivePointerId = -1; 790 if (mVelocityTracker != null) { 791 mVelocityTracker.recycle(); 792 mVelocityTracker = null; 793 } 794 Log.v(TAG, "onTouch | finger up"); 795 mAttemptedToDismissKeyguard = false; 796 onFingerUp(requestId, udfpsView); 797 mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION); 798 Trace.endSection(); 799 break; 800 801 default: 802 // Do nothing. 803 } 804 return handled; 805 } 806 shouldTryToDismissKeyguard()807 private boolean shouldTryToDismissKeyguard() { 808 return mOverlay != null 809 && mOverlay.getAnimationViewController() 810 instanceof UdfpsKeyguardViewControllerAdapter 811 && mKeyguardStateController.canDismissLockScreen() 812 && !mAttemptedToDismissKeyguard; 813 } 814 815 @Inject UdfpsController(@onNull Context context, @NonNull Execution execution, @NonNull LayoutInflater inflater, @Nullable FingerprintManager fingerprintManager, @NonNull WindowManager windowManager, @NonNull StatusBarStateController statusBarStateController, @Main DelayableExecutor fgExecutor, @NonNull ShadeExpansionStateManager shadeExpansionStateManager, @NonNull StatusBarKeyguardViewManager statusBarKeyguardViewManager, @NonNull DumpManager dumpManager, @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor, @NonNull FeatureFlags featureFlags, @NonNull FalsingManager falsingManager, @NonNull PowerManager powerManager, @NonNull AccessibilityManager accessibilityManager, @NonNull LockscreenShadeTransitionController lockscreenShadeTransitionController, @NonNull ScreenLifecycle screenLifecycle, @NonNull VibratorHelper vibrator, @NonNull UdfpsHapticsSimulator udfpsHapticsSimulator, @NonNull UdfpsShell udfpsShell, @NonNull KeyguardStateController keyguardStateController, @NonNull DisplayManager displayManager, @Main Handler mainHandler, @NonNull ConfigurationController configurationController, @NonNull SystemClock systemClock, @NonNull UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, @NonNull SystemUIDialogManager dialogManager, @NonNull LatencyTracker latencyTracker, @NonNull ActivityLaunchAnimator activityLaunchAnimator, @NonNull Optional<Provider<AlternateUdfpsTouchProvider>> alternateTouchProvider, @NonNull @BiometricsBackground Executor biometricsExecutor, @NonNull PrimaryBouncerInteractor primaryBouncerInteractor, @NonNull SinglePointerTouchProcessor singlePointerTouchProcessor, @NonNull SessionTracker sessionTracker, @NonNull AlternateBouncerInteractor alternateBouncerInteractor, @NonNull SecureSettings secureSettings, @NonNull InputManager inputManager, @NonNull UdfpsUtils udfpsUtils, @NonNull KeyguardFaceAuthInteractor keyguardFaceAuthInteractor, @NonNull UdfpsKeyguardAccessibilityDelegate udfpsKeyguardAccessibilityDelegate, @NonNull Provider<UdfpsKeyguardViewModels> udfpsKeyguardViewModelsProvider)816 public UdfpsController(@NonNull Context context, 817 @NonNull Execution execution, 818 @NonNull LayoutInflater inflater, 819 @Nullable FingerprintManager fingerprintManager, 820 @NonNull WindowManager windowManager, 821 @NonNull StatusBarStateController statusBarStateController, 822 @Main DelayableExecutor fgExecutor, 823 @NonNull ShadeExpansionStateManager shadeExpansionStateManager, 824 @NonNull StatusBarKeyguardViewManager statusBarKeyguardViewManager, 825 @NonNull DumpManager dumpManager, 826 @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor, 827 @NonNull FeatureFlags featureFlags, 828 @NonNull FalsingManager falsingManager, 829 @NonNull PowerManager powerManager, 830 @NonNull AccessibilityManager accessibilityManager, 831 @NonNull LockscreenShadeTransitionController lockscreenShadeTransitionController, 832 @NonNull ScreenLifecycle screenLifecycle, 833 @NonNull VibratorHelper vibrator, 834 @NonNull UdfpsHapticsSimulator udfpsHapticsSimulator, 835 @NonNull UdfpsShell udfpsShell, 836 @NonNull KeyguardStateController keyguardStateController, 837 @NonNull DisplayManager displayManager, 838 @Main Handler mainHandler, 839 @NonNull ConfigurationController configurationController, 840 @NonNull SystemClock systemClock, 841 @NonNull UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, 842 @NonNull SystemUIDialogManager dialogManager, 843 @NonNull LatencyTracker latencyTracker, 844 @NonNull ActivityLaunchAnimator activityLaunchAnimator, 845 @NonNull Optional<Provider<AlternateUdfpsTouchProvider>> alternateTouchProvider, 846 @NonNull @BiometricsBackground Executor biometricsExecutor, 847 @NonNull PrimaryBouncerInteractor primaryBouncerInteractor, 848 @NonNull SinglePointerTouchProcessor singlePointerTouchProcessor, 849 @NonNull SessionTracker sessionTracker, 850 @NonNull AlternateBouncerInteractor alternateBouncerInteractor, 851 @NonNull SecureSettings secureSettings, 852 @NonNull InputManager inputManager, 853 @NonNull UdfpsUtils udfpsUtils, 854 @NonNull KeyguardFaceAuthInteractor keyguardFaceAuthInteractor, 855 @NonNull UdfpsKeyguardAccessibilityDelegate udfpsKeyguardAccessibilityDelegate, 856 @NonNull Provider<UdfpsKeyguardViewModels> udfpsKeyguardViewModelsProvider) { 857 mContext = context; 858 mExecution = execution; 859 mVibrator = vibrator; 860 mInflater = inflater; 861 mIgnoreRefreshRate = mContext.getResources() 862 .getBoolean(R.bool.config_ignoreUdfpsVote); 863 // The fingerprint manager is queried for UDFPS before this class is constructed, so the 864 // fingerprint manager should never be null. 865 mFingerprintManager = checkNotNull(fingerprintManager); 866 mWindowManager = windowManager; 867 mFgExecutor = fgExecutor; 868 mShadeExpansionStateManager = shadeExpansionStateManager; 869 mStatusBarStateController = statusBarStateController; 870 mKeyguardStateController = keyguardStateController; 871 mKeyguardViewManager = statusBarKeyguardViewManager; 872 mDumpManager = dumpManager; 873 mDialogManager = dialogManager; 874 mKeyguardUpdateMonitor = keyguardUpdateMonitor; 875 mFeatureFlags = featureFlags; 876 mFalsingManager = falsingManager; 877 mPowerManager = powerManager; 878 mAccessibilityManager = accessibilityManager; 879 mLockscreenShadeTransitionController = lockscreenShadeTransitionController; 880 screenLifecycle.addObserver(mScreenObserver); 881 mScreenOn = screenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_ON; 882 mConfigurationController = configurationController; 883 mSystemClock = systemClock; 884 mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController; 885 mLatencyTracker = latencyTracker; 886 mActivityLaunchAnimator = activityLaunchAnimator; 887 mAlternateTouchProvider = alternateTouchProvider.map(Provider::get).orElse(null); 888 mSensorProps = new FingerprintSensorPropertiesInternal( 889 -1 /* sensorId */, 890 SensorProperties.STRENGTH_CONVENIENCE, 891 0 /* maxEnrollmentsPerUser */, 892 new ArrayList<>() /* componentInfo */, 893 FingerprintSensorProperties.TYPE_UNKNOWN, 894 false /* resetLockoutRequiresHardwareAuthToken */); 895 896 mBiometricExecutor = biometricsExecutor; 897 mPrimaryBouncerInteractor = primaryBouncerInteractor; 898 mAlternateBouncerInteractor = alternateBouncerInteractor; 899 mSecureSettings = secureSettings; 900 mUdfpsUtils = udfpsUtils; 901 mInputManager = inputManager; 902 mUdfpsKeyguardAccessibilityDelegate = udfpsKeyguardAccessibilityDelegate; 903 904 mTouchProcessor = mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION) 905 ? singlePointerTouchProcessor : null; 906 mSessionTracker = sessionTracker; 907 908 mDumpManager.registerDumpable(TAG, this); 909 910 mOrientationListener = new BiometricDisplayListener( 911 context, 912 displayManager, 913 mainHandler, 914 BiometricDisplayListener.SensorType.UnderDisplayFingerprint.INSTANCE, 915 () -> { 916 if (mAuthControllerUpdateUdfpsLocation != null) { 917 mAuthControllerUpdateUdfpsLocation.run(); 918 } 919 return Unit.INSTANCE; 920 }); 921 mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor; 922 mUdfpsKeyguardViewModels = udfpsKeyguardViewModelsProvider; 923 924 final UdfpsOverlayController mUdfpsOverlayController = new UdfpsOverlayController(); 925 mFingerprintManager.setUdfpsOverlayController(mUdfpsOverlayController); 926 927 final IntentFilter filter = new IntentFilter(); 928 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); 929 context.registerReceiver(mBroadcastReceiver, filter, 930 Context.RECEIVER_EXPORTED_UNAUDITED); 931 932 udfpsHapticsSimulator.setUdfpsController(this); 933 udfpsShell.setUdfpsOverlayController(mUdfpsOverlayController); 934 } 935 936 /** 937 * If a11y touchExplorationEnabled, play haptic to signal UDFPS scanning started. 938 */ 939 @VisibleForTesting playStartHaptic()940 public void playStartHaptic() { 941 if (mAccessibilityManager.isTouchExplorationEnabled()) { 942 if (mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) { 943 if (mOverlay != null && mOverlay.getOverlayView() != null) { 944 mVibrator.performHapticFeedback( 945 mOverlay.getOverlayView(), 946 HapticFeedbackConstants.CONTEXT_CLICK 947 ); 948 } else { 949 Log.e(TAG, "No haptics played. Could not obtain overlay view to perform" 950 + "vibration. Either the controller overlay is null or has no view"); 951 } 952 } else { 953 mVibrator.vibrate( 954 Process.myUid(), 955 mContext.getOpPackageName(), 956 EFFECT_CLICK, 957 "udfps-onStart-click", 958 UDFPS_VIBRATION_ATTRIBUTES); 959 } 960 } 961 } 962 963 @Override dozeTimeTick()964 public void dozeTimeTick() { 965 if (mOverlay != null) { 966 final UdfpsView view = mOverlay.getOverlayView(); 967 if (view != null) { 968 view.dozeTimeTick(); 969 } 970 } 971 } 972 redrawOverlay()973 private void redrawOverlay() { 974 UdfpsControllerOverlay overlay = mOverlay; 975 if (overlay != null) { 976 hideUdfpsOverlay(); 977 showUdfpsOverlay(overlay); 978 } 979 } 980 showUdfpsOverlay(@onNull UdfpsControllerOverlay overlay)981 private void showUdfpsOverlay(@NonNull UdfpsControllerOverlay overlay) { 982 mExecution.assertIsMainThread(); 983 984 mOverlay = overlay; 985 final int requestReason = overlay.getRequestReason(); 986 if (requestReason == REASON_AUTH_KEYGUARD 987 && !mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) { 988 Log.d(TAG, "Attempting to showUdfpsOverlay when fingerprint detection" 989 + " isn't running on keyguard. Skip show."); 990 return; 991 } 992 if (overlay.show(this, mOverlayParams)) { 993 Log.v(TAG, "showUdfpsOverlay | adding window reason=" + requestReason); 994 mOnFingerDown = false; 995 mAttemptedToDismissKeyguard = false; 996 mOrientationListener.enable(); 997 if (mFingerprintManager != null) { 998 mFingerprintManager.onUdfpsUiEvent(FingerprintManager.UDFPS_UI_OVERLAY_SHOWN, 999 overlay.getRequestId(), mSensorProps.sensorId); 1000 } 1001 } else { 1002 Log.v(TAG, "showUdfpsOverlay | the overlay is already showing"); 1003 } 1004 } 1005 hideUdfpsOverlay()1006 private void hideUdfpsOverlay() { 1007 mExecution.assertIsMainThread(); 1008 1009 if (mOverlay != null) { 1010 // Reset the controller back to its starting state. 1011 final UdfpsView oldView = mOverlay.getOverlayView(); 1012 if (oldView != null) { 1013 onFingerUp(mOverlay.getRequestId(), oldView); 1014 } 1015 final boolean removed = mOverlay.hide(); 1016 mKeyguardViewManager.hideAlternateBouncer(true); 1017 Log.v(TAG, "hideUdfpsOverlay | removing window: " + removed); 1018 } else { 1019 Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden"); 1020 } 1021 1022 mOverlay = null; 1023 mOrientationListener.disable(); 1024 1025 } 1026 unconfigureDisplay(@onNull UdfpsView view)1027 private void unconfigureDisplay(@NonNull UdfpsView view) { 1028 if (view.isDisplayConfigured()) { 1029 view.unconfigureDisplay(); 1030 } 1031 } 1032 1033 /** 1034 * Request fingerprint scan. 1035 * 1036 * This is intended to be called in response to a sensor that triggers an AOD interrupt for the 1037 * fingerprint sensor. 1038 */ onAodInterrupt(int screenX, int screenY, float major, float minor)1039 void onAodInterrupt(int screenX, int screenY, float major, float minor) { 1040 if (mIsAodInterruptActive) { 1041 return; 1042 } 1043 1044 if (!mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) { 1045 if (mFalsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY)) { 1046 Log.v(TAG, "aod lock icon long-press rejected by the falsing manager."); 1047 return; 1048 } 1049 mKeyguardViewManager.showPrimaryBouncer(true); 1050 1051 // play the same haptic as the LockIconViewController longpress 1052 if (mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) { 1053 if (mOverlay != null && mOverlay.getOverlayView() != null) { 1054 mVibrator.performHapticFeedback( 1055 mOverlay.getOverlayView(), 1056 UdfpsController.LONG_PRESS 1057 ); 1058 } else { 1059 Log.e(TAG, "No haptics played. Could not obtain overlay view to perform" 1060 + "vibration. Either the controller overlay is null or has no view"); 1061 } 1062 } else { 1063 mVibrator.vibrate( 1064 Process.myUid(), 1065 mContext.getOpPackageName(), 1066 UdfpsController.EFFECT_CLICK, 1067 "aod-lock-icon-longpress", 1068 LOCK_ICON_VIBRATION_ATTRIBUTES); 1069 } 1070 return; 1071 } 1072 1073 // TODO(b/225068271): this may not be correct but there isn't a way to track it 1074 final long requestId = mOverlay != null ? mOverlay.getRequestId() : -1; 1075 mAodInterruptRunnable = () -> { 1076 mIsAodInterruptActive = true; 1077 // Since the sensor that triggers the AOD interrupt doesn't provide 1078 // ACTION_UP/ACTION_CANCEL, we need to be careful about not letting the screen 1079 // accidentally remain in high brightness mode. As a mitigation, queue a call to 1080 // cancel the fingerprint scan. 1081 mCancelAodFingerUpAction = mFgExecutor.executeDelayed(this::tryAodSendFingerUp, 1082 AOD_SEND_FINGER_UP_DELAY_MILLIS); 1083 // using a hard-coded value for major and minor until it is available from the sensor 1084 onFingerDown(requestId, screenX, screenY, minor, major); 1085 }; 1086 1087 if (mScreenOn) { 1088 mAodInterruptRunnable.run(); 1089 mAodInterruptRunnable = null; 1090 } 1091 } 1092 1093 /** 1094 * Add a callback for fingerUp and fingerDown events 1095 */ addCallback(Callback cb)1096 public void addCallback(Callback cb) { 1097 mCallbacks.add(cb); 1098 } 1099 1100 /** 1101 * Remove callback 1102 */ removeCallback(Callback cb)1103 public void removeCallback(Callback cb) { 1104 mCallbacks.remove(cb); 1105 } 1106 1107 /** 1108 * The sensor that triggers {@link #onAodInterrupt} doesn't emit ACTION_UP or ACTION_CANCEL 1109 * events, which means the fingerprint gesture created by the AOD interrupt needs to be 1110 * cancelled manually. 1111 * This should be called when authentication either succeeds or fails. Failing to cancel the 1112 * scan will leave the display in the UDFPS mode until the user lifts their finger. On optical 1113 * sensors, this can result in illumination persisting for longer than necessary. 1114 */ 1115 @VisibleForTesting tryAodSendFingerUp()1116 void tryAodSendFingerUp() { 1117 if (!mIsAodInterruptActive) { 1118 return; 1119 } 1120 cancelAodSendFingerUpAction(); 1121 if (mOverlay != null && mOverlay.getOverlayView() != null) { 1122 onFingerUp(mOverlay.getRequestId(), mOverlay.getOverlayView()); 1123 } 1124 } 1125 1126 /** 1127 * Cancels any scheduled AoD finger-up actions without triggered the finger-up action. Only 1128 * call this method if the finger-up event has been guaranteed to have already occurred. 1129 */ 1130 @VisibleForTesting cancelAodSendFingerUpAction()1131 void cancelAodSendFingerUpAction() { 1132 mIsAodInterruptActive = false; 1133 if (mCancelAodFingerUpAction != null) { 1134 mCancelAodFingerUpAction.run(); 1135 mCancelAodFingerUpAction = null; 1136 } 1137 } 1138 isOptical()1139 private boolean isOptical() { 1140 return mSensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL; 1141 } 1142 isFingerDown()1143 public boolean isFingerDown() { 1144 return mOnFingerDown; 1145 } 1146 dispatchOnUiReady(long requestId)1147 private void dispatchOnUiReady(long requestId) { 1148 if (mAlternateTouchProvider != null) { 1149 mBiometricExecutor.execute(() -> { 1150 mAlternateTouchProvider.onUiReady(); 1151 mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE); 1152 }); 1153 } else { 1154 mFingerprintManager.onUdfpsUiEvent(FingerprintManager.UDFPS_UI_READY, requestId, 1155 mSensorProps.sensorId); 1156 mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE); 1157 } 1158 } 1159 onFingerDown( long requestId, int x, int y, float minor, float major)1160 private void onFingerDown( 1161 long requestId, 1162 int x, 1163 int y, 1164 float minor, 1165 float major) { 1166 onFingerDown( 1167 requestId, 1168 MotionEvent.INVALID_POINTER_ID /* pointerId */, 1169 x, 1170 y, 1171 minor, 1172 major, 1173 0f /* orientation */, 1174 0L /* time */, 1175 0L /* gestureStart */, 1176 false /* isAod */); 1177 } 1178 onFingerDown( long requestId, int pointerId, float x, float y, float minor, float major, float orientation, long time, long gestureStart, boolean isAod)1179 private void onFingerDown( 1180 long requestId, 1181 int pointerId, 1182 float x, 1183 float y, 1184 float minor, 1185 float major, 1186 float orientation, 1187 long time, 1188 long gestureStart, 1189 boolean isAod) { 1190 mExecution.assertIsMainThread(); 1191 1192 if (mOverlay == null) { 1193 Log.w(TAG, "Null request in onFingerDown"); 1194 return; 1195 } 1196 if (!mOverlay.matchesRequestId(requestId)) { 1197 Log.w(TAG, "Mismatched fingerDown: " + requestId 1198 + " current: " + mOverlay.getRequestId()); 1199 return; 1200 } 1201 if (isOptical()) { 1202 mLatencyTracker.onActionStart(LatencyTracker.ACTION_UDFPS_ILLUMINATE); 1203 } 1204 // Refresh screen timeout and boost process priority if possible. 1205 mPowerManager.userActivity(mSystemClock.uptimeMillis(), 1206 PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0); 1207 1208 if (!mOnFingerDown) { 1209 playStartHaptic(); 1210 1211 mKeyguardFaceAuthInteractor.onUdfpsSensorTouched(); 1212 if (!mKeyguardUpdateMonitor.isFaceDetectionRunning()) { 1213 mKeyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.UDFPS_POINTER_DOWN); 1214 } 1215 } 1216 mOnFingerDown = true; 1217 if (mAlternateTouchProvider != null) { 1218 mBiometricExecutor.execute(() -> { 1219 mAlternateTouchProvider.onPointerDown(requestId, (int) x, (int) y, minor, major); 1220 }); 1221 mFgExecutor.execute(() -> { 1222 if (mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) { 1223 mKeyguardUpdateMonitor.onUdfpsPointerDown((int) requestId); 1224 } 1225 }); 1226 } else { 1227 if (mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) { 1228 mFingerprintManager.onPointerDown(requestId, mSensorProps.sensorId, pointerId, x, y, 1229 minor, major, orientation, time, gestureStart, isAod); 1230 } else { 1231 mFingerprintManager.onPointerDown(requestId, mSensorProps.sensorId, (int) x, 1232 (int) y, minor, major); 1233 } 1234 } 1235 Trace.endAsyncSection("UdfpsController.e2e.onPointerDown", 0); 1236 final UdfpsView view = mOverlay.getOverlayView(); 1237 if (view != null && isOptical()) { 1238 if (mIgnoreRefreshRate) { 1239 dispatchOnUiReady(requestId); 1240 } else { 1241 view.configureDisplay(() -> dispatchOnUiReady(requestId)); 1242 } 1243 } 1244 1245 for (Callback cb : mCallbacks) { 1246 cb.onFingerDown(); 1247 } 1248 } 1249 onFingerUp(long requestId, @NonNull UdfpsView view)1250 private void onFingerUp(long requestId, @NonNull UdfpsView view) { 1251 onFingerUp( 1252 requestId, 1253 view, 1254 MotionEvent.INVALID_POINTER_ID /* pointerId */, 1255 0f /* x */, 1256 0f /* y */, 1257 0f /* minor */, 1258 0f /* major */, 1259 0f /* orientation */, 1260 0L /* time */, 1261 0L /* gestureStart */, 1262 false /* isAod */); 1263 } 1264 onFingerUp( long requestId, @NonNull UdfpsView view, int pointerId, float x, float y, float minor, float major, float orientation, long time, long gestureStart, boolean isAod)1265 private void onFingerUp( 1266 long requestId, 1267 @NonNull UdfpsView view, 1268 int pointerId, 1269 float x, 1270 float y, 1271 float minor, 1272 float major, 1273 float orientation, 1274 long time, 1275 long gestureStart, 1276 boolean isAod) { 1277 mExecution.assertIsMainThread(); 1278 mActivePointerId = -1; 1279 mAcquiredReceived = false; 1280 if (mOnFingerDown) { 1281 if (mAlternateTouchProvider != null) { 1282 mBiometricExecutor.execute(() -> { 1283 mAlternateTouchProvider.onPointerUp(requestId); 1284 }); 1285 mFgExecutor.execute(() -> { 1286 if (mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) { 1287 mKeyguardUpdateMonitor.onUdfpsPointerUp((int) requestId); 1288 } 1289 }); 1290 } else { 1291 if (mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) { 1292 mFingerprintManager.onPointerUp(requestId, mSensorProps.sensorId, pointerId, x, 1293 y, minor, major, orientation, time, gestureStart, isAod); 1294 } else { 1295 mFingerprintManager.onPointerUp(requestId, mSensorProps.sensorId); 1296 } 1297 } 1298 for (Callback cb : mCallbacks) { 1299 cb.onFingerUp(); 1300 } 1301 } 1302 mOnFingerDown = false; 1303 if (isOptical()) { 1304 unconfigureDisplay(view); 1305 } 1306 cancelAodSendFingerUpAction(); 1307 } 1308 1309 /** 1310 * Callback for fingerUp and fingerDown events. 1311 */ 1312 public interface Callback { 1313 /** 1314 * Called onFingerUp events. Will only be called if the finger was previously down. 1315 */ onFingerUp()1316 void onFingerUp(); 1317 1318 /** 1319 * Called onFingerDown events. 1320 */ onFingerDown()1321 void onFingerDown(); 1322 } 1323 } 1324