diff options
10 files changed, 317 insertions, 45 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/DejankUtils.java b/packages/SystemUI/src/com/android/systemui/DejankUtils.java index eba1d0f9f9c6..4ee3bd37ce3c 100644 --- a/packages/SystemUI/src/com/android/systemui/DejankUtils.java +++ b/packages/SystemUI/src/com/android/systemui/DejankUtils.java @@ -16,6 +16,7 @@ package com.android.systemui; +import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.util.Assert; import android.os.Handler; @@ -30,9 +31,13 @@ public class DejankUtils { private static final Choreographer sChoreographer = Choreographer.getInstance(); private static final Handler sHandler = new Handler(); - private static final ArrayList<Runnable> sPendingRunnables = new ArrayList<>(); + /** + * Only for testing. + */ + private static boolean sImmediate; + private static final Runnable sAnimationCallbackRunnable = new Runnable() { @Override public void run() { @@ -51,6 +56,10 @@ public class DejankUtils { * <p>Needs to be called from the main thread. */ public static void postAfterTraversal(Runnable r) { + if (sImmediate) { + r.run(); + return; + } Assert.isMainThread(); sPendingRunnables.add(r); postAnimationCallback(); @@ -71,4 +80,9 @@ public class DejankUtils { sChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, sAnimationCallbackRunnable, null); } + + @VisibleForTesting + public static void setImmediate(boolean immediate) { + sImmediate = immediate; + } } diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java index d1834e921d20..91edfda06261 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java @@ -27,6 +27,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.Dependency.DependencyProvider; +import com.android.systemui.classifier.FalsingManager; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.qs.QSTileHost; import com.android.systemui.statusbar.KeyguardIndicationController; @@ -95,7 +96,7 @@ public class SystemUIFactory { LockPatternUtils lockPatternUtils, ViewGroup container, DismissCallbackRegistry dismissCallbackRegistry) { return new KeyguardBouncer(context, callback, lockPatternUtils, container, - dismissCallbackRegistry); + dismissCallbackRegistry, FalsingManager.getInstance(context)); } public ScrimController createScrimController(LightBarController lightBarController, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index 010b1651a0d4..2a1813fecd12 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -16,10 +16,14 @@ package com.android.systemui.statusbar.phone; +import static com.android.keyguard.KeyguardHostView.OnDismissAction; +import static com.android.keyguard.KeyguardSecurityModel.SecurityMode; + import android.content.Context; import android.os.Handler; import android.os.UserHandle; import android.os.UserManager; +import android.util.Log; import android.util.MathUtils; import android.util.Slog; import android.util.StatsLog; @@ -29,7 +33,6 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.WindowInsets; -import android.view.accessibility.AccessibilityEvent; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardHostView; @@ -42,9 +45,6 @@ import com.android.systemui.DejankUtils; import com.android.systemui.classifier.FalsingManager; import com.android.systemui.keyguard.DismissCallbackRegistry; -import static com.android.keyguard.KeyguardHostView.OnDismissAction; -import static com.android.keyguard.KeyguardSecurityModel.SecurityMode; - /** * A class which manages the bouncer on the lockscreen. */ @@ -76,13 +76,13 @@ public class KeyguardBouncer { public KeyguardBouncer(Context context, ViewMediatorCallback callback, LockPatternUtils lockPatternUtils, ViewGroup container, - DismissCallbackRegistry dismissCallbackRegistry) { + DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager) { mContext = context; mCallback = callback; mLockPatternUtils = lockPatternUtils; mContainer = container; KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback); - mFalsingManager = FalsingManager.getInstance(mContext); + mFalsingManager = falsingManager; mDismissCallbackRegistry = dismissCallbackRegistry; mHandler = new Handler(); } @@ -91,7 +91,14 @@ public class KeyguardBouncer { show(resetSecuritySelection, true /* notifyFalsing */); } - public void show(boolean resetSecuritySelection, boolean notifyFalsing) { + /** + * Shows the bouncer. + * + * @param resetSecuritySelection Cleans keyguard view + * @param animated true when the bouncer show show animated, false when the user will be + * dragging it and animation should be deferred. + */ + public void show(boolean resetSecuritySelection, boolean animated) { final int keyguardUserId = KeyguardUpdateMonitor.getCurrentUser(); if (keyguardUserId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser()) { // In split system user mode, we never unlock system user. @@ -104,9 +111,11 @@ public class KeyguardBouncer { // are valid. // Later, at the end of the animation, when the bouncer is at the top of the screen, // onFullyShown() will be called and FalsingManager will stop recording touches. - if (notifyFalsing) { + if (animated) { mFalsingManager.onBouncerShown(); + setExpansion(0); } + if (resetSecuritySelection) { // showPrimarySecurityScreen() updates the current security method. This is needed in // case we are already showing and the current security method changed. @@ -157,7 +166,9 @@ public class KeyguardBouncer { public void onFullyHidden() { if (!mShowingSoon) { cancelShowRunnable(); - mRoot.setVisibility(View.INVISIBLE); + if (mRoot != null) { + mRoot.setVisibility(View.INVISIBLE); + } mFalsingManager.onBouncerHidden(); } } @@ -202,11 +213,19 @@ public class KeyguardBouncer { * and {@link KeyguardSecurityView#PROMPT_REASON_RESTART} */ public void showPromptReason(int reason) { - mKeyguardView.showPromptReason(reason); + if (mKeyguardView != null) { + mKeyguardView.showPromptReason(reason); + } else { + Log.w(TAG, "Trying to show prompt reason on empty bouncer"); + } } public void showMessage(String message, int color) { - mKeyguardView.showMessage(message, color); + if (mKeyguardView != null) { + mKeyguardView.showMessage(message, color); + } else { + Log.w(TAG, "Trying to show message on empty bouncer"); + } } private void cancelShowRunnable() { @@ -290,7 +309,8 @@ public class KeyguardBouncer { */ public void setExpansion(float fraction) { if (mKeyguardView != null) { - mKeyguardView.setAlpha(MathUtils.map(ALPHA_EXPANSION_THRESHOLD, 1, 1, 0, fraction)); + float alpha = MathUtils.map(ALPHA_EXPANSION_THRESHOLD, 1, 1, 0, fraction); + mKeyguardView.setAlpha(MathUtils.constrain(alpha, 0f, 1f)); mKeyguardView.setTranslationY(fraction * mKeyguardView.getHeight()); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 7f1e9d0e1972..04cb620be9d3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -947,6 +947,17 @@ public abstract class PanelView extends FrameLayout { return mClosing || mLaunchingNotification; } + /** + * Bouncer might need a scrim when you double tap on notifications or edit QS. + * On other cases, when you drag up the bouncer with the finger or just fling, + * the scrim should be hidden to avoid occluding the clock. + * + * @return true when we need a scrim to show content on top of the notification panel. + */ + public boolean needsScrimming() { + return !isTracking() && !isCollapsing() && !isFullyCollapsed(); + } + public boolean isTracking() { return mTracking; } 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 f8b4e0768ceb..a09b84f1dc7b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -449,7 +449,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, if (mNeedsDrawableColorUpdate) { mNeedsDrawableColorUpdate = false; final GradientColors currentScrimColors; - if (mState == ScrimState.KEYGUARD || mState == ScrimState.BOUNCER_OCCLUDED + if (mState == ScrimState.KEYGUARD || mState == ScrimState.BOUNCER_SCRIMMED || mState == ScrimState.BOUNCER) { // Always animate color changes if we're seeing the keyguard mScrimInFront.setColors(mLockColors, true /* animated */); 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 58100efbcf81..a14d056a477e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java @@ -79,7 +79,7 @@ public enum ScrimState { /** * Showing password challenge on top of a FLAG_SHOW_WHEN_LOCKED activity. */ - BOUNCER_OCCLUDED(2) { + BOUNCER_SCRIMMED(2) { @Override public void prepare(ScrimState previousState) { mCurrentBehindAlpha = 0; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 2e45b120a75f..120122f212a5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -3907,12 +3907,12 @@ public class StatusBar extends SystemUI implements DemoMode, private void showBouncerIfKeyguard() { if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { - showBouncer(); + showBouncer(true /* animated */); } } - protected void showBouncer() { - mStatusBarKeyguardViewManager.dismiss(); + protected void showBouncer(boolean animated) { + mStatusBarKeyguardViewManager.showBouncer(animated); } private void instantExpandNotificationsPanel() { @@ -4026,7 +4026,7 @@ public class StatusBar extends SystemUI implements DemoMode, public void onTrackingStopped(boolean expand) { if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { if (!expand && !mUnlockMethodCache.canSkipBouncer()) { - showBouncerIfKeyguard(); + showBouncer(false /* animated */); } } } @@ -4165,7 +4165,7 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) { mLeaveOpenOnKeyguardHide = true; - showBouncer(); + showBouncer(true /* animated */); mPendingRemoteInputView = clicked; } @@ -4631,9 +4631,10 @@ public class StatusBar extends SystemUI implements DemoMode, != FingerprintUnlockController.MODE_UNLOCK); if (mBouncerShowing) { - final boolean qsExpanded = mQSPanel != null && mQSPanel.isExpanded(); - mScrimController.transitionTo(mIsOccluded || qsExpanded ? - ScrimState.BOUNCER_OCCLUDED : ScrimState.BOUNCER); + // Bouncer needs the front scrim when it's on top of an activity, + // tapping on a notification or editing QS. + mScrimController.transitionTo(mIsOccluded || mNotificationPanel.needsScrimming() ? + ScrimState.BOUNCER_SCRIMMED : ScrimState.BOUNCER); } else if (mLaunchCameraOnScreenTurningOn || isInLaunchTransition()) { mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback); } else if (mBrightnessMirrorVisible) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 8d536d8ca45a..b26b7c950695 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -198,9 +198,9 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb cancelPendingWakeupAction(); } - private void showBouncer() { + public void showBouncer(boolean animated) { if (mShowing) { - mBouncer.show(false /* resetSecuritySelection */); + mBouncer.show(false /* resetSecuritySelection */, animated); } updateStates(); } @@ -485,10 +485,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mStatusBar.executeRunnableDismissingKeyguard(null, null, true, false, true); } - public void dismiss() { - showBouncer(); - } - /** * WARNING: This method might cause Binder calls. */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java index 40512205a8f8..f3a8417ff547 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java @@ -16,39 +16,268 @@ package com.android.systemui.statusbar.phone; -import static org.mockito.Mockito.mock; +import static com.google.common.truth.Truth.assertThat; -import android.content.Context; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyFloat; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.calls; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + +import android.graphics.Color; import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; import android.test.UiThreadTest; -import android.view.ContextThemeWrapper; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; import android.view.ViewGroup; +import android.view.ViewTreeObserver; import android.widget.FrameLayout; import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardHostView; +import com.android.keyguard.KeyguardSecurityModel; import com.android.keyguard.ViewMediatorCallback; -import com.android.systemui.R; +import com.android.systemui.DejankUtils; import com.android.systemui.SysuiTestCase; +import com.android.systemui.classifier.FalsingManager; import com.android.systemui.keyguard.DismissCallbackRegistry; +import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; @SmallTest -@RunWith(AndroidJUnit4.class) +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) public class KeyguardBouncerTest extends SysuiTestCase { - @UiThreadTest - @Test - public void inflateDetached() { + @Mock + private FalsingManager mFalsingManager; + @Mock + private ViewMediatorCallback mViewMediatorCallback; + @Mock + private LockPatternUtils mLockPatternUtils; + @Mock + private DismissCallbackRegistry mDismissCallbackRegistry; + @Mock + private KeyguardHostView mKeyguardHostView; + @Mock + private ViewTreeObserver mViewTreeObserver; + + private KeyguardBouncer mBouncer; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + DejankUtils.setImmediate(true); final ViewGroup container = new FrameLayout(getContext()); - final KeyguardBouncer bouncer = new KeyguardBouncer(getContext(), - mock(ViewMediatorCallback.class), mock(LockPatternUtils.class), container, mock( - DismissCallbackRegistry.class)); + when(mKeyguardHostView.getViewTreeObserver()).thenReturn(mViewTreeObserver); + when(mKeyguardHostView.getHeight()).thenReturn(500); + mBouncer = new KeyguardBouncer(getContext(), mViewMediatorCallback, + mLockPatternUtils, container, mDismissCallbackRegistry, mFalsingManager) { + @Override + protected void inflateView() { + super.inflateView(); + mKeyguardView = mKeyguardHostView; + } + }; + } + + @Test + public void testInflateView_doesntCrash() { + mBouncer.inflateView(); + } + + @Test + public void testShow_notifiesFalsingManager() { + mBouncer.show(true); + verify(mFalsingManager).onBouncerShown(); + + mBouncer.show(true, false); + verifyNoMoreInteractions(mFalsingManager); + } + + /** + * Regression test: Invisible bouncer when occluded. + */ + @Test + public void testShow_bouncerIsVisible() { + // Expand notification panel as if we were in the keyguard. + mBouncer.ensureView(); + mBouncer.setExpansion(1); + + reset(mKeyguardHostView); + when(mKeyguardHostView.getHeight()).thenReturn(500); + + mBouncer.show(true); + verify(mKeyguardHostView).setAlpha(eq(1f)); + verify(mKeyguardHostView).setTranslationY(eq(0f)); + } + + @Test + public void testShow_notifiesVisibility() { + mBouncer.show(true); + verify(mViewMediatorCallback).onBouncerVisiblityChanged(eq(true)); - // Detached bouncer should still be able to be inflated - bouncer.inflateView(); + // Not called again when visible + reset(mViewMediatorCallback); + mBouncer.show(true); + verifyNoMoreInteractions(mViewMediatorCallback); + } + + @Test + public void testShow_triesToDismissKeyguard() { + mBouncer.show(true); + verify(mKeyguardHostView).dismiss(anyInt()); + } + + @Test + public void testShow_resetsSecuritySelection() { + mBouncer.show(false); + verify(mKeyguardHostView, never()).showPrimarySecurityScreen(); + + mBouncer.hide(false); + mBouncer.show(true); + verify(mKeyguardHostView).showPrimarySecurityScreen(); + } + + @Test + public void testShow_animatesKeyguardView() { + mBouncer.show(true); + verify(mKeyguardHostView).startAppearAnimation(); + } + + @Test + public void testShow_showsErrorMessage() { + final String errorMessage = "an error message"; + when(mViewMediatorCallback.consumeCustomMessage()).thenReturn(errorMessage); + mBouncer.show(true); + verify(mKeyguardHostView).showErrorMessage(eq(errorMessage)); + } + + @Test + public void testOnFullyShown_notifiesFalsingManager() { + mBouncer.onFullyShown(); + verify(mFalsingManager).onBouncerShown(); + } + + @Test + public void testOnFullyHidden_notifiesFalsingManager() { + mBouncer.onFullyHidden(); + verify(mFalsingManager).onBouncerHidden(); } + @Test + public void testHide_notifiesFalsingManager() { + mBouncer.hide(false); + verify(mFalsingManager).onBouncerHidden(); + } + + @Test + public void testHide_notifiesVisibility() { + mBouncer.hide(false); + verify(mViewMediatorCallback).onBouncerVisiblityChanged(eq(false)); + } + + @Test + public void testHide_notifiesDismissCallbackIfVisible() { + mBouncer.hide(false); + verifyZeroInteractions(mDismissCallbackRegistry); + mBouncer.show(false); + mBouncer.hide(false); + verify(mDismissCallbackRegistry).notifyDismissCancelled(); + } + + @Test + public void testShowPromptReason_propagates() { + mBouncer.ensureView(); + mBouncer.showPromptReason(1); + verify(mKeyguardHostView).showPromptReason(eq(1)); + } + + @Test + public void testShowMessage_propagates() { + final String message = "a message"; + mBouncer.ensureView(); + mBouncer.showMessage(message, Color.GREEN); + verify(mKeyguardHostView).showMessage(eq(message), eq(Color.GREEN)); + } + + @Test + public void testShowOnDismissAction_showsBouncer() { + final KeyguardHostView.OnDismissAction dismissAction = () -> false; + final Runnable cancelAction = () -> {}; + mBouncer.showWithDismissAction(dismissAction, cancelAction); + verify(mKeyguardHostView).setOnDismissAction(dismissAction, cancelAction); + Assert.assertTrue("Should be showing", mBouncer.isShowing()); + } + + @Test + public void testStartPreHideAnimation_notifiesView() { + final boolean[] ran = {false}; + final Runnable r = () -> ran[0] = true; + mBouncer.startPreHideAnimation(r); + Assert.assertTrue("Callback should have been invoked", ran[0]); + + ran[0] = false; + mBouncer.ensureView(); + mBouncer.startPreHideAnimation(r); + verify(mKeyguardHostView).startDisappearAnimation(r); + Assert.assertFalse("Callback should have been deferred", ran[0]); + } + + @Test + public void testIsShowing() { + Assert.assertFalse("Show wasn't invoked yet", mBouncer.isShowing()); + mBouncer.show(true); + Assert.assertTrue("Should be showing", mBouncer.isShowing()); + } + + @Test + public void testSetExpansion() { + mBouncer.ensureView(); + mBouncer.setExpansion(0.5f); + verify(mKeyguardHostView).setAlpha(anyFloat()); + verify(mKeyguardHostView).setTranslationY(anyFloat()); + } + + @Test + public void testNeedsFullscreenBouncer_asksKeyguardView() { + mBouncer.ensureView(); + mBouncer.needsFullscreenBouncer(); + verify(mKeyguardHostView).getSecurityMode(); + verify(mKeyguardHostView, never()).getCurrentSecurityMode(); + } + + @Test + public void testIsFullscreenBouncer_asksKeyguardView() { + mBouncer.ensureView(); + mBouncer.isFullscreenBouncer(); + verify(mKeyguardHostView).getCurrentSecurityMode(); + verify(mKeyguardHostView, never()).getSecurityMode(); + } + + @Test + public void testIsSecure() { + Assert.assertTrue("Bouncer is secure before inflating views", mBouncer.isSecure()); + + mBouncer.ensureView(); + for (KeyguardSecurityModel.SecurityMode mode : KeyguardSecurityModel.SecurityMode.values()){ + reset(mKeyguardHostView); + when(mKeyguardHostView.getSecurityMode()).thenReturn(mode); + Assert.assertEquals("Security doesn't match for mode: " + mode, + mBouncer.isSecure(), mode != KeyguardSecurityModel.SecurityMode.None); + } + } } 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 6fbc0d710cc4..df29e1f9f846 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 @@ -181,7 +181,7 @@ public class ScrimControllerTest extends SysuiTestCase { @Test public void transitionToBouncer() { - mScrimController.transitionTo(ScrimState.BOUNCER_OCCLUDED); + mScrimController.transitionTo(ScrimState.BOUNCER_SCRIMMED); mScrimController.finishAnimationsImmediately(); // Front scrim should be transparent // Back scrim should be visible without tint |