diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index eec788b7add8b..f164e7d336428 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -492,12 +492,14 @@ public class KeyguardSecurityContainer extends ConstraintLayout { case MotionEvent.ACTION_MOVE: mVelocityTracker.addMovement(event); int pointerIndex = event.findPointerIndex(mActivePointerId); - float y = event.getY(pointerIndex); - if (mLastTouchY != -1) { - float dy = y - mLastTouchY; - setTranslationY(getTranslationY() + dy * TOUCH_Y_MULTIPLIER); + if (pointerIndex != -1) { + float y = event.getY(pointerIndex); + if (mLastTouchY != -1) { + float dy = y - mLastTouchY; + setTranslationY(getTranslationY() + dy * TOUCH_Y_MULTIPLIER); + } + mLastTouchY = y; } - mLastTouchY = y; break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 23f887ef00169..f1abdc68f97ea 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -17,7 +17,6 @@ package com.android.keyguard; import static android.app.StatusBarManager.SESSION_KEYGUARD; -import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT; import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_BIOMETRIC; import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_EXTENDED_ACCESS; @@ -36,7 +35,6 @@ import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; import android.hardware.biometrics.BiometricOverlayConstants; -import android.hardware.biometrics.BiometricSourceType; import android.media.AudioManager; import android.metrics.LogMaker; import android.os.SystemClock; @@ -321,7 +319,6 @@ public class KeyguardSecurityContainerController extends ViewController = repository.keyguardAuthenticated.filterNotNull() - val screenTurnedOff: Flow = repository.onScreenTurnedOff.filter { it }.map {} val show: Flow = repository.primaryBouncerShow.filterNotNull() val hide: Flow = repository.primaryBouncerHide.filter { it }.map {} val startingToHide: Flow = repository.primaryBouncerStartingToHide.filter { it }.map {} @@ -113,6 +118,24 @@ constructor( } /** Allow for interaction when just about fully visible */ val isInteractable: Flow = bouncerExpansion.map { it > 0.9 } + val sideFpsShowing: Flow = repository.sideFpsShowing + + init { + keyguardUpdateMonitor.registerCallback( + object : KeyguardUpdateMonitorCallback() { + override fun onBiometricRunningStateChanged( + running: Boolean, + biometricSourceType: BiometricSourceType? + ) { + updateSideFpsVisibility() + } + + override fun onStrongAuthStateChanged(userId: Int) { + updateSideFpsVisibility() + } + } + ) + } // TODO(b/243685699): Move isScrimmed logic to data layer. // TODO(b/243695312): Encapsulate all of the show logic for the bouncer. @@ -120,7 +143,6 @@ constructor( @JvmOverloads fun show(isScrimmed: Boolean) { // Reset some states as we show the bouncer. - repository.setOnScreenTurnedOff(false) repository.setKeyguardAuthenticated(null) repository.setPrimaryHide(false) repository.setPrimaryStartingToHide(false) @@ -254,11 +276,6 @@ constructor( repository.setKeyguardAuthenticated(strongAuth) } - /** Tell the bouncer the screen has turned off. */ - fun onScreenTurnedOff() { - repository.setOnScreenTurnedOff(true) - } - /** Update the position of the bouncer when showing. */ fun setKeyguardPosition(position: Float) { repository.setKeyguardPosition(position) @@ -293,6 +310,35 @@ constructor( repository.setPrimaryStartDisappearAnimation(finishRunnable) } + /** Determine whether to show the side fps animation. */ + fun updateSideFpsVisibility() { + val sfpsEnabled: Boolean = + context.resources.getBoolean(R.bool.config_show_sidefps_hint_on_bouncer) + val fpsDetectionRunning: Boolean = keyguardUpdateMonitor.isFingerprintDetectionRunning + val isUnlockingWithFpAllowed: Boolean = + keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed + val bouncerVisible = repository.primaryBouncerVisible.value + val toShow = + (repository.primaryBouncerVisible.value && + sfpsEnabled && + fpsDetectionRunning && + isUnlockingWithFpAllowed && + !isAnimatingAway()) + + if (KeyguardConstants.DEBUG) { + Log.d( + TAG, + ("sideFpsToShow=$toShow\n" + + "bouncerVisible=$bouncerVisible\n" + + "configEnabled=$sfpsEnabled\n" + + "fpsDetectionRunning=$fpsDetectionRunning\n" + + "isUnlockingWithFpAllowed=$isUnlockingWithFpAllowed\n" + + "isAnimatingAway=${isAnimatingAway()}") + ) + } + repository.setSideFpsShowing(toShow) + } + /** Returns whether bouncer is fully showing. */ fun isFullyShowing(): Boolean { return (repository.primaryBouncerShowingSoon.value || @@ -336,4 +382,8 @@ constructor( DejankUtils.removeCallbacks(showRunnable) mainHandler.removeCallbacks(showRunnable) } + + companion object { + private const val TAG = "PrimaryBouncerInteractor" + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt index 56f911f8b1da1..7db567b2a0e93 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt @@ -34,6 +34,7 @@ import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.plugins.ActivityStarter import kotlinx.coroutines.awaitCancellation +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch @@ -121,7 +122,6 @@ object KeyguardBouncerViewBinder { launch { viewModel.hide.collect { securityContainerController.cancelDismissAction() - securityContainerController.onPause() securityContainerController.reset() } } @@ -155,12 +155,17 @@ object KeyguardBouncerViewBinder { launch { viewModel.isBouncerVisible.collect { isVisible -> - val visibility = if (isVisible) View.VISIBLE else View.INVISIBLE - view.visibility = visibility - securityContainerController.onBouncerVisibilityChanged(visibility) + view.visibility = if (isVisible) View.VISIBLE else View.INVISIBLE + securityContainerController.onBouncerVisibilityChanged(isVisible) } } + launch { + viewModel.isBouncerVisible + .filter { !it } + .collect { securityContainerController.onPause() } + } + launch { viewModel.isInteractable.collect { isInteractable -> securityContainerController.setInteractable(isInteractable) @@ -204,10 +209,14 @@ object KeyguardBouncerViewBinder { } launch { - viewModel.screenTurnedOff.collect { - if (view.visibility == View.VISIBLE) { - securityContainerController.onPause() - } + viewModel.shouldUpdateSideFps.collect { + viewModel.updateSideFpsVisibility() + } + } + + launch { + viewModel.sideFpsShowing.collect { + securityContainerController.updateSideFpsVisibility(it) } } awaitCancellation() diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt index b8b3a8e5db204..97e94d8f3232f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt @@ -24,7 +24,9 @@ import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel import com.android.systemui.keyguard.shared.model.KeyguardBouncerModel import javax.inject.Inject import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.merge /** Models UI state for the lock screen bouncer; handles user input. */ class KeyguardBouncerViewModel @@ -66,8 +68,16 @@ constructor( /** Observe whether keyguard is authenticated already. */ val keyguardAuthenticated: Flow = interactor.keyguardAuthenticated - /** Observe whether screen is turned off. */ - val screenTurnedOff: Flow = interactor.screenTurnedOff + /** Observe whether the side fps is showing. */ + val sideFpsShowing: Flow = interactor.sideFpsShowing + + /** Observe whether we should update fps is showing. */ + val shouldUpdateSideFps: Flow = + merge( + interactor.startingToHide, + interactor.isVisible.map {}, + interactor.startingDisappearAnimation.filterNotNull().map {} + ) /** Observe whether we want to update resources. */ fun notifyUpdateResources() { @@ -84,6 +94,10 @@ constructor( interactor.onMessageShown() } + fun updateSideFpsVisibility() { + interactor.updateSideFpsVisibility() + } + /** Observe whether back button is enabled. */ fun observeOnIsBackButtonEnabled(systemUiVisibility: () -> Int): Flow { return interactor.isBackButtonEnabled.map { enabled -> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index b1152333b5e1a..183790d123fd3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -790,7 +790,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public void onFinishedGoingToSleep() { - mPrimaryBouncerInteractor.onScreenTurnedOff(); + mPrimaryBouncerInteractor.hide(); } @Override diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java index 568e8d20cd763..064bc9c0036d3 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java @@ -32,11 +32,9 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -44,7 +42,6 @@ import static org.mockito.Mockito.when; import android.content.res.Configuration; import android.content.res.Resources; import android.hardware.biometrics.BiometricOverlayConstants; -import android.hardware.biometrics.BiometricSourceType; import android.media.AudioManager; import android.telephony.TelephonyManager; import android.testing.AndroidTestingRunner; @@ -53,7 +50,6 @@ import android.testing.TestableResources; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; -import android.view.View; import android.view.WindowInsetsController; import android.widget.FrameLayout; @@ -96,10 +92,8 @@ import java.util.Optional; @TestableLooper.RunWithLooper() public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { private static final int TARGET_USER_ID = 100; - @Rule public MockitoRule mRule = MockitoJUnit.rule(); - @Mock private KeyguardSecurityContainer mView; @Mock @@ -367,134 +361,12 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { .removeUserSwitchCallback(any(UserSwitcherController.UserSwitchCallback.class)); } - @Test - public void onBouncerVisibilityChanged_allConditionsGood_sideFpsHintShown() { - setupConditionsToEnableSideFpsHint(); - reset(mSideFpsController); - - mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); - - verify(mSideFpsController).show(SideFpsUiRequestSource.PRIMARY_BOUNCER, - BiometricOverlayConstants.REASON_AUTH_KEYGUARD); - verify(mSideFpsController, never()).hide(any()); - } - - @Test - public void onBouncerVisibilityChanged_fpsSensorNotRunning_sideFpsHintHidden() { - setupConditionsToEnableSideFpsHint(); - setFingerprintDetectionRunning(false); - reset(mSideFpsController); - - mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); - - verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); - verify(mSideFpsController, never()).show(any(), anyInt()); - } - - @Test - public void onBouncerVisibilityChanged_withoutSidedSecurity_sideFpsHintHidden() { - setupConditionsToEnableSideFpsHint(); - setSideFpsHintEnabledFromResources(false); - reset(mSideFpsController); - - mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); - - verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); - verify(mSideFpsController, never()).show(any(), anyInt()); - } - - @Test - public void onBouncerVisibilityChanged_unlockingWithFingerprintNotAllowed_sideFpsHintHidden() { - setupConditionsToEnableSideFpsHint(); - setUnlockingWithFingerprintAllowed(false); - reset(mSideFpsController); - - mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); - - verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); - verify(mSideFpsController, never()).show(any(), anyInt()); - } - - @Test - public void onBouncerVisibilityChanged_sideFpsHintShown_sideFpsHintHidden() { - setupGetSecurityView(); - setupConditionsToEnableSideFpsHint(); - mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); - verify(mSideFpsController, atLeastOnce()).show(SideFpsUiRequestSource.PRIMARY_BOUNCER, - BiometricOverlayConstants.REASON_AUTH_KEYGUARD); - reset(mSideFpsController); - - mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.INVISIBLE); - - verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); - verify(mSideFpsController, never()).show(any(), anyInt()); - } - @Test public void onBouncerVisibilityChanged_resetsScale() { - mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.INVISIBLE); - + mKeyguardSecurityContainerController.onBouncerVisibilityChanged(false); verify(mView).resetScale(); } - @Test - public void onStartingToHide_sideFpsHintShown_sideFpsHintHidden() { - setupGetSecurityView(); - setupConditionsToEnableSideFpsHint(); - mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); - verify(mSideFpsController, atLeastOnce()).show(SideFpsUiRequestSource.PRIMARY_BOUNCER, - BiometricOverlayConstants.REASON_AUTH_KEYGUARD); - reset(mSideFpsController); - - mKeyguardSecurityContainerController.onStartingToHide(); - - verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); - verify(mSideFpsController, never()).show(any(), anyInt()); - } - - @Test - public void onPause_sideFpsHintShown_sideFpsHintHidden() { - setupGetSecurityView(); - setupConditionsToEnableSideFpsHint(); - mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); - verify(mSideFpsController, atLeastOnce()).show(SideFpsUiRequestSource.PRIMARY_BOUNCER, - BiometricOverlayConstants.REASON_AUTH_KEYGUARD); - reset(mSideFpsController); - - mKeyguardSecurityContainerController.onPause(); - - verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); - verify(mSideFpsController, never()).show(any(), anyInt()); - } - - @Test - public void onResume_sideFpsHintShouldBeShown_sideFpsHintShown() { - setupGetSecurityView(); - setupConditionsToEnableSideFpsHint(); - mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); - reset(mSideFpsController); - - mKeyguardSecurityContainerController.onResume(0); - - verify(mSideFpsController).show(SideFpsUiRequestSource.PRIMARY_BOUNCER, - BiometricOverlayConstants.REASON_AUTH_KEYGUARD); - verify(mSideFpsController, never()).hide(any()); - } - - @Test - public void onResume_sideFpsHintShouldNotBeShown_sideFpsHintHidden() { - setupGetSecurityView(); - setupConditionsToEnableSideFpsHint(); - setSideFpsHintEnabledFromResources(false); - mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); - reset(mSideFpsController); - - mKeyguardSecurityContainerController.onResume(0); - - verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); - verify(mSideFpsController, never()).show(any(), anyInt()); - } - @Test public void showNextSecurityScreenOrFinish_setsSecurityScreenToPinAfterSimPinUnlock() { // GIVEN the current security method is SimPin @@ -721,39 +593,31 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { any(KeyguardSecurityCallback.class)); } + @Test + public void testSideFpsControllerShow() { + mKeyguardSecurityContainerController.updateSideFpsVisibility(/* isVisible= */ true); + verify(mSideFpsController).show( + SideFpsUiRequestSource.PRIMARY_BOUNCER, + BiometricOverlayConstants.REASON_AUTH_KEYGUARD); + } + + @Test + public void testSideFpsControllerHide() { + mKeyguardSecurityContainerController.updateSideFpsVisibility(/* isVisible= */ false); + verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); + } + private KeyguardSecurityContainer.SwipeListener getRegisteredSwipeListener() { mKeyguardSecurityContainerController.onViewAttached(); verify(mView).setSwipeListener(mSwipeListenerArgumentCaptor.capture()); return mSwipeListenerArgumentCaptor.getValue(); } - private void setupConditionsToEnableSideFpsHint() { - attachView(); - setSideFpsHintEnabledFromResources(true); - setFingerprintDetectionRunning(true); - setUnlockingWithFingerprintAllowed(true); - } - private void attachView() { mKeyguardSecurityContainerController.onViewAttached(); verify(mKeyguardUpdateMonitor).registerCallback(mKeyguardUpdateMonitorCallback.capture()); } - private void setFingerprintDetectionRunning(boolean running) { - when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(running); - mKeyguardUpdateMonitorCallback.getValue().onBiometricRunningStateChanged(running, - BiometricSourceType.FINGERPRINT); - } - - private void setSideFpsHintEnabledFromResources(boolean enabled) { - mTestableResources.addOverride(R.bool.config_show_sidefps_hint_on_bouncer, - enabled); - } - - private void setUnlockingWithFingerprintAllowed(boolean allowed) { - when(mKeyguardUpdateMonitor.isUnlockingWithFingerprintAllowed()).thenReturn(allowed); - } - private void setupGetSecurityView() { when(mKeyguardSecurityViewFlipperController.getSecurityView( any(), any(KeyguardSecurityCallback.class))) diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt index c73ff1dab3d8d..54c9d392ad1c8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt @@ -86,8 +86,9 @@ class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControlle mock(PrimaryBouncerCallbackInteractor::class.java), mock(FalsingCollector::class.java), mock(DismissCallbackRegistry::class.java), + context, + mKeyguardUpdateMonitor, mock(KeyguardBypassController::class.java), - mKeyguardUpdateMonitor ) mAlternateBouncerInteractor = AlternateBouncerInteractor( diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt index 46ed829e0574a..6b7fd616e678d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt @@ -19,11 +19,13 @@ package com.android.systemui.keyguard.domain.interactor import android.os.Looper import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper +import android.testing.TestableResources import android.view.View import androidx.test.filters.SmallTest import com.android.keyguard.KeyguardSecurityModel import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.DejankUtils +import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingCollector import com.android.systemui.keyguard.DismissCallbackRegistry @@ -69,6 +71,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() { @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor private val mainHandler = FakeHandler(Looper.getMainLooper()) private lateinit var underTest: PrimaryBouncerInteractor + private lateinit var resources: TestableResources @Before fun setUp() { @@ -84,18 +87,19 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() { mPrimaryBouncerCallbackInteractor, falsingCollector, dismissCallbackRegistry, - keyguardBypassController, + context, keyguardUpdateMonitor, + keyguardBypassController, ) `when`(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null) `when`(repository.primaryBouncerShow.value).thenReturn(null) `when`(bouncerView.delegate).thenReturn(bouncerViewDelegate) + resources = context.orCreateTestableResources } @Test fun testShow_isScrimmed() { underTest.show(true) - verify(repository).setOnScreenTurnedOff(false) verify(repository).setKeyguardAuthenticated(null) verify(repository).setPrimaryHide(false) verify(repository).setPrimaryStartingToHide(false) @@ -206,12 +210,6 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() { verify(repository).setShowMessage(null) } - @Test - fun testOnScreenTurnedOff() { - underTest.onScreenTurnedOff() - verify(repository).setOnScreenTurnedOff(true) - } - @Test fun testSetKeyguardPosition() { underTest.setKeyguardPosition(0f) @@ -286,4 +284,98 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() { `when`(bouncerViewDelegate.willDismissWithActions()).thenReturn(false) assertThat(underTest.willDismissWithAction()).isFalse() } + + @Test + fun testSideFpsVisibility() { + updateSideFpsVisibilityParameters( + isVisible = true, + sfpsEnabled = true, + fpsDetectionRunning = true, + isUnlockingWithFpAllowed = true, + isAnimatingAway = false + ) + underTest.updateSideFpsVisibility() + verify(repository).setSideFpsShowing(true) + } + + @Test + fun testSideFpsVisibility_notVisible() { + updateSideFpsVisibilityParameters( + isVisible = false, + sfpsEnabled = true, + fpsDetectionRunning = true, + isUnlockingWithFpAllowed = true, + isAnimatingAway = false + ) + underTest.updateSideFpsVisibility() + verify(repository).setSideFpsShowing(false) + } + + @Test + fun testSideFpsVisibility_sfpsNotEnabled() { + updateSideFpsVisibilityParameters( + isVisible = true, + sfpsEnabled = false, + fpsDetectionRunning = true, + isUnlockingWithFpAllowed = true, + isAnimatingAway = false + ) + underTest.updateSideFpsVisibility() + verify(repository).setSideFpsShowing(false) + } + + @Test + fun testSideFpsVisibility_fpsDetectionNotRunning() { + updateSideFpsVisibilityParameters( + isVisible = true, + sfpsEnabled = true, + fpsDetectionRunning = false, + isUnlockingWithFpAllowed = true, + isAnimatingAway = false + ) + underTest.updateSideFpsVisibility() + verify(repository).setSideFpsShowing(false) + } + + @Test + fun testSideFpsVisibility_UnlockingWithFpNotAllowed() { + updateSideFpsVisibilityParameters( + isVisible = true, + sfpsEnabled = true, + fpsDetectionRunning = true, + isUnlockingWithFpAllowed = false, + isAnimatingAway = false + ) + underTest.updateSideFpsVisibility() + verify(repository).setSideFpsShowing(false) + } + + @Test + fun testSideFpsVisibility_AnimatingAway() { + updateSideFpsVisibilityParameters( + isVisible = true, + sfpsEnabled = true, + fpsDetectionRunning = true, + isUnlockingWithFpAllowed = true, + isAnimatingAway = true + ) + underTest.updateSideFpsVisibility() + verify(repository).setSideFpsShowing(false) + } + + private fun updateSideFpsVisibilityParameters( + isVisible: Boolean, + sfpsEnabled: Boolean, + fpsDetectionRunning: Boolean, + isUnlockingWithFpAllowed: Boolean, + isAnimatingAway: Boolean + ) { + `when`(repository.primaryBouncerVisible.value).thenReturn(isVisible) + resources.addOverride(R.bool.config_show_sidefps_hint_on_bouncer, sfpsEnabled) + `when`(keyguardUpdateMonitor.isFingerprintDetectionRunning).thenReturn(fpsDetectionRunning) + `when`(keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed) + .thenReturn(isUnlockingWithFpAllowed) + `when`(repository.primaryBouncerStartingDisappearAnimation.value) + .thenReturn(if (isAnimatingAway) Runnable {} else null) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt index 75b74b0cfe28c..f675e7997eb4f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt @@ -26,7 +26,6 @@ import com.android.systemui.classifier.FalsingCollector import com.android.systemui.coroutines.collectLastValue import com.android.systemui.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.data.BouncerView -import com.android.systemui.keyguard.data.BouncerViewDelegate import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.policy.KeyguardStateController @@ -44,7 +43,6 @@ import org.mockito.MockitoAnnotations class PrimaryBouncerInteractorWithCoroutinesTest : SysuiTestCase() { private lateinit var repository: FakeKeyguardBouncerRepository @Mock private lateinit var bouncerView: BouncerView - @Mock private lateinit var bouncerViewDelegate: BouncerViewDelegate @Mock private lateinit var keyguardStateController: KeyguardStateController @Mock private lateinit var keyguardSecurityModel: KeyguardSecurityModel @Mock private lateinit var primaryBouncerCallbackInteractor: PrimaryBouncerCallbackInteractor @@ -69,8 +67,9 @@ class PrimaryBouncerInteractorWithCoroutinesTest : SysuiTestCase() { primaryBouncerCallbackInteractor, falsingCollector, dismissCallbackRegistry, - keyguardBypassController, + context, keyguardUpdateMonitor, + keyguardBypassController, ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt index 586af626d29e4..65e4c10265cd7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt @@ -16,15 +16,23 @@ package com.android.systemui.keyguard.ui.viewmodel +import android.os.Looper import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.keyguard.KeyguardSecurityModel +import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.SysuiTestCase +import com.android.systemui.classifier.FalsingCollector +import com.android.systemui.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.data.BouncerView +import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository +import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel +import com.android.systemui.statusbar.phone.KeyguardBypassController +import com.android.systemui.statusbar.policy.KeyguardStateController +import com.android.systemui.utils.os.FakeHandler import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.test.runCurrent @@ -33,7 +41,6 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock -import org.mockito.Mockito import org.mockito.MockitoAnnotations @SmallTest @@ -41,31 +48,69 @@ import org.mockito.MockitoAnnotations @kotlinx.coroutines.ExperimentalCoroutinesApi class KeyguardBouncerViewModelTest : SysuiTestCase() { lateinit var underTest: KeyguardBouncerViewModel + lateinit var bouncerInteractor: PrimaryBouncerInteractor @Mock lateinit var bouncerView: BouncerView - @Mock lateinit var bouncerInteractor: PrimaryBouncerInteractor + @Mock private lateinit var keyguardStateController: KeyguardStateController + @Mock private lateinit var keyguardSecurityModel: KeyguardSecurityModel + @Mock private lateinit var primaryBouncerCallbackInteractor: PrimaryBouncerCallbackInteractor + @Mock private lateinit var falsingCollector: FalsingCollector + @Mock private lateinit var dismissCallbackRegistry: DismissCallbackRegistry + @Mock private lateinit var keyguardBypassController: KeyguardBypassController + @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor + private val mainHandler = FakeHandler(Looper.getMainLooper()) + val repository = FakeKeyguardBouncerRepository() @Before fun setup() { MockitoAnnotations.initMocks(this) + bouncerInteractor = + PrimaryBouncerInteractor( + repository, + bouncerView, + mainHandler, + keyguardStateController, + keyguardSecurityModel, + primaryBouncerCallbackInteractor, + falsingCollector, + dismissCallbackRegistry, + context, + keyguardUpdateMonitor, + keyguardBypassController, + ) underTest = KeyguardBouncerViewModel(bouncerView, bouncerInteractor) } @Test - fun setMessage() = - runTest { - val flow = MutableStateFlow(null) - var message: BouncerShowMessageModel? = null - Mockito.`when`(bouncerInteractor.showMessage) - .thenReturn(flow as Flow) - // Reinitialize the view model. - underTest = KeyguardBouncerViewModel(bouncerView, bouncerInteractor) + fun setMessage() = runTest { + var message: BouncerShowMessageModel? = null + val job = underTest.bouncerShowMessage.onEach { message = it }.launchIn(this) - flow.value = BouncerShowMessageModel(message = "abc", colorStateList = null) + repository.setShowMessage(BouncerShowMessageModel("abc", null)) + // Run the tasks that are pending at this point of virtual time. + runCurrent() + assertThat(message?.message).isEqualTo("abc") + job.cancel() + } - val job = underTest.bouncerShowMessage.onEach { message = it }.launchIn(this) - // Run the tasks that are pending at this point of virtual time. - runCurrent() - assertThat(message?.message).isEqualTo("abc") - job.cancel() - } + @Test + fun shouldUpdateSideFps() = runTest { + var count = 0 + val job = underTest.shouldUpdateSideFps.onEach { count++ }.launchIn(this) + repository.setPrimaryVisible(true) + // Run the tasks that are pending at this point of virtual time. + runCurrent() + assertThat(count).isEqualTo(1) + job.cancel() + } + + @Test + fun sideFpsShowing() = runTest { + var sideFpsIsShowing = false + val job = underTest.sideFpsShowing.onEach { sideFpsIsShowing = it }.launchIn(this) + repository.setSideFpsShowing(true) + // Run the tasks that are pending at this point of virtual time. + runCurrent() + assertThat(sideFpsIsShowing).isEqualTo(true) + job.cancel() + } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardBouncerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardBouncerRepository.kt index 337421974562e..9cdce20bbf1ee 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardBouncerRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardBouncerRepository.kt @@ -21,6 +21,7 @@ import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.E import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel import com.android.systemui.keyguard.shared.model.KeyguardBouncerModel import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow /** Fake implementation of [KeyguardRepository] */ @@ -44,8 +45,6 @@ class FakeKeyguardBouncerRepository : KeyguardBouncerRepository { override val panelExpansionAmount = _panelExpansionAmount.asStateFlow() private val _keyguardPosition = MutableStateFlow(0f) override val keyguardPosition = _keyguardPosition.asStateFlow() - private val _onScreenTurnedOff = MutableStateFlow(false) - override val onScreenTurnedOff = _onScreenTurnedOff.asStateFlow() private val _isBackButtonEnabled = MutableStateFlow(null) override val isBackButtonEnabled = _isBackButtonEnabled.asStateFlow() private val _keyguardAuthenticated = MutableStateFlow(null) @@ -61,6 +60,8 @@ class FakeKeyguardBouncerRepository : KeyguardBouncerRepository { override var lastAlternateBouncerVisibleTime: Long = 0L private val _isAlternateBouncerUIAvailable = MutableStateFlow(false) override val alternateBouncerUIAvailable = _isAlternateBouncerUIAvailable.asStateFlow() + private val _sideFpsShowing: MutableStateFlow = MutableStateFlow(false) + override val sideFpsShowing: StateFlow = _sideFpsShowing.asStateFlow() override fun setPrimaryScrimmed(isScrimmed: Boolean) { _primaryBouncerScrimmed.value = isScrimmed @@ -122,7 +123,7 @@ class FakeKeyguardBouncerRepository : KeyguardBouncerRepository { _isBackButtonEnabled.value = isBackButtonEnabled } - override fun setOnScreenTurnedOff(onScreenTurnedOff: Boolean) { - _onScreenTurnedOff.value = onScreenTurnedOff + override fun setSideFpsShowing(isShowing: Boolean) { + _sideFpsShowing.value = isShowing } }