summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/res-keyguard/values/dimens.xml2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java10
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt74
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt42
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt69
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java76
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt103
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt109
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt129
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java56
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt2
25 files changed, 597 insertions, 227 deletions
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 6cc5b9d7b7e8..992d143ff66d 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -78,7 +78,7 @@
<!-- The vertical margin between the date and the owner info. -->
<!-- The translation for disappearing security views after having solved them. -->
- <dimen name="disappear_y_translation">-32dp</dimen>
+ <dimen name="disappear_y_translation">-50dp</dimen>
<!-- Dimens for animation for the Bouncer PIN view -->
<dimen name="pin_view_trans_y_entry">120dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 29496169e04f..66d5d097ab04 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -39,7 +39,6 @@ import static java.lang.Integer.max;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
@@ -1068,13 +1067,10 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
int yTranslation = mResources.getDimensionPixelSize(R.dimen.disappear_y_translation);
- AnimatorSet anims = new AnimatorSet();
ObjectAnimator yAnim = ObjectAnimator.ofFloat(mView, View.TRANSLATION_Y, yTranslation);
- ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(mView, View.ALPHA, 0f);
-
- anims.setInterpolator(Interpolators.STANDARD_ACCELERATE);
- anims.playTogether(alphaAnim, yAnim);
- anims.start();
+ yAnim.setInterpolator(Interpolators.STANDARD_ACCELERATE);
+ yAnim.setDuration(500);
+ yAnim.start();
}
private void setupUserSwitcher() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index b8bb2603fa03..c32b8530d589 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -636,12 +636,17 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
public void startAppearAnimation() {
if (mCurrentSecurityMode != SecurityMode.None) {
- mView.setAlpha(1f);
+ setAlpha(1f);
mView.startAppearAnimation(mCurrentSecurityMode);
getCurrentSecurityController().startAppearAnimation();
}
}
+ /** Set the alpha of the security container view */
+ public void setAlpha(float alpha) {
+ mView.setAlpha(alpha);
+ }
+
public boolean startDisappearAnimation(Runnable onFinishRunnable) {
boolean didRunAnimation = false;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index a3b3d0fd0681..76f20d25b0ec 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -80,6 +80,9 @@ interface KeyguardRepository {
*/
val isKeyguardShowing: Flow<Boolean>
+ /** Is the keyguard in a unlocked state? */
+ val isKeyguardUnlocked: Flow<Boolean>
+
/** Is an activity showing over the keyguard? */
val isKeyguardOccluded: Flow<Boolean>
@@ -278,6 +281,31 @@ constructor(
}
.distinctUntilChanged()
+ override val isKeyguardUnlocked: Flow<Boolean> =
+ conflatedCallbackFlow {
+ val callback =
+ object : KeyguardStateController.Callback {
+ override fun onUnlockedChanged() {
+ trySendWithFailureLogging(
+ keyguardStateController.isUnlocked,
+ TAG,
+ "updated isKeyguardUnlocked"
+ )
+ }
+ }
+
+ keyguardStateController.addCallback(callback)
+ // Adding the callback does not send an initial update.
+ trySendWithFailureLogging(
+ keyguardStateController.isUnlocked,
+ TAG,
+ "initial isKeyguardUnlocked"
+ )
+
+ awaitClose { keyguardStateController.removeCallback(callback) }
+ }
+ .distinctUntilChanged()
+
override val isKeyguardGoingAway: Flow<Boolean> = conflatedCallbackFlow {
val callback =
object : KeyguardStateController.Callback {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
index 0c4bca616e12..100bc596103d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
@@ -68,8 +68,11 @@ interface KeyguardTransitionRepository {
/**
* Begin a transition from one state to another. Transitions are interruptible, and will issue a
* [TransitionStep] with state = [TransitionState.CANCELED] before beginning the next one.
+ *
+ * When canceled, there are two options: to continue from the current position of the prior
+ * transition, or to reset the position. When [resetIfCanceled] == true, it will do the latter.
*/
- fun startTransition(info: TransitionInfo): UUID?
+ fun startTransition(info: TransitionInfo, resetIfCanceled: Boolean = false): UUID?
/**
* Allows manual control of a transition. When calling [startTransition], the consumer must pass
@@ -130,7 +133,10 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
)
}
- override fun startTransition(info: TransitionInfo): UUID? {
+ override fun startTransition(
+ info: TransitionInfo,
+ resetIfCanceled: Boolean,
+ ): UUID? {
if (lastStep.from == info.from && lastStep.to == info.to) {
Log.i(TAG, "Duplicate call to start the transition, rejecting: $info")
return null
@@ -138,7 +144,11 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
val startingValue =
if (lastStep.transitionState != TransitionState.FINISHED) {
Log.i(TAG, "Transition still active: $lastStep, canceling")
- lastStep.value
+ if (resetIfCanceled) {
+ 0f
+ } else {
+ lastStep.value
+ }
} else {
0f
}
@@ -227,10 +237,7 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
}
private fun trace(step: TransitionStep, isManual: Boolean) {
- if (
- step.transitionState != TransitionState.STARTED &&
- step.transitionState != TransitionState.FINISHED
- ) {
+ if (step.transitionState == TransitionState.RUNNING) {
return
}
val traceName =
@@ -243,7 +250,10 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
val traceCookie = traceName.hashCode()
if (step.transitionState == TransitionState.STARTED) {
Trace.beginAsyncSection(traceName, traceCookie)
- } else if (step.transitionState == TransitionState.FINISHED) {
+ } else if (
+ step.transitionState == TransitionState.FINISHED ||
+ step.transitionState == TransitionState.CANCELED
+ ) {
Trace.endAsyncSection(traceName, traceCookie)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index 8715d1f55069..3beac0b1322e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -34,7 +34,6 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
@@ -57,14 +56,7 @@ constructor(
private fun listenForDreamingToLockscreen() {
scope.launch {
- // Dependending on the dream, either dream state or occluded change will change first,
- // so listen for both
- combine(keyguardInteractor.isAbleToDream, keyguardInteractor.isKeyguardOccluded) {
- isAbleToDream,
- isKeyguardOccluded ->
- isAbleToDream && isKeyguardOccluded
- }
- .distinctUntilChanged()
+ keyguardInteractor.isAbleToDream
.sample(
combine(
keyguardInteractor.dozeTransitionModel,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index d01f48970c97..911861ddde47 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -130,55 +130,59 @@ constructor(
shadeRepository.shadeModel
.sample(
combine(
- keyguardTransitionInteractor.finishedKeyguardState,
+ keyguardTransitionInteractor.startedKeyguardTransitionStep,
keyguardInteractor.statusBarState,
- ::Pair
+ keyguardInteractor.isKeyguardUnlocked,
+ ::toTriple
),
- ::toTriple
+ ::toQuad
)
- .collect { (shadeModel, keyguardState, statusBarState) ->
+ .collect { (shadeModel, keyguardState, statusBarState, isKeyguardUnlocked) ->
val id = transitionId
if (id != null) {
- // An existing `id` means a transition is started, and calls to
- // `updateTransition` will control it until FINISHED or CANCELED
- var nextState =
- if (shadeModel.expansionAmount == 0f) {
- TransitionState.FINISHED
- } else if (shadeModel.expansionAmount == 1f) {
- TransitionState.CANCELED
- } else {
- TransitionState.RUNNING
- }
- keyguardTransitionRepository.updateTransition(
- id,
- 1f - shadeModel.expansionAmount,
- nextState,
- )
+ if (keyguardState.to == KeyguardState.PRIMARY_BOUNCER) {
+ // An existing `id` means a transition is started, and calls to
+ // `updateTransition` will control it until FINISHED or CANCELED
+ var nextState =
+ if (shadeModel.expansionAmount == 0f) {
+ TransitionState.FINISHED
+ } else if (shadeModel.expansionAmount == 1f) {
+ TransitionState.CANCELED
+ } else {
+ TransitionState.RUNNING
+ }
+ keyguardTransitionRepository.updateTransition(
+ id,
+ 1f - shadeModel.expansionAmount,
+ nextState,
+ )
- if (
- nextState == TransitionState.CANCELED ||
- nextState == TransitionState.FINISHED
- ) {
- transitionId = null
- }
+ if (
+ nextState == TransitionState.CANCELED ||
+ nextState == TransitionState.FINISHED
+ ) {
+ transitionId = null
+ }
- // If canceled, just put the state back
- if (nextState == TransitionState.CANCELED) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.PRIMARY_BOUNCER,
- to = KeyguardState.LOCKSCREEN,
- animator = getAnimator(0.milliseconds)
+ // If canceled, just put the state back
+ if (nextState == TransitionState.CANCELED) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ ownerName = name,
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = KeyguardState.LOCKSCREEN,
+ animator = getAnimator(0.milliseconds)
+ )
)
- )
+ }
}
} else {
// TODO (b/251849525): Remove statusbarstate check when that state is
// integrated into KeyguardTransitionRepository
if (
- keyguardState == KeyguardState.LOCKSCREEN &&
+ keyguardState.to == KeyguardState.LOCKSCREEN &&
shadeModel.isUserDragging &&
+ !isKeyguardUnlocked &&
statusBarState == KEYGUARD
) {
transitionId =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index b59b413d7a40..94961cbf4240 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -17,6 +17,9 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
+import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode.Password
+import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -26,6 +29,8 @@ import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
@@ -37,7 +42,8 @@ constructor(
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
private val keyguardTransitionRepository: KeyguardTransitionRepository,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor
+ private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
+ private val keyguardSecurityModel: KeyguardSecurityModel,
) : TransitionInteractor(FromPrimaryBouncerTransitionInteractor::class.simpleName!!) {
override fun start() {
@@ -93,31 +99,47 @@ constructor(
private fun listenForPrimaryBouncerToGone() {
scope.launch {
keyguardInteractor.isKeyguardGoingAway
- .sample(keyguardTransitionInteractor.finishedKeyguardState) { a, b -> Pair(a, b) }
- .collect { pair ->
- val (isKeyguardGoingAway, keyguardState) = pair
- if (isKeyguardGoingAway && keyguardState == KeyguardState.PRIMARY_BOUNCER) {
+ .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .collect { (isKeyguardGoingAway, lastStartedTransitionStep) ->
+ if (
+ isKeyguardGoingAway &&
+ lastStartedTransitionStep.to == KeyguardState.PRIMARY_BOUNCER
+ ) {
+ val securityMode =
+ keyguardSecurityModel.getSecurityMode(
+ KeyguardUpdateMonitor.getCurrentUser()
+ )
+ // IME for password requires a slightly faster animation
+ val duration =
+ if (securityMode == Password) {
+ TO_GONE_SHORT_DURATION
+ } else {
+ TO_GONE_DURATION
+ }
keyguardTransitionRepository.startTransition(
TransitionInfo(
ownerName = name,
from = KeyguardState.PRIMARY_BOUNCER,
to = KeyguardState.GONE,
- animator = getAnimator(),
- )
+ animator = getAnimator(duration),
+ ),
+ resetIfCanceled = true,
)
}
}
}
}
- private fun getAnimator(): ValueAnimator {
+ private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
return ValueAnimator().apply {
setInterpolator(Interpolators.LINEAR)
- setDuration(TRANSITION_DURATION_MS)
+ setDuration(duration.inWholeMilliseconds)
}
}
companion object {
- private const val TRANSITION_DURATION_MS = 300L
+ private val DEFAULT_DURATION = 300.milliseconds
+ val TO_GONE_DURATION = 250.milliseconds
+ val TO_GONE_SHORT_DURATION = 200.milliseconds
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index d25aff0add86..ec99049b42e3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -33,7 +33,9 @@ import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDoz
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.WakefulnessModel
+import com.android.systemui.keyguard.shared.model.WakefulnessModel.Companion.isWakingOrStartingToWake
import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.delay
@@ -95,6 +97,9 @@ constructor(
awaitClose { commandQueue.removeCallback(callback) }
}
+ /** The device wake/sleep state */
+ val wakefulnessModel: Flow<WakefulnessModel> = repository.wakefulness
+
/**
* Dozing and dreaming have overlapping events. If the doze state remains in FINISH, it means
* that doze mode is not running and DREAMING is ok to commence.
@@ -109,6 +114,12 @@ constructor(
isDreaming && isDozeOff(dozeTransitionModel.to)
}
)
+ .sample(
+ wakefulnessModel,
+ { isAbleToDream, wakefulnessModel ->
+ isAbleToDream && isWakingOrStartingToWake(wakefulnessModel)
+ }
+ )
.flatMapLatest { isAbleToDream ->
flow {
delay(50)
@@ -119,6 +130,8 @@ constructor(
/** Whether the keyguard is showing or not. */
val isKeyguardShowing: Flow<Boolean> = repository.isKeyguardShowing
+ /** Whether the keyguard is unlocked or not. */
+ val isKeyguardUnlocked: Flow<Boolean> = repository.isKeyguardUnlocked
/** Whether the keyguard is occluded (covered by an activity). */
val isKeyguardOccluded: Flow<Boolean> = repository.isKeyguardOccluded
/** Whether the keyguard is going away. */
@@ -127,8 +140,6 @@ constructor(
val primaryBouncerShowing: Flow<Boolean> = bouncerRepository.primaryBouncerVisible
/** Whether the alternate bouncer is showing or not. */
val alternateBouncerShowing: Flow<Boolean> = bouncerRepository.alternateBouncerVisible
- /** The device wake/sleep state */
- val wakefulnessModel: Flow<WakefulnessModel> = repository.wakefulness
/** Observable for the [StatusBarState] */
val statusBarState: Flow<StatusBarState> = repository.statusBarState
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
index 51b02779a89f..e650b9fc0e47 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
@@ -61,7 +61,15 @@ constructor(
}
scope.launch {
- keyguardInteractor.isDreaming.collect { logger.log(TAG, VERBOSE, "isDreaming", it) }
+ keyguardInteractor.isAbleToDream.collect {
+ logger.log(TAG, VERBOSE, "isAbleToDream", it)
+ }
+ }
+
+ scope.launch {
+ keyguardInteractor.isKeyguardOccluded.collect {
+ logger.log(TAG, VERBOSE, "isOccluded", it)
+ }
}
scope.launch {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index 1b7da5b65a03..3c0ec350c5c5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -78,6 +78,10 @@ constructor(
val occludedToLockscreenTransition: Flow<TransitionStep> =
repository.transition(OCCLUDED, LOCKSCREEN)
+ /** PRIMARY_BOUNCER->GONE transition information. */
+ val primaryBouncerToGoneTransition: Flow<TransitionStep> =
+ repository.transition(PRIMARY_BOUNCER, GONE)
+
/**
* AOD<->LOCKSCREEN transition information, mapped to dozeAmount range of AOD (1f) <->
* Lockscreen (0f).
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
index ca1e27c9d19c..38b9d508f81c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
@@ -47,6 +47,7 @@ class KeyguardTransitionAnimationFlow(
duration: Duration,
onStep: (Float) -> Float,
startTime: Duration = 0.milliseconds,
+ onStart: (() -> Unit)? = null,
onCancel: (() -> Float)? = null,
onFinish: (() -> Float)? = null,
interpolator: Interpolator = LINEAR,
@@ -73,6 +74,7 @@ class KeyguardTransitionAnimationFlow(
// the ViewModels of the last update
STARTED -> {
isComplete = false
+ onStart?.invoke()
max(0f, min(1f, value))
}
// Always send a final value of 1. Because of rounding, [value] may never be
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 7db567b2a0e9..2337ffc35fa6 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
@@ -31,6 +31,7 @@ import com.android.settingslib.Utils
import com.android.systemui.keyguard.data.BouncerViewDelegate
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
+import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.ActivityStarter
import kotlinx.coroutines.awaitCancellation
@@ -44,6 +45,7 @@ object KeyguardBouncerViewBinder {
fun bind(
view: ViewGroup,
viewModel: KeyguardBouncerViewModel,
+ primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel,
componentFactory: KeyguardBouncerComponent.Factory
) {
// Builds the KeyguardSecurityContainerController from bouncer view group.
@@ -145,6 +147,12 @@ object KeyguardBouncerViewBinder {
}
launch {
+ primaryBouncerToGoneTransitionViewModel.bouncerAlpha.collect { alpha ->
+ securityContainerController.setAlpha(alpha)
+ }
+ }
+
+ launch {
viewModel.bouncerExpansionAmount
.filter { it == EXPANSION_VISIBLE }
.collect {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
new file mode 100644
index 000000000000..92038e24edf3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.statusbar.SysuiStatusBarStateController
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * Breaks down PRIMARY_BOUNCER->GONE transition into discrete steps for corresponding views to
+ * consume.
+ */
+@SysUISingleton
+class PrimaryBouncerToGoneTransitionViewModel
+@Inject
+constructor(
+ private val interactor: KeyguardTransitionInteractor,
+ private val statusBarStateController: SysuiStatusBarStateController,
+) {
+ private val transitionAnimation =
+ KeyguardTransitionAnimationFlow(
+ transitionDuration = TO_GONE_DURATION,
+ transitionFlow = interactor.primaryBouncerToGoneTransition,
+ )
+
+ private var leaveShadeOpen: Boolean = false
+
+ /** Bouncer container alpha */
+ val bouncerAlpha: Flow<Float> =
+ transitionAnimation.createFlow(
+ duration = 200.milliseconds,
+ onStep = { 1f - it },
+ )
+
+ /** Scrim behind alpha */
+ val scrimBehindAlpha: Flow<Float> =
+ transitionAnimation.createFlow(
+ duration = TO_GONE_DURATION,
+ interpolator = EMPHASIZED_ACCELERATE,
+ onStart = { leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide() },
+ onStep = {
+ if (leaveShadeOpen) {
+ 1f
+ } else {
+ 1f - it
+ }
+ },
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 87350b465895..c130b3913b64 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -45,6 +45,7 @@ import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.keyguard.ui.binder.KeyguardBouncerViewBinder;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationInsetsController;
@@ -133,7 +134,8 @@ public class NotificationShadeWindowViewController {
KeyguardBouncerViewModel keyguardBouncerViewModel,
KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory,
AlternateBouncerInteractor alternateBouncerInteractor,
- KeyguardTransitionInteractor keyguardTransitionInteractor
+ KeyguardTransitionInteractor keyguardTransitionInteractor,
+ PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel
) {
mLockscreenShadeTransitionController = transitionController;
mFalsingCollector = falsingCollector;
@@ -160,6 +162,7 @@ public class NotificationShadeWindowViewController {
KeyguardBouncerViewBinder.bind(
mView.findViewById(R.id.keyguard_bouncer_container),
keyguardBouncerViewModel,
+ primaryBouncerToGoneTransitionViewModel,
keyguardBouncerComponentFactory);
collectFlow(mView, keyguardTransitionInteractor.getLockscreenToDreamingTransition(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index be791f9e2242..b5d51ce2b9ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -3695,6 +3695,12 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
@Override
public void notifyBiometricAuthModeChanged() {
mDozeServiceHost.updateDozing();
+ if (mBiometricUnlockController.getMode()
+ == BiometricUnlockController.MODE_DISMISS_BOUNCER) {
+ // Don't update the scrim controller at this time, in favor of the transition repository
+ // updating the scrim
+ return;
+ }
updateScrimController();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 8e0ec284c840..8fd967594198 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
+
import static java.lang.Float.isNaN;
import android.animation.Animator;
@@ -53,9 +55,14 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
+import com.android.systemui.keyguard.shared.model.TransitionState;
+import com.android.systemui.keyguard.shared.model.TransitionStep;
+import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.shade.NotificationPanelViewController;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.stack.ViewState;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -71,6 +78,8 @@ import java.util.function.Consumer;
import javax.inject.Inject;
+import kotlinx.coroutines.CoroutineDispatcher;
+
/**
* Controls both the scrim behind the notifications and in front of the notifications (when a
* security method gets shown).
@@ -197,6 +206,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
private final ScreenOffAnimationController mScreenOffAnimationController;
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ private final SysuiStatusBarStateController mStatusBarStateController;
private GradientColors mColors;
private boolean mNeedsDrawableColorUpdate;
@@ -251,6 +261,20 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
private boolean mWakeLockHeld;
private boolean mKeyguardOccluded;
+ private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+ private CoroutineDispatcher mMainDispatcher;
+ private boolean mIsBouncerToGoneTransitionRunning = false;
+ private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
+ private final Consumer<Float> mScrimAlphaConsumer =
+ (Float alpha) -> {
+ mScrimInFront.setViewAlpha(mInFrontAlpha);
+ mNotificationsScrim.setViewAlpha(mNotificationsAlpha);
+ mBehindAlpha = alpha;
+ mScrimBehind.setViewAlpha(alpha);
+ };
+
+ Consumer<TransitionStep> mPrimaryBouncerToGoneTransition;
+
@Inject
public ScrimController(
LightBarController lightBarController,
@@ -265,13 +289,18 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
@Main Executor mainExecutor,
ScreenOffAnimationController screenOffAnimationController,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
- StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+ PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel,
+ KeyguardTransitionInteractor keyguardTransitionInteractor,
+ SysuiStatusBarStateController sysuiStatusBarStateController,
+ @Main CoroutineDispatcher mainDispatcher) {
mScrimStateListener = lightBarController::setScrimState;
mDefaultScrimAlpha = BUSY_SCRIM_ALPHA;
mKeyguardStateController = keyguardStateController;
mDarkenWhileDragging = !mKeyguardStateController.canDismissLockScreen();
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mStatusBarStateController = sysuiStatusBarStateController;
mKeyguardVisibilityCallback = new KeyguardVisibilityCallback();
mHandler = handler;
mMainExecutor = mainExecutor;
@@ -304,6 +333,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
}
});
mColors = new GradientColors();
+ mPrimaryBouncerToGoneTransitionViewModel = primaryBouncerToGoneTransitionViewModel;
+ mKeyguardTransitionInteractor = keyguardTransitionInteractor;
+ mMainDispatcher = mainDispatcher;
}
/**
@@ -343,6 +375,33 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
for (ScrimState state : ScrimState.values()) {
state.prepare(state);
}
+
+ // Directly control transition to UNLOCKED scrim state from PRIMARY_BOUNCER, and make sure
+ // to report back that keyguard has faded away. This fixes cases where the scrim state was
+ // rapidly switching on unlock, due to shifts in state in CentralSurfacesImpl
+ mPrimaryBouncerToGoneTransition =
+ (TransitionStep step) -> {
+ TransitionState state = step.getTransitionState();
+
+ mIsBouncerToGoneTransitionRunning = state == TransitionState.RUNNING;
+
+ if (state == TransitionState.STARTED) {
+ setExpansionAffectsAlpha(false);
+ transitionTo(ScrimState.UNLOCKED);
+ }
+
+ if (state == TransitionState.FINISHED || state == TransitionState.CANCELED) {
+ setExpansionAffectsAlpha(true);
+ if (mKeyguardStateController.isKeyguardFadingAway()) {
+ mStatusBarKeyguardViewManager.onKeyguardFadedAway();
+ }
+ }
+ };
+
+ collectFlow(behindScrim, mKeyguardTransitionInteractor.getPrimaryBouncerToGoneTransition(),
+ mPrimaryBouncerToGoneTransition, mMainDispatcher);
+ collectFlow(behindScrim, mPrimaryBouncerToGoneTransitionViewModel.getScrimBehindAlpha(),
+ mScrimAlphaConsumer, mMainDispatcher);
}
/**
@@ -365,6 +424,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
}
public void transitionTo(ScrimState state, Callback callback) {
+ if (mIsBouncerToGoneTransitionRunning) {
+ Log.i(TAG, "Skipping transition to: " + state
+ + " while mIsBouncerToGoneTransitionRunning");
+ return;
+ }
if (state == mState) {
// Call the callback anyway, unless it's already enqueued
if (callback != null && mCallback != callback) {
@@ -1036,7 +1100,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
mBehindAlpha = 1;
}
// Prevent notification scrim flicker when transitioning away from keyguard.
- if (mKeyguardStateController.isKeyguardGoingAway()) {
+ if (mKeyguardStateController.isKeyguardGoingAway()
+ && !mStatusBarStateController.leaveOpenOnKeyguardHide()) {
mNotificationsAlpha = 0;
}
@@ -1125,7 +1190,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
Trace.traceCounter(Trace.TRACE_TAG_APP, getScrimName(scrimView) + "_tint",
Color.alpha(tint));
scrimView.setTint(tint);
- scrimView.setViewAlpha(alpha);
+ if (!mIsBouncerToGoneTransitionRunning) {
+ scrimView.setViewAlpha(alpha);
+ }
} else {
scrim.setAlpha(alpha);
}
@@ -1473,6 +1540,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
}
public void setKeyguardOccluded(boolean keyguardOccluded) {
+ if (mKeyguardOccluded == keyguardOccluded) {
+ return;
+ }
mKeyguardOccluded = keyguardOccluded;
updateScrims();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index 0469e77ca991..0e6f8d4e0720 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -219,6 +219,29 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
}
@Test
+ fun isKeyguardUnlocked() =
+ runTest(UnconfinedTestDispatcher()) {
+ whenever(keyguardStateController.isUnlocked).thenReturn(false)
+ var latest: Boolean? = null
+ val job = underTest.isKeyguardUnlocked.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isFalse()
+
+ val captor = argumentCaptor<KeyguardStateController.Callback>()
+ verify(keyguardStateController).addCallback(captor.capture())
+
+ whenever(keyguardStateController.isUnlocked).thenReturn(true)
+ captor.value.onUnlockedChanged()
+ assertThat(latest).isTrue()
+
+ whenever(keyguardStateController.isUnlocked).thenReturn(false)
+ captor.value.onUnlockedChanged()
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
fun isDozing() =
runTest(UnconfinedTestDispatcher()) {
var latest: Boolean? = null
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index ae7a928cdb2c..fe9098fa5c25 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -19,6 +19,8 @@ package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
import androidx.test.filters.FlakyTest
import androidx.test.filters.SmallTest
+import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.Interpolators
import com.android.systemui.flags.FakeFeatureFlags
@@ -40,6 +42,7 @@ import com.android.systemui.keyguard.util.KeyguardTransitionRunner
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.cancelChildren
@@ -51,6 +54,8 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
@@ -77,6 +82,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
// Used to verify transition requests for test output
@Mock private lateinit var mockTransitionRepository: KeyguardTransitionRepository
@Mock private lateinit var commandQueue: CommandQueue
+ @Mock private lateinit var keyguardSecurityModel: KeyguardSecurityModel
private lateinit var fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor
private lateinit var fromDreamingTransitionInteractor: FromDreamingTransitionInteractor
@@ -102,6 +108,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
transitionRepository = KeyguardTransitionRepositoryImpl()
runner = KeyguardTransitionRunner(transitionRepository)
+ whenever(keyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(PIN)
+
val featureFlags = FakeFeatureFlags().apply { set(Flags.FACE_AUTH_REFACTOR, true) }
fromLockscreenTransitionInteractor =
FromLockscreenTransitionInteractor(
@@ -173,16 +181,17 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
+ keyguardSecurityModel = keyguardSecurityModel,
)
fromPrimaryBouncerTransitionInteractor.start()
}
@Test
- fun `DREAMING to LOCKSCREEN - dreaming state changes first`() =
+ fun `DREAMING to LOCKSCREEN`() =
testScope.runTest {
- // GIVEN a device is dreaming and occluded
+ // GIVEN a device is dreaming
keyguardRepository.setDreamingWithOverlay(true)
- keyguardRepository.setKeyguardOccluded(true)
+ keyguardRepository.setWakefulnessModel(startingToWake())
runCurrent()
// GIVEN a prior transition has run to DREAMING
@@ -215,56 +224,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
- }
- // THEN a transition to BOUNCER should occur
- assertThat(info.ownerName).isEqualTo("FromDreamingTransitionInteractor")
- assertThat(info.from).isEqualTo(KeyguardState.DREAMING)
- assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
- assertThat(info.animator).isNotNull()
-
- coroutineContext.cancelChildren()
- }
-
- @Test
- fun `DREAMING to LOCKSCREEN - occluded state changes first`() =
- testScope.runTest {
- // GIVEN a device is dreaming and occluded
- keyguardRepository.setDreamingWithOverlay(true)
- keyguardRepository.setKeyguardOccluded(true)
- runCurrent()
-
- // GIVEN a prior transition has run to DREAMING
- runner.startTransition(
- testScope,
- TransitionInfo(
- ownerName = "",
- from = KeyguardState.LOCKSCREEN,
- to = KeyguardState.DREAMING,
- animator =
- ValueAnimator().apply {
- duration = 10
- interpolator = Interpolators.LINEAR
- },
- )
- )
- runCurrent()
- reset(mockTransitionRepository)
-
- // WHEN doze is complete
- keyguardRepository.setDozeTransitionModel(
- DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
- )
- // AND occluded has stopped
- keyguardRepository.setKeyguardOccluded(false)
- advanceUntilIdle()
- // AND then dreaming has stopped
- keyguardRepository.setDreamingWithOverlay(false)
- advanceUntilIdle()
-
- val info =
- withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to BOUNCER should occur
assertThat(info.ownerName).isEqualTo("FromDreamingTransitionInteractor")
@@ -304,7 +264,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to PRIMARY_BOUNCER should occur
assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
@@ -345,7 +305,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
@@ -386,7 +346,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
@@ -427,7 +387,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
@@ -468,7 +428,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
@@ -505,7 +465,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromDozingTransitionInteractor")
@@ -542,7 +502,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromDozingTransitionInteractor")
@@ -583,7 +543,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -624,7 +584,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to AOD should occur
assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -661,7 +621,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to AOD should occur
assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -677,6 +637,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
testScope.runTest {
// GIVEN a device that is not dreaming or dozing
keyguardRepository.setDreamingWithOverlay(false)
+ keyguardRepository.setWakefulnessModel(startingToWake())
keyguardRepository.setDozeTransitionModel(
DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
)
@@ -704,7 +665,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DREAMING should occur
assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -741,7 +702,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to PRIMARY_BOUNCER should occur
assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -784,7 +745,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to AOD should occur
assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -828,7 +789,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -870,7 +831,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to LOCKSCREEN should occur
assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -912,7 +873,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to AOD should occur
assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
@@ -954,7 +915,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
@@ -995,7 +956,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture())
+ verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to LOCKSCREEN should occur
assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
new file mode 100644
index 000000000000..2a91799741b7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.statusbar.SysuiStatusBarStateController
+import com.android.systemui.util.mockito.whenever
+import com.google.common.collect.Range
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() {
+ private lateinit var underTest: PrimaryBouncerToGoneTransitionViewModel
+ private lateinit var repository: FakeKeyguardTransitionRepository
+ @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ repository = FakeKeyguardTransitionRepository()
+ val interactor = KeyguardTransitionInteractor(repository)
+ underTest = PrimaryBouncerToGoneTransitionViewModel(interactor, statusBarStateController)
+ }
+
+ @Test
+ fun scrimBehindAlpha_leaveShadeOpen() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<Float>()
+
+ val job = underTest.scrimBehindAlpha.onEach { values.add(it) }.launchIn(this)
+
+ whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(true)
+
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(0.6f))
+ repository.sendTransitionStep(step(1f))
+
+ assertThat(values.size).isEqualTo(4)
+ values.forEach { assertThat(it).isEqualTo(1f) }
+
+ job.cancel()
+ }
+
+ @Test
+ fun scrimBehindAlpha_doNotLeaveShadeOpen() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<Float>()
+
+ val job = underTest.scrimBehindAlpha.onEach { values.add(it) }.launchIn(this)
+
+ whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(false)
+
+ repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0.3f))
+ repository.sendTransitionStep(step(0.6f))
+ repository.sendTransitionStep(step(1f))
+
+ assertThat(values.size).isEqualTo(4)
+ values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
+ assertThat(values[3]).isEqualTo(0f)
+
+ job.cancel()
+ }
+
+ private fun step(
+ value: Float,
+ state: TransitionState = TransitionState.RUNNING
+ ): TransitionStep {
+ return TransitionStep(
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = KeyguardState.GONE,
+ value = value,
+ transitionState = state,
+ ownerName = "PrimaryBouncerToGoneTransitionViewModelTest"
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 0a401b09b6cf..82a57438052f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -33,6 +33,7 @@ import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteracto
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
+import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.NotificationInsetsController
@@ -65,48 +66,32 @@ import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@RunWithLooper(setAsMainLooper = true)
class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
- @Mock
- private lateinit var view: NotificationShadeWindowView
- @Mock
- private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController
- @Mock
- private lateinit var centralSurfaces: CentralSurfaces
- @Mock
- private lateinit var dockManager: DockManager
- @Mock
- private lateinit var notificationPanelViewController: NotificationPanelViewController
- @Mock
- private lateinit var notificationShadeDepthController: NotificationShadeDepthController
- @Mock
- private lateinit var notificationShadeWindowController: NotificationShadeWindowController
- @Mock
- private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController
- @Mock
- private lateinit var ambientState: AmbientState
- @Mock
- private lateinit var keyguardBouncerViewModel: KeyguardBouncerViewModel
- @Mock
- private lateinit var stackScrollLayoutController: NotificationStackScrollLayoutController
- @Mock
- private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
- @Mock
- private lateinit var statusBarWindowStateController: StatusBarWindowStateController
+ @Mock private lateinit var view: NotificationShadeWindowView
+ @Mock private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController
+ @Mock private lateinit var centralSurfaces: CentralSurfaces
+ @Mock private lateinit var dockManager: DockManager
+ @Mock private lateinit var notificationPanelViewController: NotificationPanelViewController
+ @Mock private lateinit var notificationShadeDepthController: NotificationShadeDepthController
+ @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
+ @Mock private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController
+ @Mock private lateinit var ambientState: AmbientState
+ @Mock private lateinit var keyguardBouncerViewModel: KeyguardBouncerViewModel
+ @Mock private lateinit var stackScrollLayoutController: NotificationStackScrollLayoutController
+ @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
+ @Mock private lateinit var statusBarWindowStateController: StatusBarWindowStateController
@Mock
private lateinit var lockscreenShadeTransitionController: LockscreenShadeTransitionController
- @Mock
- private lateinit var lockIconViewController: LockIconViewController
- @Mock
- private lateinit var phoneStatusBarViewController: PhoneStatusBarViewController
- @Mock
- private lateinit var pulsingGestureListener: PulsingGestureListener
- @Mock
- private lateinit var notificationInsetsController: NotificationInsetsController
- @Mock
- private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
+ @Mock private lateinit var lockIconViewController: LockIconViewController
+ @Mock private lateinit var phoneStatusBarViewController: PhoneStatusBarViewController
+ @Mock private lateinit var pulsingGestureListener: PulsingGestureListener
+ @Mock private lateinit var notificationInsetsController: NotificationInsetsController
+ @Mock private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
@Mock lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory
@Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent
@Mock lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
@Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
+ @Mock
+ lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel
private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
private lateinit var interactionEventHandler: InteractionEventHandler
@@ -118,43 +103,44 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
MockitoAnnotations.initMocks(this)
whenever(view.bottom).thenReturn(VIEW_BOTTOM)
whenever(view.findViewById<ViewGroup>(R.id.keyguard_bouncer_container))
- .thenReturn(mock(ViewGroup::class.java))
+ .thenReturn(mock(ViewGroup::class.java))
whenever(keyguardBouncerComponentFactory.create(any(ViewGroup::class.java)))
- .thenReturn(keyguardBouncerComponent)
+ .thenReturn(keyguardBouncerComponent)
whenever(keyguardBouncerComponent.securityContainerController)
- .thenReturn(keyguardSecurityContainerController)
+ .thenReturn(keyguardSecurityContainerController)
whenever(keyguardTransitionInteractor.lockscreenToDreamingTransition)
- .thenReturn(emptyFlow<TransitionStep>())
- underTest = NotificationShadeWindowViewController(
- lockscreenShadeTransitionController,
- FalsingCollectorFake(),
- sysuiStatusBarStateController,
- dockManager,
- notificationShadeDepthController,
- view,
- notificationPanelViewController,
- ShadeExpansionStateManager(),
- stackScrollLayoutController,
- statusBarKeyguardViewManager,
- statusBarWindowStateController,
- lockIconViewController,
- centralSurfaces,
- notificationShadeWindowController,
- keyguardUnlockAnimationController,
- notificationInsetsController,
- ambientState,
- pulsingGestureListener,
- keyguardBouncerViewModel,
- keyguardBouncerComponentFactory,
- alternateBouncerInteractor,
- keyguardTransitionInteractor,
- )
+ .thenReturn(emptyFlow<TransitionStep>())
+ underTest =
+ NotificationShadeWindowViewController(
+ lockscreenShadeTransitionController,
+ FalsingCollectorFake(),
+ sysuiStatusBarStateController,
+ dockManager,
+ notificationShadeDepthController,
+ view,
+ notificationPanelViewController,
+ ShadeExpansionStateManager(),
+ stackScrollLayoutController,
+ statusBarKeyguardViewManager,
+ statusBarWindowStateController,
+ lockIconViewController,
+ centralSurfaces,
+ notificationShadeWindowController,
+ keyguardUnlockAnimationController,
+ notificationInsetsController,
+ ambientState,
+ pulsingGestureListener,
+ keyguardBouncerViewModel,
+ keyguardBouncerComponentFactory,
+ alternateBouncerInteractor,
+ keyguardTransitionInteractor,
+ primaryBouncerToGoneTransitionViewModel,
+ )
underTest.setupExpandedStatusBar()
- interactionEventHandlerCaptor =
- ArgumentCaptor.forClass(InteractionEventHandler::class.java)
+ interactionEventHandlerCaptor = ArgumentCaptor.forClass(InteractionEventHandler::class.java)
verify(view).setInteractionEventHandler(interactionEventHandlerCaptor.capture())
- interactionEventHandler = interactionEventHandlerCaptor.value
+ interactionEventHandler = interactionEventHandlerCaptor.value
}
// Note: So far, these tests only cover interactions with the status bar view controller. More
@@ -184,14 +170,11 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
@Test
fun handleDispatchTouchEvent_downTouchBelowViewThenAnotherTouch_sendsTouchToSb() {
underTest.setStatusBarViewController(phoneStatusBarViewController)
- val downEvBelow = MotionEvent.obtain(
- 0L, 0L, MotionEvent.ACTION_DOWN, 0f, VIEW_BOTTOM + 4f, 0
- )
+ val downEvBelow =
+ MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, VIEW_BOTTOM + 4f, 0)
interactionEventHandler.handleDispatchTouchEvent(downEvBelow)
- val nextEvent = MotionEvent.obtain(
- 0L, 0L, MotionEvent.ACTION_MOVE, 0f, VIEW_BOTTOM + 5f, 0
- )
+ val nextEvent = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, VIEW_BOTTOM + 5f, 0)
whenever(phoneStatusBarViewController.sendTouchToView(nextEvent)).thenReturn(true)
val returnVal = interactionEventHandler.handleDispatchTouchEvent(nextEvent)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
index 5d719790386a..faa6221b675c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
@@ -46,6 +46,7 @@ import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationInsetsController;
@@ -101,6 +102,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
@Mock private NotificationInsetsController mNotificationInsetsController;
@Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
@Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+ @Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
@Captor private ArgumentCaptor<NotificationShadeWindowView.InteractionEventHandler>
mInteractionEventHandlerCaptor;
@@ -150,7 +152,8 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
mKeyguardBouncerViewModel,
mKeyguardBouncerComponentFactory,
mAlternateBouncerInteractor,
- mKeyguardTransitionInteractor
+ mKeyguardTransitionInteractor,
+ mPrimaryBouncerToGoneTransitionViewModel
);
mController.setupExpandedStatusBar();
mController.setDragDownHelper(mDragDownHelper);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index dc5a0472f49e..e1fba816382c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -24,6 +24,8 @@ import static com.android.systemui.statusbar.phone.ScrimState.SHADE_LOCKED;
import static com.google.common.truth.Truth.assertThat;
+import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
@@ -58,8 +60,14 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
+import com.android.systemui.keyguard.shared.model.KeyguardState;
+import com.android.systemui.keyguard.shared.model.TransitionState;
+import com.android.systemui.keyguard.shared.model.TransitionStep;
+import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
import com.android.systemui.scrim.ScrimView;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.policy.FakeConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -85,8 +93,10 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
+import kotlinx.coroutines.CoroutineDispatcher;
+
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
public class ScrimControllerTest extends SysuiTestCase {
@@ -115,6 +125,11 @@ public class ScrimControllerTest extends SysuiTestCase {
@Mock private DockManager mDockManager;
@Mock private ScreenOffAnimationController mScreenOffAnimationController;
@Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ @Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
+ @Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+ @Mock private CoroutineDispatcher mMainDispatcher;
+ @Mock private SysuiStatusBarStateController mSysuiStatusBarStateController;
+
// TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The
// event-dispatch-on-registration pattern caused some of these unit tests to fail.)
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -225,13 +240,22 @@ public class ScrimControllerTest extends SysuiTestCase {
when(mDelayedWakeLockBuilder.build()).thenReturn(mWakeLock);
when(mDockManager.isDocked()).thenReturn(false);
+ when(mKeyguardTransitionInteractor.getPrimaryBouncerToGoneTransition())
+ .thenReturn(emptyFlow());
+ when(mPrimaryBouncerToGoneTransitionViewModel.getScrimBehindAlpha())
+ .thenReturn(emptyFlow());
+
mScrimController = new ScrimController(mLightBarController,
mDozeParameters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder,
new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor,
mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
mScreenOffAnimationController,
mKeyguardUnlockAnimationController,
- mStatusBarKeyguardViewManager);
+ mStatusBarKeyguardViewManager,
+ mPrimaryBouncerToGoneTransitionViewModel,
+ mKeyguardTransitionInteractor,
+ mSysuiStatusBarStateController,
+ mMainDispatcher);
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
mScrimController.setAnimatorListener(mAnimatorListener);
@@ -861,7 +885,11 @@ public class ScrimControllerTest extends SysuiTestCase {
mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
mScreenOffAnimationController,
mKeyguardUnlockAnimationController,
- mStatusBarKeyguardViewManager);
+ mStatusBarKeyguardViewManager,
+ mPrimaryBouncerToGoneTransitionViewModel,
+ mKeyguardTransitionInteractor,
+ mSysuiStatusBarStateController,
+ mMainDispatcher);
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
mScrimController.setAnimatorListener(mAnimatorListener);
@@ -1629,6 +1657,28 @@ public class ScrimControllerTest extends SysuiTestCase {
assertScrimAlpha(mScrimBehind, 0);
}
+ @Test
+ public void ignoreTransitionRequestWhileKeyguardTransitionRunning() {
+ mScrimController.transitionTo(ScrimState.UNLOCKED);
+ mScrimController.mPrimaryBouncerToGoneTransition.accept(
+ new TransitionStep(KeyguardState.PRIMARY_BOUNCER, KeyguardState.GONE, 0f,
+ TransitionState.RUNNING, "ScrimControllerTest"));
+
+ // This request should not happen
+ mScrimController.transitionTo(ScrimState.BOUNCER);
+ assertThat(mScrimController.getState()).isEqualTo(ScrimState.UNLOCKED);
+ }
+
+ @Test
+ public void primaryBouncerToGoneOnFinishCallsKeyguardFadedAway() {
+ when(mKeyguardStateController.isKeyguardFadingAway()).thenReturn(true);
+ mScrimController.mPrimaryBouncerToGoneTransition.accept(
+ new TransitionStep(KeyguardState.PRIMARY_BOUNCER, KeyguardState.GONE, 0f,
+ TransitionState.FINISHED, "ScrimControllerTest"));
+
+ verify(mStatusBarKeyguardViewManager).onKeyguardFadedAway();
+ }
+
private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
mScrimController.setRawPanelExpansionFraction(expansion);
finishAnimationsImmediately();
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 1a371c73550c..194ed02712b2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -47,6 +47,9 @@ class FakeKeyguardRepository : KeyguardRepository {
private val _isKeyguardShowing = MutableStateFlow(false)
override val isKeyguardShowing: Flow<Boolean> = _isKeyguardShowing
+ private val _isKeyguardUnlocked = MutableStateFlow(false)
+ override val isKeyguardUnlocked: Flow<Boolean> = _isKeyguardUnlocked
+
private val _isKeyguardOccluded = MutableStateFlow(false)
override val isKeyguardOccluded: Flow<Boolean> = _isKeyguardOccluded
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
index eac1bd145033..16442bb525b6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
@@ -37,7 +37,7 @@ class FakeKeyguardTransitionRepository : KeyguardTransitionRepository {
_transitions.emit(step)
}
- override fun startTransition(info: TransitionInfo): UUID? {
+ override fun startTransition(info: TransitionInfo, resetIfCanceled: Boolean): UUID? {
return null
}