Fix multiple issues with DREAM => LOCKSCREEN transition

- The transition is now playing all parts in parallel (previously: serial) and according to spec -> proper curves, proper timings
- All parts of the transition are now based on the transition framework and are guaranteed to be synchronized
- The animations were not playing at all due to a bug in transition framework

Spec: https://direct.googleplex.com/#/spec/277250003

Bug: b/267520000
Test: atest SystemUITests
Test: manually tested and aligned with spec
Change-Id: I0a8e096d9e6c08f0ce2e7736fb5679951602cfe0
Merged-In: I0a8e096d9e6c08f0ce2e7736fb5679951602cfe0
This commit is contained in:
Andreas Miko
2023-05-19 16:53:01 +00:00
parent f4f5ce437c
commit d6c544b125
43 changed files with 329 additions and 253 deletions

View File

@@ -71,13 +71,7 @@ public abstract class DreamOverlayService extends Service {
@Override @Override
public void wakeUp() { public void wakeUp() {
mService.wakeUp(this, () -> { mService.wakeUp(this);
try {
mDreamOverlayCallback.onWakeUpComplete();
} catch (RemoteException e) {
Log.e(TAG, "Could not notify dream of wakeUp", e);
}
});
} }
@Override @Override
@@ -125,14 +119,14 @@ public abstract class DreamOverlayService extends Service {
mCurrentClient = null; mCurrentClient = null;
} }
private void wakeUp(OverlayClient client, Runnable callback) { private void wakeUp(OverlayClient client) {
// Run on executor as this is a binder call from OverlayClient. // Run on executor as this is a binder call from OverlayClient.
mExecutor.execute(() -> { mExecutor.execute(() -> {
if (mCurrentClient != client) { if (mCurrentClient != client) {
return; return;
} }
onWakeUp(callback); onWakeUp();
}); });
} }
@@ -190,19 +184,10 @@ public abstract class DreamOverlayService extends Service {
/** /**
* This method is overridden by implementations to handle when the dream has been requested * This method is overridden by implementations to handle when the dream has been requested
* to wakeup. This allows any overlay animations to run. By default, the method will invoke * to wakeup.
* the callback immediately.
*
* This callback will be run on the {@link Executor} provided in the constructor if provided, or
* on the main executor if none was provided.
*
* @param onCompleteCallback The callback to trigger to notify the dream service that the
* overlay has completed waking up.
* @hide * @hide
*/ */
public void onWakeUp(@NonNull Runnable onCompleteCallback) { public void onWakeUp() {}
onCompleteCallback.run();
}
/** /**
* This method is overridden by implementations to handle when the dream has ended. There may * This method is overridden by implementations to handle when the dream has ended. There may

View File

@@ -249,13 +249,6 @@ public class DreamService extends Service implements Window.Callback {
// Simply finish dream when exit is requested. // Simply finish dream when exit is requested.
mHandler.post(() -> finish()); mHandler.post(() -> finish());
} }
@Override
public void onWakeUpComplete() {
// Finish the dream once overlay animations are complete. Execute on handler since
// this is coming in on the overlay binder.
mHandler.post(() -> finish());
}
}; };
@@ -923,6 +916,7 @@ public class DreamService extends Service implements Window.Callback {
overlay.wakeUp(); overlay.wakeUp();
} catch (RemoteException e) { } catch (RemoteException e) {
Slog.e(TAG, "Error waking the overlay service", e); Slog.e(TAG, "Error waking the overlay service", e);
} finally {
finish(); finish();
} }
}); });

View File

@@ -28,7 +28,4 @@ interface IDreamOverlayCallback {
* Invoked to request the dream exit. * Invoked to request the dream exit.
*/ */
void onExitRequested(); void onExitRequested();
/** Invoked when the dream overlay wakeUp animation is complete. */
void onWakeUpComplete();
} }

View File

@@ -34,13 +34,11 @@ import com.android.systemui.complication.ComplicationLayoutParams.POSITION_TOP
import com.android.systemui.complication.ComplicationLayoutParams.Position import com.android.systemui.complication.ComplicationLayoutParams.Position
import com.android.systemui.dreams.dagger.DreamOverlayModule import com.android.systemui.dreams.dagger.DreamOverlayModule
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel.Companion.DREAM_ANIMATION_DURATION
import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.statusbar.BlurUtils import com.android.systemui.statusbar.BlurUtils
import com.android.systemui.statusbar.CrossFadeHelper import com.android.systemui.statusbar.CrossFadeHelper
import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
import com.android.systemui.util.concurrency.DelayableExecutor
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Named import javax.inject.Named
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@@ -129,6 +127,12 @@ constructor(
) )
} }
} }
launch {
transitionViewModel.transitionEnded.collect { _ ->
mOverlayStateController.setExitAnimationsRunning(false)
}
}
} }
configController.removeCallback(configCallback) configController.removeCallback(configCallback)
@@ -251,9 +255,9 @@ constructor(
} }
/** Starts the dream content and dream overlay exit animations. */ /** Starts the dream content and dream overlay exit animations. */
fun wakeUp(doneCallback: Runnable, executor: DelayableExecutor) { fun wakeUp() {
cancelAnimations() cancelAnimations()
executor.executeDelayed(doneCallback, DREAM_ANIMATION_DURATION.inWholeMilliseconds) mOverlayStateController.setExitAnimationsRunning(true)
} }
/** Cancels the dream content and dream overlay animations, if they're currently running. */ /** Cancels the dream content and dream overlay animations, if they're currently running. */

View File

@@ -31,8 +31,6 @@ import android.util.MathUtils;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import androidx.annotation.NonNull;
import com.android.app.animation.Interpolators; import com.android.app.animation.Interpolators;
import com.android.dream.lowlight.LowLightTransitionCoordinator; import com.android.dream.lowlight.LowLightTransitionCoordinator;
import com.android.systemui.R; import com.android.systemui.R;
@@ -46,7 +44,6 @@ import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInt
import com.android.systemui.shade.ShadeExpansionChangeEvent; import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.statusbar.BlurUtils; import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.util.ViewController; import com.android.systemui.util.ViewController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import java.util.Arrays; import java.util.Arrays;
@@ -302,20 +299,15 @@ public class DreamOverlayContainerViewController extends
/** /**
* Handle the dream waking up and run any necessary animations. * Handle the dream waking up and run any necessary animations.
*
* @param onAnimationEnd Callback to trigger once animations are finished.
* @param callbackExecutor Executor to execute the callback on.
*/ */
public void wakeUp(@NonNull Runnable onAnimationEnd, public void wakeUp() {
@NonNull DelayableExecutor callbackExecutor) {
// When swiping causes wakeup, do not run any animations as the dream should exit as soon // When swiping causes wakeup, do not run any animations as the dream should exit as soon
// as possible. // as possible.
if (mWakingUpFromSwipe) { if (mWakingUpFromSwipe) {
onAnimationEnd.run();
return; return;
} }
mDreamOverlayAnimationsController.wakeUp(onAnimationEnd, callbackExecutor); mDreamOverlayAnimationsController.wakeUp();
} }
@Override @Override

View File

@@ -116,6 +116,17 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
} }
}; };
private final DreamOverlayStateController.Callback mExitAnimationFinishedCallback =
new DreamOverlayStateController.Callback() {
@Override
public void onStateChanged() {
if (!mStateController.areExitAnimationsRunning()) {
mStateController.removeCallback(mExitAnimationFinishedCallback);
resetCurrentDreamOverlayLocked();
}
}
};
private final DreamOverlayStateController mStateController; private final DreamOverlayStateController mStateController;
@VisibleForTesting @VisibleForTesting
@@ -257,10 +268,10 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
} }
@Override @Override
public void onWakeUp(@NonNull Runnable onCompletedCallback) { public void onWakeUp() {
if (mDreamOverlayContainerViewController != null) { if (mDreamOverlayContainerViewController != null) {
mDreamOverlayCallbackController.onWakeUp(); mDreamOverlayCallbackController.onWakeUp();
mDreamOverlayContainerViewController.wakeUp(onCompletedCallback, mExecutor); mDreamOverlayContainerViewController.wakeUp();
} }
} }
@@ -329,6 +340,11 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
} }
private void resetCurrentDreamOverlayLocked() { private void resetCurrentDreamOverlayLocked() {
if (mStateController.areExitAnimationsRunning()) {
mStateController.addCallback(mExitAnimationFinishedCallback);
return;
}
if (mStarted && mWindow != null) { if (mStarted && mWindow != null) {
try { try {
mWindowManager.removeView(mWindow.getDecorView()); mWindowManager.removeView(mWindow.getDecorView());

View File

@@ -18,6 +18,7 @@ package com.android.systemui.keyguard;
import static android.app.StatusBarManager.SESSION_KEYGUARD; import static android.app.StatusBarManager.SESSION_KEYGUARD;
import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT; import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
@@ -34,8 +35,8 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
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.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS; import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
import android.animation.Animator; import android.animation.Animator;
import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter;
@@ -87,9 +88,11 @@ import android.util.SparseIntArray;
import android.view.IRemoteAnimationFinishedCallback; import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner; import android.view.IRemoteAnimationRunner;
import android.view.RemoteAnimationTarget; import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl.Transaction;
import android.view.SyncRtSurfaceTransactionApplier; import android.view.SyncRtSurfaceTransactionApplier;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewRootImpl;
import android.view.WindowManager; import android.view.WindowManager;
import android.view.WindowManagerPolicyConstants; import android.view.WindowManagerPolicyConstants;
import android.view.animation.Animation; import android.view.animation.Animation;
@@ -127,12 +130,14 @@ import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.LaunchAnimator; import com.android.systemui.animation.LaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.qualifiers.Main;
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.FeatureFlags;
import com.android.systemui.flags.Flags; import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.dagger.KeyguardModule; import com.android.systemui.keyguard.dagger.KeyguardModule;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.log.SessionTracker; import com.android.systemui.log.SessionTracker;
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;
@@ -162,6 +167,9 @@ import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.function.Consumer;
import kotlinx.coroutines.CoroutineDispatcher;
/** /**
* Mediates requests related to the keyguard. This includes queries about the * Mediates requests related to the keyguard. This includes queries about the
@@ -434,11 +442,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
*/ */
private final int mDreamOpenAnimationDuration; private final int mDreamOpenAnimationDuration;
/**
* The duration in milliseconds of the dream close animation.
*/
private final int mDreamCloseAnimationDuration;
/** /**
* The animation used for hiding keyguard. This is used to fetch the animation timings if * The animation used for hiding keyguard. This is used to fetch the animation timings if
* WindowManager is not providing us with them. * WindowManager is not providing us with them.
@@ -1125,49 +1128,57 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
return; return;
} }
final RemoteAnimationTarget primary = apps[0]; mRemoteAnimationTarget = apps[0];
final boolean isDream = (apps[0].taskInfo != null final boolean isDream = (apps[0].taskInfo != null
&& apps[0].taskInfo.topActivityType && apps[0].taskInfo.topActivityType
== WindowConfiguration.ACTIVITY_TYPE_DREAM); == WindowConfiguration.ACTIVITY_TYPE_DREAM);
final SyncRtSurfaceTransactionApplier applier =
new SyncRtSurfaceTransactionApplier(
mKeyguardViewControllerLazy.get().getViewRootImpl().getView());
final View localView = mKeyguardViewControllerLazy.get()
.getViewRootImpl().getView();
final SyncRtSurfaceTransactionApplier applier =
new SyncRtSurfaceTransactionApplier(localView);
mContext.getMainExecutor().execute(() -> { mContext.getMainExecutor().execute(() -> {
if (mUnoccludeAnimator != null) { if (mUnoccludeAnimator != null) {
mUnoccludeAnimator.cancel(); mUnoccludeAnimator.cancel();
} }
if (isDream) {
initAlphaForAnimationTargets(wallpapers);
getRemoteSurfaceAlphaApplier().accept(0.0f);
mDreamingToLockscreenTransitionViewModel.get()
.startTransition();
return;
}
mUnoccludeAnimator = ValueAnimator.ofFloat(1f, 0f); mUnoccludeAnimator = ValueAnimator.ofFloat(1f, 0f);
mUnoccludeAnimator.setDuration(isDream ? mDreamCloseAnimationDuration mUnoccludeAnimator.setDuration(UNOCCLUDE_ANIMATION_DURATION);
: UNOCCLUDE_ANIMATION_DURATION);
mUnoccludeAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE); mUnoccludeAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE);
mUnoccludeAnimator.addUpdateListener( mUnoccludeAnimator.addUpdateListener(
animation -> { animation -> {
final float animatedValue = final float animatedValue =
(float) animation.getAnimatedValue(); (float) animation.getAnimatedValue();
final float surfaceHeight = primary.screenSpaceBounds.height(); final float surfaceHeight =
mRemoteAnimationTarget.screenSpaceBounds.height();
// Fade for all types of activities. // Fade for all types of activities.
SyncRtSurfaceTransactionApplier.SurfaceParams.Builder SyncRtSurfaceTransactionApplier.SurfaceParams.Builder
paramsBuilder = paramsBuilder =
new SyncRtSurfaceTransactionApplier.SurfaceParams new SyncRtSurfaceTransactionApplier.SurfaceParams
.Builder(primary.leash) .Builder(mRemoteAnimationTarget.leash)
.withAlpha(animatedValue); .withAlpha(animatedValue);
// Set translate if the occluding activity isn't Dream.
if (!isDream) {
mUnoccludeMatrix.setTranslate(
0f,
(1f - animatedValue)
* surfaceHeight
* UNOCCLUDE_TRANSLATE_DISTANCE_PERCENT);
paramsBuilder.withMatrix(mUnoccludeMatrix).withCornerRadius( mUnoccludeMatrix.setTranslate(
mWindowCornerRadius); 0f,
} (1f - animatedValue)
* surfaceHeight
* UNOCCLUDE_TRANSLATE_DISTANCE_PERCENT);
paramsBuilder.withMatrix(mUnoccludeMatrix).withCornerRadius(
mWindowCornerRadius);
applier.scheduleApply(paramsBuilder.build()); applier.scheduleApply(paramsBuilder.build());
}); });
mUnoccludeAnimator.addListener(new AnimatorListenerAdapter() { mUnoccludeAnimator.addListener(new AnimatorListenerAdapter() {
@@ -1189,6 +1200,34 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
} }
}; };
private static void initAlphaForAnimationTargets(
@android.annotation.NonNull RemoteAnimationTarget[] targets
) {
for (RemoteAnimationTarget target : targets) {
if (target.mode != MODE_OPENING) continue;
try (Transaction t = new Transaction()) {
t.setAlpha(target.leash, 1.f);
t.apply();
}
}
}
private Consumer<Float> getRemoteSurfaceAlphaApplier() {
return (Float alpha) -> {
if (mRemoteAnimationTarget == null) return;
final View localView = mKeyguardViewControllerLazy.get().getViewRootImpl().getView();
final SyncRtSurfaceTransactionApplier applier =
new SyncRtSurfaceTransactionApplier(localView);
SyncRtSurfaceTransactionApplier.SurfaceParams
params =
new SyncRtSurfaceTransactionApplier.SurfaceParams
.Builder(mRemoteAnimationTarget.leash)
.withAlpha(alpha).build();
applier.scheduleApply(params);
};
}
private DeviceConfigProxy mDeviceConfig; private DeviceConfigProxy mDeviceConfig;
private DozeParameters mDozeParameters; private DozeParameters mDozeParameters;
@@ -1218,6 +1257,10 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
private FeatureFlags mFeatureFlags; private FeatureFlags mFeatureFlags;
private final UiEventLogger mUiEventLogger; private final UiEventLogger mUiEventLogger;
private final SessionTracker mSessionTracker; private final SessionTracker mSessionTracker;
private final CoroutineDispatcher mMainDispatcher;
private final Lazy<DreamingToLockscreenTransitionViewModel>
mDreamingToLockscreenTransitionViewModel;
private RemoteAnimationTarget mRemoteAnimationTarget;
/** /**
* Injected constructor. See {@link KeyguardModule}. * Injected constructor. See {@link KeyguardModule}.
@@ -1253,7 +1296,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy, Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy,
Lazy<ActivityLaunchAnimator> activityLaunchAnimator, Lazy<ActivityLaunchAnimator> activityLaunchAnimator,
Lazy<ScrimController> scrimControllerLazy, Lazy<ScrimController> scrimControllerLazy,
FeatureFlags featureFlags) { FeatureFlags featureFlags,
@Main CoroutineDispatcher mainDispatcher,
Lazy<DreamingToLockscreenTransitionViewModel> dreamingToLockscreenTransitionViewModel) {
mContext = context; mContext = context;
mUserTracker = userTracker; mUserTracker = userTracker;
mFalsingCollector = falsingCollector; mFalsingCollector = falsingCollector;
@@ -1308,11 +1353,13 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context); mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
mDreamOpenAnimationDuration = (int) DREAMING_ANIMATION_DURATION_MS; mDreamOpenAnimationDuration = (int) DREAMING_ANIMATION_DURATION_MS;
mDreamCloseAnimationDuration = (int) LOCKSCREEN_ANIMATION_DURATION_MS;
mFeatureFlags = featureFlags; mFeatureFlags = featureFlags;
mUiEventLogger = uiEventLogger; mUiEventLogger = uiEventLogger;
mSessionTracker = sessionTracker; mSessionTracker = sessionTracker;
mMainDispatcher = mainDispatcher;
mDreamingToLockscreenTransitionViewModel = dreamingToLockscreenTransitionViewModel;
} }
public void userActivity() { public void userActivity() {
@@ -1431,6 +1478,13 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mUpdateMonitor.registerCallback(mUpdateCallback); mUpdateMonitor.registerCallback(mUpdateCallback);
adjustStatusBarLocked(); adjustStatusBarLocked();
mDreamOverlayStateController.addCallback(mDreamOverlayStateCallback); mDreamOverlayStateController.addCallback(mDreamOverlayStateCallback);
ViewRootImpl viewRootImpl = mKeyguardViewControllerLazy.get().getViewRootImpl();
if (viewRootImpl != null) {
collectFlow(viewRootImpl.getView(),
mDreamingToLockscreenTransitionViewModel.get().getDreamOverlayAlpha(),
getRemoteSurfaceAlphaApplier(), mMainDispatcher);
}
} }
// Most services aren't available until the system reaches the ready state, so we // Most services aren't available until the system reaches the ready state, so we
// send it here when the device first boots. // send it here when the device first boots.

View File

@@ -37,6 +37,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.classifier.FalsingModule; import com.android.systemui.classifier.FalsingModule;
import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
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;
@@ -51,6 +52,7 @@ import com.android.systemui.keyguard.domain.interactor.StartKeyguardTransitionMo
import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceModule; import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceModule;
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger; import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger;
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLoggerImpl; import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLoggerImpl;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.log.SessionTracker; import com.android.systemui.log.SessionTracker;
import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.settings.UserTracker; import com.android.systemui.settings.UserTracker;
@@ -72,6 +74,8 @@ import dagger.Provides;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import kotlinx.coroutines.CoroutineDispatcher;
/** /**
* Dagger Module providing keyguard. * Dagger Module providing keyguard.
*/ */
@@ -128,7 +132,9 @@ public class KeyguardModule {
Lazy<NotificationShadeWindowController> notificationShadeWindowController, Lazy<NotificationShadeWindowController> notificationShadeWindowController,
Lazy<ActivityLaunchAnimator> activityLaunchAnimator, Lazy<ActivityLaunchAnimator> activityLaunchAnimator,
Lazy<ScrimController> scrimControllerLazy, Lazy<ScrimController> scrimControllerLazy,
FeatureFlags featureFlags) { FeatureFlags featureFlags,
@Main CoroutineDispatcher mainDispatcher,
Lazy<DreamingToLockscreenTransitionViewModel> dreamingToLockscreenTransitionViewModel) {
return new KeyguardViewMediator( return new KeyguardViewMediator(
context, context,
uiEventLogger, uiEventLogger,
@@ -162,7 +168,9 @@ public class KeyguardModule {
notificationShadeWindowController, notificationShadeWindowController,
activityLaunchAnimator, activityLaunchAnimator,
scrimControllerLazy, scrimControllerLazy,
featureFlags); featureFlags,
mainDispatcher,
dreamingToLockscreenTransitionViewModel);
} }
/** */ /** */

View File

@@ -160,35 +160,28 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
// An animator was provided, so use it to run the transition // An animator was provided, so use it to run the transition
animator.setFloatValues(startingValue, 1f) animator.setFloatValues(startingValue, 1f)
animator.duration = ((1f - startingValue) * animator.duration).toLong() animator.duration = ((1f - startingValue) * animator.duration).toLong()
val updateListener = val updateListener = AnimatorUpdateListener { animation ->
object : AnimatorUpdateListener { emitTransition(
override fun onAnimationUpdate(animation: ValueAnimator) { TransitionStep(
emitTransition( info,
TransitionStep( (animation.animatedValue as Float),
info, TransitionState.RUNNING
(animation.getAnimatedValue() as Float), )
TransitionState.RUNNING )
) }
)
}
}
val adapter = val adapter =
object : AnimatorListenerAdapter() { object : AnimatorListenerAdapter() {
override fun onAnimationStart(animation: Animator) { override fun onAnimationStart(animation: Animator) {
emitTransition(TransitionStep(info, startingValue, TransitionState.STARTED)) emitTransition(TransitionStep(info, startingValue, TransitionState.STARTED))
} }
override fun onAnimationCancel(animation: Animator) { override fun onAnimationCancel(animation: Animator) {
endAnimation(animation, lastStep.value, TransitionState.CANCELED) endAnimation(lastStep.value, TransitionState.CANCELED)
} }
override fun onAnimationEnd(animation: Animator) { override fun onAnimationEnd(animation: Animator) {
endAnimation(animation, 1f, TransitionState.FINISHED) endAnimation(1f, TransitionState.FINISHED)
} }
private fun endAnimation( private fun endAnimation(value: Float, state: TransitionState) {
animation: Animator,
value: Float,
state: TransitionState
) {
emitTransition(TransitionStep(info, value, state)) emitTransition(TransitionStep(info, value, state))
animator.removeListener(this) animator.removeListener(this)
animator.removeUpdateListener(updateListener) animator.removeUpdateListener(updateListener)
@@ -201,7 +194,7 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
return@startTransition null return@startTransition null
} }
?: run { ?: run {
emitTransition(TransitionStep(info, 0f, TransitionState.STARTED)) emitTransition(TransitionStep(info, startingValue, TransitionState.STARTED))
// No animator, so it's manual. Provide a mechanism to callback // No animator, so it's manual. Provide a mechanism to callback
updateTransitionId = UUID.randomUUID() updateTransitionId = UUID.randomUUID()

View File

@@ -52,7 +52,7 @@ constructor(
.sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair) .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { (wakefulnessModel, lastStartedTransition) -> .collect { (wakefulnessModel, lastStartedTransition) ->
if ( if (
wakefulnessModel.isStartingToWake() && wakefulnessModel.isStartingToWakeOrAwake() &&
lastStartedTransition.to == KeyguardState.DOZING lastStartedTransition.to == KeyguardState.DOZING
) { ) {
keyguardTransitionRepository.startTransition( keyguardTransitionRepository.startTransition(

View File

@@ -23,7 +23,6 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
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.KeyguardState import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionInfo import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.util.kotlin.Utils.Companion.toTriple import com.android.systemui.util.kotlin.Utils.Companion.toTriple
@@ -48,39 +47,23 @@ constructor(
) : TransitionInteractor(FromDreamingTransitionInteractor::class.simpleName!!) { ) : TransitionInteractor(FromDreamingTransitionInteractor::class.simpleName!!) {
override fun start() { override fun start() {
listenForDreamingToLockscreen()
listenForDreamingToOccluded() listenForDreamingToOccluded()
listenForDreamingToGone() listenForDreamingToGone()
listenForDreamingToDozing() listenForDreamingToDozing()
} }
private fun listenForDreamingToLockscreen() { fun startToLockscreenTransition() {
scope.launch { scope.launch {
keyguardInteractor.isAbleToDream if (keyguardTransitionInteractor.startedKeyguardState.value == KeyguardState.DREAMING) {
.sample( keyguardTransitionRepository.startTransition(
combine( TransitionInfo(
keyguardInteractor.dozeTransitionModel, name,
keyguardTransitionInteractor.startedKeyguardTransitionStep, KeyguardState.DREAMING,
::Pair KeyguardState.LOCKSCREEN,
), getAnimator(TO_LOCKSCREEN_DURATION),
::toTriple )
) )
.collect { (isDreaming, dozeTransitionModel, lastStartedTransition) -> }
if (
!isDreaming &&
isDozeOff(dozeTransitionModel.to) &&
lastStartedTransition.to == KeyguardState.DREAMING
) {
keyguardTransitionRepository.startTransition(
TransitionInfo(
name,
KeyguardState.DREAMING,
KeyguardState.LOCKSCREEN,
getAnimator(TO_LOCKSCREEN_DURATION),
)
)
}
}
} }
} }
@@ -173,6 +156,6 @@ constructor(
companion object { companion object {
private val DEFAULT_DURATION = 500.milliseconds private val DEFAULT_DURATION = 500.milliseconds
val TO_LOCKSCREEN_DURATION = 1183.milliseconds val TO_LOCKSCREEN_DURATION = 1167.milliseconds
} }
} }

View File

@@ -111,7 +111,7 @@ constructor(
isDreaming && isDozeOff(dozeTransitionModel.to) isDreaming && isDozeOff(dozeTransitionModel.to)
} }
.sample(wakefulnessModel) { isAbleToDream, wakefulnessModel -> .sample(wakefulnessModel) { isAbleToDream, wakefulnessModel ->
isAbleToDream && wakefulnessModel.isStartingToWake() isAbleToDream && wakefulnessModel.isStartingToWakeOrAwake()
} }
.flatMapLatest { isAbleToDream -> .flatMapLatest { isAbleToDream ->
flow { flow {

View File

@@ -18,6 +18,7 @@
package com.android.systemui.keyguard.domain.interactor package com.android.systemui.keyguard.domain.interactor
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
@@ -29,10 +30,14 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.keyguard.shared.model.TransitionState 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 javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.stateIn
/** Encapsulates business-logic related to the keyguard transitions. */ /** Encapsulates business-logic related to the keyguard transitions. */
@SysUISingleton @SysUISingleton
@@ -40,6 +45,7 @@ class KeyguardTransitionInteractor
@Inject @Inject
constructor( constructor(
private val repository: KeyguardTransitionRepository, private val repository: KeyguardTransitionRepository,
@Application val scope: CoroutineScope,
) { ) {
/** (any)->GONE transition information */ /** (any)->GONE transition information */
val anyStateToGoneTransition: Flow<TransitionStep> = val anyStateToGoneTransition: Flow<TransitionStep> =
@@ -108,10 +114,17 @@ constructor(
val finishedKeyguardTransitionStep: Flow<TransitionStep> = val finishedKeyguardTransitionStep: Flow<TransitionStep> =
repository.transitions.filter { step -> step.transitionState == TransitionState.FINISHED } repository.transitions.filter { step -> step.transitionState == TransitionState.FINISHED }
/** The last completed [KeyguardState] transition */ /** The destination state of the last started transition */
val finishedKeyguardState: Flow<KeyguardState> = val startedKeyguardState: StateFlow<KeyguardState> =
finishedKeyguardTransitionStep.map { step -> step.to } startedKeyguardTransitionStep
.map { step -> step.to }
.stateIn(scope, SharingStarted.Eagerly, KeyguardState.OFF)
/** The last completed [KeyguardState] transition */
val finishedKeyguardState: StateFlow<KeyguardState> =
finishedKeyguardTransitionStep
.map { step -> step.to }
.stateIn(scope, SharingStarted.Eagerly, LOCKSCREEN)
/** /**
* The amount of transition into or out of the given [KeyguardState]. * The amount of transition into or out of the given [KeyguardState].
* *

View File

@@ -29,6 +29,8 @@ data class WakefulnessModel(
fun isStartingToSleepOrAsleep() = isStartingToSleep() || state == WakefulnessState.ASLEEP fun isStartingToSleepOrAsleep() = isStartingToSleep() || state == WakefulnessState.ASLEEP
fun isStartingToWakeOrAwake() = isStartingToWake() || state == WakefulnessState.AWAKE
fun isStartingToSleepFromPowerButton() = fun isStartingToSleepFromPowerButton() =
isStartingToSleep() && lastWakeReason == WakeSleepReason.POWER_BUTTON isStartingToSleep() && lastWakeReason == WakeSleepReason.POWER_BUTTON

View File

@@ -16,15 +16,17 @@
package com.android.systemui.keyguard.ui.viewmodel package com.android.systemui.keyguard.ui.viewmodel
import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE import com.android.app.animation.Interpolators.EMPHASIZED
import com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
import javax.inject.Inject import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
/** /**
* Breaks down DREAMING->LOCKSCREEN transition into discrete steps for corresponding views to * Breaks down DREAMING->LOCKSCREEN transition into discrete steps for corresponding views to
@@ -34,22 +36,32 @@ import kotlinx.coroutines.flow.Flow
class DreamingToLockscreenTransitionViewModel class DreamingToLockscreenTransitionViewModel
@Inject @Inject
constructor( constructor(
private val interactor: KeyguardTransitionInteractor, keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val fromDreamingTransitionInteractor: FromDreamingTransitionInteractor
) { ) {
fun startTransition() = fromDreamingTransitionInteractor.startToLockscreenTransition()
private val transitionAnimation = private val transitionAnimation =
KeyguardTransitionAnimationFlow( KeyguardTransitionAnimationFlow(
transitionDuration = TO_LOCKSCREEN_DURATION, transitionDuration = TO_LOCKSCREEN_DURATION,
transitionFlow = interactor.dreamingToLockscreenTransition, transitionFlow = keyguardTransitionInteractor.dreamingToLockscreenTransition,
) )
val transitionEnded =
keyguardTransitionInteractor.dreamingToLockscreenTransition.filter { step ->
step.transitionState == TransitionState.FINISHED ||
step.transitionState == TransitionState.CANCELED
}
/** Dream overlay y-translation on exit */ /** Dream overlay y-translation on exit */
fun dreamOverlayTranslationY(translatePx: Int): Flow<Float> { fun dreamOverlayTranslationY(translatePx: Int): Flow<Float> {
return transitionAnimation.createFlow( return transitionAnimation.createFlow(
duration = 600.milliseconds, duration = TO_LOCKSCREEN_DURATION,
onStep = { it * translatePx }, onStep = { it * translatePx },
interpolator = EMPHASIZED_ACCELERATE, interpolator = EMPHASIZED,
) )
} }
/** Dream overlay views alpha - fade out */ /** Dream overlay views alpha - fade out */
val dreamOverlayAlpha: Flow<Float> = val dreamOverlayAlpha: Flow<Float> =
transitionAnimation.createFlow( transitionAnimation.createFlow(
@@ -65,7 +77,7 @@ constructor(
// Reset on cancel or finish // Reset on cancel or finish
onFinish = { 0f }, onFinish = { 0f },
onCancel = { 0f }, onCancel = { 0f },
interpolator = EMPHASIZED_DECELERATE, interpolator = EMPHASIZED,
) )
} }
@@ -76,12 +88,4 @@ constructor(
duration = 250.milliseconds, duration = 250.milliseconds,
onStep = { it }, onStep = { it },
) )
companion object {
/* Length of time before ending the dream activity, in order to start unoccluding */
val DREAM_ANIMATION_DURATION = 250.milliseconds
@JvmField
val LOCKSCREEN_ANIMATION_DURATION_MS =
(TO_LOCKSCREEN_DURATION - DREAM_ANIMATION_DURATION).inWholeMilliseconds
}
} }

View File

@@ -33,7 +33,7 @@ import kotlinx.coroutines.flow.Flow
class LockscreenToDreamingTransitionViewModel class LockscreenToDreamingTransitionViewModel
@Inject @Inject
constructor( constructor(
private val interactor: KeyguardTransitionInteractor, interactor: KeyguardTransitionInteractor,
) { ) {
private val transitionAnimation = private val transitionAnimation =
KeyguardTransitionAnimationFlow( KeyguardTransitionAnimationFlow(

View File

@@ -47,6 +47,7 @@ import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.mock
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.yield import kotlinx.coroutines.yield
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
@@ -118,7 +119,7 @@ class ClockEventControllerTest : SysuiTestCase() {
featureFlags = featureFlags, featureFlags = featureFlags,
bouncerRepository = bouncerRepository, bouncerRepository = bouncerRepository,
), ),
KeyguardTransitionInteractor(repository = transitionRepository), KeyguardTransitionInteractor(transitionRepository, TestScope().backgroundScope),
broadcastDispatcher, broadcastDispatcher,
batteryController, batteryController,
keyguardUpdateMonitor, keyguardUpdateMonitor,

View File

@@ -159,7 +159,8 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase {
mVibrator, mVibrator,
mAuthRippleController, mAuthRippleController,
mResources, mResources,
new KeyguardTransitionInteractor(mTransitionRepository), new KeyguardTransitionInteractor(mTransitionRepository,
TestScopeProvider.getTestScope().getBackgroundScope()),
new KeyguardInteractor( new KeyguardInteractor(
new FakeKeyguardRepository(), new FakeKeyguardRepository(),
mCommandQueue, mCommandQueue,

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2022 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.keyguard
import kotlinx.coroutines.test.TestScope
class TestScopeProvider {
companion object {
@JvmStatic fun getTestScope() = TestScope()
}
}

View File

@@ -56,6 +56,7 @@ class LogContextInteractorImplTest : SysuiTestCase() {
foldProvider, foldProvider,
KeyguardTransitionInteractor( KeyguardTransitionInteractor(
keyguardTransitionRepository, keyguardTransitionRepository,
testScope.backgroundScope
), ),
) )
} }

View File

@@ -11,7 +11,6 @@ import com.android.systemui.complication.ComplicationHostViewController
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
import com.android.systemui.statusbar.BlurUtils import com.android.systemui.statusbar.BlurUtils
import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.whenever
@@ -23,9 +22,7 @@ import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor import org.mockito.ArgumentCaptor
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito.anyLong
import org.mockito.Mockito.atLeastOnce import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.eq
import org.mockito.Mockito.never import org.mockito.Mockito.never
import org.mockito.Mockito.times import org.mockito.Mockito.times
import org.mockito.Mockito.verify import org.mockito.Mockito.verify
@@ -92,16 +89,10 @@ class DreamOverlayAnimationsControllerTest : SysuiTestCase() {
} }
@Test @Test
fun testWakeUpCallsExecutor() { fun testWakeUpSetsExitAnimationsRunning() {
val mockExecutor: DelayableExecutor = mock() controller.wakeUp()
val mockCallback: Runnable = mock()
controller.wakeUp( verify(stateController).setExitAnimationsRunning(true)
doneCallback = mockCallback,
executor = mockExecutor,
)
verify(mockExecutor).executeDelayed(eq(mockCallback), anyLong())
} }
@Test @Test
@@ -112,10 +103,7 @@ class DreamOverlayAnimationsControllerTest : SysuiTestCase() {
verify(mockStartAnimator, never()).cancel() verify(mockStartAnimator, never()).cancel()
controller.wakeUp( controller.wakeUp()
doneCallback = mock(),
executor = mock(),
)
// Verify that we cancelled the start animator in favor of the exit // Verify that we cancelled the start animator in favor of the exit
// animator. // animator.

View File

@@ -23,7 +23,6 @@ import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -498,18 +497,14 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
true /*shouldShowComplication*/); true /*shouldShowComplication*/);
mMainExecutor.runAllReady(); mMainExecutor.runAllReady();
final Runnable callback = mock(Runnable.class); mService.onWakeUp();
mService.onWakeUp(callback); verify(mDreamOverlayContainerViewController).wakeUp();
mMainExecutor.runAllReady();
verify(mDreamOverlayContainerViewController).wakeUp(callback, mMainExecutor);
verify(mDreamOverlayCallbackController).onWakeUp(); verify(mDreamOverlayCallbackController).onWakeUp();
} }
@Test @Test
public void testWakeUpBeforeStartDoesNothing() { public void testWakeUpBeforeStartDoesNothing() {
final Runnable callback = mock(Runnable.class); mService.onWakeUp();
mService.onWakeUp(callback); verify(mDreamOverlayContainerViewController, never()).wakeUp();
mMainExecutor.runAllReady();
verify(mDreamOverlayContainerViewController, never()).wakeUp(callback, mMainExecutor);
} }
} }

View File

@@ -71,6 +71,7 @@ import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.dump.DumpManager; import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlags; import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.flags.Flags; import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.log.SessionTracker; import com.android.systemui.log.SessionTracker;
import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.settings.UserTracker; import com.android.systemui.settings.UserTracker;
@@ -105,6 +106,9 @@ import org.mockito.Captor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import kotlinx.coroutines.CoroutineDispatcher;
import kotlinx.coroutines.flow.Flow;
@RunWith(AndroidTestingRunner.class) @RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper @TestableLooper.RunWithLooper
@SmallTest @SmallTest
@@ -156,6 +160,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
private @Mock CentralSurfaces mCentralSurfaces; private @Mock CentralSurfaces mCentralSurfaces;
private @Mock UiEventLogger mUiEventLogger; private @Mock UiEventLogger mUiEventLogger;
private @Mock SessionTracker mSessionTracker; private @Mock SessionTracker mSessionTracker;
private @Mock CoroutineDispatcher mDispatcher;
private @Mock DreamingToLockscreenTransitionViewModel mDreamingToLockscreenTransitionViewModel;
private FakeFeatureFlags mFeatureFlags; private FakeFeatureFlags mFeatureFlags;
@@ -171,6 +177,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
final ViewRootImpl testViewRoot = mock(ViewRootImpl.class); final ViewRootImpl testViewRoot = mock(ViewRootImpl.class);
when(testViewRoot.getView()).thenReturn(mock(View.class)); when(testViewRoot.getView()).thenReturn(mock(View.class));
when(mStatusBarKeyguardViewManager.getViewRootImpl()).thenReturn(testViewRoot); when(mStatusBarKeyguardViewManager.getViewRootImpl()).thenReturn(testViewRoot);
when(mDreamingToLockscreenTransitionViewModel.getDreamOverlayAlpha())
.thenReturn(mock(Flow.class));
mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl(mContext, mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl(mContext,
mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController, mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController,
mConfigurationController, mViewMediator, mKeyguardBypassController, mConfigurationController, mViewMediator, mKeyguardBypassController,
@@ -186,6 +194,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
} }
@Test @Test
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public void onLockdown_showKeyguard_evenIfKeyguardIsNotEnabledExternally() { public void onLockdown_showKeyguard_evenIfKeyguardIsNotEnabledExternally() {
// GIVEN keyguard is not enabled and isn't showing // GIVEN keyguard is not enabled and isn't showing
mViewMediator.onSystemReady(); mViewMediator.onSystemReady();
@@ -629,7 +638,9 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
() -> mNotificationShadeWindowController, () -> mNotificationShadeWindowController,
() -> mActivityLaunchAnimator, () -> mActivityLaunchAnimator,
() -> mScrimController, () -> mScrimController,
mFeatureFlags); mFeatureFlags,
mDispatcher,
() -> mDreamingToLockscreenTransitionViewModel);
mViewMediator.start(); mViewMediator.start();
mViewMediator.registerCentralSurfaces(mCentralSurfaces, null, null, null, null, null); mViewMediator.registerCentralSurfaces(mCentralSurfaces, null, null, null, null, null);

View File

@@ -70,7 +70,10 @@ class ResourceTrimmerTest : SysuiTestCase() {
resourceTrimmer = resourceTrimmer =
ResourceTrimmer( ResourceTrimmer(
keyguardInteractor, keyguardInteractor,
KeyguardTransitionInteractor(keyguardTransitionRepository), KeyguardTransitionInteractor(
keyguardTransitionRepository,
testScope.backgroundScope
),
globalWindowManager, globalWindowManager,
testScope.backgroundScope, testScope.backgroundScope,
testDispatcher, testDispatcher,

View File

@@ -215,7 +215,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
) )
keyguardTransitionRepository = FakeKeyguardTransitionRepository() keyguardTransitionRepository = FakeKeyguardTransitionRepository()
val keyguardTransitionInteractor = val keyguardTransitionInteractor =
KeyguardTransitionInteractor(keyguardTransitionRepository) KeyguardTransitionInteractor(keyguardTransitionRepository, testScope.backgroundScope)
return DeviceEntryFaceAuthRepositoryImpl( return DeviceEntryFaceAuthRepositoryImpl(
mContext, mContext,
fmOverride, fmOverride,

View File

@@ -82,7 +82,8 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
bouncerRepository = FakeKeyguardBouncerRepository() bouncerRepository = FakeKeyguardBouncerRepository()
faceAuthRepository = FakeDeviceEntryFaceAuthRepository() faceAuthRepository = FakeDeviceEntryFaceAuthRepository()
keyguardTransitionRepository = FakeKeyguardTransitionRepository() keyguardTransitionRepository = FakeKeyguardTransitionRepository()
keyguardTransitionInteractor = KeyguardTransitionInteractor(keyguardTransitionRepository) keyguardTransitionInteractor =
KeyguardTransitionInteractor(keyguardTransitionRepository, testScope.backgroundScope)
underTest = underTest =
SystemUIKeyguardFaceAuthInteractor( SystemUIKeyguardFaceAuthInteractor(

View File

@@ -292,7 +292,8 @@ class KeyguardLongPressInteractorTest : SysuiTestCase() {
scope = testScope.backgroundScope, scope = testScope.backgroundScope,
transitionInteractor = transitionInteractor =
KeyguardTransitionInteractor( KeyguardTransitionInteractor(
repository = keyguardTransitionRepository, keyguardTransitionRepository,
testScope.backgroundScope
), ),
repository = keyguardRepository, repository = keyguardRepository,
logger = logger, logger = logger,

View File

@@ -27,11 +27,14 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.KeyguardState.OFF
import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
import com.android.systemui.keyguard.shared.model.TransitionState.STARTED import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.keyguard.shared.model.TransitionStep
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Before import org.junit.Before
@@ -46,11 +49,12 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {
private lateinit var underTest: KeyguardTransitionInteractor private lateinit var underTest: KeyguardTransitionInteractor
private lateinit var repository: FakeKeyguardTransitionRepository private lateinit var repository: FakeKeyguardTransitionRepository
private val testScope = TestScope()
@Before @Before
fun setUp() { fun setUp() {
repository = FakeKeyguardTransitionRepository() repository = FakeKeyguardTransitionRepository()
underTest = KeyguardTransitionInteractor(repository) underTest = KeyguardTransitionInteractor(repository, testScope.backgroundScope)
} }
@Test @Test
@@ -108,17 +112,17 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {
} }
@Test @Test
fun keyguardStateTests() = runTest { fun finishedKeyguardStateTests() = testScope.runTest {
val finishedSteps by collectValues(underTest.finishedKeyguardState) val finishedSteps by collectValues(underTest.finishedKeyguardState)
runCurrent()
val steps = mutableListOf<TransitionStep>() val steps = mutableListOf<TransitionStep>()
steps.add(TransitionStep(AOD, LOCKSCREEN, 0f, STARTED)) steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 0f, STARTED))
steps.add(TransitionStep(AOD, LOCKSCREEN, 0.5f, RUNNING)) steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 0.5f, RUNNING))
steps.add(TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED)) steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 1f, FINISHED))
steps.add(TransitionStep(LOCKSCREEN, AOD, 0f, STARTED)) steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 0f, STARTED))
steps.add(TransitionStep(LOCKSCREEN, AOD, 0.9f, RUNNING)) steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 0.9f, RUNNING))
steps.add(TransitionStep(LOCKSCREEN, AOD, 1f, FINISHED)) steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 1f, FINISHED))
steps.add(TransitionStep(AOD, GONE, 1f, STARTED)) steps.add(TransitionStep(AOD, GONE, 1f, STARTED))
steps.forEach { steps.forEach {
@@ -126,7 +130,29 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {
runCurrent() runCurrent()
} }
assertThat(finishedSteps).isEqualTo(listOf(LOCKSCREEN, AOD)) assertThat(finishedSteps).isEqualTo(listOf(LOCKSCREEN, PRIMARY_BOUNCER, AOD))
}
@Test
fun startedKeyguardStateTests() = testScope.runTest {
val finishedSteps by collectValues(underTest.startedKeyguardState)
runCurrent()
val steps = mutableListOf<TransitionStep>()
steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 0f, STARTED))
steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 0.5f, RUNNING))
steps.add(TransitionStep(AOD, PRIMARY_BOUNCER, 1f, FINISHED))
steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 0f, STARTED))
steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 0.9f, RUNNING))
steps.add(TransitionStep(PRIMARY_BOUNCER, AOD, 1f, FINISHED))
steps.add(TransitionStep(AOD, GONE, 1f, STARTED))
steps.forEach {
repository.sendTransitionStep(it)
runCurrent()
}
assertThat(finishedSteps).isEqualTo(listOf(OFF, PRIMARY_BOUNCER, AOD, GONE))
} }
@Test @Test

View File

@@ -110,7 +110,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
keyguardInteractor = createKeyguardInteractor(featureFlags), keyguardInteractor = createKeyguardInteractor(featureFlags),
shadeRepository = shadeRepository, shadeRepository = shadeRepository,
keyguardTransitionRepository = mockTransitionRepository, keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository), keyguardTransitionInteractor =
KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
) )
fromLockscreenTransitionInteractor.start() fromLockscreenTransitionInteractor.start()
@@ -119,7 +120,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
scope = testScope, scope = testScope,
keyguardInteractor = createKeyguardInteractor(featureFlags), keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository, keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository), keyguardTransitionInteractor =
KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
) )
fromDreamingTransitionInteractor.start() fromDreamingTransitionInteractor.start()
@@ -128,7 +130,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
scope = testScope, scope = testScope,
keyguardInteractor = createKeyguardInteractor(featureFlags), keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository, keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository), keyguardTransitionInteractor =
KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
) )
fromAodTransitionInteractor.start() fromAodTransitionInteractor.start()
@@ -137,7 +140,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
scope = testScope, scope = testScope,
keyguardInteractor = createKeyguardInteractor(featureFlags), keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository, keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository), keyguardTransitionInteractor =
KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
) )
fromGoneTransitionInteractor.start() fromGoneTransitionInteractor.start()
@@ -146,7 +150,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
scope = testScope, scope = testScope,
keyguardInteractor = createKeyguardInteractor(featureFlags), keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository, keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository), keyguardTransitionInteractor =
KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
) )
fromDozingTransitionInteractor.start() fromDozingTransitionInteractor.start()
@@ -155,7 +160,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
scope = testScope, scope = testScope,
keyguardInteractor = createKeyguardInteractor(featureFlags), keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository, keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository), keyguardTransitionInteractor =
KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
) )
fromOccludedTransitionInteractor.start() fromOccludedTransitionInteractor.start()
@@ -164,7 +170,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
scope = testScope, scope = testScope,
keyguardInteractor = createKeyguardInteractor(featureFlags), keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository, keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository), keyguardTransitionInteractor =
KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
) )
fromAlternateBouncerTransitionInteractor.start() fromAlternateBouncerTransitionInteractor.start()
@@ -173,47 +180,13 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
scope = testScope, scope = testScope,
keyguardInteractor = createKeyguardInteractor(featureFlags), keyguardInteractor = createKeyguardInteractor(featureFlags),
keyguardTransitionRepository = mockTransitionRepository, keyguardTransitionRepository = mockTransitionRepository,
keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository), keyguardTransitionInteractor =
KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
keyguardSecurityModel = keyguardSecurityModel, keyguardSecurityModel = keyguardSecurityModel,
) )
fromPrimaryBouncerTransitionInteractor.start() fromPrimaryBouncerTransitionInteractor.start()
} }
@Test
fun dreamingToLockscreen() =
testScope.runTest {
// GIVEN a device is dreaming
keyguardRepository.setDreamingWithOverlay(true)
keyguardRepository.setWakefulnessModel(startingToWake())
runCurrent()
// GIVEN a prior transition has run to DREAMING
runTransition(KeyguardState.LOCKSCREEN, KeyguardState.DREAMING)
// WHEN doze is complete
keyguardRepository.setDozeTransitionModel(
DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
)
// AND dreaming has stopped
keyguardRepository.setDreamingWithOverlay(false)
advanceUntilIdle()
// AND then occluded has stopped
keyguardRepository.setKeyguardOccluded(false)
advanceUntilIdle()
val info =
withArgCaptor<TransitionInfo> {
verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to BOUNCER should occur
assertThat(info.ownerName).isEqualTo("FromDreamingTransitionInteractor")
assertThat(info.from).isEqualTo(KeyguardState.DREAMING)
assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN)
assertThat(info.animator).isNotNull()
coroutineContext.cancelChildren()
}
@Test @Test
fun lockscreenToPrimaryBouncerViaBouncerShowingCall() = fun lockscreenToPrimaryBouncerViaBouncerShowingCall() =
testScope.runTest { testScope.runTest {

View File

@@ -29,6 +29,7 @@ import com.android.systemui.statusbar.LightRevealEffect
import com.android.systemui.statusbar.LightRevealScrim import com.android.systemui.statusbar.LightRevealScrim
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
@@ -45,7 +46,7 @@ class LightRevealScrimInteractorTest : SysuiTestCase() {
private val fakeLightRevealScrimRepository = FakeLightRevealScrimRepository() private val fakeLightRevealScrimRepository = FakeLightRevealScrimRepository()
private val keyguardTransitionInteractor = private val keyguardTransitionInteractor =
KeyguardTransitionInteractor(fakeKeyguardTransitionRepository) KeyguardTransitionInteractor(fakeKeyguardTransitionRepository, TestScope().backgroundScope)
private lateinit var underTest: LightRevealScrimInteractor private lateinit var underTest: LightRevealScrimInteractor

View File

@@ -25,11 +25,12 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac
import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState 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.KeyguardTransitionAnimationFlow import com.android.systemui.util.mockito.mock
import com.google.common.collect.Range import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Before import org.junit.Before
@@ -42,13 +43,12 @@ import org.junit.runner.RunWith
class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() { class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() {
private lateinit var underTest: DreamingToLockscreenTransitionViewModel private lateinit var underTest: DreamingToLockscreenTransitionViewModel
private lateinit var repository: FakeKeyguardTransitionRepository private lateinit var repository: FakeKeyguardTransitionRepository
private lateinit var transitionAnimation: KeyguardTransitionAnimationFlow
@Before @Before
fun setUp() { fun setUp() {
repository = FakeKeyguardTransitionRepository() repository = FakeKeyguardTransitionRepository()
val interactor = KeyguardTransitionInteractor(repository) val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
underTest = DreamingToLockscreenTransitionViewModel(interactor) underTest = DreamingToLockscreenTransitionViewModel(interactor, mock())
} }
@Test @Test
@@ -60,17 +60,15 @@ class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() {
val job = val job =
underTest.dreamOverlayTranslationY(pixels).onEach { values.add(it) }.launchIn(this) underTest.dreamOverlayTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
// Should start running here...
repository.sendTransitionStep(step(0f, TransitionState.STARTED)) repository.sendTransitionStep(step(0f, TransitionState.STARTED))
repository.sendTransitionStep(step(0f)) repository.sendTransitionStep(step(0f))
repository.sendTransitionStep(step(0.3f)) repository.sendTransitionStep(step(0.3f))
repository.sendTransitionStep(step(0.5f)) repository.sendTransitionStep(step(0.5f))
repository.sendTransitionStep(step(0.6f)) repository.sendTransitionStep(step(0.6f))
// ...up to here
repository.sendTransitionStep(step(0.8f)) repository.sendTransitionStep(step(0.8f))
repository.sendTransitionStep(step(1f)) repository.sendTransitionStep(step(1f))
assertThat(values.size).isEqualTo(5) assertThat(values.size).isEqualTo(7)
values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) } values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) }
job.cancel() job.cancel()

View File

@@ -29,6 +29,7 @@ import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Before import org.junit.Before
@@ -45,7 +46,7 @@ class GoneToDreamingTransitionViewModelTest : SysuiTestCase() {
@Before @Before
fun setUp() { fun setUp() {
repository = FakeKeyguardTransitionRepository() repository = FakeKeyguardTransitionRepository()
val interactor = KeyguardTransitionInteractor(repository) val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
underTest = GoneToDreamingTransitionViewModel(interactor) underTest = GoneToDreamingTransitionViewModel(interactor)
} }

View File

@@ -219,6 +219,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
transitionInteractor = transitionInteractor =
KeyguardTransitionInteractor( KeyguardTransitionInteractor(
repository = FakeKeyguardTransitionRepository(), repository = FakeKeyguardTransitionRepository(),
scope = testScope.backgroundScope
), ),
repository = repository, repository = repository,
logger = UiEventLoggerFake(), logger = UiEventLoggerFake(),

View File

@@ -29,6 +29,7 @@ import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Before import org.junit.Before
@@ -45,7 +46,7 @@ class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() {
@Before @Before
fun setUp() { fun setUp() {
repository = FakeKeyguardTransitionRepository() repository = FakeKeyguardTransitionRepository()
val interactor = KeyguardTransitionInteractor(repository) val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
underTest = LockscreenToDreamingTransitionViewModel(interactor) underTest = LockscreenToDreamingTransitionViewModel(interactor)
} }

View File

@@ -29,6 +29,7 @@ import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Before import org.junit.Before
@@ -45,7 +46,7 @@ class LockscreenToOccludedTransitionViewModelTest : SysuiTestCase() {
@Before @Before
fun setUp() { fun setUp() {
repository = FakeKeyguardTransitionRepository() repository = FakeKeyguardTransitionRepository()
val interactor = KeyguardTransitionInteractor(repository) val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
underTest = LockscreenToOccludedTransitionViewModel(interactor) underTest = LockscreenToOccludedTransitionViewModel(interactor)
} }

View File

@@ -29,6 +29,7 @@ import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Before import org.junit.Before
@@ -45,7 +46,7 @@ class OccludedToLockscreenTransitionViewModelTest : SysuiTestCase() {
@Before @Before
fun setUp() { fun setUp() {
repository = FakeKeyguardTransitionRepository() repository = FakeKeyguardTransitionRepository()
val interactor = KeyguardTransitionInteractor(repository) val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
underTest = OccludedToLockscreenTransitionViewModel(interactor) underTest = OccludedToLockscreenTransitionViewModel(interactor)
} }

View File

@@ -33,6 +33,7 @@ import com.google.common.collect.Range
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Before import org.junit.Before
@@ -54,7 +55,7 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() {
fun setUp() { fun setUp() {
MockitoAnnotations.initMocks(this) MockitoAnnotations.initMocks(this)
repository = FakeKeyguardTransitionRepository() repository = FakeKeyguardTransitionRepository()
val interactor = KeyguardTransitionInteractor(repository) val interactor = KeyguardTransitionInteractor(repository, TestScope().backgroundScope)
underTest = underTest =
PrimaryBouncerToGoneTransitionViewModel( PrimaryBouncerToGoneTransitionViewModel(
interactor, interactor,

View File

@@ -63,6 +63,7 @@ import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertFalse import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue import junit.framework.Assert.assertTrue
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Before import org.junit.Before
@@ -146,7 +147,7 @@ class MediaCarouselControllerTest : SysuiTestCase() {
debugLogger, debugLogger,
mediaFlags, mediaFlags,
keyguardUpdateMonitor, keyguardUpdateMonitor,
KeyguardTransitionInteractor(repository = transitionRepository), KeyguardTransitionInteractor(transitionRepository, TestScope().backgroundScope),
) )
verify(configurationController).addCallback(capture(configListener)) verify(configurationController).addCallback(capture(configListener))
verify(mediaDataManager).addListener(capture(listener)) verify(mediaDataManager).addListener(capture(listener))

View File

@@ -99,6 +99,7 @@ class MultiShadeMotionEventInteractorTest : SysuiTestCase() {
keyguardTransitionInteractor = keyguardTransitionInteractor =
KeyguardTransitionInteractor( KeyguardTransitionInteractor(
repository = keyguardTransitionRepository, repository = keyguardTransitionRepository,
scope = testScope.backgroundScope
), ),
falsingManager = falsingManager, falsingManager = falsingManager,
shadeController = shadeController, shadeController = shadeController,

View File

@@ -103,8 +103,8 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
@Mock lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory @Mock lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory
@Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent @Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent
@Mock lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController @Mock lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
@Mock @Mock private lateinit var unfoldTransitionProgressProvider:
private lateinit var unfoldTransitionProgressProvider: Optional<UnfoldTransitionProgressProvider> Optional<UnfoldTransitionProgressProvider>
@Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor @Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
@Mock @Mock
lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel
@@ -184,6 +184,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
keyguardTransitionInteractor = keyguardTransitionInteractor =
KeyguardTransitionInteractor( KeyguardTransitionInteractor(
repository = FakeKeyguardTransitionRepository(), repository = FakeKeyguardTransitionRepository(),
scope = testScope.backgroundScope
), ),
falsingManager = FalsingManagerFake(), falsingManager = FalsingManagerFake(),
shadeController = shadeController, shadeController = shadeController,

View File

@@ -59,6 +59,7 @@ import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import java.util.Optional
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope
@@ -72,7 +73,6 @@ import org.mockito.Mock
import org.mockito.Mockito.spy import org.mockito.Mockito.spy
import org.mockito.Mockito.verify import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations
import java.util.Optional
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidTestingRunner::class) @RunWith(AndroidTestingRunner::class)
@@ -106,7 +106,8 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
@Mock @Mock
private lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController private lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
@Mock @Mock
private lateinit var unfoldTransitionProgressProvider: Optional<UnfoldTransitionProgressProvider> private lateinit var unfoldTransitionProgressProvider:
Optional<UnfoldTransitionProgressProvider>
@Mock private lateinit var notificationInsetsController: NotificationInsetsController @Mock private lateinit var notificationInsetsController: NotificationInsetsController
@Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor @Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
@Mock @Mock
@@ -195,6 +196,7 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
keyguardTransitionInteractor = keyguardTransitionInteractor =
KeyguardTransitionInteractor( KeyguardTransitionInteractor(
repository = FakeKeyguardTransitionRepository(), repository = FakeKeyguardTransitionRepository(),
scope = testScope.backgroundScope
), ),
falsingManager = FalsingManagerFake(), falsingManager = FalsingManagerFake(),
shadeController = shadeController, shadeController = shadeController,

View File

@@ -47,7 +47,8 @@ class CollapsedStatusBarViewModelImplTest : SysuiTestCase() {
testScope = TestScope(UnconfinedTestDispatcher()) testScope = TestScope(UnconfinedTestDispatcher())
keyguardTransitionRepository = FakeKeyguardTransitionRepository() keyguardTransitionRepository = FakeKeyguardTransitionRepository()
val interactor = KeyguardTransitionInteractor(keyguardTransitionRepository) val interactor =
KeyguardTransitionInteractor(keyguardTransitionRepository, testScope.backgroundScope)
underTest = CollapsedStatusBarViewModelImpl(interactor, testScope.backgroundScope) underTest = CollapsedStatusBarViewModelImpl(interactor, testScope.backgroundScope)
} }

View File

@@ -101,12 +101,6 @@ public class DreamOverlayServiceTest {
mMonitor.onEndDream(); mMonitor.onEndDream();
super.onEndDream(); super.onEndDream();
} }
@Override
public void onWakeUp(@NonNull Runnable onCompleteCallback) {
mMonitor.onWakeUp();
super.onWakeUp(onCompleteCallback);
}
} }
/** /**