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