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 // Wait to receive up or cancel before pausing auth 557 if (mActivePointerId == MotionEvent.INVALID_POINTER_ID 558 && mOverlay.getAnimationViewController().shouldPauseAuth()) { 559 Log.w(TAG, "ignoring onTouch with shouldPauseAuth = true"); 560 return false; 561 } 562 if (!mOverlay.matchesRequestId(requestId)) { 563 Log.w(TAG, "ignoring stale touch event: " + requestId + " current: " 564 + mOverlay.getRequestId()); 565 return false; 566 } 567 if (event.getAction() == MotionEvent.ACTION_DOWN 568 || event.getAction() == MotionEvent.ACTION_HOVER_ENTER) { 569 // Reset on ACTION_DOWN, start of new gesture 570 mPointerPilfered = false; 571 } 572 573 final TouchProcessorResult result = mTouchProcessor.processTouch(event, mActivePointerId, 574 mOverlayParams); 575 if (result instanceof TouchProcessorResult.Failure) { 576 Log.w(TAG, ((TouchProcessorResult.Failure) result).getReason()); 577 return false; 578 } 579 580 final TouchProcessorResult.ProcessedTouch processedTouch = 581 (TouchProcessorResult.ProcessedTouch) result; 582 final NormalizedTouchData data = processedTouch.getTouchData(); 583 584 boolean shouldPilfer = false; 585 mActivePointerId = processedTouch.getPointerOnSensorId(); 586 switch (processedTouch.getEvent()) { 587 case DOWN: 588 if (shouldTryToDismissKeyguard()) { 589 tryDismissingKeyguard(); 590 } 591 if (!mOnFingerDown) { 592 onFingerDown(requestId, 593 data.getPointerId(), 594 data.getX(), 595 data.getY(), 596 data.getMinor(), 597 data.getMajor(), 598 data.getOrientation(), 599 data.getTime(), 600 data.getGestureStart(), 601 mStatusBarStateController.isDozing()); 602 } 603 604 // Pilfer if valid overlap, don't allow following events to reach keyguard 605 shouldPilfer = true; 606 607 // Touch is a valid UDFPS touch. Inform the falsing manager so that the touch 608 // isn't counted against the falsing algorithm as an accidental touch. 609 // We do this on the DOWN event instead of CANCEL/UP because the CANCEL/UP events 610 // get sent too late to this receiver (after the actual cancel/up motions occur), 611 // and therefore wouldn't end up being used as part of the falsing algo. 612 mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION); 613 break; 614 615 case UP: 616 case CANCEL: 617 if (InteractionEvent.CANCEL.equals(processedTouch.getEvent())) { 618 Log.w(TAG, "This is a CANCEL event that's reported as an UP event!"); 619 } 620 mAttemptedToDismissKeyguard = false; 621 onFingerUp(requestId, 622 mOverlay.getOverlayView(), 623 data.getPointerId(), 624 data.getX(), 625 data.getY(), 626 data.getMinor(), 627 data.getMajor(), 628 data.getOrientation(), 629 data.getTime(), 630 data.getGestureStart(), 631 mStatusBarStateController.isDozing()); 632 break; 633 634 case UNCHANGED: 635 if (!isWithinSensorArea(mOverlay.getOverlayView(), event.getRawX(), event.getRawY(), 636 true) && mActivePointerId == MotionEvent.INVALID_POINTER_ID 637 && mAlternateBouncerInteractor.isVisibleState()) { 638 // No pointer on sensor, forward to keyguard if alternateBouncer is visible 639 mKeyguardViewManager.onTouch(event); 640 } 641 642 default: 643 break; 644 } 645 logBiometricTouch(processedTouch.getEvent(), data); 646 647 // Always pilfer pointers that are within sensor area or when alternate bouncer is showing 648 if (isWithinSensorArea(mOverlay.getOverlayView(), event.getRawX(), event.getRawY(), true) 649 || mAlternateBouncerInteractor.isVisibleState()) { 650 shouldPilfer = true; 651 } 652 653 // Pilfer only once per gesture, don't pilfer for BP 654 if (shouldPilfer && !mPointerPilfered 655 && getBiometricSessionType() != SESSION_BIOMETRIC_PROMPT) { 656 mInputManager.pilferPointers( 657 mOverlay.getOverlayView().getViewRootImpl().getInputToken()); 658 mPointerPilfered = true; 659 } 660 661 return processedTouch.getTouchData().isWithinBounds(mOverlayParams.getNativeSensorBounds()); 662 } 663 oldOnTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView)664 private boolean oldOnTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) { 665 if (mOverlay == null) { 666 Log.w(TAG, "ignoring onTouch with null overlay"); 667 return false; 668 } 669 if (!mOverlay.matchesRequestId(requestId)) { 670 Log.w(TAG, "ignoring stale touch event: " + requestId + " current: " 671 + mOverlay.getRequestId()); 672 return false; 673 } 674 675 final UdfpsView udfpsView = mOverlay.getOverlayView(); 676 boolean handled = false; 677 switch (event.getActionMasked()) { 678 case MotionEvent.ACTION_DOWN: 679 case MotionEvent.ACTION_HOVER_ENTER: 680 Trace.beginSection("UdfpsController.onTouch.ACTION_DOWN"); 681 // To simplify the lifecycle of the velocity tracker, make sure it's never null 682 // after ACTION_DOWN, and always null after ACTION_CANCEL or ACTION_UP. 683 if (mVelocityTracker == null) { 684 mVelocityTracker = VelocityTracker.obtain(); 685 } else { 686 // ACTION_UP or ACTION_CANCEL is not guaranteed to be called before a new 687 // ACTION_DOWN, in that case we should just reuse the old instance. 688 mVelocityTracker.clear(); 689 } 690 691 final boolean withinSensorArea = 692 isWithinSensorArea(udfpsView, event.getX(), event.getY(), fromUdfpsView); 693 if (withinSensorArea) { 694 Trace.beginAsyncSection("UdfpsController.e2e.onPointerDown", 0); 695 Log.v(TAG, "onTouch | action down"); 696 // The pointer that causes ACTION_DOWN is always at index 0. 697 // We need to persist its ID to track it during ACTION_MOVE that could include 698 // data for many other pointers because of multi-touch support. 699 mActivePointerId = event.getPointerId(0); 700 mVelocityTracker.addMovement(event); 701 handled = true; 702 mAcquiredReceived = false; 703 } 704 if ((withinSensorArea || fromUdfpsView) && shouldTryToDismissKeyguard()) { 705 Log.v(TAG, "onTouch | dismiss keyguard ACTION_DOWN"); 706 tryDismissingKeyguard(); 707 } 708 709 Trace.endSection(); 710 break; 711 712 case MotionEvent.ACTION_MOVE: 713 case MotionEvent.ACTION_HOVER_MOVE: 714 Trace.beginSection("UdfpsController.onTouch.ACTION_MOVE"); 715 final int idx = mActivePointerId == -1 716 ? event.getPointerId(0) 717 : event.findPointerIndex(mActivePointerId); 718 if (idx == event.getActionIndex()) { 719 final boolean actionMoveWithinSensorArea = 720 isWithinSensorArea(udfpsView, event.getX(idx), event.getY(idx), 721 fromUdfpsView); 722 if ((fromUdfpsView || actionMoveWithinSensorArea) 723 && shouldTryToDismissKeyguard()) { 724 Log.v(TAG, "onTouch | dismiss keyguard ACTION_MOVE"); 725 tryDismissingKeyguard(); 726 break; 727 } 728 // Map the touch to portrait mode if the device is in landscape mode. 729 final Point scaledTouch = mUdfpsUtils.getTouchInNativeCoordinates( 730 idx, event, mOverlayParams); 731 if (actionMoveWithinSensorArea) { 732 if (mVelocityTracker == null) { 733 // touches could be injected, so the velocity tracker may not have 734 // been initialized (via ACTION_DOWN). 735 mVelocityTracker = VelocityTracker.obtain(); 736 } 737 mVelocityTracker.addMovement(event); 738 // Compute pointer velocity in pixels per second. 739 mVelocityTracker.computeCurrentVelocity(1000); 740 // Compute pointer speed from X and Y velocities. 741 final float v = computePointerSpeed(mVelocityTracker, mActivePointerId); 742 final float minor = event.getTouchMinor(idx); 743 final float major = event.getTouchMajor(idx); 744 final boolean exceedsVelocityThreshold = exceedsVelocityThreshold(v); 745 final String touchInfo = String.format( 746 "minor: %.1f, major: %.1f, v: %.1f, exceedsVelocityThreshold: %b", 747 minor, major, v, exceedsVelocityThreshold); 748 final long sinceLastLog = mSystemClock.elapsedRealtime() - mTouchLogTime; 749 750 if (!mOnFingerDown && !mAcquiredReceived && !exceedsVelocityThreshold) { 751 final float scale = mOverlayParams.getScaleFactor(); 752 float scaledMinor = minor / scale; 753 float scaledMajor = major / scale; 754 onFingerDown(requestId, scaledTouch.x, scaledTouch.y, scaledMinor, 755 scaledMajor); 756 757 Log.v(TAG, "onTouch | finger down: " + touchInfo); 758 mTouchLogTime = mSystemClock.elapsedRealtime(); 759 handled = true; 760 } else if (sinceLastLog >= MIN_TOUCH_LOG_INTERVAL) { 761 Log.v(TAG, "onTouch | finger move: " + touchInfo); 762 mTouchLogTime = mSystemClock.elapsedRealtime(); 763 } 764 } else { 765 Log.v(TAG, "onTouch | finger outside"); 766 onFingerUp(requestId, udfpsView); 767 // Maybe announce for accessibility. 768 mFgExecutor.execute(() -> { 769 if (mOverlay == null) { 770 Log.e(TAG, "touch outside sensor area received" 771 + "but serverRequest is null"); 772 return; 773 } 774 mOverlay.onTouchOutsideOfSensorArea(scaledTouch); 775 }); 776 } 777 } 778 Trace.endSection(); 779 break; 780 781 case MotionEvent.ACTION_UP: 782 case MotionEvent.ACTION_CANCEL: 783 case MotionEvent.ACTION_HOVER_EXIT: 784 Trace.beginSection("UdfpsController.onTouch.ACTION_UP"); 785 mActivePointerId = -1; 786 if (mVelocityTracker != null) { 787 mVelocityTracker.recycle(); 788 mVelocityTracker = null; 789 } 790 Log.v(TAG, "onTouch | finger up"); 791 mAttemptedToDismissKeyguard = false; 792 onFingerUp(requestId, udfpsView); 793 mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION); 794 Trace.endSection(); 795 break; 796 797 default: 798 // Do nothing. 799 } 800 return handled; 801 } 802 shouldTryToDismissKeyguard()803 private boolean shouldTryToDismissKeyguard() { 804 return mOverlay != null 805 && mOverlay.getAnimationViewController() 806 instanceof UdfpsKeyguardViewControllerAdapter 807 && mKeyguardStateController.canDismissLockScreen() 808 && !mAttemptedToDismissKeyguard; 809 } 810 811 @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)812 public UdfpsController(@NonNull Context context, 813 @NonNull Execution execution, 814 @NonNull LayoutInflater inflater, 815 @Nullable FingerprintManager fingerprintManager, 816 @NonNull WindowManager windowManager, 817 @NonNull StatusBarStateController statusBarStateController, 818 @Main DelayableExecutor fgExecutor, 819 @NonNull ShadeExpansionStateManager shadeExpansionStateManager, 820 @NonNull StatusBarKeyguardViewManager statusBarKeyguardViewManager, 821 @NonNull DumpManager dumpManager, 822 @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor, 823 @NonNull FeatureFlags featureFlags, 824 @NonNull FalsingManager falsingManager, 825 @NonNull PowerManager powerManager, 826 @NonNull AccessibilityManager accessibilityManager, 827 @NonNull LockscreenShadeTransitionController lockscreenShadeTransitionController, 828 @NonNull ScreenLifecycle screenLifecycle, 829 @NonNull VibratorHelper vibrator, 830 @NonNull UdfpsHapticsSimulator udfpsHapticsSimulator, 831 @NonNull UdfpsShell udfpsShell, 832 @NonNull KeyguardStateController keyguardStateController, 833 @NonNull DisplayManager displayManager, 834 @Main Handler mainHandler, 835 @NonNull ConfigurationController configurationController, 836 @NonNull SystemClock systemClock, 837 @NonNull UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, 838 @NonNull SystemUIDialogManager dialogManager, 839 @NonNull LatencyTracker latencyTracker, 840 @NonNull ActivityLaunchAnimator activityLaunchAnimator, 841 @NonNull Optional<Provider<AlternateUdfpsTouchProvider>> alternateTouchProvider, 842 @NonNull @BiometricsBackground Executor biometricsExecutor, 843 @NonNull PrimaryBouncerInteractor primaryBouncerInteractor, 844 @NonNull SinglePointerTouchProcessor singlePointerTouchProcessor, 845 @NonNull SessionTracker sessionTracker, 846 @NonNull AlternateBouncerInteractor alternateBouncerInteractor, 847 @NonNull SecureSettings secureSettings, 848 @NonNull InputManager inputManager, 849 @NonNull UdfpsUtils udfpsUtils, 850 @NonNull KeyguardFaceAuthInteractor keyguardFaceAuthInteractor, 851 @NonNull UdfpsKeyguardAccessibilityDelegate udfpsKeyguardAccessibilityDelegate, 852 @NonNull Provider<UdfpsKeyguardViewModels> udfpsKeyguardViewModelsProvider) { 853 mContext = context; 854 mExecution = execution; 855 mVibrator = vibrator; 856 mInflater = inflater; 857 mIgnoreRefreshRate = mContext.getResources() 858 .getBoolean(R.bool.config_ignoreUdfpsVote); 859 // The fingerprint manager is queried for UDFPS before this class is constructed, so the 860 // fingerprint manager should never be null. 861 mFingerprintManager = checkNotNull(fingerprintManager); 862 mWindowManager = windowManager; 863 mFgExecutor = fgExecutor; 864 mShadeExpansionStateManager = shadeExpansionStateManager; 865 mStatusBarStateController = statusBarStateController; 866 mKeyguardStateController = keyguardStateController; 867 mKeyguardViewManager = statusBarKeyguardViewManager; 868 mDumpManager = dumpManager; 869 mDialogManager = dialogManager; 870 mKeyguardUpdateMonitor = keyguardUpdateMonitor; 871 mFeatureFlags = featureFlags; 872 mFalsingManager = falsingManager; 873 mPowerManager = powerManager; 874 mAccessibilityManager = accessibilityManager; 875 mLockscreenShadeTransitionController = lockscreenShadeTransitionController; 876 screenLifecycle.addObserver(mScreenObserver); 877 mScreenOn = screenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_ON; 878 mConfigurationController = configurationController; 879 mSystemClock = systemClock; 880 mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController; 881 mLatencyTracker = latencyTracker; 882 mActivityLaunchAnimator = activityLaunchAnimator; 883 mAlternateTouchProvider = alternateTouchProvider.map(Provider::get).orElse(null); 884 mSensorProps = new FingerprintSensorPropertiesInternal( 885 -1 /* sensorId */, 886 SensorProperties.STRENGTH_CONVENIENCE, 887 0 /* maxEnrollmentsPerUser */, 888 new ArrayList<>() /* componentInfo */, 889 FingerprintSensorProperties.TYPE_UNKNOWN, 890 false /* resetLockoutRequiresHardwareAuthToken */); 891 892 mBiometricExecutor = biometricsExecutor; 893 mPrimaryBouncerInteractor = primaryBouncerInteractor; 894 mAlternateBouncerInteractor = alternateBouncerInteractor; 895 mSecureSettings = secureSettings; 896 mUdfpsUtils = udfpsUtils; 897 mInputManager = inputManager; 898 mUdfpsKeyguardAccessibilityDelegate = udfpsKeyguardAccessibilityDelegate; 899 900 mTouchProcessor = mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION) 901 ? singlePointerTouchProcessor : null; 902 mSessionTracker = sessionTracker; 903 904 mDumpManager.registerDumpable(TAG, this); 905 906 mOrientationListener = new BiometricDisplayListener( 907 context, 908 displayManager, 909 mainHandler, 910 BiometricDisplayListener.SensorType.UnderDisplayFingerprint.INSTANCE, 911 () -> { 912 if (mAuthControllerUpdateUdfpsLocation != null) { 913 mAuthControllerUpdateUdfpsLocation.run(); 914 } 915 return Unit.INSTANCE; 916 }); 917 mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor; 918 mUdfpsKeyguardViewModels = udfpsKeyguardViewModelsProvider; 919 920 final UdfpsOverlayController mUdfpsOverlayController = new UdfpsOverlayController(); 921 mFingerprintManager.setUdfpsOverlayController(mUdfpsOverlayController); 922 923 final IntentFilter filter = new IntentFilter(); 924 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); 925 context.registerReceiver(mBroadcastReceiver, filter, 926 Context.RECEIVER_EXPORTED_UNAUDITED); 927 928 udfpsHapticsSimulator.setUdfpsController(this); 929 udfpsShell.setUdfpsOverlayController(mUdfpsOverlayController); 930 } 931 932 /** 933 * If a11y touchExplorationEnabled, play haptic to signal UDFPS scanning started. 934 */ 935 @VisibleForTesting playStartHaptic()936 public void playStartHaptic() { 937 if (mAccessibilityManager.isTouchExplorationEnabled()) { 938 if (mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) { 939 if (mOverlay != null && mOverlay.getOverlayView() != null) { 940 mVibrator.performHapticFeedback( 941 mOverlay.getOverlayView(), 942 HapticFeedbackConstants.CONTEXT_CLICK 943 ); 944 } else { 945 Log.e(TAG, "No haptics played. Could not obtain overlay view to perform" 946 + "vibration. Either the controller overlay is null or has no view"); 947 } 948 } else { 949 mVibrator.vibrate( 950 Process.myUid(), 951 mContext.getOpPackageName(), 952 EFFECT_CLICK, 953 "udfps-onStart-click", 954 UDFPS_VIBRATION_ATTRIBUTES); 955 } 956 } 957 } 958 959 @Override dozeTimeTick()960 public void dozeTimeTick() { 961 if (mOverlay != null) { 962 final UdfpsView view = mOverlay.getOverlayView(); 963 if (view != null) { 964 view.dozeTimeTick(); 965 } 966 } 967 } 968 redrawOverlay()969 private void redrawOverlay() { 970 UdfpsControllerOverlay overlay = mOverlay; 971 if (overlay != null) { 972 hideUdfpsOverlay(); 973 showUdfpsOverlay(overlay); 974 } 975 } 976 showUdfpsOverlay(@onNull UdfpsControllerOverlay overlay)977 private void showUdfpsOverlay(@NonNull UdfpsControllerOverlay overlay) { 978 mExecution.assertIsMainThread(); 979 980 mOverlay = overlay; 981 final int requestReason = overlay.getRequestReason(); 982 if (requestReason == REASON_AUTH_KEYGUARD 983 && !mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) { 984 Log.d(TAG, "Attempting to showUdfpsOverlay when fingerprint detection" 985 + " isn't running on keyguard. Skip show."); 986 return; 987 } 988 if (overlay.show(this, mOverlayParams)) { 989 Log.v(TAG, "showUdfpsOverlay | adding window reason=" + requestReason); 990 mOnFingerDown = false; 991 mAttemptedToDismissKeyguard = false; 992 mOrientationListener.enable(); 993 if (mFingerprintManager != null) { 994 mFingerprintManager.onUdfpsUiEvent(FingerprintManager.UDFPS_UI_OVERLAY_SHOWN, 995 overlay.getRequestId(), mSensorProps.sensorId); 996 } 997 } else { 998 Log.v(TAG, "showUdfpsOverlay | the overlay is already showing"); 999 } 1000 } 1001 hideUdfpsOverlay()1002 private void hideUdfpsOverlay() { 1003 mExecution.assertIsMainThread(); 1004 1005 if (mOverlay != null) { 1006 // Reset the controller back to its starting state. 1007 final UdfpsView oldView = mOverlay.getOverlayView(); 1008 if (oldView != null) { 1009 onFingerUp(mOverlay.getRequestId(), oldView); 1010 } 1011 final boolean removed = mOverlay.hide(); 1012 mKeyguardViewManager.hideAlternateBouncer(true); 1013 Log.v(TAG, "hideUdfpsOverlay | removing window: " + removed); 1014 } else { 1015 Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden"); 1016 } 1017 1018 mOverlay = null; 1019 mOrientationListener.disable(); 1020 1021 } 1022 unconfigureDisplay(@onNull UdfpsView view)1023 private void unconfigureDisplay(@NonNull UdfpsView view) { 1024 if (view.isDisplayConfigured()) { 1025 view.unconfigureDisplay(); 1026 } 1027 } 1028 1029 /** 1030 * Request fingerprint scan. 1031 * 1032 * This is intended to be called in response to a sensor that triggers an AOD interrupt for the 1033 * fingerprint sensor. 1034 */ onAodInterrupt(int screenX, int screenY, float major, float minor)1035 void onAodInterrupt(int screenX, int screenY, float major, float minor) { 1036 if (mIsAodInterruptActive) { 1037 return; 1038 } 1039 1040 if (!mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) { 1041 if (mFalsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY)) { 1042 Log.v(TAG, "aod lock icon long-press rejected by the falsing manager."); 1043 return; 1044 } 1045 mKeyguardViewManager.showPrimaryBouncer(true); 1046 1047 // play the same haptic as the LockIconViewController longpress 1048 if (mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) { 1049 if (mOverlay != null && mOverlay.getOverlayView() != null) { 1050 mVibrator.performHapticFeedback( 1051 mOverlay.getOverlayView(), 1052 UdfpsController.LONG_PRESS 1053 ); 1054 } else { 1055 Log.e(TAG, "No haptics played. Could not obtain overlay view to perform" 1056 + "vibration. Either the controller overlay is null or has no view"); 1057 } 1058 } else { 1059 mVibrator.vibrate( 1060 Process.myUid(), 1061 mContext.getOpPackageName(), 1062 UdfpsController.EFFECT_CLICK, 1063 "aod-lock-icon-longpress", 1064 LOCK_ICON_VIBRATION_ATTRIBUTES); 1065 } 1066 return; 1067 } 1068 1069 // TODO(b/225068271): this may not be correct but there isn't a way to track it 1070 final long requestId = mOverlay != null ? mOverlay.getRequestId() : -1; 1071 mAodInterruptRunnable = () -> { 1072 mIsAodInterruptActive = true; 1073 // Since the sensor that triggers the AOD interrupt doesn't provide 1074 // ACTION_UP/ACTION_CANCEL, we need to be careful about not letting the screen 1075 // accidentally remain in high brightness mode. As a mitigation, queue a call to 1076 // cancel the fingerprint scan. 1077 mCancelAodFingerUpAction = mFgExecutor.executeDelayed(this::tryAodSendFingerUp, 1078 AOD_SEND_FINGER_UP_DELAY_MILLIS); 1079 // using a hard-coded value for major and minor until it is available from the sensor 1080 onFingerDown(requestId, screenX, screenY, minor, major); 1081 }; 1082 1083 if (mScreenOn) { 1084 mAodInterruptRunnable.run(); 1085 mAodInterruptRunnable = null; 1086 } 1087 } 1088 1089 /** 1090 * Add a callback for fingerUp and fingerDown events 1091 */ addCallback(Callback cb)1092 public void addCallback(Callback cb) { 1093 mCallbacks.add(cb); 1094 } 1095 1096 /** 1097 * Remove callback 1098 */ removeCallback(Callback cb)1099 public void removeCallback(Callback cb) { 1100 mCallbacks.remove(cb); 1101 } 1102 1103 /** 1104 * The sensor that triggers {@link #onAodInterrupt} doesn't emit ACTION_UP or ACTION_CANCEL 1105 * events, which means the fingerprint gesture created by the AOD interrupt needs to be 1106 * cancelled manually. 1107 * This should be called when authentication either succeeds or fails. Failing to cancel the 1108 * scan will leave the display in the UDFPS mode until the user lifts their finger. On optical 1109 * sensors, this can result in illumination persisting for longer than necessary. 1110 */ 1111 @VisibleForTesting tryAodSendFingerUp()1112 void tryAodSendFingerUp() { 1113 if (!mIsAodInterruptActive) { 1114 return; 1115 } 1116 cancelAodSendFingerUpAction(); 1117 if (mOverlay != null && mOverlay.getOverlayView() != null) { 1118 onFingerUp(mOverlay.getRequestId(), mOverlay.getOverlayView()); 1119 } 1120 } 1121 1122 /** 1123 * Cancels any scheduled AoD finger-up actions without triggered the finger-up action. Only 1124 * call this method if the finger-up event has been guaranteed to have already occurred. 1125 */ 1126 @VisibleForTesting cancelAodSendFingerUpAction()1127 void cancelAodSendFingerUpAction() { 1128 mIsAodInterruptActive = false; 1129 if (mCancelAodFingerUpAction != null) { 1130 mCancelAodFingerUpAction.run(); 1131 mCancelAodFingerUpAction = null; 1132 } 1133 } 1134 isOptical()1135 private boolean isOptical() { 1136 return mSensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL; 1137 } 1138 isFingerDown()1139 public boolean isFingerDown() { 1140 return mOnFingerDown; 1141 } 1142 dispatchOnUiReady(long requestId)1143 private void dispatchOnUiReady(long requestId) { 1144 if (mAlternateTouchProvider != null) { 1145 mBiometricExecutor.execute(() -> { 1146 mAlternateTouchProvider.onUiReady(); 1147 mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE); 1148 }); 1149 } else { 1150 mFingerprintManager.onUdfpsUiEvent(FingerprintManager.UDFPS_UI_READY, requestId, 1151 mSensorProps.sensorId); 1152 mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE); 1153 } 1154 } 1155 onFingerDown( long requestId, int x, int y, float minor, float major)1156 private void onFingerDown( 1157 long requestId, 1158 int x, 1159 int y, 1160 float minor, 1161 float major) { 1162 onFingerDown( 1163 requestId, 1164 MotionEvent.INVALID_POINTER_ID /* pointerId */, 1165 x, 1166 y, 1167 minor, 1168 major, 1169 0f /* orientation */, 1170 0L /* time */, 1171 0L /* gestureStart */, 1172 false /* isAod */); 1173 } 1174 onFingerDown( long requestId, int pointerId, float x, float y, float minor, float major, float orientation, long time, long gestureStart, boolean isAod)1175 private void onFingerDown( 1176 long requestId, 1177 int pointerId, 1178 float x, 1179 float y, 1180 float minor, 1181 float major, 1182 float orientation, 1183 long time, 1184 long gestureStart, 1185 boolean isAod) { 1186 mExecution.assertIsMainThread(); 1187 1188 if (mOverlay == null) { 1189 Log.w(TAG, "Null request in onFingerDown"); 1190 return; 1191 } 1192 if (!mOverlay.matchesRequestId(requestId)) { 1193 Log.w(TAG, "Mismatched fingerDown: " + requestId 1194 + " current: " + mOverlay.getRequestId()); 1195 return; 1196 } 1197 if (isOptical()) { 1198 mLatencyTracker.onActionStart(LatencyTracker.ACTION_UDFPS_ILLUMINATE); 1199 } 1200 // Refresh screen timeout and boost process priority if possible. 1201 mPowerManager.userActivity(mSystemClock.uptimeMillis(), 1202 PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0); 1203 1204 if (!mOnFingerDown) { 1205 playStartHaptic(); 1206 1207 mKeyguardFaceAuthInteractor.onUdfpsSensorTouched(); 1208 if (!mKeyguardUpdateMonitor.isFaceDetectionRunning()) { 1209 mKeyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.UDFPS_POINTER_DOWN); 1210 } 1211 } 1212 mOnFingerDown = true; 1213 if (mAlternateTouchProvider != null) { 1214 mBiometricExecutor.execute(() -> { 1215 mAlternateTouchProvider.onPointerDown(requestId, (int) x, (int) y, minor, major); 1216 }); 1217 mFgExecutor.execute(() -> { 1218 if (mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) { 1219 mKeyguardUpdateMonitor.onUdfpsPointerDown((int) requestId); 1220 } 1221 }); 1222 } else { 1223 if (mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) { 1224 mFingerprintManager.onPointerDown(requestId, mSensorProps.sensorId, pointerId, x, y, 1225 minor, major, orientation, time, gestureStart, isAod); 1226 } else { 1227 mFingerprintManager.onPointerDown(requestId, mSensorProps.sensorId, (int) x, 1228 (int) y, minor, major); 1229 } 1230 } 1231 Trace.endAsyncSection("UdfpsController.e2e.onPointerDown", 0); 1232 final UdfpsView view = mOverlay.getOverlayView(); 1233 if (view != null && isOptical()) { 1234 if (mIgnoreRefreshRate) { 1235 dispatchOnUiReady(requestId); 1236 } else { 1237 view.configureDisplay(() -> dispatchOnUiReady(requestId)); 1238 } 1239 } 1240 1241 for (Callback cb : mCallbacks) { 1242 cb.onFingerDown(); 1243 } 1244 } 1245 onFingerUp(long requestId, @NonNull UdfpsView view)1246 private void onFingerUp(long requestId, @NonNull UdfpsView view) { 1247 onFingerUp( 1248 requestId, 1249 view, 1250 MotionEvent.INVALID_POINTER_ID /* pointerId */, 1251 0f /* x */, 1252 0f /* y */, 1253 0f /* minor */, 1254 0f /* major */, 1255 0f /* orientation */, 1256 0L /* time */, 1257 0L /* gestureStart */, 1258 false /* isAod */); 1259 } 1260 onFingerUp( long requestId, @NonNull UdfpsView view, int pointerId, float x, float y, float minor, float major, float orientation, long time, long gestureStart, boolean isAod)1261 private void onFingerUp( 1262 long requestId, 1263 @NonNull UdfpsView view, 1264 int pointerId, 1265 float x, 1266 float y, 1267 float minor, 1268 float major, 1269 float orientation, 1270 long time, 1271 long gestureStart, 1272 boolean isAod) { 1273 mExecution.assertIsMainThread(); 1274 mActivePointerId = -1; 1275 mAcquiredReceived = false; 1276 if (mOnFingerDown) { 1277 if (mAlternateTouchProvider != null) { 1278 mBiometricExecutor.execute(() -> { 1279 mAlternateTouchProvider.onPointerUp(requestId); 1280 }); 1281 mFgExecutor.execute(() -> { 1282 if (mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) { 1283 mKeyguardUpdateMonitor.onUdfpsPointerUp((int) requestId); 1284 } 1285 }); 1286 } else { 1287 if (mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) { 1288 mFingerprintManager.onPointerUp(requestId, mSensorProps.sensorId, pointerId, x, 1289 y, minor, major, orientation, time, gestureStart, isAod); 1290 } else { 1291 mFingerprintManager.onPointerUp(requestId, mSensorProps.sensorId); 1292 } 1293 } 1294 for (Callback cb : mCallbacks) { 1295 cb.onFingerUp(); 1296 } 1297 } 1298 mOnFingerDown = false; 1299 if (isOptical()) { 1300 unconfigureDisplay(view); 1301 } 1302 cancelAodSendFingerUpAction(); 1303 } 1304 1305 /** 1306 * Callback for fingerUp and fingerDown events. 1307 */ 1308 public interface Callback { 1309 /** 1310 * Called onFingerUp events. Will only be called if the finger was previously down. 1311 */ onFingerUp()1312 void onFingerUp(); 1313 1314 /** 1315 * Called onFingerDown events. 1316 */ onFingerDown()1317 void onFingerDown(); 1318 } 1319 } 1320