Transitions - Smooth out bouncer -> gone
If the device unlocks while the bouncer is in transit, the bouncer will remain visible over the launcher for half a second while the appear animation completes while the scrim immediately disappears (while also undergoing numerous bad requests to transition to invalid states). To fix, control this animation using the transition repo instead and ignore all other incoming requests while it is running. Also, support a new mode for canceling transitions. Some transitions may want to continue from the canceled point, others may want to run the starting transition in full. Fixes: 268596047 Test: ScrimControllerTest KeyguardRepositoryImplTest NotificationShadeWindowViewControllerTest KeyguardTransitionScenariosTest KeyguardTransitionRepositoryTest Test: manual - Tested all bouncer variations, with and without face unlock Change-Id: I6fdd0b796e8833539d06c8534182f1298c7e3a58
This commit is contained in:
@@ -82,7 +82,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>
|
||||
|
||||
@@ -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;
|
||||
@@ -1044,13 +1043,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() {
|
||||
|
||||
@@ -637,12 +637,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;
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 (
|
||||
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 (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 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 =
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
/**
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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.
|
||||
@@ -144,6 +146,12 @@ object KeyguardBouncerViewBinder {
|
||||
}
|
||||
}
|
||||
|
||||
launch {
|
||||
primaryBouncerToGoneTransitionViewModel.bouncerAlpha.collect { alpha ->
|
||||
securityContainerController.setAlpha(alpha)
|
||||
}
|
||||
}
|
||||
|
||||
launch {
|
||||
viewModel.bouncerExpansionAmount
|
||||
.filter { it == EXPANSION_VISIBLE }
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 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 transitionAnimation =
|
||||
KeyguardTransitionAnimationFlow(
|
||||
transitionDuration = TO_GONE_DURATION,
|
||||
transitionFlow = interactor.primaryBouncerToGoneTransition,
|
||||
)
|
||||
|
||||
/** Bouncer container alpha */
|
||||
val bouncerAlpha: Flow<Float> =
|
||||
transitionAnimation.createFlow(
|
||||
duration = 200.milliseconds,
|
||||
onStep = { 1f - it },
|
||||
)
|
||||
|
||||
/** Scrim alpha */
|
||||
val scrimAlpha: Flow<Float> =
|
||||
transitionAnimation.createFlow(
|
||||
duration = TO_GONE_DURATION,
|
||||
interpolator = EMPHASIZED_ACCELERATE,
|
||||
onStep = { 1f - it },
|
||||
)
|
||||
}
|
||||
@@ -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(),
|
||||
|
||||
@@ -3747,6 +3747,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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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,7 +55,11 @@ 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.notification.stack.ViewState;
|
||||
@@ -71,6 +77,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).
|
||||
@@ -251,6 +259,28 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
|
||||
private boolean mWakeLockHeld;
|
||||
private boolean mKeyguardOccluded;
|
||||
|
||||
private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
|
||||
private CoroutineDispatcher mMainDispatcher;
|
||||
private boolean mIsBouncerToGoneTransitionStarted = false;
|
||||
private boolean mIsBouncerToGoneTransitionRunning = false;
|
||||
private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
|
||||
private final Consumer<Float> mScrimAlphaConsumer =
|
||||
(Float alpha) -> {
|
||||
mScrimInFront.setViewAlpha(0f);
|
||||
mNotificationsScrim.setViewAlpha(0f);
|
||||
mScrimBehind.setViewAlpha(alpha);
|
||||
};
|
||||
final Consumer<TransitionStep> mPrimaryBouncerToGoneTransition =
|
||||
(TransitionStep step) -> {
|
||||
mIsBouncerToGoneTransitionRunning =
|
||||
step.getTransitionState() == TransitionState.RUNNING;
|
||||
mIsBouncerToGoneTransitionStarted =
|
||||
step.getTransitionState() == TransitionState.STARTED;
|
||||
if (mIsBouncerToGoneTransitionStarted) {
|
||||
transitionTo(ScrimState.UNLOCKED);
|
||||
}
|
||||
};
|
||||
|
||||
@Inject
|
||||
public ScrimController(
|
||||
LightBarController lightBarController,
|
||||
@@ -265,7 +295,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
|
||||
@Main Executor mainExecutor,
|
||||
ScreenOffAnimationController screenOffAnimationController,
|
||||
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
|
||||
StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
|
||||
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
|
||||
PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel,
|
||||
KeyguardTransitionInteractor keyguardTransitionInteractor,
|
||||
@Main CoroutineDispatcher mainDispatcher) {
|
||||
mScrimStateListener = lightBarController::setScrimState;
|
||||
mDefaultScrimAlpha = BUSY_SCRIM_ALPHA;
|
||||
|
||||
@@ -304,6 +337,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
|
||||
}
|
||||
});
|
||||
mColors = new GradientColors();
|
||||
mPrimaryBouncerToGoneTransitionViewModel = primaryBouncerToGoneTransitionViewModel;
|
||||
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
|
||||
mMainDispatcher = mainDispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -343,6 +379,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
|
||||
for (ScrimState state : ScrimState.values()) {
|
||||
state.prepare(state);
|
||||
}
|
||||
|
||||
collectFlow(behindScrim, mKeyguardTransitionInteractor.getPrimaryBouncerToGoneTransition(),
|
||||
mPrimaryBouncerToGoneTransition, mMainDispatcher);
|
||||
collectFlow(behindScrim, mPrimaryBouncerToGoneTransitionViewModel.getScrimAlpha(),
|
||||
mScrimAlphaConsumer, mMainDispatcher);
|
||||
}
|
||||
|
||||
// TODO(b/270984686) recompute scrim height accurately, based on shade contents.
|
||||
@@ -372,6 +413,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) {
|
||||
@@ -797,10 +843,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
|
||||
mBehindAlpha = 0;
|
||||
mNotificationsAlpha = 0;
|
||||
} else {
|
||||
// Behind scrim will finish fading in at 30% expansion.
|
||||
float behindFraction = MathUtils
|
||||
.constrainedMap(0f, 1f, 0f, 0.3f, mPanelExpansionFraction);
|
||||
mBehindAlpha = behindFraction * mDefaultScrimAlpha;
|
||||
if (!mIsBouncerToGoneTransitionStarted) {
|
||||
mBehindAlpha = behindFraction * mDefaultScrimAlpha;
|
||||
}
|
||||
// Delay fade-in of notification scrim a bit further, to coincide with the
|
||||
// behind scrim finishing fading in.
|
||||
// Also to coincide with the view starting to fade in, otherwise the empty
|
||||
@@ -1138,7 +1185,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);
|
||||
}
|
||||
@@ -1486,6 +1535,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
|
||||
}
|
||||
|
||||
public void setKeyguardOccluded(boolean keyguardOccluded) {
|
||||
if (mKeyguardOccluded == keyguardOccluded) {
|
||||
return;
|
||||
}
|
||||
mKeyguardOccluded = keyguardOccluded;
|
||||
updateScrims();
|
||||
}
|
||||
|
||||
@@ -218,6 +218,29 @@ class KeyguardRepositoryImplTest : SysuiTestCase() {
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@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()) {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,7 +60,12 @@ 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.policy.FakeConfigurationController;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
@@ -85,8 +92,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 +124,10 @@ 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;
|
||||
|
||||
// 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 +238,20 @@ public class ScrimControllerTest extends SysuiTestCase {
|
||||
when(mDelayedWakeLockBuilder.build()).thenReturn(mWakeLock);
|
||||
when(mDockManager.isDocked()).thenReturn(false);
|
||||
|
||||
when(mKeyguardTransitionInteractor.getPrimaryBouncerToGoneTransition())
|
||||
.thenReturn(emptyFlow());
|
||||
when(mPrimaryBouncerToGoneTransitionViewModel.getScrimAlpha()).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,
|
||||
mMainDispatcher);
|
||||
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
|
||||
mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
|
||||
mScrimController.setAnimatorListener(mAnimatorListener);
|
||||
@@ -861,7 +881,10 @@ public class ScrimControllerTest extends SysuiTestCase {
|
||||
mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
|
||||
mScreenOffAnimationController,
|
||||
mKeyguardUnlockAnimationController,
|
||||
mStatusBarKeyguardViewManager);
|
||||
mStatusBarKeyguardViewManager,
|
||||
mPrimaryBouncerToGoneTransitionViewModel,
|
||||
mKeyguardTransitionInteractor,
|
||||
mMainDispatcher);
|
||||
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
|
||||
mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
|
||||
mScrimController.setAnimatorListener(mAnimatorListener);
|
||||
@@ -1629,6 +1652,18 @@ 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);
|
||||
}
|
||||
|
||||
private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
|
||||
mScrimController.setRawPanelExpansionFraction(expansion);
|
||||
finishAnimationsImmediately();
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user