[DO NOT MERGE] Transitions: LOCKSCREEN->DREAMING

Add general support for lockscren->occluded/dreaming transitions,
including improved support for camera gesture occlusion. Double-tap
power will send various signals, so capture the double-tap as soon as
possible to cancel a transition in favor of the occlusion transition.

For LOCKSCREEN->DREAMING only, delay call to setOccluded, as it causes
jank when done too early. Also absorb touches while this transition is
running to prevent strange artifacts from popping in if the display is
touched.

Test: atest KeyguardRepositoryImplTest
KeyguardTransitionRepositoryTest
NotificationShadeWindowViewControllerTest
LockscreenToDreamingTransitionViewModelTest
LockscreenToOccludedTransitionViewModelTest
NotificationShadeWindowViewTest NotificationPanelViewControllerTest
Bug: 260637747

Change-Id: Ie2593706f2848ca715e557c8d4dfc129d93a29f1
This commit is contained in:
Matt Pietal
2022-12-23 19:33:15 +00:00
parent 06da15b36e
commit d991f01a22
31 changed files with 1095 additions and 306 deletions

View File

@@ -1279,6 +1279,12 @@
<!-- OCCLUDED -> LOCKSCREEN transition: Amount to shift lockscreen content on entering --> <!-- OCCLUDED -> LOCKSCREEN transition: Amount to shift lockscreen content on entering -->
<dimen name="occluded_to_lockscreen_transition_lockscreen_translation_y">40dp</dimen> <dimen name="occluded_to_lockscreen_transition_lockscreen_translation_y">40dp</dimen>
<!-- LOCKSCREEN -> DREAMING transition: Amount to shift lockscreen content on entering -->
<dimen name="lockscreen_to_dreaming_transition_lockscreen_translation_y">-40dp</dimen>
<!-- LOCKSCREEN -> OCCLUDED transition: Amount to shift lockscreen content on entering -->
<dimen name="lockscreen_to_occluded_transition_lockscreen_translation_y">-40dp</dimen>
<!-- The amount of vertical offset for the keyguard during the full shade transition. --> <!-- The amount of vertical offset for the keyguard during the full shade transition. -->
<dimen name="lockscreen_shade_keyguard_transition_vertical_offset">0dp</dimen> <dimen name="lockscreen_shade_keyguard_transition_vertical_offset">0dp</dimen>

View File

@@ -34,6 +34,7 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
import static com.android.systemui.DejankUtils.whitelistIpcs; import static com.android.systemui.DejankUtils.whitelistIpcs;
import static com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel.LOCKSCREEN_ANIMATION_DURATION_MS; import static com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel.LOCKSCREEN_ANIMATION_DURATION_MS;
import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS;
import android.animation.Animator; import android.animation.Animator;
import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter;
@@ -122,6 +123,8 @@ import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dump.DumpManager; import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.dagger.KeyguardModule; import com.android.systemui.keyguard.dagger.KeyguardModule;
import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -507,6 +510,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
private CentralSurfaces mCentralSurfaces; private CentralSurfaces mCentralSurfaces;
private boolean mUnocclusionTransitionFlagEnabled = false;
private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener = private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
new DeviceConfig.OnPropertiesChangedListener() { new DeviceConfig.OnPropertiesChangedListener() {
@Override @Override
@@ -958,8 +963,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
public void onAnimationStart(int transit, RemoteAnimationTarget[] apps, public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException { IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
if (!mUnocclusionTransitionFlagEnabled) {
setOccluded(true /* isOccluded */, true /* animate */); setOccluded(true /* isOccluded */, true /* animate */);
}
if (apps == null || apps.length == 0 || apps[0] == null) { if (apps == null || apps.length == 0 || apps[0] == null) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "No apps provided to the OccludeByDream runner; " Log.d(TAG, "No apps provided to the OccludeByDream runner; "
@@ -1001,9 +1007,20 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
applier.scheduleApply(paramsBuilder.build()); applier.scheduleApply(paramsBuilder.build());
}); });
mOccludeByDreamAnimator.addListener(new AnimatorListenerAdapter() { mOccludeByDreamAnimator.addListener(new AnimatorListenerAdapter() {
private boolean mIsCancelled = false;
@Override
public void onAnimationCancel(Animator animation) {
mIsCancelled = true;
}
@Override @Override
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
try { try {
if (!mIsCancelled && mUnocclusionTransitionFlagEnabled) {
// We're already on the main thread, don't queue this call
handleSetOccluded(true /* isOccluded */,
false /* animate */);
}
finishedCallback.onAnimationFinished(); finishedCallback.onAnimationFinished();
mOccludeByDreamAnimator = null; mOccludeByDreamAnimator = null;
} catch (RemoteException e) { } catch (RemoteException e) {
@@ -1176,6 +1193,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
ScreenOnCoordinator screenOnCoordinator, ScreenOnCoordinator screenOnCoordinator,
InteractionJankMonitor interactionJankMonitor, InteractionJankMonitor interactionJankMonitor,
DreamOverlayStateController dreamOverlayStateController, DreamOverlayStateController dreamOverlayStateController,
FeatureFlags featureFlags,
Lazy<ShadeController> shadeControllerLazy, Lazy<ShadeController> shadeControllerLazy,
Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy, Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy,
Lazy<ActivityLaunchAnimator> activityLaunchAnimator, Lazy<ActivityLaunchAnimator> activityLaunchAnimator,
@@ -1230,9 +1248,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
R.dimen.physical_power_button_center_screen_location_y); R.dimen.physical_power_button_center_screen_location_y);
mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context); mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
mDreamOpenAnimationDuration = context.getResources().getInteger( mDreamOpenAnimationDuration = (int) DREAMING_ANIMATION_DURATION_MS;
com.android.internal.R.integer.config_dreamOpenAnimationDuration);
mDreamCloseAnimationDuration = (int) LOCKSCREEN_ANIMATION_DURATION_MS; mDreamCloseAnimationDuration = (int) LOCKSCREEN_ANIMATION_DURATION_MS;
mUnocclusionTransitionFlagEnabled = featureFlags.isEnabled(Flags.UNOCCLUSION_TRANSITION);
} }
public void userActivity() { public void userActivity() {
@@ -1792,7 +1810,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
Trace.beginSection("KeyguardViewMediator#setOccluded"); Trace.beginSection("KeyguardViewMediator#setOccluded");
if (DEBUG) Log.d(TAG, "setOccluded " + isOccluded); if (DEBUG) Log.d(TAG, "setOccluded " + isOccluded);
mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_TRANSITION_FROM_AOD);
mHandler.removeMessages(SET_OCCLUDED); mHandler.removeMessages(SET_OCCLUDED);
Message msg = mHandler.obtainMessage(SET_OCCLUDED, isOccluded ? 1 : 0, animate ? 1 : 0); Message msg = mHandler.obtainMessage(SET_OCCLUDED, isOccluded ? 1 : 0, animate ? 1 : 0);
mHandler.sendMessage(msg); mHandler.sendMessage(msg);
@@ -1825,6 +1842,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
private void handleSetOccluded(boolean isOccluded, boolean animate) { private void handleSetOccluded(boolean isOccluded, boolean animate) {
Trace.beginSection("KeyguardViewMediator#handleSetOccluded"); Trace.beginSection("KeyguardViewMediator#handleSetOccluded");
Log.d(TAG, "handleSetOccluded(" + isOccluded + ")"); Log.d(TAG, "handleSetOccluded(" + isOccluded + ")");
mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_TRANSITION_FROM_AOD);
synchronized (KeyguardViewMediator.this) { synchronized (KeyguardViewMediator.this) {
if (mHiding && isOccluded) { if (mHiding && isOccluded) {
// We're in the process of going away but WindowManager wants to show a // We're in the process of going away but WindowManager wants to show a

View File

@@ -39,6 +39,7 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dump.DumpManager; import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -112,6 +113,7 @@ public class KeyguardModule {
ScreenOnCoordinator screenOnCoordinator, ScreenOnCoordinator screenOnCoordinator,
InteractionJankMonitor interactionJankMonitor, InteractionJankMonitor interactionJankMonitor,
DreamOverlayStateController dreamOverlayStateController, DreamOverlayStateController dreamOverlayStateController,
FeatureFlags featureFlags,
Lazy<ShadeController> shadeController, Lazy<ShadeController> shadeController,
Lazy<NotificationShadeWindowController> notificationShadeWindowController, Lazy<NotificationShadeWindowController> notificationShadeWindowController,
Lazy<ActivityLaunchAnimator> activityLaunchAnimator, Lazy<ActivityLaunchAnimator> activityLaunchAnimator,
@@ -142,6 +144,7 @@ public class KeyguardModule {
screenOnCoordinator, screenOnCoordinator,
interactionJankMonitor, interactionJankMonitor,
dreamOverlayStateController, dreamOverlayStateController,
featureFlags,
shadeController, shadeController,
notificationShadeWindowController, notificationShadeWindowController,
activityLaunchAnimator, activityLaunchAnimator,

View File

@@ -135,11 +135,14 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
Log.i(TAG, "Duplicate call to start the transition, rejecting: $info") Log.i(TAG, "Duplicate call to start the transition, rejecting: $info")
return null return null
} }
val startingValue =
if (lastStep.transitionState != TransitionState.FINISHED) { if (lastStep.transitionState != TransitionState.FINISHED) {
Log.i(TAG, "Transition still active: $lastStep, canceling") Log.i(TAG, "Transition still active: $lastStep, canceling")
lastStep.value
} else {
0f
} }
val startingValue = 1f - lastStep.value
lastAnimator?.cancel() lastAnimator?.cancel()
lastAnimator = info.animator lastAnimator = info.animator

View File

@@ -30,6 +30,8 @@ import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.util.kotlin.sample import com.android.systemui.util.kotlin.sample
import java.util.UUID import java.util.UUID
import javax.inject.Inject import javax.inject.Inject
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
@@ -51,6 +53,7 @@ constructor(
override fun start() { override fun start() {
listenForLockscreenToGone() listenForLockscreenToGone()
listenForLockscreenToOccluded() listenForLockscreenToOccluded()
listenForLockscreenToCamera()
listenForLockscreenToAod() listenForLockscreenToAod()
listenForLockscreenToBouncer() listenForLockscreenToBouncer()
listenForLockscreenToDreaming() listenForLockscreenToDreaming()
@@ -69,7 +72,7 @@ constructor(
name, name,
KeyguardState.LOCKSCREEN, KeyguardState.LOCKSCREEN,
KeyguardState.DREAMING, KeyguardState.DREAMING,
getAnimator(), getAnimator(TO_DREAMING_DURATION),
) )
) )
} }
@@ -184,17 +187,42 @@ constructor(
), ),
::toTriple ::toTriple
) )
.collect { triple -> .collect { (isOccluded, keyguardState, isDreaming) ->
val (isOccluded, keyguardState, isDreaming) = triple if (isOccluded && !isDreaming && keyguardState == KeyguardState.LOCKSCREEN) {
// Occlusion signals come from the framework, and should interrupt any
// existing transition
if (isOccluded && !isDreaming) {
keyguardTransitionRepository.startTransition( keyguardTransitionRepository.startTransition(
TransitionInfo( TransitionInfo(
name, name,
keyguardState, keyguardState,
KeyguardState.OCCLUDED, KeyguardState.OCCLUDED,
getAnimator(), getAnimator(TO_OCCLUDED_DURATION),
)
)
}
}
}
}
/** This signal may come in before the occlusion signal, and can provide a custom transition */
private fun listenForLockscreenToCamera() {
scope.launch {
keyguardInteractor.onCameraLaunchDetected
.sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { (_, lastStartedStep) ->
// DREAMING/AOD/OFF may trigger on the first power button push, so include this
// state in order to cancel and correct the transition
if (
lastStartedStep.to == KeyguardState.LOCKSCREEN ||
lastStartedStep.to == KeyguardState.DREAMING ||
lastStartedStep.to == KeyguardState.DOZING ||
lastStartedStep.to == KeyguardState.AOD ||
lastStartedStep.to == KeyguardState.OFF
) {
keyguardTransitionRepository.startTransition(
TransitionInfo(
name,
KeyguardState.LOCKSCREEN,
KeyguardState.OCCLUDED,
getAnimator(TO_OCCLUDED_DURATION),
) )
) )
} }
@@ -223,14 +251,16 @@ constructor(
} }
} }
private fun getAnimator(): ValueAnimator { private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
return ValueAnimator().apply { return ValueAnimator().apply {
setInterpolator(Interpolators.LINEAR) setInterpolator(Interpolators.LINEAR)
setDuration(TRANSITION_DURATION_MS) setDuration(duration.inWholeMilliseconds)
} }
} }
companion object { companion object {
private const val TRANSITION_DURATION_MS = 500L private val DEFAULT_DURATION = 500.milliseconds
val TO_DREAMING_DURATION = 933.milliseconds
val TO_OCCLUDED_DURATION = 450.milliseconds
} }
} }

View File

@@ -17,17 +17,24 @@
package com.android.systemui.keyguard.domain.interactor package com.android.systemui.keyguard.domain.interactor
import android.app.StatusBarManager
import android.graphics.Point import android.graphics.Point
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.KeyguardRepository import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
import com.android.systemui.keyguard.shared.model.DozeStateModel import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDozeOff import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDozeOff
import com.android.systemui.keyguard.shared.model.DozeTransitionModel import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.WakefulnessModel import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.CommandQueue.Callbacks
import com.android.systemui.util.kotlin.sample import com.android.systemui.util.kotlin.sample
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter
@@ -41,6 +48,7 @@ class KeyguardInteractor
@Inject @Inject
constructor( constructor(
private val repository: KeyguardRepository, private val repository: KeyguardRepository,
private val commandQueue: CommandQueue,
) { ) {
/** /**
* The amount of doze the system is in, where `1.0` is fully dozing and `0.0` is not dozing at * The amount of doze the system is in, where `1.0` is fully dozing and `0.0` is not dozing at
@@ -58,6 +66,23 @@ constructor(
val isDreaming: Flow<Boolean> = repository.isDreaming val isDreaming: Flow<Boolean> = repository.isDreaming
/** Whether the system is dreaming with an overlay active */ /** Whether the system is dreaming with an overlay active */
val isDreamingWithOverlay: Flow<Boolean> = repository.isDreamingWithOverlay val isDreamingWithOverlay: Flow<Boolean> = repository.isDreamingWithOverlay
/** Event for when the camera gesture is detected */
val onCameraLaunchDetected: Flow<CameraLaunchSourceModel> = conflatedCallbackFlow {
val callback =
object : CommandQueue.Callbacks {
override fun onCameraLaunchGestureDetected(source: Int) {
trySendWithFailureLogging(
cameraLaunchSourceIntToModel(source),
TAG,
"updated onCameraLaunchGestureDetected"
)
}
}
commandQueue.addCallback(callback)
awaitClose { commandQueue.removeCallback(callback) }
}
/** /**
* Dozing and dreaming have overlapping events. If the doze state remains in FINISH, it means * Dozing and dreaming have overlapping events. If the doze state remains in FINISH, it means
@@ -103,4 +128,21 @@ constructor(
fun isKeyguardShowing(): Boolean { fun isKeyguardShowing(): Boolean {
return repository.isKeyguardShowing() return repository.isKeyguardShowing()
} }
private fun cameraLaunchSourceIntToModel(value: Int): CameraLaunchSourceModel {
return when (value) {
StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE -> CameraLaunchSourceModel.WIGGLE
StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP ->
CameraLaunchSourceModel.POWER_DOUBLE_TAP
StatusBarManager.CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER ->
CameraLaunchSourceModel.LIFT_TRIGGER
StatusBarManager.CAMERA_LAUNCH_SOURCE_QUICK_AFFORDANCE ->
CameraLaunchSourceModel.QUICK_AFFORDANCE
else -> throw IllegalArgumentException("Invalid CameraLaunchSourceModel value: $value")
}
}
companion object {
private const val TAG = "KeyguardInteractor"
}
} }

View File

@@ -42,24 +42,32 @@ class KeyguardTransitionInteractor
constructor( constructor(
repository: KeyguardTransitionRepository, repository: KeyguardTransitionRepository,
) { ) {
/** (any)->AOD transition information */
val anyStateToAodTransition: Flow<TransitionStep> =
repository.transitions.filter { step -> step.to == KeyguardState.AOD }
/** AOD->LOCKSCREEN transition information. */ /** AOD->LOCKSCREEN transition information. */
val aodToLockscreenTransition: Flow<TransitionStep> = repository.transition(AOD, LOCKSCREEN) val aodToLockscreenTransition: Flow<TransitionStep> = repository.transition(AOD, LOCKSCREEN)
/** LOCKSCREEN->AOD transition information. */
val lockscreenToAodTransition: Flow<TransitionStep> = repository.transition(LOCKSCREEN, AOD)
/** DREAMING->LOCKSCREEN transition information. */ /** DREAMING->LOCKSCREEN transition information. */
val dreamingToLockscreenTransition: Flow<TransitionStep> = val dreamingToLockscreenTransition: Flow<TransitionStep> =
repository.transition(DREAMING, LOCKSCREEN) repository.transition(DREAMING, LOCKSCREEN)
/** LOCKSCREEN->AOD transition information. */
val lockscreenToAodTransition: Flow<TransitionStep> = repository.transition(LOCKSCREEN, AOD)
/** LOCKSCREEN->DREAMING transition information. */
val lockscreenToDreamingTransition: Flow<TransitionStep> =
repository.transition(LOCKSCREEN, DREAMING)
/** LOCKSCREEN->OCCLUDED transition information. */
val lockscreenToOccludedTransition: Flow<TransitionStep> =
repository.transition(LOCKSCREEN, OCCLUDED)
/** OCCLUDED->LOCKSCREEN transition information. */ /** OCCLUDED->LOCKSCREEN transition information. */
val occludedToLockscreenTransition: Flow<TransitionStep> = val occludedToLockscreenTransition: Flow<TransitionStep> =
repository.transition(OCCLUDED, LOCKSCREEN) repository.transition(OCCLUDED, LOCKSCREEN)
/** (any)->AOD transition information */
val anyStateToAodTransition: Flow<TransitionStep> =
repository.transitions.filter { step -> step.to == KeyguardState.AOD }
/** /**
* AOD<->LOCKSCREEN transition information, mapped to dozeAmount range of AOD (1f) <-> * AOD<->LOCKSCREEN transition information, mapped to dozeAmount range of AOD (1f) <->
* Lockscreen (0f). * Lockscreen (0f).

View File

@@ -0,0 +1,28 @@
/*
* 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.shared.model
/** Camera launch sources */
enum class CameraLaunchSourceModel {
/** Device is wiggled */
WIGGLE,
/** Power button has been double tapped */
POWER_DOUBLE_TAP,
/** Device has been lifted */
LIFT_TRIGGER,
/** Quick affordance button has been pressed */
QUICK_AFFORDANCE,
}

View File

@@ -0,0 +1,73 @@
/*
* 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.FromLockscreenTransitionInteractor.Companion.TO_DREAMING_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.AnimationParams
import com.android.systemui.keyguard.shared.model.TransitionState
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
/**
* Breaks down LOCKSCREEN->DREAMING transition into discrete steps for corresponding views to
* consume.
*/
@SysUISingleton
class LockscreenToDreamingTransitionViewModel
@Inject
constructor(
private val interactor: KeyguardTransitionInteractor,
) {
/** Lockscreen views y-translation */
fun lockscreenTranslationY(translatePx: Int): Flow<Float> {
return merge(
flowForAnimation(LOCKSCREEN_TRANSLATION_Y).map { value ->
(EMPHASIZED_ACCELERATE.getInterpolation(value) * translatePx)
},
// On end, reset the translation to 0
interactor.lockscreenToDreamingTransition
.filter { step -> step.transitionState == TransitionState.FINISHED }
.map { 0f }
)
}
/** Lockscreen views alpha */
val lockscreenAlpha: Flow<Float> = flowForAnimation(LOCKSCREEN_ALPHA).map { 1f - it }
private fun flowForAnimation(params: AnimationParams): Flow<Float> {
return interactor.transitionStepAnimation(
interactor.lockscreenToDreamingTransition,
params,
totalDuration = TO_DREAMING_DURATION
)
}
companion object {
@JvmField val DREAMING_ANIMATION_DURATION_MS = TO_DREAMING_DURATION.inWholeMilliseconds
val LOCKSCREEN_TRANSLATION_Y = AnimationParams(duration = 500.milliseconds)
val LOCKSCREEN_ALPHA = AnimationParams(duration = 250.milliseconds)
}
}

View File

@@ -0,0 +1,71 @@
/*
* 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.FromLockscreenTransitionInteractor.Companion.TO_OCCLUDED_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.AnimationParams
import com.android.systemui.keyguard.shared.model.TransitionState
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
/**
* Breaks down LOCKSCREEN->OCCLUDED transition into discrete steps for corresponding views to
* consume.
*/
@SysUISingleton
class LockscreenToOccludedTransitionViewModel
@Inject
constructor(
private val interactor: KeyguardTransitionInteractor,
) {
/** Lockscreen views y-translation */
fun lockscreenTranslationY(translatePx: Int): Flow<Float> {
return merge(
flowForAnimation(LOCKSCREEN_TRANSLATION_Y).map { value ->
(EMPHASIZED_ACCELERATE.getInterpolation(value) * translatePx)
},
// On end, reset the translation to 0
interactor.lockscreenToOccludedTransition
.filter { step -> step.transitionState == TransitionState.FINISHED }
.map { 0f }
)
}
/** Lockscreen views alpha */
val lockscreenAlpha: Flow<Float> = flowForAnimation(LOCKSCREEN_ALPHA).map { 1f - it }
private fun flowForAnimation(params: AnimationParams): Flow<Float> {
return interactor.transitionStepAnimation(
interactor.lockscreenToOccludedTransition,
params,
totalDuration = TO_OCCLUDED_DURATION
)
}
companion object {
val LOCKSCREEN_TRANSLATION_Y = AnimationParams(duration = TO_OCCLUDED_DURATION)
val LOCKSCREEN_ALPHA = AnimationParams(duration = 250.milliseconds)
}
}

View File

@@ -144,6 +144,8 @@ import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep; import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel; import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel; import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel;
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel; import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel;
import com.android.systemui.media.controls.pipeline.MediaDataManager; import com.android.systemui.media.controls.pipeline.MediaDataManager;
import com.android.systemui.media.controls.ui.KeyguardMediaController; import com.android.systemui.media.controls.ui.KeyguardMediaController;
@@ -687,12 +689,16 @@ public final class NotificationPanelViewController implements Dumpable {
private boolean mExpandLatencyTracking; private boolean mExpandLatencyTracking;
private DreamingToLockscreenTransitionViewModel mDreamingToLockscreenTransitionViewModel; private DreamingToLockscreenTransitionViewModel mDreamingToLockscreenTransitionViewModel;
private OccludedToLockscreenTransitionViewModel mOccludedToLockscreenTransitionViewModel; private OccludedToLockscreenTransitionViewModel mOccludedToLockscreenTransitionViewModel;
private LockscreenToDreamingTransitionViewModel mLockscreenToDreamingTransitionViewModel;
private LockscreenToOccludedTransitionViewModel mLockscreenToOccludedTransitionViewModel;
private KeyguardTransitionInteractor mKeyguardTransitionInteractor; private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
private CoroutineDispatcher mMainDispatcher; private CoroutineDispatcher mMainDispatcher;
private boolean mIsToLockscreenTransitionRunning = false; private boolean mIsOcclusionTransitionRunning = false;
private int mDreamingToLockscreenTransitionTranslationY; private int mDreamingToLockscreenTransitionTranslationY;
private int mOccludedToLockscreenTransitionTranslationY; private int mOccludedToLockscreenTransitionTranslationY;
private int mLockscreenToDreamingTransitionTranslationY;
private int mLockscreenToOccludedTransitionTranslationY;
private boolean mUnocclusionTransitionFlagEnabled = false; private boolean mUnocclusionTransitionFlagEnabled = false;
private final Runnable mFlingCollapseRunnable = () -> fling(0, false /* expand */, private final Runnable mFlingCollapseRunnable = () -> fling(0, false /* expand */,
@@ -711,13 +717,25 @@ public final class NotificationPanelViewController implements Dumpable {
private final Consumer<TransitionStep> mDreamingToLockscreenTransition = private final Consumer<TransitionStep> mDreamingToLockscreenTransition =
(TransitionStep step) -> { (TransitionStep step) -> {
mIsToLockscreenTransitionRunning = mIsOcclusionTransitionRunning =
step.getTransitionState() == TransitionState.RUNNING; step.getTransitionState() == TransitionState.RUNNING;
}; };
private final Consumer<TransitionStep> mOccludedToLockscreenTransition = private final Consumer<TransitionStep> mOccludedToLockscreenTransition =
(TransitionStep step) -> { (TransitionStep step) -> {
mIsToLockscreenTransitionRunning = mIsOcclusionTransitionRunning =
step.getTransitionState() == TransitionState.RUNNING;
};
private final Consumer<TransitionStep> mLockscreenToDreamingTransition =
(TransitionStep step) -> {
mIsOcclusionTransitionRunning =
step.getTransitionState() == TransitionState.RUNNING;
};
private final Consumer<TransitionStep> mLockscreenToOccludedTransition =
(TransitionStep step) -> {
mIsOcclusionTransitionRunning =
step.getTransitionState() == TransitionState.RUNNING; step.getTransitionState() == TransitionState.RUNNING;
}; };
@@ -791,6 +809,8 @@ public final class NotificationPanelViewController implements Dumpable {
KeyguardBottomAreaInteractor keyguardBottomAreaInteractor, KeyguardBottomAreaInteractor keyguardBottomAreaInteractor,
DreamingToLockscreenTransitionViewModel dreamingToLockscreenTransitionViewModel, DreamingToLockscreenTransitionViewModel dreamingToLockscreenTransitionViewModel,
OccludedToLockscreenTransitionViewModel occludedToLockscreenTransitionViewModel, OccludedToLockscreenTransitionViewModel occludedToLockscreenTransitionViewModel,
LockscreenToDreamingTransitionViewModel lockscreenToDreamingTransitionViewModel,
LockscreenToOccludedTransitionViewModel lockscreenToOccludedTransitionViewModel,
@Main CoroutineDispatcher mainDispatcher, @Main CoroutineDispatcher mainDispatcher,
KeyguardTransitionInteractor keyguardTransitionInteractor, KeyguardTransitionInteractor keyguardTransitionInteractor,
DumpManager dumpManager) { DumpManager dumpManager) {
@@ -810,6 +830,8 @@ public final class NotificationPanelViewController implements Dumpable {
mGutsManager = gutsManager; mGutsManager = gutsManager;
mDreamingToLockscreenTransitionViewModel = dreamingToLockscreenTransitionViewModel; mDreamingToLockscreenTransitionViewModel = dreamingToLockscreenTransitionViewModel;
mOccludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel; mOccludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel;
mLockscreenToDreamingTransitionViewModel = lockscreenToDreamingTransitionViewModel;
mLockscreenToOccludedTransitionViewModel = lockscreenToOccludedTransitionViewModel;
mKeyguardTransitionInteractor = keyguardTransitionInteractor; mKeyguardTransitionInteractor = keyguardTransitionInteractor;
mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override @Override
@@ -1117,22 +1139,44 @@ public final class NotificationPanelViewController implements Dumpable {
collectFlow(mView, mKeyguardTransitionInteractor.getDreamingToLockscreenTransition(), collectFlow(mView, mKeyguardTransitionInteractor.getDreamingToLockscreenTransition(),
mDreamingToLockscreenTransition, mMainDispatcher); mDreamingToLockscreenTransition, mMainDispatcher);
collectFlow(mView, mDreamingToLockscreenTransitionViewModel.getLockscreenAlpha(), collectFlow(mView, mDreamingToLockscreenTransitionViewModel.getLockscreenAlpha(),
toLockscreenTransitionAlpha(mNotificationStackScrollLayoutController), setTransitionAlpha(mNotificationStackScrollLayoutController),
mMainDispatcher); mMainDispatcher);
collectFlow(mView, mDreamingToLockscreenTransitionViewModel.lockscreenTranslationY( collectFlow(mView, mDreamingToLockscreenTransitionViewModel.lockscreenTranslationY(
mDreamingToLockscreenTransitionTranslationY), mDreamingToLockscreenTransitionTranslationY),
toLockscreenTransitionY(mNotificationStackScrollLayoutController), setTransitionY(mNotificationStackScrollLayoutController),
mMainDispatcher); mMainDispatcher);
// Occluded->Lockscreen // Occluded->Lockscreen
collectFlow(mView, mKeyguardTransitionInteractor.getOccludedToLockscreenTransition(), collectFlow(mView, mKeyguardTransitionInteractor.getOccludedToLockscreenTransition(),
mOccludedToLockscreenTransition, mMainDispatcher); mOccludedToLockscreenTransition, mMainDispatcher);
collectFlow(mView, mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha(), collectFlow(mView, mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha(),
toLockscreenTransitionAlpha(mNotificationStackScrollLayoutController), setTransitionAlpha(mNotificationStackScrollLayoutController),
mMainDispatcher); mMainDispatcher);
collectFlow(mView, mOccludedToLockscreenTransitionViewModel.lockscreenTranslationY( collectFlow(mView, mOccludedToLockscreenTransitionViewModel.lockscreenTranslationY(
mOccludedToLockscreenTransitionTranslationY), mOccludedToLockscreenTransitionTranslationY),
toLockscreenTransitionY(mNotificationStackScrollLayoutController), setTransitionY(mNotificationStackScrollLayoutController),
mMainDispatcher);
// Lockscreen->Dreaming
collectFlow(mView, mKeyguardTransitionInteractor.getLockscreenToDreamingTransition(),
mLockscreenToDreamingTransition, mMainDispatcher);
collectFlow(mView, mLockscreenToDreamingTransitionViewModel.getLockscreenAlpha(),
setTransitionAlpha(mNotificationStackScrollLayoutController),
mMainDispatcher);
collectFlow(mView, mLockscreenToDreamingTransitionViewModel.lockscreenTranslationY(
mLockscreenToDreamingTransitionTranslationY),
setTransitionY(mNotificationStackScrollLayoutController),
mMainDispatcher);
// Lockscreen->Occluded
collectFlow(mView, mKeyguardTransitionInteractor.getLockscreenToOccludedTransition(),
mLockscreenToOccludedTransition, mMainDispatcher);
collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenAlpha(),
setTransitionAlpha(mNotificationStackScrollLayoutController),
mMainDispatcher);
collectFlow(mView, mLockscreenToOccludedTransitionViewModel.lockscreenTranslationY(
mLockscreenToOccludedTransitionTranslationY),
setTransitionY(mNotificationStackScrollLayoutController),
mMainDispatcher); mMainDispatcher);
} }
} }
@@ -1173,6 +1217,10 @@ public final class NotificationPanelViewController implements Dumpable {
R.dimen.dreaming_to_lockscreen_transition_lockscreen_translation_y); R.dimen.dreaming_to_lockscreen_transition_lockscreen_translation_y);
mOccludedToLockscreenTransitionTranslationY = mResources.getDimensionPixelSize( mOccludedToLockscreenTransitionTranslationY = mResources.getDimensionPixelSize(
R.dimen.occluded_to_lockscreen_transition_lockscreen_translation_y); R.dimen.occluded_to_lockscreen_transition_lockscreen_translation_y);
mLockscreenToDreamingTransitionTranslationY = mResources.getDimensionPixelSize(
R.dimen.lockscreen_to_dreaming_transition_lockscreen_translation_y);
mLockscreenToOccludedTransitionTranslationY = mResources.getDimensionPixelSize(
R.dimen.lockscreen_to_occluded_transition_lockscreen_translation_y);
} }
private void updateViewControllers(KeyguardStatusView keyguardStatusView, private void updateViewControllers(KeyguardStatusView keyguardStatusView,
@@ -1836,7 +1884,7 @@ public final class NotificationPanelViewController implements Dumpable {
} }
private void updateClock() { private void updateClock() {
if (mIsToLockscreenTransitionRunning) { if (mIsOcclusionTransitionRunning) {
return; return;
} }
float alpha = mClockPositionResult.clockAlpha * mKeyguardOnlyContentAlpha; float alpha = mClockPositionResult.clockAlpha * mKeyguardOnlyContentAlpha;
@@ -2727,7 +2775,7 @@ public final class NotificationPanelViewController implements Dumpable {
} else if (statusBarState == KEYGUARD } else if (statusBarState == KEYGUARD
|| statusBarState == StatusBarState.SHADE_LOCKED) { || statusBarState == StatusBarState.SHADE_LOCKED) {
mKeyguardBottomArea.setVisibility(View.VISIBLE); mKeyguardBottomArea.setVisibility(View.VISIBLE);
if (!mIsToLockscreenTransitionRunning) { if (!mIsOcclusionTransitionRunning) {
mKeyguardBottomArea.setAlpha(1f); mKeyguardBottomArea.setAlpha(1f);
} }
} else { } else {
@@ -3596,7 +3644,7 @@ public final class NotificationPanelViewController implements Dumpable {
} }
private void updateNotificationTranslucency() { private void updateNotificationTranslucency() {
if (mIsToLockscreenTransitionRunning) { if (mIsOcclusionTransitionRunning) {
return; return;
} }
float alpha = 1f; float alpha = 1f;
@@ -3654,7 +3702,7 @@ public final class NotificationPanelViewController implements Dumpable {
} }
private void updateKeyguardBottomAreaAlpha() { private void updateKeyguardBottomAreaAlpha() {
if (mIsToLockscreenTransitionRunning) { if (mIsOcclusionTransitionRunning) {
return; return;
} }
// There are two possible panel expansion behaviors: // There are two possible panel expansion behaviors:
@@ -5886,7 +5934,7 @@ public final class NotificationPanelViewController implements Dumpable {
mCurrentPanelState = state; mCurrentPanelState = state;
} }
private Consumer<Float> toLockscreenTransitionAlpha( private Consumer<Float> setTransitionAlpha(
NotificationStackScrollLayoutController stackScroller) { NotificationStackScrollLayoutController stackScroller) {
return (Float alpha) -> { return (Float alpha) -> {
mKeyguardStatusViewController.setAlpha(alpha); mKeyguardStatusViewController.setAlpha(alpha);
@@ -5904,7 +5952,7 @@ public final class NotificationPanelViewController implements Dumpable {
}; };
} }
private Consumer<Float> toLockscreenTransitionY( private Consumer<Float> setTransitionY(
NotificationStackScrollLayoutController stackScroller) { NotificationStackScrollLayoutController stackScroller) {
return (Float translationY) -> { return (Float translationY) -> {
mKeyguardStatusViewController.setTranslationY(translationY, /* excludeMedia= */false); mKeyguardStatusViewController.setTranslationY(translationY, /* excludeMedia= */false);

View File

@@ -16,6 +16,8 @@
package com.android.systemui.shade; package com.android.systemui.shade;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
import android.app.StatusBarManager; import android.app.StatusBarManager;
import android.media.AudioManager; import android.media.AudioManager;
import android.media.session.MediaSessionLegacyHelper; import android.media.session.MediaSessionLegacyHelper;
@@ -39,6 +41,9 @@ import com.android.systemui.dock.DockManager;
import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags; import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
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.binder.KeyguardBouncerViewBinder;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel; import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel;
import com.android.systemui.statusbar.DragDownHelper; import com.android.systemui.statusbar.DragDownHelper;
@@ -57,6 +62,7 @@ import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
import com.android.systemui.statusbar.window.StatusBarWindowStateController; import com.android.systemui.statusbar.window.StatusBarWindowStateController;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.function.Consumer;
import javax.inject.Inject; import javax.inject.Inject;
@@ -96,6 +102,13 @@ public class NotificationShadeWindowViewController {
private final ShadeExpansionStateManager mShadeExpansionStateManager; private final ShadeExpansionStateManager mShadeExpansionStateManager;
private boolean mIsTrackingBarGesture = false; private boolean mIsTrackingBarGesture = false;
private boolean mIsOcclusionTransitionRunning = false;
private final Consumer<TransitionStep> mLockscreenToDreamingTransition =
(TransitionStep step) -> {
mIsOcclusionTransitionRunning =
step.getTransitionState() == TransitionState.RUNNING;
};
@Inject @Inject
public NotificationShadeWindowViewController( public NotificationShadeWindowViewController(
@@ -119,6 +132,7 @@ public class NotificationShadeWindowViewController {
PulsingGestureListener pulsingGestureListener, PulsingGestureListener pulsingGestureListener,
FeatureFlags featureFlags, FeatureFlags featureFlags,
KeyguardBouncerViewModel keyguardBouncerViewModel, KeyguardBouncerViewModel keyguardBouncerViewModel,
KeyguardTransitionInteractor keyguardTransitionInteractor,
KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory
) { ) {
mLockscreenShadeTransitionController = transitionController; mLockscreenShadeTransitionController = transitionController;
@@ -148,6 +162,11 @@ public class NotificationShadeWindowViewController {
keyguardBouncerViewModel, keyguardBouncerViewModel,
keyguardBouncerComponentFactory); keyguardBouncerComponentFactory);
} }
if (featureFlags.isEnabled(Flags.UNOCCLUSION_TRANSITION)) {
collectFlow(mView, keyguardTransitionInteractor.getLockscreenToDreamingTransition(),
mLockscreenToDreamingTransition);
}
} }
/** /**
@@ -215,6 +234,10 @@ public class NotificationShadeWindowViewController {
return true; return true;
} }
if (mIsOcclusionTransitionRunning) {
return false;
}
mFalsingCollector.onTouchEvent(ev); mFalsingCollector.onTouchEvent(ev);
mPulsingWakeupGestureHandler.onTouchEvent(ev); mPulsingWakeupGestureHandler.onTouchEvent(ev);
mStatusBarKeyguardViewManager.onTouch(ev); mStatusBarKeyguardViewManager.onTouch(ev);

View File

@@ -15,6 +15,7 @@
*/ */
package com.android.keyguard package com.android.keyguard
import com.android.systemui.statusbar.CommandQueue
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.testing.AndroidTestingRunner import android.testing.AndroidTestingRunner
import android.view.View import android.view.View
@@ -81,6 +82,7 @@ class ClockEventControllerTest : SysuiTestCase() {
@Mock private lateinit var largeClockEvents: ClockFaceEvents @Mock private lateinit var largeClockEvents: ClockFaceEvents
@Mock private lateinit var parentView: View @Mock private lateinit var parentView: View
@Mock private lateinit var transitionRepository: KeyguardTransitionRepository @Mock private lateinit var transitionRepository: KeyguardTransitionRepository
@Mock private lateinit var commandQueue: CommandQueue
private lateinit var repository: FakeKeyguardRepository private lateinit var repository: FakeKeyguardRepository
@Mock private lateinit var logBuffer: LogBuffer @Mock private lateinit var logBuffer: LogBuffer
private lateinit var underTest: ClockEventController private lateinit var underTest: ClockEventController
@@ -99,7 +101,7 @@ class ClockEventControllerTest : SysuiTestCase() {
repository = FakeKeyguardRepository() repository = FakeKeyguardRepository()
underTest = ClockEventController( underTest = ClockEventController(
KeyguardInteractor(repository = repository), KeyguardInteractor(repository = repository, commandQueue = commandQueue),
KeyguardTransitionInteractor(repository = transitionRepository), KeyguardTransitionInteractor(repository = transitionRepository),
broadcastDispatcher, broadcastDispatcher,
batteryController, batteryController,

View File

@@ -49,6 +49,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -91,6 +92,7 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase {
protected @Mock AuthRippleController mAuthRippleController; protected @Mock AuthRippleController mAuthRippleController;
protected @Mock FeatureFlags mFeatureFlags; protected @Mock FeatureFlags mFeatureFlags;
protected @Mock KeyguardTransitionRepository mTransitionRepository; protected @Mock KeyguardTransitionRepository mTransitionRepository;
protected @Mock CommandQueue mCommandQueue;
protected FakeExecutor mDelayableExecutor = new FakeExecutor(new FakeSystemClock()); protected FakeExecutor mDelayableExecutor = new FakeExecutor(new FakeSystemClock());
protected LockIconViewController mUnderTest; protected LockIconViewController mUnderTest;
@@ -157,7 +159,7 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase {
mAuthRippleController, mAuthRippleController,
mResources, mResources,
new KeyguardTransitionInteractor(mTransitionRepository), new KeyguardTransitionInteractor(mTransitionRepository),
new KeyguardInteractor(new FakeKeyguardRepository()), new KeyguardInteractor(new FakeKeyguardRepository(), mCommandQueue),
mFeatureFlags mFeatureFlags
); );
} }

View File

@@ -51,6 +51,7 @@ import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.FakeSharedPreferences import com.android.systemui.util.FakeSharedPreferences
import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.any
@@ -86,9 +87,9 @@ class CustomizationProviderTest : SysuiTestCase() {
@Mock private lateinit var backgroundHandler: Handler @Mock private lateinit var backgroundHandler: Handler
@Mock private lateinit var previewSurfacePackage: SurfaceControlViewHost.SurfacePackage @Mock private lateinit var previewSurfacePackage: SurfaceControlViewHost.SurfacePackage
@Mock private lateinit var launchAnimator: DialogLaunchAnimator @Mock private lateinit var launchAnimator: DialogLaunchAnimator
@Mock private lateinit var commandQueue: CommandQueue
private lateinit var underTest: CustomizationProvider private lateinit var underTest: CustomizationProvider
private lateinit var testScope: TestScope private lateinit var testScope: TestScope
@Before @Before
@@ -160,6 +161,7 @@ class CustomizationProviderTest : SysuiTestCase() {
keyguardInteractor = keyguardInteractor =
KeyguardInteractor( KeyguardInteractor(
repository = FakeKeyguardRepository(), repository = FakeKeyguardRepository(),
commandQueue = commandQueue,
), ),
registry = mock(), registry = mock(),
lockPatternUtils = lockPatternUtils, lockPatternUtils = lockPatternUtils,

View File

@@ -66,6 +66,7 @@ import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dump.DumpManager; import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.settings.UserTracker; import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.NotificationShadeWindowControllerImpl; import com.android.systemui.shade.NotificationShadeWindowControllerImpl;
@@ -135,6 +136,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
private @Mock AuthController mAuthController; private @Mock AuthController mAuthController;
private @Mock ShadeExpansionStateManager mShadeExpansionStateManager; private @Mock ShadeExpansionStateManager mShadeExpansionStateManager;
private @Mock ShadeWindowLogger mShadeWindowLogger; private @Mock ShadeWindowLogger mShadeWindowLogger;
private @Mock FeatureFlags mFeatureFlags;
private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake(); private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake();
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
@@ -510,6 +512,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
mScreenOnCoordinator, mScreenOnCoordinator,
mInteractionJankMonitor, mInteractionJankMonitor,
mDreamOverlayStateController, mDreamOverlayStateController,
mFeatureFlags,
() -> mShadeController, () -> mShadeController,
() -> mNotificationShadeWindowController, () -> mNotificationShadeWindowController,
() -> mActivityLaunchAnimator, () -> mActivityLaunchAnimator,

View File

@@ -104,7 +104,7 @@ class KeyguardTransitionRepositoryTest : SysuiTestCase() {
val firstTransitionSteps = listWithStep(step = BigDecimal(.1), stop = BigDecimal(.1)) val firstTransitionSteps = listWithStep(step = BigDecimal(.1), stop = BigDecimal(.1))
assertSteps(steps.subList(0, 4), firstTransitionSteps, AOD, LOCKSCREEN) assertSteps(steps.subList(0, 4), firstTransitionSteps, AOD, LOCKSCREEN)
val secondTransitionSteps = listWithStep(step = BigDecimal(.1), start = BigDecimal(.9)) val secondTransitionSteps = listWithStep(step = BigDecimal(.1), start = BigDecimal(.1))
assertSteps(steps.subList(4, steps.size), secondTransitionSteps, LOCKSCREEN, AOD) assertSteps(steps.subList(4, steps.size), secondTransitionSteps, LOCKSCREEN, AOD)
job.cancel() job.cancel()
@@ -201,7 +201,10 @@ class KeyguardTransitionRepositoryTest : SysuiTestCase() {
) )
) )
fractions.forEachIndexed { index, fraction -> fractions.forEachIndexed { index, fraction ->
assertThat(steps[index + 1]) val step = steps[index + 1]
val truncatedValue =
BigDecimal(step.value.toDouble()).setScale(2, RoundingMode.HALF_UP).toFloat()
assertThat(step.copy(value = truncatedValue))
.isEqualTo( .isEqualTo(
TransitionStep( TransitionStep(
from, from,

View File

@@ -0,0 +1,86 @@
/*
* 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.domain.interactor
import android.app.StatusBarManager
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.CommandQueue.Callbacks
import com.android.systemui.util.mockito.argumentCaptor
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(JUnit4::class)
class KeyguardInteractorTest : SysuiTestCase() {
@Mock private lateinit var commandQueue: CommandQueue
private lateinit var underTest: KeyguardInteractor
private lateinit var repository: FakeKeyguardRepository
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
repository = FakeKeyguardRepository()
underTest = KeyguardInteractor(repository, commandQueue)
}
@Test
fun onCameraLaunchDetected() = runTest {
val flow = underTest.onCameraLaunchDetected
var cameraLaunchSource = collectLastValue(flow)
runCurrent()
val captor = argumentCaptor<CommandQueue.Callbacks>()
verify(commandQueue).addCallback(captor.capture())
captor.value.onCameraLaunchGestureDetected(StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE)
assertThat(cameraLaunchSource()).isEqualTo(CameraLaunchSourceModel.WIGGLE)
captor.value.onCameraLaunchGestureDetected(
StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP
)
assertThat(cameraLaunchSource()).isEqualTo(CameraLaunchSourceModel.POWER_DOUBLE_TAP)
captor.value.onCameraLaunchGestureDetected(
StatusBarManager.CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER
)
assertThat(cameraLaunchSource()).isEqualTo(CameraLaunchSourceModel.LIFT_TRIGGER)
captor.value.onCameraLaunchGestureDetected(
StatusBarManager.CAMERA_LAUNCH_SOURCE_QUICK_AFFORDANCE
)
assertThat(cameraLaunchSource()).isEqualTo(CameraLaunchSourceModel.QUICK_AFFORDANCE)
flow.onCompletion { verify(commandQueue).removeCallback(captor.value) }
}
}

View File

@@ -44,6 +44,7 @@ import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.settings.FakeUserTracker import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.FakeSharedPreferences import com.android.systemui.util.FakeSharedPreferences
import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.any
@@ -216,6 +217,7 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() {
@Mock private lateinit var animationController: ActivityLaunchAnimator.Controller @Mock private lateinit var animationController: ActivityLaunchAnimator.Controller
@Mock private lateinit var expandable: Expandable @Mock private lateinit var expandable: Expandable
@Mock private lateinit var launchAnimator: DialogLaunchAnimator @Mock private lateinit var launchAnimator: DialogLaunchAnimator
@Mock private lateinit var commandQueue: CommandQueue
private lateinit var underTest: KeyguardQuickAffordanceInteractor private lateinit var underTest: KeyguardQuickAffordanceInteractor
@@ -286,7 +288,11 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() {
) )
underTest = underTest =
KeyguardQuickAffordanceInteractor( KeyguardQuickAffordanceInteractor(
keyguardInteractor = KeyguardInteractor(repository = FakeKeyguardRepository()), keyguardInteractor =
KeyguardInteractor(
repository = FakeKeyguardRepository(),
commandQueue = commandQueue
),
registry = registry =
FakeKeyguardQuickAffordanceRegistry( FakeKeyguardQuickAffordanceRegistry(
mapOf( mapOf(

View File

@@ -46,6 +46,7 @@ import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.FakeSharedPreferences import com.android.systemui.util.FakeSharedPreferences
import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.mock
@@ -75,6 +76,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() {
@Mock private lateinit var userTracker: UserTracker @Mock private lateinit var userTracker: UserTracker
@Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var launchAnimator: DialogLaunchAnimator @Mock private lateinit var launchAnimator: DialogLaunchAnimator
@Mock private lateinit var commandQueue: CommandQueue
private lateinit var underTest: KeyguardQuickAffordanceInteractor private lateinit var underTest: KeyguardQuickAffordanceInteractor
@@ -152,7 +154,8 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() {
underTest = underTest =
KeyguardQuickAffordanceInteractor( KeyguardQuickAffordanceInteractor(
keyguardInteractor = KeyguardInteractor(repository = repository), keyguardInteractor =
KeyguardInteractor(repository = repository, commandQueue = commandQueue),
registry = registry =
FakeKeyguardQuickAffordanceRegistry( FakeKeyguardQuickAffordanceRegistry(
mapOf( mapOf(

View File

@@ -33,6 +33,7 @@ import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.keyguard.util.KeyguardTransitionRunner import com.android.systemui.keyguard.util.KeyguardTransitionRunner
import com.android.systemui.shade.data.repository.FakeShadeRepository import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.shade.data.repository.ShadeRepository import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.util.mockito.withArgCaptor import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.cancelChildren import kotlinx.coroutines.cancelChildren
@@ -66,6 +67,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
// Used to verify transition requests for test output // Used to verify transition requests for test output
@Mock private lateinit var mockTransitionRepository: KeyguardTransitionRepository @Mock private lateinit var mockTransitionRepository: KeyguardTransitionRepository
@Mock private lateinit var commandQueue: CommandQueue
private lateinit var fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor private lateinit var fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor
private lateinit var fromDreamingTransitionInteractor: FromDreamingTransitionInteractor private lateinit var fromDreamingTransitionInteractor: FromDreamingTransitionInteractor
@@ -85,7 +87,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
fromLockscreenTransitionInteractor = fromLockscreenTransitionInteractor =
FromLockscreenTransitionInteractor( FromLockscreenTransitionInteractor(
scope = testScope, scope = testScope,
keyguardInteractor = KeyguardInteractor(keyguardRepository), keyguardInteractor = KeyguardInteractor(keyguardRepository, commandQueue),
shadeRepository = shadeRepository, shadeRepository = shadeRepository,
keyguardTransitionRepository = mockTransitionRepository, keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository), keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
@@ -95,7 +97,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
fromDreamingTransitionInteractor = fromDreamingTransitionInteractor =
FromDreamingTransitionInteractor( FromDreamingTransitionInteractor(
scope = testScope, scope = testScope,
keyguardInteractor = KeyguardInteractor(keyguardRepository), keyguardInteractor = KeyguardInteractor(keyguardRepository, commandQueue),
keyguardTransitionRepository = mockTransitionRepository, keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository), keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository),
) )

View File

@@ -47,6 +47,7 @@ import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.FakeSharedPreferences import com.android.systemui.util.FakeSharedPreferences
import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.any
@@ -84,6 +85,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
@Mock private lateinit var userTracker: UserTracker @Mock private lateinit var userTracker: UserTracker
@Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var launchAnimator: DialogLaunchAnimator @Mock private lateinit var launchAnimator: DialogLaunchAnimator
@Mock private lateinit var commandQueue: CommandQueue
private lateinit var underTest: KeyguardBottomAreaViewModel private lateinit var underTest: KeyguardBottomAreaViewModel
@@ -124,7 +126,8 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
) )
repository = FakeKeyguardRepository() repository = FakeKeyguardRepository()
val keyguardInteractor = KeyguardInteractor(repository = repository) val keyguardInteractor =
KeyguardInteractor(repository = repository, commandQueue = commandQueue)
whenever(userTracker.userHandle).thenReturn(mock()) whenever(userTracker.userHandle).thenReturn(mock())
whenever(lockPatternUtils.getStrongAuthForUser(anyInt())) whenever(lockPatternUtils.getStrongAuthForUser(anyInt()))
.thenReturn(LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED) .thenReturn(LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED)

View File

@@ -0,0 +1,135 @@
/*
* 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.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_DREAMING_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.AnimationParams
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.LockscreenToDreamingTransitionViewModel.Companion.LOCKSCREEN_ALPHA
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.Companion.LOCKSCREEN_TRANSLATION_Y
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.junit.runners.JUnit4
@SmallTest
@RunWith(JUnit4::class)
class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() {
private lateinit var underTest: LockscreenToDreamingTransitionViewModel
private lateinit var repository: FakeKeyguardTransitionRepository
@Before
fun setUp() {
repository = FakeKeyguardTransitionRepository()
val interactor = KeyguardTransitionInteractor(repository)
underTest = LockscreenToDreamingTransitionViewModel(interactor)
}
@Test
fun lockscreenFadeOut() =
runTest(UnconfinedTestDispatcher()) {
val values = mutableListOf<Float>()
val job = underTest.lockscreenAlpha.onEach { values.add(it) }.launchIn(this)
// Should start running here...
repository.sendTransitionStep(step(0f))
repository.sendTransitionStep(step(0.1f))
repository.sendTransitionStep(step(0.2f))
// ...up to here
repository.sendTransitionStep(step(0.3f))
repository.sendTransitionStep(step(1f))
// Only three values should be present, since the dream overlay runs for a small
// fraction
// of the overall animation time
assertThat(values.size).isEqualTo(3)
assertThat(values[0]).isEqualTo(1f - animValue(0f, LOCKSCREEN_ALPHA))
assertThat(values[1]).isEqualTo(1f - animValue(0.1f, LOCKSCREEN_ALPHA))
assertThat(values[2]).isEqualTo(1f - animValue(0.2f, LOCKSCREEN_ALPHA))
job.cancel()
}
@Test
fun lockscreenTranslationY() =
runTest(UnconfinedTestDispatcher()) {
val values = mutableListOf<Float>()
val pixels = 100
val job =
underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
// Should start running here...
repository.sendTransitionStep(step(0f))
repository.sendTransitionStep(step(0.3f))
repository.sendTransitionStep(step(0.5f))
// ...up to here
repository.sendTransitionStep(step(1f))
assertThat(values.size).isEqualTo(3)
assertThat(values[0])
.isEqualTo(
EMPHASIZED_ACCELERATE.getInterpolation(
animValue(0f, LOCKSCREEN_TRANSLATION_Y)
) * pixels
)
assertThat(values[1])
.isEqualTo(
EMPHASIZED_ACCELERATE.getInterpolation(
animValue(0.3f, LOCKSCREEN_TRANSLATION_Y)
) * pixels
)
assertThat(values[2])
.isEqualTo(
EMPHASIZED_ACCELERATE.getInterpolation(
animValue(0.5f, LOCKSCREEN_TRANSLATION_Y)
) * pixels
)
job.cancel()
}
private fun animValue(stepValue: Float, params: AnimationParams): Float {
val totalDuration = TO_DREAMING_DURATION
val startValue = (params.startTime / totalDuration).toFloat()
val multiplier = (totalDuration / params.duration).toFloat()
return (stepValue - startValue) * multiplier
}
private fun step(value: Float): TransitionStep {
return TransitionStep(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.DREAMING,
value = value,
transitionState = TransitionState.RUNNING,
ownerName = "LockscreenToDreamingTransitionViewModelTest"
)
}
}

View File

@@ -0,0 +1,140 @@
/*
* 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.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_OCCLUDED_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.AnimationParams
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.LockscreenToOccludedTransitionViewModel.Companion.LOCKSCREEN_ALPHA
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel.Companion.LOCKSCREEN_TRANSLATION_Y
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.junit.runners.JUnit4
@SmallTest
@RunWith(JUnit4::class)
class LockscreenToOccludedTransitionViewModelTest : SysuiTestCase() {
private lateinit var underTest: LockscreenToOccludedTransitionViewModel
private lateinit var repository: FakeKeyguardTransitionRepository
@Before
fun setUp() {
repository = FakeKeyguardTransitionRepository()
val interactor = KeyguardTransitionInteractor(repository)
underTest = LockscreenToOccludedTransitionViewModel(interactor)
}
@Test
fun lockscreenFadeOut() =
runTest(UnconfinedTestDispatcher()) {
val values = mutableListOf<Float>()
val job = underTest.lockscreenAlpha.onEach { values.add(it) }.launchIn(this)
// Should start running here...
repository.sendTransitionStep(step(0f))
repository.sendTransitionStep(step(0.1f))
repository.sendTransitionStep(step(0.4f))
// ...up to here
repository.sendTransitionStep(step(0.7f))
repository.sendTransitionStep(step(1f))
// Only 3 values should be present, since the dream overlay runs for a small fraction
// of the overall animation time
assertThat(values.size).isEqualTo(3)
assertThat(values[0]).isEqualTo(1f - animValue(0f, LOCKSCREEN_ALPHA))
assertThat(values[1]).isEqualTo(1f - animValue(0.1f, LOCKSCREEN_ALPHA))
assertThat(values[2]).isEqualTo(1f - animValue(0.4f, LOCKSCREEN_ALPHA))
job.cancel()
}
@Test
fun lockscreenTranslationY() =
runTest(UnconfinedTestDispatcher()) {
val values = mutableListOf<Float>()
val pixels = 100
val job =
underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
// Should start running here...
repository.sendTransitionStep(step(0f))
repository.sendTransitionStep(step(0.3f))
repository.sendTransitionStep(step(0.5f))
repository.sendTransitionStep(step(1f))
// ...up to here
assertThat(values.size).isEqualTo(4)
assertThat(values[0])
.isEqualTo(
EMPHASIZED_ACCELERATE.getInterpolation(
animValue(0f, LOCKSCREEN_TRANSLATION_Y)
) * pixels
)
assertThat(values[1])
.isEqualTo(
EMPHASIZED_ACCELERATE.getInterpolation(
animValue(0.3f, LOCKSCREEN_TRANSLATION_Y)
) * pixels
)
assertThat(values[2])
.isEqualTo(
EMPHASIZED_ACCELERATE.getInterpolation(
animValue(0.5f, LOCKSCREEN_TRANSLATION_Y)
) * pixels
)
assertThat(values[3])
.isEqualTo(
EMPHASIZED_ACCELERATE.getInterpolation(
animValue(1f, LOCKSCREEN_TRANSLATION_Y)
) * pixels
)
job.cancel()
}
private fun animValue(stepValue: Float, params: AnimationParams): Float {
val totalDuration = TO_OCCLUDED_DURATION
val startValue = (params.startTime / totalDuration).toFloat()
val multiplier = (totalDuration / params.duration).toFloat()
return (stepValue - startValue) * multiplier
}
private fun step(value: Float): TransitionStep {
return TransitionStep(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.OCCLUDED,
value = value,
transitionState = TransitionState.RUNNING,
ownerName = "LockscreenToOccludedTransitionViewModelTest"
)
}
}

View File

@@ -107,6 +107,8 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInterac
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel; import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel; import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel;
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel; import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel;
import com.android.systemui.media.controls.pipeline.MediaDataManager; import com.android.systemui.media.controls.pipeline.MediaDataManager;
import com.android.systemui.media.controls.ui.KeyguardMediaController; import com.android.systemui.media.controls.ui.KeyguardMediaController;
@@ -293,6 +295,9 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
@Mock private KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor; @Mock private KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
@Mock private DreamingToLockscreenTransitionViewModel mDreamingToLockscreenTransitionViewModel; @Mock private DreamingToLockscreenTransitionViewModel mDreamingToLockscreenTransitionViewModel;
@Mock private OccludedToLockscreenTransitionViewModel mOccludedToLockscreenTransitionViewModel; @Mock private OccludedToLockscreenTransitionViewModel mOccludedToLockscreenTransitionViewModel;
@Mock private LockscreenToDreamingTransitionViewModel mLockscreenToDreamingTransitionViewModel;
@Mock private LockscreenToOccludedTransitionViewModel mLockscreenToOccludedTransitionViewModel;
@Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor; @Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
@Mock private CoroutineDispatcher mMainDispatcher; @Mock private CoroutineDispatcher mMainDispatcher;
@Mock private MotionEvent mDownMotionEvent; @Mock private MotionEvent mDownMotionEvent;
@@ -513,6 +518,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mKeyguardBottomAreaInteractor, mKeyguardBottomAreaInteractor,
mDreamingToLockscreenTransitionViewModel, mDreamingToLockscreenTransitionViewModel,
mOccludedToLockscreenTransitionViewModel, mOccludedToLockscreenTransitionViewModel,
mLockscreenToDreamingTransitionViewModel,
mLockscreenToOccludedTransitionViewModel,
mMainDispatcher, mMainDispatcher,
mKeyguardTransitionInteractor, mKeyguardTransitionInteractor,
mDumpManager); mDumpManager);

View File

@@ -30,6 +30,7 @@ import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.dock.DockManager import com.android.systemui.dock.DockManager
import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.FeatureFlags
import com.android.systemui.keyguard.KeyguardUnlockAnimationController import com.android.systemui.keyguard.KeyguardUnlockAnimationController
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
import com.android.systemui.statusbar.LockscreenShadeTransitionController import com.android.systemui.statusbar.LockscreenShadeTransitionController
@@ -101,6 +102,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
@Mock lateinit var keyguardBouncerContainer: ViewGroup @Mock lateinit var keyguardBouncerContainer: ViewGroup
@Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent @Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent
@Mock lateinit var keyguardHostViewController: KeyguardHostViewController @Mock lateinit var keyguardHostViewController: KeyguardHostViewController
@Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler> private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
private lateinit var interactionEventHandler: InteractionEventHandler private lateinit var interactionEventHandler: InteractionEventHandler
@@ -132,7 +134,8 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
pulsingGestureListener, pulsingGestureListener,
featureFlags, featureFlags,
keyguardBouncerViewModel, keyguardBouncerViewModel,
keyguardBouncerComponentFactory keyguardTransitionInteractor,
keyguardBouncerComponentFactory,
) )
underTest.setupExpandedStatusBar() underTest.setupExpandedStatusBar()

View File

@@ -40,6 +40,7 @@ import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManager;
import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel; import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel;
import com.android.systemui.statusbar.DragDownHelper; import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.LockscreenShadeTransitionController;
@@ -93,6 +94,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
@Mock private KeyguardBouncerViewModel mKeyguardBouncerViewModel; @Mock private KeyguardBouncerViewModel mKeyguardBouncerViewModel;
@Mock private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory; @Mock private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
@Mock private NotificationInsetsController mNotificationInsetsController; @Mock private NotificationInsetsController mNotificationInsetsController;
@Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
@Captor private ArgumentCaptor<NotificationShadeWindowView.InteractionEventHandler> @Captor private ArgumentCaptor<NotificationShadeWindowView.InteractionEventHandler>
mInteractionEventHandlerCaptor; mInteractionEventHandlerCaptor;
@@ -132,6 +134,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
mPulsingGestureListener, mPulsingGestureListener,
mFeatureFlags, mFeatureFlags,
mKeyguardBouncerViewModel, mKeyguardBouncerViewModel,
mKeyguardTransitionInteractor,
mKeyguardBouncerComponentFactory mKeyguardBouncerComponentFactory
); );
mController.setupExpandedStatusBar(); mController.setupExpandedStatusBar();

View File

@@ -29,6 +29,7 @@ import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.shade.NotificationPanelViewController import com.android.systemui.shade.NotificationPanelViewController
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.LightRevealScrim import com.android.systemui.statusbar.LightRevealScrim
import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.unfold.util.FoldableDeviceStates import com.android.systemui.unfold.util.FoldableDeviceStates
@@ -73,6 +74,8 @@ class FoldAodAnimationControllerTest : SysuiTestCase() {
@Mock lateinit var viewTreeObserver: ViewTreeObserver @Mock lateinit var viewTreeObserver: ViewTreeObserver
@Mock private lateinit var commandQueue: CommandQueue
@Captor private lateinit var foldStateListenerCaptor: ArgumentCaptor<FoldStateListener> @Captor private lateinit var foldStateListenerCaptor: ArgumentCaptor<FoldStateListener>
private lateinit var deviceStates: FoldableDeviceStates private lateinit var deviceStates: FoldableDeviceStates
@@ -102,7 +105,8 @@ class FoldAodAnimationControllerTest : SysuiTestCase() {
} }
keyguardRepository = FakeKeyguardRepository() keyguardRepository = FakeKeyguardRepository()
val keyguardInteractor = KeyguardInteractor(repository = keyguardRepository) val keyguardInteractor =
KeyguardInteractor(repository = keyguardRepository, commandQueue = commandQueue)
// Needs to be run on the main thread // Needs to be run on the main thread
runBlocking(IMMEDIATE) { runBlocking(IMMEDIATE) {

View File

@@ -42,6 +42,7 @@ import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.qs.user.UserSwitchDialogController import com.android.systemui.qs.user.UserSwitchDialogController
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.telephony.data.repository.FakeTelephonyRepository import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
import com.android.systemui.telephony.domain.interactor.TelephonyInteractor import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
@@ -90,6 +91,7 @@ class UserInteractorTest : SysuiTestCase() {
@Mock private lateinit var dialogShower: UserSwitchDialogController.DialogShower @Mock private lateinit var dialogShower: UserSwitchDialogController.DialogShower
@Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver @Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver
@Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver @Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver
@Mock private lateinit var commandQueue: CommandQueue
private lateinit var underTest: UserInteractor private lateinit var underTest: UserInteractor
@@ -132,6 +134,7 @@ class UserInteractorTest : SysuiTestCase() {
keyguardInteractor = keyguardInteractor =
KeyguardInteractor( KeyguardInteractor(
repository = keyguardRepository, repository = keyguardRepository,
commandQueue = commandQueue,
), ),
manager = manager, manager = manager,
applicationScope = testCoroutineScope, applicationScope = testCoroutineScope,

View File

@@ -34,6 +34,7 @@ import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.telephony.data.repository.FakeTelephonyRepository import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
import com.android.systemui.telephony.domain.interactor.TelephonyInteractor import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
@@ -75,6 +76,7 @@ class StatusBarUserChipViewModelTest : SysuiTestCase() {
@Mock private lateinit var uiEventLogger: UiEventLogger @Mock private lateinit var uiEventLogger: UiEventLogger
@Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver @Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver
@Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver @Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver
@Mock private lateinit var commandQueue: CommandQueue
private lateinit var underTest: StatusBarUserChipViewModel private lateinit var underTest: StatusBarUserChipViewModel
@@ -241,6 +243,7 @@ class StatusBarUserChipViewModelTest : SysuiTestCase() {
keyguardInteractor = keyguardInteractor =
KeyguardInteractor( KeyguardInteractor(
repository = keyguardRepository, repository = keyguardRepository,
commandQueue = commandQueue,
), ),
featureFlags = featureFlags =
FakeFeatureFlags().apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) }, FakeFeatureFlags().apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) },

View File

@@ -34,6 +34,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.power.data.repository.FakePowerRepository import com.android.systemui.power.data.repository.FakePowerRepository
import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.telephony.data.repository.FakeTelephonyRepository import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
import com.android.systemui.telephony.domain.interactor.TelephonyInteractor import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
@@ -76,6 +77,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
@Mock private lateinit var uiEventLogger: UiEventLogger @Mock private lateinit var uiEventLogger: UiEventLogger
@Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver @Mock private lateinit var resumeSessionReceiver: GuestResumeSessionReceiver
@Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver @Mock private lateinit var resetOrExitSessionReceiver: GuestResetOrExitSessionReceiver
@Mock private lateinit var commandQueue: CommandQueue
private lateinit var underTest: UserSwitcherViewModel private lateinit var underTest: UserSwitcherViewModel
@@ -142,6 +144,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
keyguardInteractor = keyguardInteractor =
KeyguardInteractor( KeyguardInteractor(
repository = keyguardRepository, repository = keyguardRepository,
commandQueue = commandQueue,
), ),
featureFlags = featureFlags =
FakeFeatureFlags().apply { FakeFeatureFlags().apply {
@@ -169,14 +172,17 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
} }
@Test @Test
fun users() = testScope.runTest { fun users() =
testScope.runTest {
val userInfos = val userInfos =
listOf( listOf(
UserInfo( UserInfo(
/* id= */ 0, /* id= */ 0,
/* name= */ "zero", /* name= */ "zero",
/* iconPath= */ "", /* iconPath= */ "",
/* flags= */ UserInfo.FLAG_PRIMARY or UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL, /* flags= */ UserInfo.FLAG_PRIMARY or
UserInfo.FLAG_ADMIN or
UserInfo.FLAG_FULL,
UserManager.USER_TYPE_FULL_SYSTEM, UserManager.USER_TYPE_FULL_SYSTEM,
), ),
UserInfo( UserInfo(
@@ -223,7 +229,8 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
} }
@Test @Test
fun `maximumUserColumns - few users`() = testScope.runTest { fun `maximumUserColumns - few users`() =
testScope.runTest {
setUsers(count = 2) setUsers(count = 2)
val values = mutableListOf<Int>() val values = mutableListOf<Int>()
val job = launch(testDispatcher) { underTest.maximumUserColumns.toList(values) } val job = launch(testDispatcher) { underTest.maximumUserColumns.toList(values) }
@@ -234,7 +241,8 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
} }
@Test @Test
fun `maximumUserColumns - many users`() = testScope.runTest { fun `maximumUserColumns - many users`() =
testScope.runTest {
setUsers(count = 5) setUsers(count = 5)
val values = mutableListOf<Int>() val values = mutableListOf<Int>()
val job = launch(testDispatcher) { underTest.maximumUserColumns.toList(values) } val job = launch(testDispatcher) { underTest.maximumUserColumns.toList(values) }
@@ -244,7 +252,8 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
} }
@Test @Test
fun `isOpenMenuButtonVisible - has actions - true`() = testScope.runTest { fun `isOpenMenuButtonVisible - has actions - true`() =
testScope.runTest {
setUsers(2) setUsers(2)
val isVisible = mutableListOf<Boolean>() val isVisible = mutableListOf<Boolean>()
@@ -255,7 +264,8 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
} }
@Test @Test
fun `isOpenMenuButtonVisible - no actions - false`() = testScope.runTest { fun `isOpenMenuButtonVisible - no actions - false`() =
testScope.runTest {
val userInfos = setUsers(2) val userInfos = setUsers(2)
userRepository.setSelectedUserInfo(userInfos[1]) userRepository.setSelectedUserInfo(userInfos[1])
keyguardRepository.setKeyguardShowing(true) keyguardRepository.setKeyguardShowing(true)
@@ -269,7 +279,8 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
} }
@Test @Test
fun menu() = testScope.runTest { fun menu() =
testScope.runTest {
val isMenuVisible = mutableListOf<Boolean>() val isMenuVisible = mutableListOf<Boolean>()
val job = launch(testDispatcher) { underTest.isMenuVisible.toList(isMenuVisible) } val job = launch(testDispatcher) { underTest.isMenuVisible.toList(isMenuVisible) }
assertThat(isMenuVisible.last()).isFalse() assertThat(isMenuVisible.last()).isFalse()
@@ -284,7 +295,8 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
} }
@Test @Test
fun `menu actions`() = testScope.runTest { fun `menu actions`() =
testScope.runTest {
setUsers(2) setUsers(2)
val actions = mutableListOf<List<UserActionViewModel>>() val actions = mutableListOf<List<UserActionViewModel>>()
val job = launch(testDispatcher) { underTest.menu.toList(actions) } val job = launch(testDispatcher) { underTest.menu.toList(actions) }
@@ -303,10 +315,12 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
} }
@Test @Test
fun `isFinishRequested - finishes when user is switched`() = testScope.runTest { fun `isFinishRequested - finishes when user is switched`() =
testScope.runTest {
val userInfos = setUsers(count = 2) val userInfos = setUsers(count = 2)
val isFinishRequested = mutableListOf<Boolean>() val isFinishRequested = mutableListOf<Boolean>()
val job = launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) } val job =
launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) }
assertThat(isFinishRequested.last()).isFalse() assertThat(isFinishRequested.last()).isFalse()
userRepository.setSelectedUserInfo(userInfos[1]) userRepository.setSelectedUserInfo(userInfos[1])
@@ -317,11 +331,13 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
} }
@Test @Test
fun `isFinishRequested - finishes when the screen turns off`() = testScope.runTest { fun `isFinishRequested - finishes when the screen turns off`() =
testScope.runTest {
setUsers(count = 2) setUsers(count = 2)
powerRepository.setInteractive(true) powerRepository.setInteractive(true)
val isFinishRequested = mutableListOf<Boolean>() val isFinishRequested = mutableListOf<Boolean>()
val job = launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) } val job =
launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) }
assertThat(isFinishRequested.last()).isFalse() assertThat(isFinishRequested.last()).isFalse()
powerRepository.setInteractive(false) powerRepository.setInteractive(false)
@@ -332,11 +348,13 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
} }
@Test @Test
fun `isFinishRequested - finishes when cancel button is clicked`() = testScope.runTest { fun `isFinishRequested - finishes when cancel button is clicked`() =
testScope.runTest {
setUsers(count = 2) setUsers(count = 2)
powerRepository.setInteractive(true) powerRepository.setInteractive(true)
val isFinishRequested = mutableListOf<Boolean>() val isFinishRequested = mutableListOf<Boolean>()
val job = launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) } val job =
launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) }
assertThat(isFinishRequested.last()).isFalse() assertThat(isFinishRequested.last()).isFalse()
underTest.onCancelButtonClicked() underTest.onCancelButtonClicked()
@@ -351,14 +369,17 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
} }
@Test @Test
fun `guest selected -- name is exit guest`() = testScope.runTest { fun `guest selected -- name is exit guest`() =
testScope.runTest {
val userInfos = val userInfos =
listOf( listOf(
UserInfo( UserInfo(
/* id= */ 0, /* id= */ 0,
/* name= */ "zero", /* name= */ "zero",
/* iconPath= */ "", /* iconPath= */ "",
/* flags= */ UserInfo.FLAG_PRIMARY or UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL, /* flags= */ UserInfo.FLAG_PRIMARY or
UserInfo.FLAG_ADMIN or
UserInfo.FLAG_FULL,
UserManager.USER_TYPE_FULL_SYSTEM, UserManager.USER_TYPE_FULL_SYSTEM,
), ),
UserInfo( UserInfo(
@@ -386,7 +407,8 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
assertUserViewModel( assertUserViewModel(
viewModel = userViewModels.last()[1], viewModel = userViewModels.last()[1],
viewKey = 1, viewKey = 1,
name = Text.Resource( name =
Text.Resource(
com.android.settingslib.R.string.guest_exit_quick_settings_button com.android.settingslib.R.string.guest_exit_quick_settings_button
), ),
isSelectionMarkerVisible = true, isSelectionMarkerVisible = true,
@@ -395,14 +417,17 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
} }
@Test @Test
fun `guest not selected -- name is guest`() = testScope.runTest { fun `guest not selected -- name is guest`() =
testScope.runTest {
val userInfos = val userInfos =
listOf( listOf(
UserInfo( UserInfo(
/* id= */ 0, /* id= */ 0,
/* name= */ "zero", /* name= */ "zero",
/* iconPath= */ "", /* iconPath= */ "",
/* flags= */ UserInfo.FLAG_PRIMARY or UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL, /* flags= */ UserInfo.FLAG_PRIMARY or
UserInfo.FLAG_ADMIN or
UserInfo.FLAG_FULL,
UserManager.USER_TYPE_FULL_SYSTEM, UserManager.USER_TYPE_FULL_SYSTEM,
), ),
UserInfo( UserInfo(