diff options
| author | 2023-02-02 10:18:40 -0800 | |
|---|---|---|
| committer | 2023-03-07 15:13:19 -0800 | |
| commit | c95ced466b1610f4b01936c152cc65339986ba1c (patch) | |
| tree | 47ace0147e2e6a7fcf61263a168a28b4ed5969fc | |
| parent | 04884f21453d96beb63be8b38a1e603c5c0a654e (diff) | |
Prevent alternateBouncer from consuming touches in new UdfpsOverlay
UdfpsController now passes UdfpsOverlayParams to
AlternateBouncerInteractor to allow the
NotificationShadeWIndowViewController to check if a touch is within the
UdfpsOverlay bounds before intercepting the touch.
UdfpsController sends the touch back if it's not being used for
authentication.
Bug: 267487141
Bug: 269788322
Test: atest SystemUITests:com.android.systemui.biometrics
Change-Id: Ie6f253365210bb5262008a1dad154bc8212f4500
11 files changed, 276 insertions, 17 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index bfd99d355a2a..1ae380e53c52 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -51,6 +51,7 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; +import com.android.settingslib.udfps.UdfpsOverlayParams; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.biometrics.AuthController; @@ -778,7 +779,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme } @Override - public void onUdfpsLocationChanged() { + public void onUdfpsLocationChanged(UdfpsOverlayParams udfpsOverlayParams) { updateUdfpsConfig(); } }; diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 08efd89029ed..c31d45ff0b83 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -148,6 +148,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, @NonNull private final WindowManager mWindowManager; @NonNull private final DisplayManager mDisplayManager; @Nullable private UdfpsController mUdfpsController; + @Nullable private UdfpsOverlayParams mUdfpsOverlayParams; @Nullable private IUdfpsRefreshRateRequestCallback mUdfpsRefreshRateRequestCallback; @Nullable private SideFpsController mSideFpsController; @Nullable private UdfpsLogger mUdfpsLogger; @@ -806,6 +807,8 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, final FingerprintSensorPropertiesInternal udfpsProp = mUdfpsProps.get(0); final Rect previousUdfpsBounds = mUdfpsBounds; + final UdfpsOverlayParams previousUdfpsOverlayParams = mUdfpsOverlayParams; + mUdfpsBounds = udfpsProp.getLocation().getRect(); mUdfpsBounds.scale(mScaleFactor); @@ -815,7 +818,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, mCachedDisplayInfo.getNaturalWidth(), /* right */ mCachedDisplayInfo.getNaturalHeight() /* botom */); - final UdfpsOverlayParams overlayParams = new UdfpsOverlayParams( + mUdfpsOverlayParams = new UdfpsOverlayParams( mUdfpsBounds, overlayBounds, mCachedDisplayInfo.getNaturalWidth(), @@ -823,10 +826,11 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, mScaleFactor, mCachedDisplayInfo.rotation); - mUdfpsController.updateOverlayParams(udfpsProp, overlayParams); - if (!Objects.equals(previousUdfpsBounds, mUdfpsBounds)) { + mUdfpsController.updateOverlayParams(udfpsProp, mUdfpsOverlayParams); + if (!Objects.equals(previousUdfpsBounds, mUdfpsBounds) || !Objects.equals( + previousUdfpsOverlayParams, mUdfpsOverlayParams)) { for (Callback cb : mCallbacks) { - cb.onUdfpsLocationChanged(); + cb.onUdfpsLocationChanged(mUdfpsOverlayParams); } } } @@ -1336,7 +1340,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, * On devices with UDFPS, this is always called alongside * {@link #onFingerprintLocationChanged}. */ - default void onUdfpsLocationChanged() {} + default void onUdfpsLocationChanged(UdfpsOverlayParams udfpsOverlayParams) {} /** * Called when the location of the face unlock sensor (typically the front facing camera) diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt index 93b57dc127dd..fbb6451973c7 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt @@ -28,6 +28,7 @@ import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.keyguard.logging.KeyguardLogger import com.android.settingslib.Utils +import com.android.settingslib.udfps.UdfpsOverlayParams import com.android.systemui.R import com.android.systemui.animation.Interpolators import com.android.systemui.flags.FeatureFlags @@ -326,7 +327,7 @@ class AuthRippleController @Inject constructor( updateUdfpsDependentParams() } - override fun onUdfpsLocationChanged() { + override fun onUdfpsLocationChanged(udfpsOverlayParams: UdfpsOverlayParams) { updateUdfpsDependentParams() } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index 9e8326400e13..bb35355ba03a 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -100,6 +100,8 @@ import com.android.systemui.util.concurrency.Execution; import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.util.time.SystemClock; +import kotlin.Unit; + import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashSet; @@ -110,8 +112,6 @@ import java.util.concurrent.Executor; import javax.inject.Inject; import javax.inject.Provider; -import kotlin.Unit; - /** * Shows and hides the under-display fingerprint sensor (UDFPS) overlay, handles UDFPS touch events, * and toggles the UDFPS display mode. @@ -598,14 +598,20 @@ public class UdfpsController implements DozeReceiver, Dumpable { mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION); break; + case UNCHANGED: + if (!isWithinSensorArea(mOverlay.getOverlayView(), event.getX(), event.getY(), + true) && mActivePointerId == MotionEvent.INVALID_POINTER_ID + && event.getActionMasked() == MotionEvent.ACTION_DOWN + && mAlternateBouncerInteractor.isVisibleState()) { + // No pointer on sensor, forward to keyguard if alternateBouncer is visible + mKeyguardViewManager.onTouch(event); + } + default: break; } logBiometricTouch(processedTouch.getEvent(), data); - // We should only consume touches that are within the sensor. By returning "false" for - // touches outside of the sensor, we let other UI components consume these events and act on - // them appropriately. return processedTouch.getTouchData().isWithinSensor(mOverlayParams.getNativeSensorBounds()); } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt new file mode 100644 index 000000000000..92a7094c22bf --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.biometrics.domain.interactor + +import android.view.MotionEvent +import com.android.keyguard.KeyguardUpdateMonitor +import com.android.settingslib.udfps.UdfpsOverlayParams +import com.android.systemui.biometrics.AuthController +import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging +import com.android.systemui.common.coroutine.ConflatedCallbackFlow +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.stateIn + +/** Encapsulates business logic for interacting with the UDFPS overlay. */ +@SysUISingleton +class UdfpsOverlayInteractor +@Inject +constructor(private val authController: AuthController, @Application scope: CoroutineScope) { + + /** Whether a touch should be intercepted or allowed to pass to the UdfpsOverlay */ + fun canInterceptTouchInUdfpsBounds(ev: MotionEvent): Boolean { + val isUdfpsEnrolled = authController.isUdfpsEnrolled(KeyguardUpdateMonitor.getCurrentUser()) + val isWithinUdfpsOverlayBounds = + udfpsOverlayParams.value.overlayBounds.contains(ev.rawX.toInt(), ev.rawY.toInt()) + return !isUdfpsEnrolled || !isWithinUdfpsOverlayBounds + } + + /** Returns the current udfpsOverlayParams */ + val udfpsOverlayParams: StateFlow<UdfpsOverlayParams> = + ConflatedCallbackFlow.conflatedCallbackFlow { + val callback = + object : AuthController.Callback { + override fun onUdfpsLocationChanged( + udfpsOverlayParams: UdfpsOverlayParams + ) { + trySendWithFailureLogging( + udfpsOverlayParams, + TAG, + "update udfpsOverlayParams" + ) + } + } + authController.addCallback(callback) + awaitClose { authController.removeCallback(callback) } + } + .stateIn(scope, started = SharingStarted.Eagerly, initialValue = UdfpsOverlayParams()) + + companion object { + private const val TAG = "UdfpsOverlayInteractor" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java index c130b3913b64..c09524bac613 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java @@ -36,6 +36,7 @@ import com.android.keyguard.AuthKeyguardMessageArea; import com.android.keyguard.LockIconViewController; import com.android.keyguard.dagger.KeyguardBouncerComponent; import com.android.systemui.R; +import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.dock.DockManager; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; @@ -86,7 +87,7 @@ public class NotificationShadeWindowViewController { private final PulsingGestureListener mPulsingGestureListener; private final NotificationInsetsController mNotificationInsetsController; private final AlternateBouncerInteractor mAlternateBouncerInteractor; - + private final UdfpsOverlayInteractor mUdfpsOverlayInteractor; private GestureDetector mPulsingWakeupGestureHandler; private View mBrightnessMirror; private boolean mTouchActive; @@ -134,6 +135,7 @@ public class NotificationShadeWindowViewController { KeyguardBouncerViewModel keyguardBouncerViewModel, KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory, AlternateBouncerInteractor alternateBouncerInteractor, + UdfpsOverlayInteractor udfpsOverlayInteractor, KeyguardTransitionInteractor keyguardTransitionInteractor, PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel ) { @@ -156,6 +158,7 @@ public class NotificationShadeWindowViewController { mPulsingGestureListener = pulsingGestureListener; mNotificationInsetsController = notificationInsetsController; mAlternateBouncerInteractor = alternateBouncerInteractor; + mUdfpsOverlayInteractor = udfpsOverlayInteractor; // This view is not part of the newly inflated expanded status bar. mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container); @@ -240,7 +243,6 @@ public class NotificationShadeWindowViewController { mFalsingCollector.onTouchEvent(ev); mPulsingWakeupGestureHandler.onTouchEvent(ev); - mStatusBarKeyguardViewManager.onTouch(ev); if (mBrightnessMirror != null && mBrightnessMirror.getVisibility() == View.VISIBLE) { // Disallow new pointers while the brightness mirror is visible. This is so that @@ -316,8 +318,8 @@ public class NotificationShadeWindowViewController { } if (mAlternateBouncerInteractor.isVisibleState()) { - // capture all touches if the alt auth bouncer is showing - return true; + // If using UDFPS, don't intercept touches that are within its overlay bounds + return mUdfpsOverlayInteractor.canInterceptTouchInUdfpsBounds(ev); } if (mLockIconViewController.onInterceptTouchEvent(ev)) { @@ -355,6 +357,7 @@ public class NotificationShadeWindowViewController { if (mAlternateBouncerInteractor.isVisibleState()) { // eat the touch + mStatusBarKeyguardViewManager.onTouch(ev); handled = true; } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java index f370ad6dc298..33f0ae5563f7 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java @@ -36,6 +36,7 @@ import android.util.Pair; import androidx.test.filters.SmallTest; +import com.android.settingslib.udfps.UdfpsOverlayParams; import com.android.systemui.doze.util.BurnInHelperKt; import org.junit.Test; @@ -107,7 +108,7 @@ public class LockIconViewControllerTest extends LockIconViewControllerBaseTest { Pair<Float, Point> udfps = setupUdfps(); // WHEN udfps location changes - mAuthControllerCallback.onUdfpsLocationChanged(); + mAuthControllerCallback.onUdfpsLocationChanged(new UdfpsOverlayParams()); mDelayableExecutor.runAllReady(); // THEN lock icon view location is updated with the same coordinates as auth controller vals diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index 05266f1894ac..9a73898ca7c7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -1224,6 +1224,44 @@ public class UdfpsControllerTest extends SysuiTestCase { } @Test + public void onTouch_WithNewTouchDetection_forwardToKeyguard() throws RemoteException { + final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L, + 0L); + final TouchProcessorResult processorResultDown = new TouchProcessorResult.ProcessedTouch( + InteractionEvent.UNCHANGED, -1 /* pointerOnSensorId */, touchData); + + // Enable new touch detection. + when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true); + + // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider. + initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */); + + // Configure UdfpsView to accept the ACTION_DOWN event + when(mUdfpsView.isDisplayConfigured()).thenReturn(false); + when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(false); + + // GIVEN that the overlay is showing and a11y touch exploration NOT enabled + when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true); + when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false); + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId, + BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback); + mFgExecutor.runAllReady(); + + verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture()); + + // WHEN ACTION_DOWN is received + when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn( + processorResultDown); + MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0); + mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent); + mBiometricExecutor.runAllReady(); + + // THEN the touch is forwarded to Keyguard + verify(mStatusBarKeyguardViewManager).onTouch(downEvent); + downEvent.recycle(); + } + + @Test public void onAodInterrupt_onAcquiredGood_fingerNoLongerDown() throws RemoteException { // GIVEN UDFPS overlay is showing mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId, diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt new file mode 100644 index 000000000000..87d5ae64dee8 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.biometrics.domain.interactor + +import android.graphics.Rect +import android.test.suitebuilder.annotation.SmallTest +import android.view.MotionEvent +import android.view.Surface +import com.android.settingslib.udfps.UdfpsOverlayParams +import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.AuthController +import com.android.systemui.coroutines.collectLastValue +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.Captor +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` as whenever +import org.mockito.junit.MockitoJUnit + +@SmallTest +@RunWith(JUnit4::class) +class UdfpsOverlayInteractorTest : SysuiTestCase() { + + @JvmField @Rule var mockitoRule = MockitoJUnit.rule() + + private lateinit var testScope: TestScope + + @Mock private lateinit var authController: AuthController + @Captor private lateinit var authControllerCallback: ArgumentCaptor<AuthController.Callback> + + @Mock private lateinit var udfpsOverlayParams: UdfpsOverlayParams + @Mock private lateinit var overlayBounds: Rect + + private lateinit var underTest: UdfpsOverlayInteractor + + @Before + fun setUp() { + testScope = TestScope(StandardTestDispatcher()) + } + + @Test + fun testShouldInterceptTouch() = + testScope.runTest { + createUdpfsOverlayInteractor() + + // When fingerprint enrolled and touch is within bounds + verify(authController).addCallback(authControllerCallback.capture()) + authControllerCallback.value.onUdfpsLocationChanged(udfpsOverlayParams) + whenever(authController.isUdfpsEnrolled(anyInt())).thenReturn(true) + whenever(udfpsOverlayParams.overlayBounds).thenReturn(overlayBounds) + whenever(overlayBounds.contains(downEv.x.toInt(), downEv.y.toInt())).thenReturn(true) + + runCurrent() + + // Then touch should not be intercepted + val canInterceptTrue = underTest.canInterceptTouchInUdfpsBounds(downEv) + assertThat(canInterceptTrue).isFalse() + + // When touch is outside of bounds + whenever(overlayBounds.contains(downEv.x.toInt(), downEv.y.toInt())).thenReturn(false) + + // Then touch should be intercepted + val canInterceptFalse = underTest.canInterceptTouchInUdfpsBounds(downEv) + assertThat(canInterceptFalse).isTrue() + } + + @Test + fun testUdfpsOverlayParamsChange() = + testScope.runTest { + createUdpfsOverlayInteractor() + val udfpsOverlayParams = collectLastValue(underTest.udfpsOverlayParams) + runCurrent() + + verify(authController).addCallback(authControllerCallback.capture()) + + // When udfpsLocationChanges in authcontroller + authControllerCallback.value.onUdfpsLocationChanged(firstParams) + + // Then the value in the interactor should be updated + assertThat(udfpsOverlayParams()).isEqualTo(firstParams) + } + + private fun createUdpfsOverlayInteractor() { + underTest = UdfpsOverlayInteractor(authController, testScope.backgroundScope) + testScope.runCurrent() + } +} + +private val firstParams = + UdfpsOverlayParams(Rect(0, 0, 10, 10), Rect(0, 0, 10, 10), 1, 1, 1f, Surface.ROTATION_0) +private val downEv = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt index 82a57438052f..51492eb8e532 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt @@ -26,6 +26,7 @@ import com.android.keyguard.LockIconViewController import com.android.keyguard.dagger.KeyguardBouncerComponent import com.android.systemui.R import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor import com.android.systemui.classifier.FalsingCollectorFake import com.android.systemui.dock.DockManager import com.android.systemui.keyguard.KeyguardUnlockAnimationController @@ -86,6 +87,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { @Mock private lateinit var pulsingGestureListener: PulsingGestureListener @Mock private lateinit var notificationInsetsController: NotificationInsetsController @Mock private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor + @Mock private lateinit var udfpsOverlayInteractor: UdfpsOverlayInteractor @Mock lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory @Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent @Mock lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController @@ -133,6 +135,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { keyguardBouncerViewModel, keyguardBouncerComponentFactory, alternateBouncerInteractor, + udfpsOverlayInteractor, keyguardTransitionInteractor, primaryBouncerToGoneTransitionViewModel, ) @@ -265,6 +268,17 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { } @Test + fun shouldInterceptTouchEvent_downEventAlternateBouncer_ignoreIfInUdfpsOverlay() { + // Down event within udfpsOverlay bounds while alternateBouncer is showing + whenever(udfpsOverlayInteractor.canInterceptTouchInUdfpsBounds(downEv)).thenReturn(false) + whenever(alternateBouncerInteractor.isVisibleState()).thenReturn(true) + + // Then touch should not be intercepted + val shouldIntercept = interactionEventHandler.shouldInterceptTouchEvent(downEv) + assertThat(shouldIntercept).isFalse() + } + + @Test fun testGetBouncerContainer() { Mockito.clearInvocations(view) underTest.bouncerContainer diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java index faa6221b675c..2f528a86cc2d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java @@ -40,6 +40,7 @@ import com.android.keyguard.LockIconViewController; import com.android.keyguard.dagger.KeyguardBouncerComponent; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor; import com.android.systemui.classifier.FalsingCollectorFake; import com.android.systemui.dock.DockManager; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; @@ -101,6 +102,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { @Mock private KeyguardSecurityContainerController mKeyguardSecurityContainerController; @Mock private NotificationInsetsController mNotificationInsetsController; @Mock private AlternateBouncerInteractor mAlternateBouncerInteractor; + @Mock private UdfpsOverlayInteractor mUdfpsOverlayInteractor; @Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor; @Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel; @@ -152,6 +154,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { mKeyguardBouncerViewModel, mKeyguardBouncerComponentFactory, mAlternateBouncerInteractor, + mUdfpsOverlayInteractor, mKeyguardTransitionInteractor, mPrimaryBouncerToGoneTransitionViewModel ); @@ -177,6 +180,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { // WHEN showing alt auth, not dozing, drag down helper doesn't want to intercept when(mStatusBarStateController.isDozing()).thenReturn(false); when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true); + when(mUdfpsOverlayInteractor.canInterceptTouchInUdfpsBounds(any())).thenReturn(true); when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false); // THEN we should intercept touch |