diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt index 4cd40d2f186b3..2035781239994 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt @@ -15,9 +15,11 @@ */ package com.android.systemui.biometrics +import com.android.systemui.broadcast.BroadcastSender import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.phone.SystemUIDialogManager +import com.android.systemui.statusbar.phone.panelstate.PanelExpansionListener import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager /** @@ -28,6 +30,7 @@ class UdfpsBpViewController( statusBarStateController: StatusBarStateController, panelExpansionStateManager: PanelExpansionStateManager, systemUIDialogManager: SystemUIDialogManager, + val broadcastSender: BroadcastSender, dumpManager: DumpManager ) : UdfpsAnimationViewController( view, @@ -37,4 +40,29 @@ class UdfpsBpViewController( dumpManager ) { override val tag = "UdfpsBpViewController" + private val bpPanelExpansionListener = PanelExpansionListener { event -> + // Notification shade can be expanded but not visible (fraction: 0.0), for example + // when a heads-up notification (HUN) is showing. + notificationShadeVisible = event.expanded && event.fraction > 0f + view.onExpansionChanged(event.fraction) + cancelAuth() + } + + fun cancelAuth() { + if (shouldPauseAuth()) { + broadcastSender.closeSystemDialogs() + } + } + + override fun onViewAttached() { + super.onViewAttached() + + panelExpansionStateManager.addExpansionListener(bpPanelExpansionListener) + } + + override fun onViewDetached() { + super.onViewDetached() + + panelExpansionStateManager.removeExpansionListener(bpPanelExpansionListener) + } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index a35f0427e55a7..7657269643aa9 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -54,6 +54,7 @@ import com.android.internal.util.LatencyTracker; import com.android.keyguard.ActiveUnlockConfig; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.animation.ActivityLaunchAnimator; +import com.android.systemui.broadcast.BroadcastSender; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.doze.DozeReceiver; @@ -125,6 +126,7 @@ public class UdfpsController implements DozeReceiver { @NonNull private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController; @NonNull private final LatencyTracker mLatencyTracker; + @NonNull private final BroadcastSender mBroadcastSender; @VisibleForTesting @NonNull final BiometricDisplayListener mOrientationListener; @NonNull private final ActivityLaunchAnimator mActivityLaunchAnimator; @@ -205,7 +207,7 @@ public class UdfpsController implements DozeReceiver { mUnlockedScreenOffAnimationController, mHalControlsIllumination, mHbmProvider, requestId, reason, callback, (view, event, fromUdfpsView) -> onTouch(requestId, event, - fromUdfpsView), mActivityLaunchAnimator))); + fromUdfpsView), mActivityLaunchAnimator, mBroadcastSender))); } @Override @@ -574,7 +576,8 @@ public class UdfpsController implements DozeReceiver { @NonNull SystemUIDialogManager dialogManager, @NonNull LatencyTracker latencyTracker, @NonNull ActivityLaunchAnimator activityLaunchAnimator, - @NonNull Optional aternateTouchProvider) { + @NonNull Optional aternateTouchProvider, + @NonNull BroadcastSender broadcastSender) { mContext = context; mExecution = execution; mVibrator = vibrator; @@ -604,6 +607,7 @@ public class UdfpsController implements DozeReceiver { mLatencyTracker = latencyTracker; mActivityLaunchAnimator = activityLaunchAnimator; mAlternateTouchProvider = aternateTouchProvider.orElse(null); + mBroadcastSender = broadcastSender; mOrientationListener = new BiometricDisplayListener( context, diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt index 2d51c973b0b1d..faa93a5a2ad34 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt @@ -41,6 +41,7 @@ import androidx.annotation.LayoutRes import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.R import com.android.systemui.animation.ActivityLaunchAnimator +import com.android.systemui.broadcast.BroadcastSender import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.LockscreenShadeTransitionController @@ -83,7 +84,8 @@ class UdfpsControllerOverlay( @ShowReason val requestReason: Int, private val controllerCallback: IUdfpsOverlayControllerCallback, private val onTouch: (View, MotionEvent, Boolean) -> Boolean, - private val activityLaunchAnimator: ActivityLaunchAnimator + private val activityLaunchAnimator: ActivityLaunchAnimator, + private val broadcastSender: BroadcastSender ) { /** The view, when [isShowing], or null. */ var overlayView: UdfpsView? = null @@ -102,8 +104,8 @@ class UdfpsControllerOverlay( fitInsetsTypes = 0 gravity = android.view.Gravity.TOP or android.view.Gravity.LEFT layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS - flags = - (Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS or WindowManager.LayoutParams.FLAG_SPLIT_TOUCH) + flags = (Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS + or WindowManager.LayoutParams.FLAG_SPLIT_TOUCH) privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY // Avoid announcing window title. accessibilityTitle = " " @@ -221,6 +223,7 @@ class UdfpsControllerOverlay( statusBarStateController, panelExpansionStateManager, dialogManager, + broadcastSender, dumpManager ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt new file mode 100644 index 0000000000000..a52c4a3978b44 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2022 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 + +import android.app.Instrumentation +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import android.testing.ViewUtils +import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation +import com.android.internal.jank.InteractionJankMonitor +import com.android.internal.logging.testing.UiEventLoggerFake +import com.android.systemui.R +import com.android.systemui.SysuiTestCase +import com.android.systemui.broadcast.BroadcastSender +import com.android.systemui.dump.DumpManager +import com.android.systemui.statusbar.StatusBarStateControllerImpl +import com.android.systemui.statusbar.phone.SystemUIDialogManager +import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager +import com.android.systemui.util.mockito.any +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.spy +import org.mockito.Mockito.times +import org.mockito.Mockito.verify +import org.mockito.junit.MockitoJUnit + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper +class UdfpsBpViewControllerTest : SysuiTestCase() { + + @JvmField @Rule var rule = MockitoJUnit.rule() + + @Mock lateinit var dumpManager: DumpManager + @Mock lateinit var systemUIDialogManager: SystemUIDialogManager + @Mock lateinit var broadcastSender: BroadcastSender + @Mock lateinit var interactionJankMonitor: InteractionJankMonitor + @Mock lateinit var panelExpansionStateManager: PanelExpansionStateManager + + private lateinit var instrumentation: Instrumentation + private lateinit var uiEventLogger: UiEventLoggerFake + private lateinit var udfpsBpView: UdfpsBpView + private lateinit var statusBarStateController: StatusBarStateControllerImpl + private lateinit var udfpsBpViewController: UdfpsBpViewController + + @Before + fun setup() { + instrumentation = getInstrumentation() + instrumentation.runOnMainSync { createUdfpsView() } + instrumentation.waitForIdleSync() + + uiEventLogger = UiEventLoggerFake() + statusBarStateController = + StatusBarStateControllerImpl(uiEventLogger, dumpManager, interactionJankMonitor) + udfpsBpViewController = UdfpsBpViewController( + udfpsBpView, + statusBarStateController, + panelExpansionStateManager, + systemUIDialogManager, + broadcastSender, + dumpManager) + udfpsBpViewController.init() + } + + @After + fun tearDown() { + if (udfpsBpViewController.isAttachedToWindow) { + instrumentation.runOnMainSync { ViewUtils.detachView(udfpsBpView) } + instrumentation.waitForIdleSync() + } + } + + private fun createUdfpsView() { + context.setTheme(R.style.Theme_AppCompat) + context.orCreateTestableResources.addOverride( + com.android.internal.R.integer.config_udfps_illumination_transition_ms, 0) + udfpsBpView = UdfpsBpView(context, null) + } + + @Test + fun addExpansionListener() { + instrumentation.runOnMainSync { ViewUtils.attachView(udfpsBpView) } + instrumentation.waitForIdleSync() + + // Both UdfpsBpViewController & UdfpsAnimationViewController add listener + verify(panelExpansionStateManager, times(2)).addExpansionListener(any()) + } + + @Test + fun removeExpansionListener() { + instrumentation.runOnMainSync { ViewUtils.attachView(udfpsBpView) } + instrumentation.waitForIdleSync() + instrumentation.runOnMainSync { ViewUtils.detachView(udfpsBpView) } + instrumentation.waitForIdleSync() + + // Both UdfpsBpViewController & UdfpsAnimationViewController remove listener + verify(panelExpansionStateManager, times(2)).removeExpansionListener(any()) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt index fc5ccbcb4a765..6eba2154e46ce 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt @@ -40,6 +40,7 @@ import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.animation.ActivityLaunchAnimator +import com.android.systemui.broadcast.BroadcastSender import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.LockscreenShadeTransitionController @@ -102,6 +103,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { @Mock private lateinit var udfpsView: UdfpsView @Mock private lateinit var udfpsEnrollView: UdfpsEnrollView @Mock private lateinit var activityLaunchAnimator: ActivityLaunchAnimator + @Mock private lateinit var broadcastSender: BroadcastSender @Captor private lateinit var layoutParamsCaptor: ArgumentCaptor private val onTouch = { _: View, _: MotionEvent, _: Boolean -> true } @@ -131,7 +133,8 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { keyguardUpdateMonitor, dialogManager, dumpManager, transitionController, configurationController, systemClock, keyguardStateController, unlockedScreenOffAnimationController, HAL_CONTROLS_ILLUMINATION, hbmProvider, - REQUEST_ID, reason, controllerCallback, onTouch, activityLaunchAnimator) + REQUEST_ID, reason, controllerCallback, onTouch, activityLaunchAnimator, + broadcastSender) block() } 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 87d3cd0cf0a01..290965c33509f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -66,6 +66,7 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.animation.ActivityLaunchAnimator; +import com.android.systemui.broadcast.BroadcastSender; import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.plugins.FalsingManager; @@ -186,6 +187,8 @@ public class UdfpsControllerTest extends SysuiTestCase { private ActivityLaunchAnimator mActivityLaunchAnimator; @Mock private AlternateUdfpsTouchProvider mAlternateTouchProvider; + @Mock + private BroadcastSender mBroadcastSender; // Capture listeners so that they can be used to send events @Captor private ArgumentCaptor mOverlayCaptor; @@ -261,7 +264,8 @@ public class UdfpsControllerTest extends SysuiTestCase { mSystemUIDialogManager, mLatencyTracker, mActivityLaunchAnimator, - Optional.of(mAlternateTouchProvider)); + Optional.of(mAlternateTouchProvider), + mBroadcastSender); verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture()); mOverlayController = mOverlayCaptor.getValue(); verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());