Merge "Move sidefps bouncer logic into interactor." into tm-qpr-dev am: e871505cdb

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21483187

Change-Id: I1128afbcf47448d2e50c81093f2ea2288ae3e27e
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Aaron Liu
2023-02-22 05:26:47 +00:00
committed by Automerger Merge Worker
13 changed files with 311 additions and 268 deletions

View File

@@ -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:

View File

@@ -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;
@@ -320,7 +318,6 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
KeyguardSecurityContainerController.this.onDensityOrFontScaleChanged();
}
};
private boolean mBouncerVisible = false;
private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
new KeyguardUpdateMonitorCallback() {
@Override
@@ -355,19 +352,6 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
public void onDevicePolicyManagerStateChanged() {
showPrimarySecurityScreen(false);
}
@Override
public void onBiometricRunningStateChanged(boolean running,
BiometricSourceType biometricSourceType) {
if (biometricSourceType == FINGERPRINT) {
updateSideFpsVisibility();
}
}
@Override
public void onStrongAuthStateChanged(int userId) {
updateSideFpsVisibility();
}
};
@Inject
@@ -459,35 +443,24 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
getCurrentSecurityController().onPause();
}
mView.onPause();
// It might happen that onStartingToHide is not called when the device is locked while on
// bouncer.
setBouncerVisible(false);
mView.clearFocus();
}
private void updateSideFpsVisibility() {
/**
* Shows and hides the side finger print sensor animation.
*
* @param isVisible sets whether we show or hide the side fps animation
*/
public void updateSideFpsVisibility(boolean isVisible) {
if (!mSideFpsController.isPresent()) {
return;
}
final boolean sfpsEnabled = getResources().getBoolean(
R.bool.config_show_sidefps_hint_on_bouncer);
final boolean fpsDetectionRunning = mUpdateMonitor.isFingerprintDetectionRunning();
final boolean isUnlockingWithFpAllowed =
mUpdateMonitor.isUnlockingWithFingerprintAllowed();
boolean toShow = mBouncerVisible && sfpsEnabled && fpsDetectionRunning
&& isUnlockingWithFpAllowed;
if (DEBUG) {
Log.d(TAG, "sideFpsToShow=" + toShow + ", "
+ "mBouncerVisible=" + mBouncerVisible + ", "
+ "configEnabled=" + sfpsEnabled + ", "
+ "fpsDetectionRunning=" + fpsDetectionRunning + ", "
+ "isUnlockingWithFpAllowed=" + isUnlockingWithFpAllowed);
}
if (toShow) {
mSideFpsController.get().show(SideFpsUiRequestSource.PRIMARY_BOUNCER,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD);
if (isVisible) {
mSideFpsController.get().show(
SideFpsUiRequestSource.PRIMARY_BOUNCER,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD
);
} else {
mSideFpsController.get().hide(SideFpsUiRequestSource.PRIMARY_BOUNCER);
}
@@ -636,7 +609,6 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED, state);
getCurrentSecurityController().onResume(reason);
updateSideFpsVisibility();
}
mView.onResume(
mSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser()),
@@ -690,22 +662,15 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
if (mCurrentSecurityMode != SecurityMode.None) {
getCurrentSecurityController().onStartingToHide();
}
setBouncerVisible(false);
}
/** Called when the bouncer changes visibility. */
public void onBouncerVisibilityChanged(@View.Visibility int visibility) {
setBouncerVisible(visibility == View.VISIBLE);
if (visibility == View.INVISIBLE) {
public void onBouncerVisibilityChanged(boolean isVisible) {
if (!isVisible) {
mView.resetScale();
}
}
private void setBouncerVisible(boolean visible) {
mBouncerVisible = visible;
updateSideFpsVisibility();
}
/**
* Shows the next security screen if there is one.
* @param authenticated true if the user entered the correct authentication

View File

@@ -60,7 +60,6 @@ interface KeyguardBouncerRepository {
*/
val panelExpansionAmount: StateFlow<Float>
val keyguardPosition: StateFlow<Float>
val onScreenTurnedOff: StateFlow<Boolean>
val isBackButtonEnabled: StateFlow<Boolean?>
/** Determines if user is already unlocked */
val keyguardAuthenticated: StateFlow<Boolean?>
@@ -70,6 +69,8 @@ interface KeyguardBouncerRepository {
val bouncerErrorMessage: CharSequence?
val alternateBouncerVisible: StateFlow<Boolean>
val alternateBouncerUIAvailable: StateFlow<Boolean>
val sideFpsShowing: StateFlow<Boolean>
var lastAlternateBouncerVisibleTime: Long
fun setPrimaryScrimmed(isScrimmed: Boolean)
@@ -98,11 +99,11 @@ interface KeyguardBouncerRepository {
fun setIsBackButtonEnabled(isBackButtonEnabled: Boolean)
fun setOnScreenTurnedOff(onScreenTurnedOff: Boolean)
fun setAlternateVisible(isVisible: Boolean)
fun setAlternateBouncerUIAvailable(isAvailable: Boolean)
fun setSideFpsShowing(isShowing: Boolean)
}
@SysUISingleton
@@ -142,8 +143,6 @@ constructor(
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<Boolean?>(null)
override val isBackButtonEnabled = _isBackButtonEnabled.asStateFlow()
private val _keyguardAuthenticated = MutableStateFlow<Boolean?>(null)
@@ -165,6 +164,8 @@ constructor(
private val _alternateBouncerUIAvailable = MutableStateFlow(false)
override val alternateBouncerUIAvailable: StateFlow<Boolean> =
_alternateBouncerUIAvailable.asStateFlow()
private val _sideFpsShowing = MutableStateFlow(false)
override val sideFpsShowing: StateFlow<Boolean> = _sideFpsShowing.asStateFlow()
init {
setUpLogging()
@@ -235,8 +236,8 @@ constructor(
_isBackButtonEnabled.value = isBackButtonEnabled
}
override fun setOnScreenTurnedOff(onScreenTurnedOff: Boolean) {
_onScreenTurnedOff.value = onScreenTurnedOff
override fun setSideFpsShowing(isShowing: Boolean) {
_sideFpsShowing.value = isShowing
}
/** Sets up logs for state flows. */
@@ -276,9 +277,6 @@ constructor(
.map { it.toInt() }
.logDiffsForTable(buffer, "", "KeyguardPosition", -1)
.launchIn(applicationScope)
onScreenTurnedOff
.logDiffsForTable(buffer, "", "OnScreenTurnedOff", false)
.launchIn(applicationScope)
isBackButtonEnabled
.filterNotNull()
.logDiffsForTable(buffer, "", "IsBackButtonEnabled", false)
@@ -293,6 +291,9 @@ constructor(
alternateBouncerUIAvailable
.logDiffsForTable(buffer, "", "IsAlternateBouncerUIAvailable", false)
.launchIn(applicationScope)
sideFpsShowing
.logDiffsForTable(buffer, "", "isSideFpsShowing", false)
.launchIn(applicationScope)
}
companion object {

View File

@@ -16,6 +16,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.content.Context
import android.content.res.ColorStateList
import android.hardware.biometrics.BiometricSourceType
import android.os.Handler
@@ -23,9 +24,13 @@ import android.os.Trace
import android.os.UserHandle
import android.os.UserManager
import android.view.View
import android.util.Log
import com.android.keyguard.KeyguardConstants
import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.DejankUtils
import com.android.systemui.R
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
@@ -62,8 +67,9 @@ constructor(
private val primaryBouncerCallbackInteractor: PrimaryBouncerCallbackInteractor,
private val falsingCollector: FalsingCollector,
private val dismissCallbackRegistry: DismissCallbackRegistry,
private val context: Context,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
keyguardBypassController: KeyguardBypassController,
keyguardUpdateMonitor: KeyguardUpdateMonitor,
) {
/** Whether we want to wait for face auth. */
private val primaryBouncerFaceDelay =
@@ -90,7 +96,6 @@ constructor(
}
val keyguardAuthenticated: Flow<Boolean> = repository.keyguardAuthenticated.filterNotNull()
val screenTurnedOff: Flow<Unit> = repository.onScreenTurnedOff.filter { it }.map {}
val show: Flow<KeyguardBouncerModel> = repository.primaryBouncerShow.filterNotNull()
val hide: Flow<Unit> = repository.primaryBouncerHide.filter { it }.map {}
val startingToHide: Flow<Unit> = repository.primaryBouncerStartingToHide.filter { it }.map {}
@@ -115,6 +120,24 @@ constructor(
}
/** Allow for interaction when just about fully visible */
val isInteractable: Flow<Boolean> = bouncerExpansion.map { it > 0.9 }
val sideFpsShowing: Flow<Boolean> = 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.
@@ -122,7 +145,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)
@@ -262,11 +284,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)
@@ -301,6 +318,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 ||
@@ -344,4 +390,8 @@ constructor(
DejankUtils.removeCallbacks(showRunnable)
mainHandler.removeCallbacks(showRunnable)
}
companion object {
private const val TAG = "PrimaryBouncerInteractor"
}
}

View File

@@ -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()

View File

@@ -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<Boolean> = interactor.keyguardAuthenticated
/** Observe whether screen is turned off. */
val screenTurnedOff: Flow<Unit> = interactor.screenTurnedOff
/** Observe whether the side fps is showing. */
val sideFpsShowing: Flow<Boolean> = interactor.sideFpsShowing
/** Observe whether we should update fps is showing. */
val shouldUpdateSideFps: Flow<Unit> =
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<Int> {
return interactor.isBackButtonEnabled.map { enabled ->

View File

@@ -790,7 +790,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
@Override
public void onFinishedGoingToSleep() {
mPrimaryBouncerInteractor.onScreenTurnedOff();
mPrimaryBouncerInteractor.hide();
}
@Override

View File

@@ -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
@@ -719,39 +591,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)))

View File

@@ -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(

View File

@@ -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)
}
}

View File

@@ -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,
)
}

View File

@@ -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<BouncerShowMessageModel?>(null)
var message: BouncerShowMessageModel? = null
Mockito.`when`(bouncerInteractor.showMessage)
.thenReturn(flow as Flow<BouncerShowMessageModel>)
// 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()
}
}

View File

@@ -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<Boolean?>(null)
override val isBackButtonEnabled = _isBackButtonEnabled.asStateFlow()
private val _keyguardAuthenticated = MutableStateFlow<Boolean?>(null)
@@ -61,6 +60,8 @@ class FakeKeyguardBouncerRepository : KeyguardBouncerRepository {
override var lastAlternateBouncerVisibleTime: Long = 0L
private val _isAlternateBouncerUIAvailable = MutableStateFlow<Boolean>(false)
override val alternateBouncerUIAvailable = _isAlternateBouncerUIAvailable.asStateFlow()
private val _sideFpsShowing: MutableStateFlow<Boolean> = MutableStateFlow(false)
override val sideFpsShowing: StateFlow<Boolean> = _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
}
}