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.view.MotionEvent.ACTION_DOWN;
21 import static android.view.MotionEvent.ACTION_MOVE;
22 import static android.view.MotionEvent.ACTION_UP;
23 
24 import static com.android.internal.util.FunctionalUtils.ThrowingConsumer;
25 import static com.android.systemui.classifier.Classifier.UDFPS_AUTHENTICATION;
26 import static com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION;
27 
28 import static junit.framework.Assert.assertEquals;
29 import static junit.framework.Assert.assertFalse;
30 import static junit.framework.Assert.assertTrue;
31 
32 import static org.mockito.ArgumentMatchers.any;
33 import static org.mockito.ArgumentMatchers.anyBoolean;
34 import static org.mockito.ArgumentMatchers.anyFloat;
35 import static org.mockito.ArgumentMatchers.anyInt;
36 import static org.mockito.ArgumentMatchers.anyLong;
37 import static org.mockito.ArgumentMatchers.anyString;
38 import static org.mockito.ArgumentMatchers.eq;
39 import static org.mockito.Mockito.inOrder;
40 import static org.mockito.Mockito.mock;
41 import static org.mockito.Mockito.never;
42 import static org.mockito.Mockito.reset;
43 import static org.mockito.Mockito.times;
44 import static org.mockito.Mockito.verify;
45 import static org.mockito.Mockito.when;
46 
47 import android.graphics.Rect;
48 import android.hardware.biometrics.BiometricFingerprintConstants;
49 import android.hardware.biometrics.BiometricOverlayConstants;
50 import android.hardware.biometrics.ComponentInfoInternal;
51 import android.hardware.biometrics.SensorProperties;
52 import android.hardware.display.DisplayManager;
53 import android.hardware.fingerprint.FingerprintManager;
54 import android.hardware.fingerprint.FingerprintSensorProperties;
55 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
56 import android.hardware.fingerprint.IUdfpsOverlayController;
57 import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
58 import android.hardware.input.InputManager;
59 import android.os.Handler;
60 import android.os.PowerManager;
61 import android.os.RemoteException;
62 import android.os.VibrationAttributes;
63 import android.testing.TestableLooper.RunWithLooper;
64 import android.util.Pair;
65 import android.view.HapticFeedbackConstants;
66 import android.view.LayoutInflater;
67 import android.view.MotionEvent;
68 import android.view.Surface;
69 import android.view.View;
70 import android.view.ViewRootImpl;
71 import android.view.WindowManager;
72 import android.view.accessibility.AccessibilityManager;
73 
74 import androidx.test.ext.junit.runners.AndroidJUnit4;
75 import androidx.test.filters.SmallTest;
76 
77 import com.android.internal.logging.InstanceIdSequence;
78 import com.android.internal.util.LatencyTracker;
79 import com.android.keyguard.KeyguardUpdateMonitor;
80 import com.android.settingslib.udfps.UdfpsOverlayParams;
81 import com.android.settingslib.udfps.UdfpsUtils;
82 import com.android.systemui.R;
83 import com.android.systemui.RoboPilotTest;
84 import com.android.systemui.SysuiTestCase;
85 import com.android.systemui.animation.ActivityLaunchAnimator;
86 import com.android.systemui.biometrics.udfps.InteractionEvent;
87 import com.android.systemui.biometrics.udfps.NormalizedTouchData;
88 import com.android.systemui.biometrics.udfps.SinglePointerTouchProcessor;
89 import com.android.systemui.biometrics.udfps.TouchProcessorResult;
90 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
91 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
92 import com.android.systemui.dump.DumpManager;
93 import com.android.systemui.flags.FeatureFlags;
94 import com.android.systemui.flags.Flags;
95 import com.android.systemui.keyguard.ScreenLifecycle;
96 import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
97 import com.android.systemui.keyguard.ui.viewmodel.UdfpsKeyguardViewModels;
98 import com.android.systemui.log.SessionTracker;
99 import com.android.systemui.plugins.FalsingManager;
100 import com.android.systemui.plugins.statusbar.StatusBarStateController;
101 import com.android.systemui.shade.ShadeExpansionStateManager;
102 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
103 import com.android.systemui.statusbar.VibratorHelper;
104 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
105 import com.android.systemui.statusbar.phone.SystemUIDialogManager;
106 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
107 import com.android.systemui.statusbar.policy.ConfigurationController;
108 import com.android.systemui.statusbar.policy.KeyguardStateController;
109 import com.android.systemui.util.concurrency.Execution;
110 import com.android.systemui.util.concurrency.FakeExecution;
111 import com.android.systemui.util.concurrency.FakeExecutor;
112 import com.android.systemui.util.settings.SecureSettings;
113 import com.android.systemui.util.time.FakeSystemClock;
114 import com.android.systemui.util.time.SystemClock;
115 
116 import org.junit.Before;
117 import org.junit.Rule;
118 import org.junit.Test;
119 import org.junit.runner.RunWith;
120 import org.mockito.ArgumentCaptor;
121 import org.mockito.Captor;
122 import org.mockito.InOrder;
123 import org.mockito.Mock;
124 import org.mockito.junit.MockitoJUnit;
125 import org.mockito.junit.MockitoRule;
126 
127 import java.util.ArrayList;
128 import java.util.List;
129 import java.util.Optional;
130 
131 import javax.inject.Provider;
132 
133 @SmallTest
134 @RoboPilotTest
135 @RunWith(AndroidJUnit4.class)
136 @RunWithLooper(setAsMainLooper = true)
137 public class UdfpsControllerTest extends SysuiTestCase {
138 
139     private static final long TEST_REQUEST_ID = 70;
140 
141     @Rule
142     public MockitoRule rule = MockitoJUnit.rule();
143     // Unit under test
144     private UdfpsController mUdfpsController;
145     // Dependencies
146     private FakeExecutor mBiometricExecutor;
147     @Mock
148     private LayoutInflater mLayoutInflater;
149     @Mock
150     private FingerprintManager mFingerprintManager;
151     @Mock
152     private WindowManager mWindowManager;
153     @Mock
154     private StatusBarStateController mStatusBarStateController;
155     @Mock
156     private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
157     @Mock
158     private DumpManager mDumpManager;
159     @Mock
160     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
161     @Mock
162     private IUdfpsOverlayControllerCallback mUdfpsOverlayControllerCallback;
163     @Mock
164     private FalsingManager mFalsingManager;
165     @Mock
166     private PowerManager mPowerManager;
167     @Mock
168     private AccessibilityManager mAccessibilityManager;
169     @Mock
170     private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
171     @Mock
172     private ScreenLifecycle mScreenLifecycle;
173     @Mock
174     private VibratorHelper mVibrator;
175     @Mock
176     private UdfpsHapticsSimulator mUdfpsHapticsSimulator;
177     @Mock
178     private UdfpsShell mUdfpsShell;
179     @Mock
180     private KeyguardStateController mKeyguardStateController;
181     @Mock
182     private DisplayManager mDisplayManager;
183     @Mock
184     private Handler mHandler;
185     @Mock
186     private ConfigurationController mConfigurationController;
187     @Mock
188     private SystemClock mSystemClock;
189     @Mock
190     private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
191     @Mock
192     private LatencyTracker mLatencyTracker;
193     private FakeExecutor mFgExecutor;
194     @Mock
195     private UdfpsDisplayMode mUdfpsDisplayMode;
196     @Mock
197     private FeatureFlags mFeatureFlags;
198     // Stuff for configuring mocks
199     @Mock
200     private UdfpsView mUdfpsView;
201     @Mock
202     private UdfpsBpView mBpView;
203     @Mock
204     private UdfpsFpmEmptyView mFpmEmptyView;
205     @Mock
206     private UdfpsKeyguardViewLegacy mKeyguardView;
207     private final UdfpsAnimationViewController mUdfpsKeyguardViewController =
208             mock(UdfpsKeyguardViewControllerLegacy.class);
209     @Mock
210     private UdfpsAnimationViewController mUdfpsAnimationViewController;
211     @Mock
212     private SystemUIDialogManager mSystemUIDialogManager;
213     @Mock
214     private ActivityLaunchAnimator mActivityLaunchAnimator;
215     @Mock
216     private AlternateUdfpsTouchProvider mAlternateTouchProvider;
217     @Mock
218     private PrimaryBouncerInteractor mPrimaryBouncerInteractor;
219     @Mock
220     private SinglePointerTouchProcessor mSinglePointerTouchProcessor;
221     @Mock
222     private SessionTracker mSessionTracker;
223     @Mock
224     private AlternateBouncerInteractor mAlternateBouncerInteractor;
225     @Mock
226     private SecureSettings mSecureSettings;
227     @Mock
228     private UdfpsKeyguardAccessibilityDelegate mUdfpsKeyguardAccessibilityDelegate;
229     @Mock
230     private Provider<UdfpsKeyguardViewModels> mUdfpsKeyguardViewModels;
231 
232     // Capture listeners so that they can be used to send events
233     @Captor
234     private ArgumentCaptor<IUdfpsOverlayController> mOverlayCaptor;
235     private IUdfpsOverlayController mOverlayController;
236     @Captor
237     private ArgumentCaptor<UdfpsView.OnTouchListener> mTouchListenerCaptor;
238     @Captor
239     private ArgumentCaptor<View.OnHoverListener> mHoverListenerCaptor;
240     @Captor
241     private ArgumentCaptor<Runnable> mOnDisplayConfiguredCaptor;
242     @Captor
243     private ArgumentCaptor<ScreenLifecycle.Observer> mScreenObserverCaptor;
244     @Captor
245     private ArgumentCaptor<UdfpsController.UdfpsOverlayController> mUdfpsOverlayControllerCaptor;
246     private ScreenLifecycle.Observer mScreenObserver;
247     private FingerprintSensorPropertiesInternal mOpticalProps;
248     private FingerprintSensorPropertiesInternal mUltrasonicProps;
249     private UdfpsUtils mUdfpsUtils;
250     @Mock
251     private InputManager mInputManager;
252     @Mock
253     private ViewRootImpl mViewRootImpl;
254 
255     @Before
setUp()256     public void setUp() {
257         Execution execution = new FakeExecution();
258         mUdfpsUtils = new UdfpsUtils();
259 
260         when(mLayoutInflater.inflate(R.layout.udfps_view, null, false))
261                 .thenReturn(mUdfpsView);
262         when(mLayoutInflater.inflate(R.layout.udfps_keyguard_view_legacy, null))
263                 .thenReturn(mKeyguardView); // for showOverlay REASON_AUTH_FPM_KEYGUARD
264         when(mLayoutInflater.inflate(R.layout.udfps_bp_view, null))
265                 .thenReturn(mBpView);
266         when(mLayoutInflater.inflate(R.layout.udfps_fpm_empty_view, null))
267                 .thenReturn(mFpmEmptyView);
268         when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
269         when(mSessionTracker.getSessionId(anyInt())).thenReturn(
270                 (new InstanceIdSequence(1 << 20)).newInstanceId());
271         when(mUdfpsView.getViewRootImpl()).thenReturn(mViewRootImpl);
272         when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsAnimationViewController);
273 
274         final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
275         componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
276                 "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
277                 "00000001" /* serialNumber */, "" /* softwareVersion */));
278         componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
279                 "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
280                 "vendor/version/revision" /* softwareVersion */));
281 
282         mOpticalProps = new FingerprintSensorPropertiesInternal(1 /* sensorId */,
283                 SensorProperties.STRENGTH_STRONG,
284                 5 /* maxEnrollmentsPerUser */,
285                 componentInfo,
286                 FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
287                 true /* resetLockoutRequiresHardwareAuthToken */);
288 
289         mUltrasonicProps = new FingerprintSensorPropertiesInternal(2 /* sensorId */,
290                 SensorProperties.STRENGTH_STRONG,
291                 5 /* maxEnrollmentsPerUser */,
292                 componentInfo,
293                 FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC,
294                 true /* resetLockoutRequiresHardwareAuthToken */);
295 
296         mFgExecutor = new FakeExecutor(new FakeSystemClock());
297 
298         // Create a fake background executor.
299         mBiometricExecutor = new FakeExecutor(new FakeSystemClock());
300 
301         initUdfpsController(true /* hasAlternateTouchProvider */);
302     }
303 
304 
initUdfpsController(boolean hasAlternateTouchProvider)305     private void initUdfpsController(boolean hasAlternateTouchProvider) {
306         initUdfpsController(mOpticalProps, hasAlternateTouchProvider);
307     }
308 
initUdfpsController(FingerprintSensorPropertiesInternal sensorProps, boolean hasAlternateTouchProvider)309     private void initUdfpsController(FingerprintSensorPropertiesInternal sensorProps,
310             boolean hasAlternateTouchProvider) {
311         reset(mFingerprintManager);
312         reset(mScreenLifecycle);
313 
314         final Optional<Provider<AlternateUdfpsTouchProvider>> alternateTouchProvider =
315                 hasAlternateTouchProvider ? Optional.of(
316                         (Provider<AlternateUdfpsTouchProvider>) () -> mAlternateTouchProvider)
317                         : Optional.empty();
318 
319         mUdfpsController = new UdfpsController(mContext, new FakeExecution(), mLayoutInflater,
320                 mFingerprintManager, mWindowManager, mStatusBarStateController, mFgExecutor,
321                 new ShadeExpansionStateManager(), mStatusBarKeyguardViewManager, mDumpManager,
322                 mKeyguardUpdateMonitor, mFeatureFlags, mFalsingManager, mPowerManager,
323                 mAccessibilityManager, mLockscreenShadeTransitionController, mScreenLifecycle,
324                 mVibrator, mUdfpsHapticsSimulator, mUdfpsShell, mKeyguardStateController,
325                 mDisplayManager, mHandler, mConfigurationController, mSystemClock,
326                 mUnlockedScreenOffAnimationController, mSystemUIDialogManager, mLatencyTracker,
327                 mActivityLaunchAnimator, alternateTouchProvider, mBiometricExecutor,
328                 mPrimaryBouncerInteractor, mSinglePointerTouchProcessor, mSessionTracker,
329                 mAlternateBouncerInteractor, mSecureSettings, mInputManager, mUdfpsUtils,
330                 mock(KeyguardFaceAuthInteractor.class),
331                 mUdfpsKeyguardAccessibilityDelegate, mUdfpsKeyguardViewModels);
332         verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
333         mOverlayController = mOverlayCaptor.getValue();
334         verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
335         mScreenObserver = mScreenObserverCaptor.getValue();
336 
337         mUdfpsController.updateOverlayParams(sensorProps, new UdfpsOverlayParams());
338         mUdfpsController.setUdfpsDisplayMode(mUdfpsDisplayMode);
339     }
340 
341     @Test
dozeTimeTick()342     public void dozeTimeTick() throws RemoteException {
343         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
344                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
345         mFgExecutor.runAllReady();
346         mUdfpsController.dozeTimeTick();
347         verify(mUdfpsView).dozeTimeTick();
348     }
349 
350     @Test
onActionDownTouch_whenCanDismissLockScreen_entersDevice()351     public void onActionDownTouch_whenCanDismissLockScreen_entersDevice() throws RemoteException {
352         // GIVEN can dismiss lock screen and the current animation is an UdfpsKeyguardViewController
353         when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
354         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
355         when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
356 
357         // GIVEN that the overlay is showing
358         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
359                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
360         mFgExecutor.runAllReady();
361 
362         // WHEN ACTION_DOWN is received
363         verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
364         MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
365         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
366         mBiometricExecutor.runAllReady();
367         downEvent.recycle();
368 
369         // THEN notify keyguard authenticate to dismiss the keyguard
370         verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(anyBoolean());
371     }
372 
373     @Test
onActionMoveTouch_whenCanDismissLockScreen_entersDevice()374     public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice() throws RemoteException {
375         onActionMoveTouch_whenCanDismissLockScreen_entersDevice(false /* stale */);
376     }
377 
378     @Test
onActionMoveTouch_whenCanDismissLockScreen_entersDevice_ignoreStale()379     public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice_ignoreStale()
380             throws RemoteException {
381         onActionMoveTouch_whenCanDismissLockScreen_entersDevice(true /* stale */);
382     }
383 
onActionMoveTouch_whenCanDismissLockScreen_entersDevice(boolean stale)384     public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice(boolean stale)
385             throws RemoteException {
386         // GIVEN can dismiss lock screen and the current animation is an UdfpsKeyguardViewController
387         when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
388         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
389         when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
390 
391         // GIVEN that the overlay is showing
392         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
393                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
394         mFgExecutor.runAllReady();
395 
396         // WHEN ACTION_MOVE is received
397         verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
398         MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
399         if (stale) {
400             mOverlayController.hideUdfpsOverlay(mOpticalProps.sensorId);
401             mFgExecutor.runAllReady();
402         }
403         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
404         mBiometricExecutor.runAllReady();
405         moveEvent.recycle();
406 
407         // THEN notify keyguard authenticate to dismiss the keyguard
408         verify(mStatusBarKeyguardViewManager, stale ? never() : times(1))
409                 .notifyKeyguardAuthenticated(anyBoolean());
410     }
411 
412     @Test
onMultipleTouch_whenCanDismissLockScreen_entersDeviceOnce()413     public void onMultipleTouch_whenCanDismissLockScreen_entersDeviceOnce() throws RemoteException {
414         // GIVEN can dismiss lock screen and the current animation is an UdfpsKeyguardViewController
415         when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
416         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
417         when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
418 
419         // GIVEN that the overlay is showing
420         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
421                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
422         mFgExecutor.runAllReady();
423 
424         // WHEN multiple touches are received
425         verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
426         MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
427         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
428         mBiometricExecutor.runAllReady();
429         downEvent.recycle();
430         MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
431         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
432         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
433         mBiometricExecutor.runAllReady();
434         moveEvent.recycle();
435 
436         // THEN notify keyguard authenticate to dismiss the keyguard
437         verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(anyBoolean());
438     }
439 
440     @Test
hideUdfpsOverlay_resetsAltAuthBouncerWhenShowing()441     public void hideUdfpsOverlay_resetsAltAuthBouncerWhenShowing() throws RemoteException {
442         // GIVEN overlay was showing and the udfps bouncer is showing
443         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
444                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
445         when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
446 
447         // WHEN the overlay is hidden
448         mOverlayController.hideUdfpsOverlay(mOpticalProps.sensorId);
449         mFgExecutor.runAllReady();
450 
451         // THEN the udfps bouncer is reset
452         verify(mStatusBarKeyguardViewManager).hideAlternateBouncer(eq(true));
453     }
454 
455     @Test
showUdfpsOverlay_callsListener()456     public void showUdfpsOverlay_callsListener() throws RemoteException {
457         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
458                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
459         mFgExecutor.runAllReady();
460 
461         verify(mFingerprintManager).onUdfpsUiEvent(FingerprintManager.UDFPS_UI_OVERLAY_SHOWN,
462                 TEST_REQUEST_ID, mOpticalProps.sensorId);
463     }
464 
465     @Test
testSubscribesToOrientationChangesWhenShowingOverlay()466     public void testSubscribesToOrientationChangesWhenShowingOverlay() throws Exception {
467         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
468                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
469         mFgExecutor.runAllReady();
470 
471         verify(mDisplayManager).registerDisplayListener(any(), eq(mHandler), anyLong());
472 
473         mOverlayController.hideUdfpsOverlay(mOpticalProps.sensorId);
474         mFgExecutor.runAllReady();
475 
476         verify(mDisplayManager).unregisterDisplayListener(any());
477     }
478 
479     @Test
updateOverlayParams_recreatesOverlay_ifParamsChanged()480     public void updateOverlayParams_recreatesOverlay_ifParamsChanged() throws Exception {
481         final Rect[] sensorBounds = new Rect[]{new Rect(10, 10, 20, 20), new Rect(5, 5, 25, 25)};
482         final int[] displayWidth = new int[]{1080, 1440};
483         final int[] displayHeight = new int[]{1920, 2560};
484         final float[] scaleFactor = new float[]{1f, displayHeight[1] / (float) displayHeight[0]};
485         final int[] rotation = new int[]{Surface.ROTATION_0, Surface.ROTATION_90};
486         final UdfpsOverlayParams oldParams = new UdfpsOverlayParams(sensorBounds[0],
487                 sensorBounds[0], displayWidth[0], displayHeight[0], scaleFactor[0], rotation[0]);
488 
489         for (int i1 = 0; i1 <= 1; ++i1) {
490             for (int i2 = 0; i2 <= 1; ++i2) {
491                 for (int i3 = 0; i3 <= 1; ++i3) {
492                     for (int i4 = 0; i4 <= 1; ++i4) {
493                         for (int i5 = 0; i5 <= 1; ++i5) {
494                             final UdfpsOverlayParams newParams = new UdfpsOverlayParams(
495                                     sensorBounds[i1], sensorBounds[i1], displayWidth[i2],
496                                     displayHeight[i3], scaleFactor[i4], rotation[i5]);
497 
498                             if (newParams.equals(oldParams)) {
499                                 continue;
500                             }
501 
502                             // Initialize the overlay with old parameters.
503                             mUdfpsController.updateOverlayParams(mOpticalProps, oldParams);
504 
505                             // Show the overlay.
506                             reset(mWindowManager);
507                             mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID,
508                                     mOpticalProps.sensorId,
509                                     BiometricOverlayConstants.REASON_ENROLL_ENROLLING,
510                                     mUdfpsOverlayControllerCallback);
511                             mFgExecutor.runAllReady();
512                             verify(mWindowManager).addView(any(), any());
513 
514                             // Update overlay parameters.
515                             reset(mWindowManager);
516                             mUdfpsController.updateOverlayParams(mOpticalProps, newParams);
517                             mFgExecutor.runAllReady();
518 
519                             // Ensure the overlay was recreated.
520                             verify(mWindowManager).removeView(any());
521                             verify(mWindowManager).addView(any(), any());
522                         }
523                     }
524                 }
525             }
526         }
527     }
528 
529     @Test
updateOverlayParams_doesNothing_ifParamsDidntChange()530     public void updateOverlayParams_doesNothing_ifParamsDidntChange() throws Exception {
531         final Rect sensorBounds = new Rect(10, 10, 20, 20);
532         final int displayWidth = 1080;
533         final int displayHeight = 1920;
534         final float scaleFactor = 1f;
535         final int rotation = Surface.ROTATION_0;
536 
537         // Initialize the overlay.
538         mUdfpsController.updateOverlayParams(mOpticalProps,
539                 new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight,
540                         scaleFactor, rotation));
541 
542         // Show the overlay.
543         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
544                 BiometricOverlayConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback);
545         mFgExecutor.runAllReady();
546         verify(mWindowManager).addView(any(), any());
547 
548         // Update overlay with the same parameters.
549         mUdfpsController.updateOverlayParams(mOpticalProps,
550                 new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight,
551                         scaleFactor, rotation));
552         mFgExecutor.runAllReady();
553 
554         // Ensure the overlay was not recreated.
555         verify(mWindowManager, never()).removeView(any());
556     }
557 
obtainMotionEvent(int action, float x, float y, float minor, float major)558     private static MotionEvent obtainMotionEvent(int action, float x, float y, float minor,
559             float major) {
560         MotionEvent.PointerProperties pp = new MotionEvent.PointerProperties();
561         pp.id = 1;
562         MotionEvent.PointerCoords pc = new MotionEvent.PointerCoords();
563         pc.x = x;
564         pc.y = y;
565         pc.touchMinor = minor;
566         pc.touchMajor = major;
567         return MotionEvent.obtain(0, 0, action, 1, new MotionEvent.PointerProperties[]{pp},
568                 new MotionEvent.PointerCoords[]{pc}, 0, 0, 1f, 1f, 0, 0, 0, 0);
569     }
570 
571     private static class TestParams {
572         public final FingerprintSensorPropertiesInternal sensorProps;
573         public final boolean hasAlternateTouchProvider;
574 
TestParams(FingerprintSensorPropertiesInternal sensorProps, boolean hasAlternateTouchProvider)575         TestParams(FingerprintSensorPropertiesInternal sensorProps,
576                 boolean hasAlternateTouchProvider) {
577             this.sensorProps = sensorProps;
578             this.hasAlternateTouchProvider = hasAlternateTouchProvider;
579         }
580     }
581 
runWithAllParams(ThrowingConsumer<TestParams> testParamsConsumer)582     private void runWithAllParams(ThrowingConsumer<TestParams> testParamsConsumer) {
583         for (FingerprintSensorPropertiesInternal sensorProps : List.of(mOpticalProps,
584                 mUltrasonicProps)) {
585             for (boolean hasAlternateTouchProvider : new boolean[]{false, true}) {
586                 initUdfpsController(sensorProps, hasAlternateTouchProvider);
587                 testParamsConsumer.accept(new TestParams(sensorProps, hasAlternateTouchProvider));
588             }
589         }
590     }
591 
592     @Test
onTouch_propagatesTouchInNativeOrientationAndResolution()593     public void onTouch_propagatesTouchInNativeOrientationAndResolution() {
594         runWithAllParams(
595                 this::onTouch_propagatesTouchInNativeOrientationAndResolutionParameterized);
596     }
597 
onTouch_propagatesTouchInNativeOrientationAndResolutionParameterized( TestParams testParams)598     private void onTouch_propagatesTouchInNativeOrientationAndResolutionParameterized(
599             TestParams testParams) throws RemoteException {
600         reset(mUdfpsView);
601 
602         final Rect sensorBounds = new Rect(1000, 1900, 1080, 1920); // Bottom right corner.
603         final int displayWidth = 1080;
604         final int displayHeight = 1920;
605         final float scaleFactor = 0.75f; // This means the native resolution is 1440x2560.
606         final float touchMinor = 10f;
607         final float touchMajor = 20f;
608 
609         // Expecting a touch at the very bottom right corner in native orientation and resolution.
610         final int expectedX = (int) (displayWidth / scaleFactor);
611         final int expectedY = (int) (displayHeight / scaleFactor);
612         final float expectedMinor = touchMinor / scaleFactor;
613         final float expectedMajor = touchMajor / scaleFactor;
614 
615         // Configure UdfpsView to accept the ACTION_DOWN event
616         when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
617         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
618 
619         // Show the overlay.
620         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
621                 BiometricOverlayConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback);
622         mFgExecutor.runAllReady();
623         verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
624 
625         // Test ROTATION_0
626         mUdfpsController.updateOverlayParams(testParams.sensorProps,
627                 new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight,
628                         scaleFactor, Surface.ROTATION_0));
629         MotionEvent event = obtainMotionEvent(ACTION_DOWN, displayWidth, displayHeight, touchMinor,
630                 touchMajor);
631         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
632         mBiometricExecutor.runAllReady();
633         event.recycle();
634         event = obtainMotionEvent(ACTION_MOVE, displayWidth, displayHeight, touchMinor, touchMajor);
635         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
636         mBiometricExecutor.runAllReady();
637         event.recycle();
638         if (testParams.hasAlternateTouchProvider) {
639             verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(expectedX),
640                     eq(expectedY), eq(expectedMinor), eq(expectedMajor));
641         } else {
642             verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
643                     eq(testParams.sensorProps.sensorId), eq(expectedX), eq(expectedY),
644                     eq(expectedMinor), eq(expectedMajor));
645         }
646 
647         // Test ROTATION_90
648         reset(mAlternateTouchProvider);
649         reset(mFingerprintManager);
650         mUdfpsController.updateOverlayParams(testParams.sensorProps,
651                 new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight,
652                         scaleFactor, Surface.ROTATION_90));
653         event = obtainMotionEvent(ACTION_DOWN, displayHeight, 0, touchMinor, touchMajor);
654         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
655         mBiometricExecutor.runAllReady();
656         event.recycle();
657         event = obtainMotionEvent(ACTION_MOVE, displayHeight, 0, touchMinor, touchMajor);
658         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
659         mBiometricExecutor.runAllReady();
660         event.recycle();
661         if (testParams.hasAlternateTouchProvider) {
662             verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(expectedX),
663                     eq(expectedY), eq(expectedMinor), eq(expectedMajor));
664         } else {
665             verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
666                     eq(testParams.sensorProps.sensorId), eq(expectedX), eq(expectedY),
667                     eq(expectedMinor), eq(expectedMajor));
668         }
669 
670         // Test ROTATION_270
671         reset(mAlternateTouchProvider);
672         reset(mFingerprintManager);
673         mUdfpsController.updateOverlayParams(testParams.sensorProps,
674                 new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight,
675                         scaleFactor, Surface.ROTATION_270));
676         event = obtainMotionEvent(ACTION_DOWN, 0, displayWidth, touchMinor, touchMajor);
677         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
678         mBiometricExecutor.runAllReady();
679         event.recycle();
680         event = obtainMotionEvent(ACTION_MOVE, 0, displayWidth, touchMinor, touchMajor);
681         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
682         mBiometricExecutor.runAllReady();
683         event.recycle();
684         if (testParams.hasAlternateTouchProvider) {
685             verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(expectedX),
686                     eq(expectedY), eq(expectedMinor), eq(expectedMajor));
687         } else {
688             verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
689                     eq(testParams.sensorProps.sensorId), eq(expectedX), eq(expectedY),
690                     eq(expectedMinor), eq(expectedMajor));
691         }
692 
693         // Test ROTATION_180
694         reset(mAlternateTouchProvider);
695         reset(mFingerprintManager);
696         mUdfpsController.updateOverlayParams(testParams.sensorProps,
697                 new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight,
698                         scaleFactor, Surface.ROTATION_180));
699         // ROTATION_180 is not supported. It should be treated like ROTATION_0.
700         event = obtainMotionEvent(ACTION_DOWN, displayWidth, displayHeight, touchMinor, touchMajor);
701         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
702         mBiometricExecutor.runAllReady();
703         event.recycle();
704         event = obtainMotionEvent(ACTION_MOVE, displayWidth, displayHeight, touchMinor, touchMajor);
705         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
706         mBiometricExecutor.runAllReady();
707         event.recycle();
708         if (testParams.hasAlternateTouchProvider) {
709             verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(expectedX),
710                     eq(expectedY), eq(expectedMinor), eq(expectedMajor));
711         } else {
712             verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
713                     eq(testParams.sensorProps.sensorId), eq(expectedX), eq(expectedY),
714                     eq(expectedMinor), eq(expectedMajor));
715         }
716     }
717 
718     @Test
fingerDown()719     public void fingerDown() {
720         runWithAllParams(this::fingerDownParameterized);
721     }
722 
fingerDownParameterized(TestParams testParams)723     private void fingerDownParameterized(TestParams testParams) throws RemoteException {
724         reset(mUdfpsView, mAlternateTouchProvider, mFingerprintManager, mLatencyTracker,
725                 mKeyguardUpdateMonitor);
726 
727         // Configure UdfpsView to accept the ACTION_DOWN event
728         when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
729         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
730         when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
731 
732         // GIVEN that the overlay is showing
733         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
734                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
735         mFgExecutor.runAllReady();
736         verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
737 
738         // WHEN ACTION_DOWN is received
739         MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
740         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
741         mBiometricExecutor.runAllReady();
742         downEvent.recycle();
743 
744         MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
745         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
746         mBiometricExecutor.runAllReady();
747         moveEvent.recycle();
748 
749         mFgExecutor.runAllReady();
750 
751         // THEN the touch provider is notified about onPointerDown.
752         if (testParams.hasAlternateTouchProvider) {
753             verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(0), eq(0), eq(0f),
754                     eq(0f));
755             verify(mFingerprintManager, never()).onPointerDown(anyLong(), anyInt(), anyInt(),
756                     anyInt(), anyFloat(), anyFloat());
757             verify(mKeyguardUpdateMonitor).onUdfpsPointerDown(eq((int) TEST_REQUEST_ID));
758         } else {
759             verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
760                     eq(testParams.sensorProps.sensorId), eq(0), eq(0), eq(0f), eq(0f));
761             verify(mAlternateTouchProvider, never()).onPointerDown(anyInt(), anyInt(), anyInt(),
762                     anyFloat(), anyFloat());
763         }
764 
765         // AND display configuration begins
766         if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
767             verify(mLatencyTracker).onActionStart(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
768             verify(mUdfpsView).configureDisplay(mOnDisplayConfiguredCaptor.capture());
769         } else {
770             verify(mLatencyTracker, never()).onActionStart(
771                     eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
772             verify(mUdfpsView, never()).configureDisplay(any());
773         }
774         verify(mLatencyTracker, never()).onActionEnd(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
775 
776         if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
777             // AND onDisplayConfigured notifies FingerprintManager about onUiReady
778             mOnDisplayConfiguredCaptor.getValue().run();
779             mBiometricExecutor.runAllReady();
780             if (testParams.hasAlternateTouchProvider) {
781                 InOrder inOrder = inOrder(mAlternateTouchProvider, mLatencyTracker);
782                 inOrder.verify(mAlternateTouchProvider).onUiReady();
783                 inOrder.verify(mLatencyTracker).onActionEnd(
784                         eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
785                 verify(mFingerprintManager, never()).onUdfpsUiEvent(
786                         eq(FingerprintManager.UDFPS_UI_READY), anyLong(), anyInt());
787             } else {
788                 InOrder inOrder = inOrder(mFingerprintManager, mLatencyTracker);
789                 inOrder.verify(mFingerprintManager).onUdfpsUiEvent(
790                         eq(FingerprintManager.UDFPS_UI_READY), eq(TEST_REQUEST_ID),
791                         eq(testParams.sensorProps.sensorId));
792                 inOrder.verify(mLatencyTracker).onActionEnd(
793                         eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
794                 verify(mAlternateTouchProvider, never()).onUiReady();
795             }
796         } else {
797             verify(mFingerprintManager, never()).onUdfpsUiEvent(
798                     eq(FingerprintManager.UDFPS_UI_READY), anyLong(), anyInt());
799             verify(mAlternateTouchProvider, never()).onUiReady();
800             verify(mLatencyTracker, never()).onActionEnd(
801                     eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
802         }
803     }
804 
805 
806 
807     @Test
aodInterrupt()808     public void aodInterrupt() {
809         runWithAllParams(this::aodInterruptParameterized);
810     }
811 
aodInterruptParameterized(TestParams testParams)812     private void aodInterruptParameterized(TestParams testParams) throws RemoteException {
813         mUdfpsController.cancelAodSendFingerUpAction();
814         reset(mUdfpsView, mAlternateTouchProvider, mFingerprintManager, mKeyguardUpdateMonitor);
815         when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
816 
817         // GIVEN that the overlay is showing and screen is on and fp is running
818         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
819                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
820         mScreenObserver.onScreenTurnedOn();
821         mFgExecutor.runAllReady();
822         // WHEN fingerprint is requested because of AOD interrupt
823         mUdfpsController.onAodInterrupt(0, 0, 2f, 3f);
824         mFgExecutor.runAllReady();
825         if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
826             // THEN display configuration begins
827             // AND onDisplayConfigured notifies FingerprintManager about onUiReady
828             verify(mUdfpsView).configureDisplay(mOnDisplayConfiguredCaptor.capture());
829             mOnDisplayConfiguredCaptor.getValue().run();
830         } else {
831             verify(mUdfpsView, never()).configureDisplay(mOnDisplayConfiguredCaptor.capture());
832         }
833         mBiometricExecutor.runAllReady();
834 
835         if (testParams.hasAlternateTouchProvider) {
836             verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(0), eq(0),
837                     eq(3f) /* minor */, eq(2f) /* major */);
838             verify(mFingerprintManager, never()).onPointerDown(anyLong(), anyInt(), anyInt(),
839                     anyInt(), anyFloat(), anyFloat());
840             verify(mKeyguardUpdateMonitor).onUdfpsPointerDown(eq((int) TEST_REQUEST_ID));
841         } else {
842             verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
843                     eq(testParams.sensorProps.sensorId), eq(0), eq(0), eq(3f) /* minor */,
844                     eq(2f) /* major */);
845             verify(mAlternateTouchProvider, never()).onPointerDown(anyLong(), anyInt(), anyInt(),
846                     anyFloat(), anyFloat());
847         }
848     }
849 
850     @Test
tryAodSendFingerUp_displayConfigurationChanges()851     public void tryAodSendFingerUp_displayConfigurationChanges() {
852         runWithAllParams(this::cancelAodInterruptParameterized);
853     }
854 
cancelAodInterruptParameterized(TestParams testParams)855     private void cancelAodInterruptParameterized(TestParams testParams) throws RemoteException {
856         reset(mUdfpsView);
857 
858         // GIVEN AOD interrupt
859         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
860                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
861         mScreenObserver.onScreenTurnedOn();
862         mFgExecutor.runAllReady();
863         mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
864         if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
865             when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
866             // WHEN it is cancelled
867             mUdfpsController.tryAodSendFingerUp();
868             // THEN the display is unconfigured
869             verify(mUdfpsView).unconfigureDisplay();
870         } else {
871             when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
872             // WHEN it is cancelled
873             mUdfpsController.tryAodSendFingerUp();
874             // THEN the display configuration is unchanged.
875             verify(mUdfpsView, never()).unconfigureDisplay();
876         }
877     }
878 
879     @Test
onFingerUp_displayConfigurationChange()880     public void onFingerUp_displayConfigurationChange() {
881         runWithAllParams(this::onFingerUp_displayConfigurationParameterized);
882     }
883 
onFingerUp_displayConfigurationParameterized(TestParams testParams)884     private void onFingerUp_displayConfigurationParameterized(TestParams testParams)
885             throws RemoteException {
886         reset(mUdfpsView);
887 
888         // GIVEN AOD interrupt
889         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
890                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
891         mScreenObserver.onScreenTurnedOn();
892         mFgExecutor.runAllReady();
893         mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
894         if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
895             when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
896 
897             // WHEN up-action received
898             verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
899             MotionEvent upEvent = MotionEvent.obtain(0, 0, ACTION_UP, 0, 0, 0);
900             mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
901             mBiometricExecutor.runAllReady();
902             upEvent.recycle();
903             mFgExecutor.runAllReady();
904 
905             // THEN the display is unconfigured
906             verify(mUdfpsView).unconfigureDisplay();
907         } else {
908             when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
909 
910             // WHEN up-action received
911             verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
912             MotionEvent upEvent = MotionEvent.obtain(0, 0, ACTION_UP, 0, 0, 0);
913             mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
914             mBiometricExecutor.runAllReady();
915             upEvent.recycle();
916             mFgExecutor.runAllReady();
917 
918             // THEN the display configuration is unchanged.
919             verify(mUdfpsView, never()).unconfigureDisplay();
920         }
921     }
922 
923     @Test
onAcquiredGood_displayConfigurationChange()924     public void onAcquiredGood_displayConfigurationChange() {
925         runWithAllParams(this::onAcquiredGood_displayConfigurationParameterized);
926     }
927 
onAcquiredGood_displayConfigurationParameterized(TestParams testParams)928     private void onAcquiredGood_displayConfigurationParameterized(TestParams testParams)
929             throws RemoteException {
930         reset(mUdfpsView);
931 
932         // GIVEN overlay is showing
933         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
934                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
935         mFgExecutor.runAllReady();
936         if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
937             when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
938             // WHEN ACQUIRED_GOOD received
939             mOverlayController.onAcquired(testParams.sensorProps.sensorId,
940                     BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD);
941             mFgExecutor.runAllReady();
942             // THEN the display is unconfigured
943             verify(mUdfpsView).unconfigureDisplay();
944         } else {
945             when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
946             // WHEN ACQUIRED_GOOD received
947             mOverlayController.onAcquired(testParams.sensorProps.sensorId,
948                     BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD);
949             mFgExecutor.runAllReady();
950             // THEN the display configuration is unchanged.
951             verify(mUdfpsView, never()).unconfigureDisplay();
952         }
953     }
954 
955     @Test
aodInterruptTimeout()956     public void aodInterruptTimeout() {
957         runWithAllParams(this::aodInterruptTimeoutParameterized);
958     }
959 
aodInterruptTimeoutParameterized(TestParams testParams)960     private void aodInterruptTimeoutParameterized(TestParams testParams) throws RemoteException {
961         reset(mUdfpsView);
962 
963         // GIVEN AOD interrupt
964         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
965                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
966         mScreenObserver.onScreenTurnedOn();
967         mFgExecutor.runAllReady();
968         mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
969         mFgExecutor.runAllReady();
970         if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
971             when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
972         } else {
973             when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
974         }
975         // WHEN it times out
976         mFgExecutor.advanceClockToNext();
977         mFgExecutor.runAllReady();
978         if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
979             // THEN the display is unconfigured.
980             verify(mUdfpsView).unconfigureDisplay();
981         } else {
982             // THEN the display configuration is unchanged.
983             verify(mUdfpsView, never()).unconfigureDisplay();
984         }
985     }
986 
987     @Test
aodInterruptCancelTimeoutActionOnFingerUp()988     public void aodInterruptCancelTimeoutActionOnFingerUp() {
989         runWithAllParams(this::aodInterruptCancelTimeoutActionOnFingerUpParameterized);
990     }
991 
aodInterruptCancelTimeoutActionOnFingerUpParameterized(TestParams testParams)992     private void aodInterruptCancelTimeoutActionOnFingerUpParameterized(TestParams testParams)
993             throws RemoteException {
994         reset(mUdfpsView);
995         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
996 
997         // GIVEN AOD interrupt
998         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
999                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
1000         mScreenObserver.onScreenTurnedOn();
1001         mFgExecutor.runAllReady();
1002         mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
1003         mFgExecutor.runAllReady();
1004 
1005         if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
1006             // Configure UdfpsView to accept the ACTION_UP event
1007             when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
1008         } else {
1009             when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
1010         }
1011 
1012         // WHEN ACTION_UP is received
1013         verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
1014         MotionEvent upEvent = MotionEvent.obtain(0, 0, ACTION_UP, 0, 0, 0);
1015         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
1016         mBiometricExecutor.runAllReady();
1017         upEvent.recycle();
1018 
1019         // Configure UdfpsView to accept the ACTION_DOWN event
1020         when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
1021 
1022         // WHEN ACTION_DOWN is received
1023         MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
1024         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
1025         mBiometricExecutor.runAllReady();
1026         downEvent.recycle();
1027 
1028         // WHEN ACTION_MOVE is received
1029         MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
1030         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
1031         mBiometricExecutor.runAllReady();
1032         moveEvent.recycle();
1033         mFgExecutor.runAllReady();
1034 
1035         if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
1036             // Configure UdfpsView to accept the finger up event
1037             when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
1038         } else {
1039             when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
1040         }
1041 
1042         // WHEN it times out
1043         mFgExecutor.advanceClockToNext();
1044         mFgExecutor.runAllReady();
1045 
1046         if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
1047             // THEN the display should be unconfigured once. If the timeout action is not
1048             // cancelled, the display would be unconfigured twice which would cause two
1049             // FP attempts.
1050             verify(mUdfpsView).unconfigureDisplay();
1051         } else {
1052             verify(mUdfpsView, never()).unconfigureDisplay();
1053         }
1054     }
1055 
1056     @Test
aodInterruptScreenOff()1057     public void aodInterruptScreenOff() {
1058         runWithAllParams(this::aodInterruptScreenOffParameterized);
1059     }
1060 
aodInterruptScreenOffParameterized(TestParams testParams)1061     private void aodInterruptScreenOffParameterized(TestParams testParams) throws RemoteException {
1062         reset(mUdfpsView);
1063 
1064         // GIVEN screen off
1065         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
1066                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
1067         mScreenObserver.onScreenTurnedOff();
1068         mFgExecutor.runAllReady();
1069 
1070         // WHEN aod interrupt is received
1071         mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
1072 
1073         // THEN display doesn't get configured because it's off
1074         verify(mUdfpsView, never()).configureDisplay(any());
1075     }
1076 
1077     @Test
aodInterrupt_fingerprintNotRunning()1078     public void aodInterrupt_fingerprintNotRunning() {
1079         runWithAllParams(this::aodInterrupt_fingerprintNotRunningParameterized);
1080     }
1081 
aodInterrupt_fingerprintNotRunningParameterized(TestParams testParams)1082     private void aodInterrupt_fingerprintNotRunningParameterized(TestParams testParams)
1083             throws RemoteException {
1084         reset(mUdfpsView);
1085 
1086         // GIVEN showing overlay
1087         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
1088                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
1089         mScreenObserver.onScreenTurnedOn();
1090         mFgExecutor.runAllReady();
1091 
1092         // WHEN aod interrupt is received when the fingerprint service isn't running
1093         when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(false);
1094         mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
1095 
1096         // THEN display doesn't get configured because it's off
1097         verify(mUdfpsView, never()).configureDisplay(any());
1098     }
1099 
1100     @Test
playHapticOnTouchUdfpsArea_a11yTouchExplorationEnabled()1101     public void playHapticOnTouchUdfpsArea_a11yTouchExplorationEnabled() throws RemoteException {
1102         // Configure UdfpsView to accept the ACTION_DOWN event
1103         when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
1104         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
1105 
1106         // GIVEN that the overlay is showing and a11y touch exploration enabled
1107         when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true);
1108         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
1109                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
1110         mFgExecutor.runAllReady();
1111 
1112         // WHEN ACTION_HOVER is received
1113         verify(mUdfpsView).setOnHoverListener(mHoverListenerCaptor.capture());
1114         MotionEvent enterEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0, 0, 0);
1115         mHoverListenerCaptor.getValue().onHover(mUdfpsView, enterEvent);
1116         enterEvent.recycle();
1117         MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0);
1118         mHoverListenerCaptor.getValue().onHover(mUdfpsView, moveEvent);
1119         moveEvent.recycle();
1120 
1121         // THEN tick haptic is played
1122         verify(mVibrator).vibrate(
1123                 anyInt(),
1124                 anyString(),
1125                 any(),
1126                 eq("udfps-onStart-click"),
1127                 eq(UdfpsController.UDFPS_VIBRATION_ATTRIBUTES));
1128 
1129         // THEN make sure vibration attributes has so that it always will play the haptic,
1130         // even in battery saver mode
1131         assertEquals(VibrationAttributes.USAGE_COMMUNICATION_REQUEST,
1132                 UdfpsController.UDFPS_VIBRATION_ATTRIBUTES.getUsage());
1133     }
1134 
1135     @Test
playHapticOnTouchUdfpsArea_a11yTouchExplorationEnabled_oneWayHapticsEnabled()1136     public void playHapticOnTouchUdfpsArea_a11yTouchExplorationEnabled_oneWayHapticsEnabled()
1137             throws RemoteException {
1138         when(mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)).thenReturn(true);
1139         // Configure UdfpsView to accept the ACTION_DOWN event
1140         when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
1141         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
1142 
1143         // GIVEN that the overlay is showing and a11y touch exploration enabled
1144         when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true);
1145         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
1146                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
1147         mFgExecutor.runAllReady();
1148 
1149         // WHEN ACTION_HOVER is received
1150         verify(mUdfpsView).setOnHoverListener(mHoverListenerCaptor.capture());
1151         MotionEvent enterEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0, 0, 0);
1152         mHoverListenerCaptor.getValue().onHover(mUdfpsView, enterEvent);
1153         enterEvent.recycle();
1154         MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0);
1155         mHoverListenerCaptor.getValue().onHover(mUdfpsView, moveEvent);
1156         moveEvent.recycle();
1157 
1158         // THEN context click haptic is played
1159         verify(mVibrator).performHapticFeedback(
1160                 any(),
1161                 eq(HapticFeedbackConstants.CONTEXT_CLICK)
1162         );
1163     }
1164 
1165     @Test
noHapticOnTouchUdfpsArea_a11yTouchExplorationDisabled()1166     public void noHapticOnTouchUdfpsArea_a11yTouchExplorationDisabled() throws RemoteException {
1167         // Configure UdfpsView to accept the ACTION_DOWN event
1168         when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
1169         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
1170 
1171         // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
1172         when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
1173         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
1174                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
1175         mFgExecutor.runAllReady();
1176 
1177         // WHEN ACTION_DOWN is received
1178         verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
1179         MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
1180         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
1181         mBiometricExecutor.runAllReady();
1182         downEvent.recycle();
1183         MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
1184         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
1185         mBiometricExecutor.runAllReady();
1186         moveEvent.recycle();
1187 
1188         // THEN NO haptic played
1189         verify(mVibrator, never()).vibrate(
1190                 anyInt(),
1191                 anyString(),
1192                 any(),
1193                 anyString(),
1194                 any());
1195     }
1196 
1197     @Test
noHapticOnTouchUdfpsArea_a11yTouchExplorationDisabled__oneWayHapticsEnabled()1198     public void noHapticOnTouchUdfpsArea_a11yTouchExplorationDisabled__oneWayHapticsEnabled()
1199             throws RemoteException {
1200         when(mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)).thenReturn(true);
1201         // Configure UdfpsView to accept the ACTION_DOWN event
1202         when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
1203         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
1204 
1205         // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
1206         when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
1207         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
1208                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
1209         mFgExecutor.runAllReady();
1210 
1211         // WHEN ACTION_DOWN is received
1212         verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
1213         MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
1214         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
1215         mBiometricExecutor.runAllReady();
1216         downEvent.recycle();
1217         MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
1218         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
1219         mBiometricExecutor.runAllReady();
1220         moveEvent.recycle();
1221 
1222         // THEN NO haptic played
1223         verify(mVibrator, never()).performHapticFeedback(any(), anyInt());
1224     }
1225 
1226     @Test
onTouch_withoutNewTouchDetection_shouldCallOldFingerprintManagerPath()1227     public void onTouch_withoutNewTouchDetection_shouldCallOldFingerprintManagerPath()
1228             throws RemoteException {
1229         // Disable new touch detection.
1230         when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(false);
1231 
1232         // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
1233         initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
1234 
1235         // Configure UdfpsView to accept the ACTION_DOWN event
1236         when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
1237         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
1238 
1239         // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
1240         when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
1241         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
1242                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
1243         mFgExecutor.runAllReady();
1244 
1245         verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
1246 
1247         // WHEN ACTION_DOWN is received
1248         MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
1249         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
1250         mBiometricExecutor.runAllReady();
1251         downEvent.recycle();
1252 
1253         // AND ACTION_MOVE is received
1254         MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
1255         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
1256         mBiometricExecutor.runAllReady();
1257         moveEvent.recycle();
1258 
1259         // AND ACTION_UP is received
1260         MotionEvent upEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0);
1261         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
1262         mBiometricExecutor.runAllReady();
1263         upEvent.recycle();
1264 
1265         // THEN the old FingerprintManager path is invoked.
1266         verify(mFingerprintManager).onPointerDown(anyLong(), anyInt(), anyInt(), anyInt(),
1267                 anyFloat(), anyFloat());
1268         verify(mFingerprintManager).onPointerUp(anyLong(), anyInt());
1269     }
1270 
1271     @Test
fingerDown_falsingManagerInformed()1272     public void fingerDown_falsingManagerInformed() throws RemoteException {
1273         final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
1274                 givenAcceptFingerDownEvent();
1275 
1276         // WHEN ACTION_DOWN is received
1277         when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
1278                 touchProcessorResult.first);
1279         MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
1280         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
1281         mBiometricExecutor.runAllReady();
1282         downEvent.recycle();
1283 
1284         // THEN falsing manager is informed of the touch
1285         verify(mFalsingManager).isFalseTouch(UDFPS_AUTHENTICATION);
1286     }
1287 
1288     @Test
onTouch_withNewTouchDetection_shouldCallNewFingerprintManagerPath()1289     public void onTouch_withNewTouchDetection_shouldCallNewFingerprintManagerPath()
1290             throws RemoteException {
1291         final Pair<TouchProcessorResult, TouchProcessorResult> processorResultDownAndUp =
1292                 givenAcceptFingerDownEvent();
1293 
1294         // WHEN ACTION_DOWN is received
1295         when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
1296                 processorResultDownAndUp.first);
1297         MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
1298         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
1299         mBiometricExecutor.runAllReady();
1300         downEvent.recycle();
1301 
1302         // AND ACTION_UP is received
1303         when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
1304                 processorResultDownAndUp.second);
1305         MotionEvent upEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0);
1306         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
1307         mBiometricExecutor.runAllReady();
1308         upEvent.recycle();
1309 
1310         // THEN the new FingerprintManager path is invoked.
1311         verify(mFingerprintManager).onPointerDown(anyLong(), anyInt(), anyInt(), anyFloat(),
1312                 anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(), anyBoolean());
1313         verify(mFingerprintManager).onPointerUp(anyLong(), anyInt(), anyInt(), anyFloat(),
1314                 anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(), anyBoolean());
1315     }
1316 
givenAcceptFingerDownEvent()1317     private Pair<TouchProcessorResult, TouchProcessorResult> givenAcceptFingerDownEvent()
1318             throws RemoteException {
1319         final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
1320                 0L);
1321         final TouchProcessorResult processorResultDown = new TouchProcessorResult.ProcessedTouch(
1322                 InteractionEvent.DOWN, 1 /* pointerId */, touchData);
1323         final TouchProcessorResult processorResultUp = new TouchProcessorResult.ProcessedTouch(
1324                 InteractionEvent.UP, 1 /* pointerId */, touchData);
1325 
1326         // Enable new touch detection.
1327         when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true);
1328 
1329         // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
1330         initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
1331 
1332         // Configure UdfpsView to accept the ACTION_DOWN event
1333         when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
1334         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
1335 
1336         // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
1337         when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
1338         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
1339                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
1340         mFgExecutor.runAllReady();
1341 
1342         verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
1343 
1344         return new Pair<>(processorResultDown, processorResultUp);
1345     }
1346 
1347     @Test
onTouch_WithNewTouchDetection_forwardToKeyguard()1348     public void onTouch_WithNewTouchDetection_forwardToKeyguard() throws RemoteException {
1349         final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
1350                 0L);
1351         final TouchProcessorResult processorResultDown = new TouchProcessorResult.ProcessedTouch(
1352                 InteractionEvent.UNCHANGED, -1 /* pointerOnSensorId */, touchData);
1353 
1354         // Enable new touch detection.
1355         when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true);
1356 
1357         // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
1358         initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
1359 
1360         // Configure UdfpsView to accept the ACTION_DOWN event
1361         when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
1362         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(false);
1363 
1364         // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
1365         when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
1366         when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
1367         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
1368                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
1369         mFgExecutor.runAllReady();
1370 
1371         verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
1372 
1373         // WHEN ACTION_DOWN is received
1374         when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
1375                 processorResultDown);
1376         MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
1377         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
1378         mBiometricExecutor.runAllReady();
1379 
1380         // THEN the touch is forwarded to Keyguard
1381         verify(mStatusBarKeyguardViewManager).onTouch(downEvent);
1382         downEvent.recycle();
1383     }
1384 
1385     @Test
onTouch_withNewTouchDetection_ignoreIfAuthPaused()1386     public void onTouch_withNewTouchDetection_ignoreIfAuthPaused() throws RemoteException {
1387         final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
1388                 0L);
1389         final TouchProcessorResult processorResultDown =
1390                 new TouchProcessorResult.ProcessedTouch(InteractionEvent.DOWN,
1391                         1 /* pointerId */, touchData);
1392 
1393         // Enable new touch detection.
1394         when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true);
1395 
1396         // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
1397         initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
1398 
1399         // Configure UdfpsView to accept the ACTION_DOWN event
1400         when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
1401         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
1402 
1403         // GIVEN that auth is paused
1404         when(mUdfpsAnimationViewController.shouldPauseAuth()).thenReturn(true);
1405 
1406         // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
1407         when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
1408         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
1409                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
1410         mFgExecutor.runAllReady();
1411 
1412         verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
1413 
1414         // WHEN ACTION_DOWN is received and touch is within sensor
1415         when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
1416                 processorResultDown);
1417         MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
1418         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
1419         mBiometricExecutor.runAllReady();
1420         downEvent.recycle();
1421 
1422         // THEN the touch is ignored
1423         verify(mInputManager, never()).pilferPointers(any());
1424         verify(mFingerprintManager, never()).onPointerDown(anyLong(), anyInt(), anyInt(),
1425                 anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(),
1426                 anyBoolean());
1427     }
1428 
1429     @Test
onTouch_withNewTouchDetection_ignoreAuthPauseIfFingerDown()1430     public void onTouch_withNewTouchDetection_ignoreAuthPauseIfFingerDown() throws RemoteException {
1431         final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
1432                 0L);
1433         final TouchProcessorResult processorResultDown =
1434                 new TouchProcessorResult.ProcessedTouch(InteractionEvent.DOWN,
1435                         0 /* pointerId */, touchData);
1436         final TouchProcessorResult processorResultUp =
1437                 new TouchProcessorResult.ProcessedTouch(InteractionEvent.UP,
1438                         -1 /* pointerId */, touchData);
1439 
1440         // Enable new touch detection.
1441         when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true);
1442 
1443         // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
1444         initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
1445 
1446         // Configure UdfpsView to accept the ACTION_DOWN event
1447         when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
1448         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
1449 
1450         // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
1451         when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
1452         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
1453                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
1454         mFgExecutor.runAllReady();
1455 
1456         verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
1457 
1458         // WHEN ACTION_DOWN is received and touch is within sensor
1459         when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
1460                 processorResultDown);
1461         MotionEvent event = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
1462         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
1463         mBiometricExecutor.runAllReady();
1464 
1465         // THEN the down touch is received
1466         verify(mInputManager).pilferPointers(any());
1467         verify(mFingerprintManager).onPointerDown(anyLong(), anyInt(), anyInt(),
1468                 anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(),
1469                 anyBoolean());
1470 
1471         // GIVEN that auth is paused
1472         when(mUdfpsAnimationViewController.shouldPauseAuth()).thenReturn(true);
1473 
1474         // WHEN ACTION_UP is received and touch is within sensor
1475         when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
1476                 processorResultUp);
1477         event.setAction(ACTION_UP);
1478         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
1479         mBiometricExecutor.runAllReady();
1480         event.recycle();
1481 
1482         // THEN the UP is still received
1483         verify(mInputManager).pilferPointers(any());
1484         verify(mFingerprintManager).onPointerUp(anyLong(), anyInt(), anyInt(),
1485                 anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(),
1486                 anyBoolean());
1487     }
1488 
1489     @Test
onTouch_withNewTouchDetection_pilferPointer()1490     public void onTouch_withNewTouchDetection_pilferPointer() throws RemoteException {
1491         final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
1492                 0L);
1493         final TouchProcessorResult processorResultDown = new TouchProcessorResult.ProcessedTouch(
1494                 InteractionEvent.DOWN, 1 /* pointerId */, touchData);
1495 
1496         // Enable new touch detection.
1497         when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true);
1498 
1499         // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
1500         initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
1501 
1502         // Configure UdfpsView to accept the ACTION_DOWN event
1503         when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
1504         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
1505 
1506         // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
1507         when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
1508         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
1509                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
1510         mFgExecutor.runAllReady();
1511 
1512         verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
1513 
1514         // WHEN ACTION_DOWN is received
1515         when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
1516                 processorResultDown);
1517         MotionEvent event = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
1518         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
1519         mBiometricExecutor.runAllReady();
1520 
1521         // WHEN ACTION_MOVE is received after
1522         final TouchProcessorResult processorResultUnchanged =
1523                 new TouchProcessorResult.ProcessedTouch(
1524                         InteractionEvent.UNCHANGED, 1 /* pointerId */, touchData);
1525         when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
1526                 processorResultUnchanged);
1527         event.setAction(ACTION_MOVE);
1528         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
1529         mBiometricExecutor.runAllReady();
1530         event.recycle();
1531 
1532         // THEN only pilfer once on the initial down
1533         verify(mInputManager).pilferPointers(any());
1534     }
1535 
1536     @Test
onTouch_withNewTouchDetection_doNotPilferPointer()1537     public void onTouch_withNewTouchDetection_doNotPilferPointer() throws RemoteException {
1538         final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
1539                 0L);
1540         final TouchProcessorResult processorResultUnchanged =
1541                 new TouchProcessorResult.ProcessedTouch(InteractionEvent.UNCHANGED,
1542                         1 /* pointerId */, touchData);
1543 
1544         // Enable new touch detection.
1545         when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true);
1546 
1547         // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
1548         initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
1549 
1550         // Configure UdfpsView to not accept the ACTION_DOWN event
1551         when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
1552         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(false);
1553 
1554         // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
1555         when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
1556         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
1557                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
1558         mFgExecutor.runAllReady();
1559 
1560         verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
1561 
1562         // WHEN ACTION_DOWN is received and touch is not within sensor
1563         when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
1564                 processorResultUnchanged);
1565         MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
1566         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
1567         mBiometricExecutor.runAllReady();
1568         downEvent.recycle();
1569 
1570         // THEN the touch is NOT pilfered
1571         verify(mInputManager, never()).pilferPointers(any());
1572     }
1573 
1574     @Test
onTouch_withNewTouchDetection_pilferPointerWhenAltBouncerShowing()1575     public void onTouch_withNewTouchDetection_pilferPointerWhenAltBouncerShowing()
1576             throws RemoteException {
1577         final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
1578                 0L);
1579         final TouchProcessorResult processorResultUnchanged =
1580                 new TouchProcessorResult.ProcessedTouch(InteractionEvent.UNCHANGED,
1581                         1 /* pointerId */, touchData);
1582 
1583         // Enable new touch detection.
1584         when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true);
1585 
1586         // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
1587         initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
1588 
1589         // Configure UdfpsView to not accept the ACTION_DOWN event
1590         when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
1591         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(false);
1592 
1593         // GIVEN that the alternate bouncer is showing and a11y touch exploration NOT enabled
1594         when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
1595         when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
1596         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
1597                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
1598         mFgExecutor.runAllReady();
1599 
1600         verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
1601 
1602         // WHEN ACTION_DOWN is received and touch is not within sensor
1603         when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
1604                 processorResultUnchanged);
1605         MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
1606         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
1607         mBiometricExecutor.runAllReady();
1608         downEvent.recycle();
1609 
1610         // THEN the touch is pilfered
1611         verify(mInputManager).pilferPointers(any());
1612     }
1613 
1614     @Test
onTouch_withNewTouchDetection_qsDrag_processesTouchWhenAlternateBouncerVisible()1615     public void onTouch_withNewTouchDetection_qsDrag_processesTouchWhenAlternateBouncerVisible()
1616             throws RemoteException {
1617         final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
1618                 0L);
1619         final TouchProcessorResult processorResultMove =
1620                 new TouchProcessorResult.ProcessedTouch(InteractionEvent.DOWN,
1621                         1 /* pointerId */, touchData);
1622 
1623         // Enable new touch detection.
1624         when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true);
1625 
1626         // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
1627         initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
1628 
1629         // Configure UdfpsView to accept the ACTION_MOVE event
1630         when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
1631         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
1632 
1633         // GIVEN that the alternate bouncer is showing and a11y touch exploration NOT enabled
1634         when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
1635         when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
1636         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
1637                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
1638         mFgExecutor.runAllReady();
1639 
1640         verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
1641 
1642         // GIVEN swipe down for QS
1643         when(mPrimaryBouncerInteractor.isInTransit()).thenReturn(false);
1644         when(mLockscreenShadeTransitionController.getQSDragProgress()).thenReturn(1f);
1645 
1646         // WHEN ACTION_MOVE is received and touch is within sensor
1647         when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
1648                 processorResultMove);
1649         MotionEvent moveEvent = MotionEvent.obtain(0, 0, ACTION_MOVE, 0, 0, 0);
1650         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
1651         mBiometricExecutor.runAllReady();
1652         moveEvent.recycle();
1653 
1654         // THEN the touch is still processed
1655         verify(mFingerprintManager).onPointerDown(anyLong(), anyInt(), anyInt(),
1656                 anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(),
1657                 anyBoolean());
1658     }
1659 
1660     @Test
onAodInterrupt_onAcquiredGood_fingerNoLongerDown()1661     public void onAodInterrupt_onAcquiredGood_fingerNoLongerDown() throws RemoteException {
1662         // GIVEN UDFPS overlay is showing
1663         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
1664                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
1665         mFgExecutor.runAllReady();
1666 
1667         // GIVEN there's been an AoD interrupt
1668         when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
1669         mScreenObserver.onScreenTurnedOn();
1670         mUdfpsController.onAodInterrupt(0, 0, 0, 0);
1671 
1672         // THEN finger is considered down
1673         assertTrue(mUdfpsController.isFingerDown());
1674 
1675         // WHEN udfps receives an ACQUIRED_GOOD after the display is configured
1676         when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
1677         verify(mFingerprintManager).setUdfpsOverlayController(
1678                 mUdfpsOverlayControllerCaptor.capture());
1679         mUdfpsOverlayControllerCaptor.getValue().onAcquired(0, FINGERPRINT_ACQUIRED_GOOD);
1680         mFgExecutor.runAllReady();
1681 
1682         // THEN is fingerDown should be FALSE
1683         assertFalse(mUdfpsController.isFingerDown());
1684     }
1685 
1686     @Test
playHaptic_onAodInterrupt_oneWayHapticsDisabled_onAcquiredBad_usesVibrate()1687     public void playHaptic_onAodInterrupt_oneWayHapticsDisabled_onAcquiredBad_usesVibrate()
1688             throws RemoteException {
1689         // GIVEN UDFPS overlay is showing
1690         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
1691                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
1692         mFgExecutor.runAllReady();
1693 
1694         // GIVEN there's been an AoD interrupt
1695         when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(false);
1696         mScreenObserver.onScreenTurnedOn();
1697         mUdfpsController.onAodInterrupt(0, 0, 0, 0);
1698 
1699         // THEN vibrate is used
1700         verify(mVibrator).vibrate(
1701                 anyInt(),
1702                 anyString(),
1703                 eq(UdfpsController.EFFECT_CLICK),
1704                 eq("aod-lock-icon-longpress"),
1705                 eq(UdfpsController.LOCK_ICON_VIBRATION_ATTRIBUTES)
1706         );
1707     }
1708 
1709     @Test
playHaptic_onAodInterrupt_oneWayHapticsEnabled_onAcquiredBad_performHapticFeedback()1710     public void playHaptic_onAodInterrupt_oneWayHapticsEnabled_onAcquiredBad_performHapticFeedback()
1711             throws RemoteException {
1712         when(mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)).thenReturn(true);
1713         // GIVEN UDFPS overlay is showing
1714         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
1715                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
1716         mFgExecutor.runAllReady();
1717 
1718         // GIVEN there's been an AoD interrupt
1719         when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(false);
1720         mScreenObserver.onScreenTurnedOn();
1721         mUdfpsController.onAodInterrupt(0, 0, 0, 0);
1722 
1723         // THEN vibrate is used
1724         verify(mVibrator).performHapticFeedback(any(), eq(UdfpsController.LONG_PRESS));
1725     }
1726 
1727     @Test
aodInterrupt_withNewTouchDetection()1728     public void aodInterrupt_withNewTouchDetection() throws RemoteException {
1729         mUdfpsController.cancelAodSendFingerUpAction();
1730         final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
1731                 0L);
1732         final TouchProcessorResult processorResultDown =
1733                 new TouchProcessorResult.ProcessedTouch(InteractionEvent.DOWN,
1734                         1 /* pointerId */, touchData);
1735 
1736         // Enable new touch detection.
1737         when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true);
1738 
1739         // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
1740         initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
1741 
1742         // GIVEN that the overlay is showing and screen is on and fp is running
1743         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, 0,
1744                 BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
1745         mScreenObserver.onScreenTurnedOn();
1746         mFgExecutor.runAllReady();
1747 
1748         // WHEN fingerprint is requested because of AOD interrupt
1749         mUdfpsController.onAodInterrupt(0, 0, 2f, 3f);
1750 
1751         // Check case where touch driver sends touch to UdfpsView as well
1752         verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
1753         when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
1754         when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
1755                 processorResultDown);
1756         MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
1757         mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
1758 
1759         mBiometricExecutor.runAllReady();
1760 
1761         // THEN only one onPointerDown is sent
1762         verify(mFingerprintManager).onPointerDown(anyLong(), anyInt(), anyInt(), anyFloat(),
1763                 anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(), anyBoolean());
1764     }
1765 }
1766