Merge "Add scrim transitions to/from glanceable hub" into main
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index ade417d..64fcef5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -125,6 +125,7 @@
import com.android.systemui.charging.WirelessChargingAnimation;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.communal.domain.interactor.CommunalInteractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -245,6 +246,7 @@
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
import javax.inject.Inject;
import javax.inject.Named;
@@ -551,6 +553,25 @@
private final WakefulnessLifecycle mWakefulnessLifecycle;
protected final PowerInteractor mPowerInteractor;
+ private final CommunalInteractor mCommunalInteractor;
+
+ /**
+ * True if the device is showing the glanceable hub. See
+ * {@link CommunalInteractor#isIdleOnCommunal()} for more details.
+ */
+ private boolean mIsIdleOnCommunal = false;
+ private final Consumer<Boolean> mIdleOnCommunalConsumer = (Boolean idleOnCommunal) -> {
+ if (idleOnCommunal == mIsIdleOnCommunal) {
+ // Ignore initial value coming through the flow.
+ return;
+ }
+
+ mIsIdleOnCommunal = idleOnCommunal;
+ // Trigger an update for the scrim state when we enter or exit glanceable hub, so that we
+ // can transition to/from ScrimState.GLANCEABLE_HUB if needed.
+ updateScrimController();
+ };
+
private boolean mNoAnimationOnNextBarModeChange;
private final SysuiStatusBarStateController mStatusBarStateController;
@@ -618,6 +639,7 @@
ScreenLifecycle screenLifecycle,
WakefulnessLifecycle wakefulnessLifecycle,
PowerInteractor powerInteractor,
+ CommunalInteractor communalInteractor,
SysuiStatusBarStateController statusBarStateController,
Optional<Bubbles> bubblesOptional,
Lazy<NoteTaskController> noteTaskControllerLazy,
@@ -722,6 +744,7 @@
mScreenLifecycle = screenLifecycle;
mWakefulnessLifecycle = wakefulnessLifecycle;
mPowerInteractor = powerInteractor;
+ mCommunalInteractor = communalInteractor;
mStatusBarStateController = statusBarStateController;
mBubblesOptional = bubblesOptional;
mNoteTaskControllerLazy = noteTaskControllerLazy;
@@ -1051,6 +1074,10 @@
//TODO(b/264502026) move the rest of the listeners here.
mDeviceStateManager.registerCallback(mMainExecutor,
new FoldStateListener(mContext, this::onFoldedStateChanged));
+
+ mJavaAdapter.alwaysCollectFlow(
+ mCommunalInteractor.isIdleOnCommunal(),
+ mIdleOnCommunalConsumer);
}
/**
@@ -2795,6 +2822,8 @@
// This will cancel the keyguardFadingAway animation if it is running. We need to do
// this as otherwise it can remain pending and leave keyguard in a weird state.
mUnlockScrimCallback.onCancelled();
+ } else if (mIsIdleOnCommunal) {
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
} else if (mKeyguardStateController.isShowing()
&& !mKeyguardStateController.isOccluded()
&& !unlocking) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 3f20eaf..6f78604 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -17,7 +17,9 @@
package com.android.systemui.statusbar.phone;
import static com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER;
+import static com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB;
import static com.android.systemui.keyguard.shared.model.KeyguardState.GONE;
+import static com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN;
import static com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
@@ -62,6 +64,7 @@
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.keyguard.shared.model.ScrimAlpha;
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
@@ -292,6 +295,30 @@
mScrimBehind.setViewAlpha(mBehindAlpha);
};
+ /**
+ * Consumer that fades the behind scrim in and out during the transition between the lock screen
+ * and the glanceable hub.
+ *
+ * While the lock screen is showing, the behind scrim is used to slightly darken the lock screen
+ * wallpaper underneath. Since the glanceable hub is under all of the scrims, we want to fade
+ * out the scrim so that the glanceable hub isn't darkened when it opens.
+ *
+ * {@link #applyState()} handles the scrim alphas once on the glanceable hub, this is only
+ * responsible for setting the behind alpha during the transition.
+ */
+ private final Consumer<TransitionStep> mGlanceableHubConsumer = (TransitionStep step) -> {
+ final float baseAlpha = ScrimState.KEYGUARD.getBehindAlpha();
+ final float transitionProgress = step.getValue();
+ if (step.getTo() == KeyguardState.LOCKSCREEN) {
+ // Transitioning back to lock screen, fade in behind scrim again.
+ mBehindAlpha = baseAlpha * transitionProgress;
+ } else if (step.getTo() == GLANCEABLE_HUB) {
+ // Transitioning to glanceable hub, fade out behind scrim.
+ mBehindAlpha = baseAlpha * (1 - transitionProgress);
+ }
+ mScrimBehind.setViewAlpha(mBehindAlpha);
+ };
+
Consumer<TransitionStep> mBouncerToGoneTransition;
@Inject
@@ -444,6 +471,14 @@
mBouncerToGoneTransition, mMainDispatcher);
collectFlow(behindScrim, mAlternateBouncerToGoneTransitionViewModel.getScrimAlpha(),
mScrimAlphaConsumer, mMainDispatcher);
+
+ // LOCKSCREEN<->GLANCEABLE_HUB
+ collectFlow(behindScrim,
+ mKeyguardTransitionInteractor.transition(LOCKSCREEN, GLANCEABLE_HUB),
+ mGlanceableHubConsumer, mMainDispatcher);
+ collectFlow(behindScrim,
+ mKeyguardTransitionInteractor.transition(GLANCEABLE_HUB, LOCKSCREEN),
+ mGlanceableHubConsumer, mMainDispatcher);
}
// TODO(b/270984686) recompute scrim height accurately, based on shade contents.
@@ -815,9 +850,9 @@
return;
}
mBouncerHiddenFraction = bouncerHiddenAmount;
- if (mState == ScrimState.DREAMING) {
- // Only the dreaming state requires this for the scrim calculation, so we should
- // only trigger an update if dreaming.
+ if (mState == ScrimState.DREAMING || mState == ScrimState.GLANCEABLE_HUB) {
+ // The dreaming and glanceable hub states requires this for the scrim calculation, so we
+ // should only trigger an update in those states.
applyAndDispatchState();
}
}
@@ -939,7 +974,7 @@
} else if (mState == ScrimState.AUTH_SCRIMMED_SHADE) {
mNotificationsAlpha = (float) Math.pow(getInterpolatedFraction(), 0.8f);
} else if (mState == ScrimState.KEYGUARD || mState == ScrimState.SHADE_LOCKED
- || mState == ScrimState.PULSING) {
+ || mState == ScrimState.PULSING || mState == ScrimState.GLANCEABLE_HUB) {
Pair<Integer, Float> result = calculateBackStateForState(mState);
int behindTint = result.first;
float behindAlpha = result.second;
@@ -950,6 +985,11 @@
mTransitionToFullShadeProgress);
behindTint = ColorUtils.blendARGB(behindTint, shadeResult.first,
mTransitionToFullShadeProgress);
+ } else if (mState == ScrimState.GLANCEABLE_HUB && mTransitionToFullShadeProgress == 0.0f
+ && mBouncerHiddenFraction == KeyguardBouncerConstants.EXPANSION_HIDDEN) {
+ // Behind scrim should not be visible when idle on the glanceable hub and neither
+ // bouncer nor shade are showing.
+ behindAlpha = 0f;
}
mInFrontAlpha = mState.getFrontAlpha();
if (mClipsQsScrim) {
@@ -965,6 +1005,13 @@
} else if (mState == ScrimState.SHADE_LOCKED) {
// going from KEYGUARD to SHADE_LOCKED state
mNotificationsAlpha = getInterpolatedFraction();
+ } else if (mState == ScrimState.GLANCEABLE_HUB
+ && mTransitionToFullShadeProgress == 0.0f) {
+ // Notification scrim should not be visible on the glanceable hub unless the
+ // shade is showing or transitioning in. Otherwise the notification scrim will
+ // be visible as the bouncer transitions in or after the notification shade
+ // closes.
+ mNotificationsAlpha = 0;
} else {
mNotificationsAlpha = Math.max(1.0f - getInterpolatedFraction(), mQsExpansion);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 61bd112..f2a649b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -296,6 +296,21 @@
updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor);
}
}
+ },
+
+ /**
+ * Device is locked or on dream and user has swiped from the right edge to enter the glanceable
+ * hub UI. From this state, the user can swipe from the left edge to go back to the lock screen
+ * or dream, as well as swipe down for the notifications and up for the bouncer.
+ */
+ GLANCEABLE_HUB {
+ @Override
+ public void prepare(ScrimState previousState) {
+ // No scrims should be visible by default in this state.
+ mBehindAlpha = 0;
+ mNotifAlpha = 0;
+ mFrontAlpha = 0;
+ }
};
boolean mBlankScreen = false;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 9c4984e..849a13b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -41,6 +41,8 @@
import static java.util.Collections.emptySet;
+import static kotlinx.coroutines.flow.FlowKt.flowOf;
+
import android.app.ActivityManager;
import android.app.IWallpaperManager;
import android.app.WallpaperManager;
@@ -77,7 +79,6 @@
import com.android.internal.logging.testing.FakeMetricsLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.TestScopeProvider;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.InitController;
import com.android.systemui.SysuiTestCase;
@@ -92,6 +93,10 @@
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.communal.data.repository.CommunalRepository;
+import com.android.systemui.communal.domain.interactor.CommunalInteractor;
+import com.android.systemui.communal.shared.model.CommunalSceneKey;
+import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlags;
@@ -102,6 +107,7 @@
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.notetask.NoteTaskController;
@@ -195,6 +201,8 @@
import javax.inject.Provider;
+import kotlinx.coroutines.test.TestScope;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper(setAsMainLooper = true)
@@ -203,11 +211,17 @@
private static final int FOLD_STATE_FOLDED = 0;
private static final int FOLD_STATE_UNFOLDED = 1;
+ private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
+
private CentralSurfacesImpl mCentralSurfaces;
private FakeMetricsLogger mMetricsLogger;
private PowerManager mPowerManager;
private VisualInterruptionDecisionProvider mVisualInterruptionDecisionProvider;
+
+ private final TestScope mTestScope = mKosmos.getTestScope();
+ private final CommunalInteractor mCommunalInteractor = mKosmos.getCommunalInteractor();
+ private final CommunalRepository mCommunalRepository = mKosmos.getCommunalRepository();
@Mock private NotificationsController mNotificationsController;
@Mock private LightBarController mLightBarController;
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -461,7 +475,7 @@
new DisplayMetrics(),
mMetricsLogger,
mShadeLogger,
- new JavaAdapter(TestScopeProvider.getTestScope()),
+ new JavaAdapter(mTestScope),
mUiBgExecutor,
mNotificationPanelViewController,
mNotificationMediaManager,
@@ -473,6 +487,7 @@
mScreenLifecycle,
mWakefulnessLifecycle,
mPowerInteractor,
+ mCommunalInteractor,
mStatusBarStateController,
Optional.of(mBubbles),
() -> mNoteTaskController,
@@ -821,6 +836,25 @@
}
@Test
+ public void testEnteringGlanceableHub_updatesScrim() {
+ // Transition to the glanceable hub.
+ mCommunalRepository.setTransitionState(flowOf(new ObservableCommunalTransitionState.Idle(
+ CommunalSceneKey.Communal.INSTANCE)));
+ mTestScope.getTestScheduler().runCurrent();
+
+ // ScrimState also transitions.
+ verify(mScrimController).transitionTo(ScrimState.GLANCEABLE_HUB);
+
+ // Transition away from the glanceable hub.
+ mCommunalRepository.setTransitionState(flowOf(new ObservableCommunalTransitionState.Idle(
+ CommunalSceneKey.Blank.INSTANCE)));
+ mTestScope.getTestScheduler().runCurrent();
+
+ // ScrimState goes back to UNLOCKED.
+ verify(mScrimController).transitionTo(eq(ScrimState.UNLOCKED), any());
+ }
+
+ @Test
public void testShowKeyguardImplementation_setsState() {
when(mLockscreenUserManager.getCurrentProfiles()).thenReturn(new SparseArray<>());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 423cc84..3bde6e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -51,6 +51,7 @@
import android.graphics.Color;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.testing.ViewUtils;
import android.util.MathUtils;
import android.view.View;
@@ -59,13 +60,13 @@
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.TestScopeProvider;
import com.android.systemui.DejankUtils;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.shared.model.KeyguardState;
@@ -73,6 +74,7 @@
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToGoneTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
import com.android.systemui.shade.transition.LinearLargeScreenShadeInterpolator;
@@ -103,7 +105,6 @@
import java.util.HashSet;
import java.util.Map;
-import kotlinx.coroutines.CoroutineDispatcher;
import kotlinx.coroutines.test.TestScope;
@RunWith(AndroidTestingRunner.class)
@@ -112,13 +113,14 @@
public class ScrimControllerTest extends SysuiTestCase {
@Rule public Expect mExpect = Expect.create();
+ private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
private final FakeConfigurationController mConfigurationController =
new FakeConfigurationController();
private final LargeScreenShadeInterpolator
mLinearLargeScreenShadeInterpolator = new LinearLargeScreenShadeInterpolator();
- private final TestScope mTestScope = TestScopeProvider.getTestScope();
+ private final TestScope mTestScope = mKosmos.getTestScope();
private final JavaAdapter mJavaAdapter = new JavaAdapter(mTestScope.getBackgroundScope());
private ScrimController mScrimController;
@@ -145,10 +147,12 @@
@Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
@Mock private AlternateBouncerToGoneTransitionViewModel
mAlternateBouncerToGoneTransitionViewModel;
- @Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+ private final KeyguardTransitionInteractor mKeyguardTransitionInteractor =
+ mKosmos.getKeyguardTransitionInteractor();
+ private final FakeKeyguardTransitionRepository mKeyguardTransitionRepository =
+ mKosmos.getKeyguardTransitionRepository();
@Mock private KeyguardInteractor mKeyguardInteractor;
private final FakeWallpaperRepository mWallpaperRepository = new FakeWallpaperRepository();
- @Mock private CoroutineDispatcher mMainDispatcher;
@Mock private TypedArray mMockTypedArray;
// TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The
@@ -265,8 +269,6 @@
when(mDelayedWakeLockFactory.create(any(String.class))).thenReturn(mWakeLock);
when(mDockManager.isDocked()).thenReturn(false);
- when(mKeyguardTransitionInteractor.transition(any(), any()))
- .thenReturn(emptyFlow());
when(mPrimaryBouncerToGoneTransitionViewModel.getScrimAlpha())
.thenReturn(emptyFlow());
when(mAlternateBouncerToGoneTransitionViewModel.getScrimAlpha())
@@ -292,13 +294,16 @@
mKeyguardTransitionInteractor,
mKeyguardInteractor,
mWallpaperRepository,
- mMainDispatcher,
+ mKosmos.getTestDispatcher(),
mLinearLargeScreenShadeInterpolator);
mScrimController.start();
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
mScrimController.setAnimatorListener(mAnimatorListener);
+ // Attach behind scrim so flows that are collecting on it start running.
+ ViewUtils.attachView(mScrimBehind);
+
mScrimController.setHasBackdrop(false);
mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(false);
@@ -629,6 +634,164 @@
}
@Test
+ public void lockscreenToHubTransition_setsBehindScrimAlpha() {
+ // Start on lockscreen.
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ finishAnimationsImmediately();
+
+ // Behind scrim starts at default alpha.
+ final float transitionProgress = 0f;
+ float expectedAlpha = ScrimState.KEYGUARD.getBehindAlpha();
+ mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+ new TransitionStep(
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.GLANCEABLE_HUB,
+ transitionProgress,
+ TransitionState.STARTED
+ ), true);
+ mTestScope.getTestScheduler().runCurrent();
+ assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+
+ // Scrim fades out as transition runs.
+ final float runningProgress = 0.2f;
+ expectedAlpha = (1 - runningProgress) * ScrimState.KEYGUARD.getBehindAlpha();
+ mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+ new TransitionStep(
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.GLANCEABLE_HUB,
+ runningProgress,
+ TransitionState.RUNNING
+ ), true);
+ mTestScope.getTestScheduler().runCurrent();
+ assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+
+ // Scrim invisible at end of transition.
+ final float finishedProgress = 1f;
+ expectedAlpha = 0f;
+ mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+ new TransitionStep(
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.GLANCEABLE_HUB,
+ finishedProgress,
+ TransitionState.FINISHED
+ ), true);
+ mTestScope.getTestScheduler().runCurrent();
+ assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+ }
+
+ @Test
+ public void hubToLockscreenTransition_setsViewAlpha() {
+ // Start on glanceable hub.
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+ finishAnimationsImmediately();
+
+ // Behind scrim starts at 0 alpha.
+ final float transitionProgress = 0f;
+ float expectedAlpha = 0f;
+ mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+ new TransitionStep(
+ KeyguardState.GLANCEABLE_HUB,
+ KeyguardState.LOCKSCREEN,
+ transitionProgress,
+ TransitionState.STARTED
+ ), true);
+ mTestScope.getTestScheduler().runCurrent();
+ assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+
+ // Scrim fades in as transition runs.
+ final float runningProgress = 0.2f;
+ expectedAlpha = runningProgress * ScrimState.KEYGUARD.getBehindAlpha();
+ mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+ new TransitionStep(
+ KeyguardState.GLANCEABLE_HUB,
+ KeyguardState.LOCKSCREEN,
+ runningProgress,
+ TransitionState.RUNNING
+ ), true);
+ mTestScope.getTestScheduler().runCurrent();
+ assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+
+ // Scrim at default visibility at end of transition.
+ final float finishedProgress = 1f;
+ expectedAlpha = finishedProgress * ScrimState.KEYGUARD.getBehindAlpha();
+ mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+ new TransitionStep(
+ KeyguardState.GLANCEABLE_HUB,
+ KeyguardState.LOCKSCREEN,
+ finishedProgress,
+ TransitionState.FINISHED
+ ), true);
+ mTestScope.getTestScheduler().runCurrent();
+ assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+ }
+
+ @Test
+ public void transitionToHub() {
+ mScrimController.setRawPanelExpansionFraction(0f);
+ mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_HIDDEN);
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+ finishAnimationsImmediately();
+
+ // All scrims transparent on the hub.
+ assertScrimAlpha(Map.of(
+ mScrimInFront, TRANSPARENT,
+ mNotificationsScrim, TRANSPARENT,
+ mScrimBehind, TRANSPARENT));
+ }
+
+ @Test
+ public void openBouncerOnHub() {
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+
+ // Open the bouncer.
+ mScrimController.setRawPanelExpansionFraction(0f);
+ mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_VISIBLE);
+ finishAnimationsImmediately();
+
+ // Only behind widget is visible.
+ assertScrimAlpha(Map.of(
+ mScrimInFront, TRANSPARENT,
+ mNotificationsScrim, TRANSPARENT,
+ mScrimBehind, OPAQUE));
+
+ // Bouncer is closed.
+ mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_HIDDEN);
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+ finishAnimationsImmediately();
+
+ // All scrims are transparent.
+ assertScrimAlpha(Map.of(
+ mScrimInFront, TRANSPARENT,
+ mNotificationsScrim, TRANSPARENT,
+ mScrimBehind, TRANSPARENT));
+ }
+
+ @Test
+ public void openShadeOnHub() {
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+
+ // Open the shade.
+ mScrimController.transitionTo(SHADE_LOCKED);
+ mScrimController.setQsPosition(1f, 0);
+ finishAnimationsImmediately();
+
+ // Shade scrims are visible.
+ assertScrimAlpha(Map.of(
+ mNotificationsScrim, OPAQUE,
+ mScrimInFront, TRANSPARENT,
+ mScrimBehind, OPAQUE));
+
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+ finishAnimationsImmediately();
+
+ // All scrims are transparent.
+ assertScrimAlpha(Map.of(
+ mScrimInFront, TRANSPARENT,
+ mNotificationsScrim, TRANSPARENT,
+ mScrimBehind, TRANSPARENT));
+ }
+
+ @Test
public void onThemeChange_bouncerBehindTint_isUpdatedToSurfaceColor() {
assertEquals(BOUNCER.getBehindTint(), 0x112233);
mSurfaceColor = 0x223344;
@@ -1001,7 +1164,7 @@
mKeyguardTransitionInteractor,
mKeyguardInteractor,
mWallpaperRepository,
- mMainDispatcher,
+ mKosmos.getTestDispatcher(),
mLinearLargeScreenShadeInterpolator);
mScrimController.start();
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
@@ -1267,7 +1430,7 @@
ScrimState.UNINITIALIZED, ScrimState.KEYGUARD, BOUNCER,
ScrimState.DREAMING, ScrimState.BOUNCER_SCRIMMED, ScrimState.BRIGHTNESS_MIRROR,
ScrimState.UNLOCKED, SHADE_LOCKED, ScrimState.AUTH_SCRIMMED,
- ScrimState.AUTH_SCRIMMED_SHADE));
+ ScrimState.AUTH_SCRIMMED_SHADE, ScrimState.GLANCEABLE_HUB));
for (ScrimState state : ScrimState.values()) {
if (!lowPowerModeStates.contains(state) && !regularStates.contains(state)) {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
index 0c1dbfe..e20a0ab 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
@@ -28,9 +28,12 @@
import java.util.UUID
import javax.inject.Inject
import junit.framework.Assert.fail
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestCoroutineScheduler
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
@@ -150,6 +153,15 @@
_transitions.emit(step)
}
+ /** Version of [sendTransitionStep] that's usable from Java tests. */
+ fun sendTransitionStepJava(
+ coroutineScope: CoroutineScope,
+ step: TransitionStep,
+ validateStep: Boolean = true
+ ): Job {
+ return coroutineScope.launch { sendTransitionStep(step, validateStep) }
+ }
+
suspend fun sendTransitionSteps(
steps: List<TransitionStep>,
testScope: TestScope,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
index 11f2938..083de10 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
@@ -32,6 +32,8 @@
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.jank.interactionJankMonitor
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.model.sceneContainerPlugin
import com.android.systemui.plugins.statusbar.statusBarStateController
import com.android.systemui.power.data.repository.fakePowerRepository
@@ -61,6 +63,8 @@
val bouncerRepository by lazy { kosmos.bouncerRepository }
val communalRepository by lazy { kosmos.fakeCommunalRepository }
val keyguardRepository by lazy { kosmos.fakeKeyguardRepository }
+ val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository }
+ val keyguardTransitionInteractor by lazy { kosmos.keyguardTransitionInteractor }
val powerRepository by lazy { kosmos.fakePowerRepository }
val clock by lazy { kosmos.systemClock }
val mobileConnectionsRepository by lazy { kosmos.fakeMobileConnectionsRepository }