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

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

Change-Id: I5eae4f3421ec76b8356ce8693647487ec13105f2
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Aaron Liu
2023-02-22 06:29:56 +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;
@@ -321,7 +319,6 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
KeyguardSecurityContainerController.this.onDensityOrFontScaleChanged();
}
};
private boolean mBouncerVisible = false;
private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
new KeyguardUpdateMonitorCallback() {
@Override
@@ -356,19 +353,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
@@ -460,35 +444,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);
}
@@ -637,7 +610,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()),
@@ -691,22 +663,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,14 +16,19 @@
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
import android.os.Trace
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
@@ -60,8 +65,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 =
@@ -88,7 +94,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 {}
@@ -113,6 +118,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.
@@ -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"
}
}

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

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