Merge "[DO NOT MERGE] Transitions: LOCKSCREEN->DREAMING" into tm-qpr-dev

This commit is contained in:
TreeHugger Robot
2023-01-10 02:47:54 +00:00
committed by Android (Google) Code Review
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

@@ -43,6 +43,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
@@ -93,6 +94,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
@@ -136,6 +138,7 @@ class UserInteractorTest : SysuiTestCase() {
keyguardInteractor = keyguardInteractor =
KeyguardInteractor( KeyguardInteractor(
repository = keyguardRepository, repository = keyguardRepository,
commandQueue = commandQueue,
), ),
manager = manager, manager = manager,
applicationScope = testScope.backgroundScope, applicationScope = testScope.backgroundScope,

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(