• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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