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