summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Austin Delgado <austindelgado@google.com> 2023-02-02 10:18:40 -0800
committer Austin Delgado <austindelgado@google.com> 2023-03-07 15:13:19 -0800
commitc95ced466b1610f4b01936c152cc65339986ba1c (patch)
tree47ace0147e2e6a7fcf61263a168a28b4ed5969fc
parent04884f21453d96beb63be8b38a1e603c5c0a654e (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
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt71
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java38
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt116
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java4
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