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