1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.systemui.statusbar.phone;
18 
19 import static com.android.systemui.statusbar.phone.ScrimController.OPAQUE;
20 import static com.android.systemui.statusbar.phone.ScrimController.SEMI_TRANSPARENT;
21 import static com.android.systemui.statusbar.phone.ScrimController.TRANSPARENT;
22 import static com.android.systemui.statusbar.phone.ScrimState.BOUNCER;
23 import static com.android.systemui.statusbar.phone.ScrimState.SHADE_LOCKED;
24 
25 import static com.google.common.truth.Truth.assertThat;
26 
27 import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
28 
29 import static org.junit.Assert.assertEquals;
30 import static org.junit.Assert.assertFalse;
31 import static org.mockito.ArgumentMatchers.any;
32 import static org.mockito.ArgumentMatchers.anyFloat;
33 import static org.mockito.ArgumentMatchers.anyInt;
34 import static org.mockito.ArgumentMatchers.anyLong;
35 import static org.mockito.ArgumentMatchers.anyString;
36 import static org.mockito.ArgumentMatchers.eq;
37 import static org.mockito.Mockito.doAnswer;
38 import static org.mockito.Mockito.mock;
39 import static org.mockito.Mockito.never;
40 import static org.mockito.Mockito.reset;
41 import static org.mockito.Mockito.spy;
42 import static org.mockito.Mockito.verify;
43 import static org.mockito.Mockito.verifyZeroInteractions;
44 import static org.mockito.Mockito.when;
45 
46 import android.animation.Animator;
47 import android.app.AlarmManager;
48 import android.content.Context;
49 import android.content.res.ColorStateList;
50 import android.content.res.TypedArray;
51 import android.graphics.Color;
52 import android.testing.TestableLooper;
53 import android.testing.ViewUtils;
54 import android.util.MathUtils;
55 import android.view.View;
56 
57 import androidx.test.ext.junit.runners.AndroidJUnit4;
58 import androidx.test.filters.SmallTest;
59 
60 import com.android.internal.colorextraction.ColorExtractor.GradientColors;
61 import com.android.keyguard.BouncerPanelExpansionCalculator;
62 import com.android.keyguard.KeyguardUpdateMonitor;
63 import com.android.systemui.DejankUtils;
64 import com.android.systemui.SysuiTestCase;
65 import com.android.systemui.animation.ShadeInterpolation;
66 import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
67 import com.android.systemui.dock.DockManager;
68 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
69 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository;
70 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
71 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
72 import com.android.systemui.keyguard.shared.model.KeyguardState;
73 import com.android.systemui.keyguard.shared.model.TransitionState;
74 import com.android.systemui.keyguard.shared.model.TransitionStep;
75 import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToGoneTransitionViewModel;
76 import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
77 import com.android.systemui.kosmos.KosmosJavaAdapter;
78 import com.android.systemui.scrim.ScrimView;
79 import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
80 import com.android.systemui.shade.transition.LinearLargeScreenShadeInterpolator;
81 import com.android.systemui.statusbar.policy.FakeConfigurationController;
82 import com.android.systemui.statusbar.policy.KeyguardStateController;
83 import com.android.systemui.util.concurrency.FakeExecutor;
84 import com.android.systemui.util.kotlin.JavaAdapter;
85 import com.android.systemui.util.time.FakeSystemClock;
86 import com.android.systemui.util.wakelock.DelayedWakeLock;
87 import com.android.systemui.utils.os.FakeHandler;
88 import com.android.systemui.wallpapers.data.repository.FakeWallpaperRepository;
89 
90 import com.google.common.truth.Expect;
91 
92 import kotlinx.coroutines.test.TestScope;
93 
94 import org.junit.After;
95 import org.junit.Assert;
96 import org.junit.Before;
97 import org.junit.Rule;
98 import org.junit.Test;
99 import org.junit.runner.RunWith;
100 import org.mockito.Mock;
101 import org.mockito.MockitoAnnotations;
102 import org.mockito.stubbing.Answer;
103 
104 import java.util.Arrays;
105 import java.util.Collections;
106 import java.util.HashMap;
107 import java.util.HashSet;
108 import java.util.Map;
109 
110 @RunWith(AndroidJUnit4.class)
111 @TestableLooper.RunWithLooper(setAsMainLooper = true)
112 @SmallTest
113 public class ScrimControllerTest extends SysuiTestCase {
114 
115     @Rule public Expect mExpect = Expect.create();
116     private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
117 
118     private final FakeConfigurationController mConfigurationController =
119             new FakeConfigurationController();
120     private final LargeScreenShadeInterpolator
121             mLinearLargeScreenShadeInterpolator = new LinearLargeScreenShadeInterpolator();
122 
123     private final TestScope mTestScope = mKosmos.getTestScope();
124     private final JavaAdapter mJavaAdapter = new JavaAdapter(mTestScope.getBackgroundScope());
125 
126     private ScrimController mScrimController;
127     private ScrimView mScrimBehind;
128     private ScrimView mNotificationsScrim;
129     private ScrimView mScrimInFront;
130     private ScrimState mScrimState;
131     private float mScrimBehindAlpha;
132     private GradientColors mScrimInFrontColor;
133     private int mScrimVisibility;
134     private boolean mAlwaysOnEnabled;
135     private TestableLooper mLooper;
136     private Context mContext;
137     @Mock private AlarmManager mAlarmManager;
138     @Mock private DozeParameters mDozeParameters;
139     @Mock private LightBarController mLightBarController;
140     @Mock private DelayedWakeLock.Factory mDelayedWakeLockFactory;
141     @Mock private DelayedWakeLock mWakeLock;
142     @Mock private KeyguardStateController mKeyguardStateController;
143     @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
144     @Mock private DockManager mDockManager;
145     @Mock private ScreenOffAnimationController mScreenOffAnimationController;
146     @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
147     @Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
148     @Mock private AlternateBouncerToGoneTransitionViewModel
149             mAlternateBouncerToGoneTransitionViewModel;
150     private final KeyguardTransitionInteractor mKeyguardTransitionInteractor =
151             mKosmos.getKeyguardTransitionInteractor();
152     private final FakeKeyguardTransitionRepository mKeyguardTransitionRepository =
153             mKosmos.getKeyguardTransitionRepository();
154     @Mock private KeyguardInteractor mKeyguardInteractor;
155     private final FakeWallpaperRepository mWallpaperRepository = new FakeWallpaperRepository();
156     @Mock private TypedArray mMockTypedArray;
157 
158     // TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The
159     //   event-dispatch-on-registration pattern caused some of these unit tests to fail.)
160     @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
161 
162     private static class AnimatorListener implements Animator.AnimatorListener {
163         private int mNumStarts;
164         private int mNumEnds;
165         private int mNumCancels;
166 
167         @Override
onAnimationStart(Animator animation)168         public void onAnimationStart(Animator animation) {
169             mNumStarts++;
170         }
171 
172         @Override
onAnimationEnd(Animator animation)173         public void onAnimationEnd(Animator animation) {
174             mNumEnds++;
175         }
176 
177         @Override
onAnimationCancel(Animator animation)178         public void onAnimationCancel(Animator animation) {
179             mNumCancels++;
180         }
181 
182         @Override
onAnimationRepeat(Animator animation)183         public void onAnimationRepeat(Animator animation) {
184 
185         }
186 
getNumStarts()187         public int getNumStarts() {
188             return mNumStarts;
189         }
190 
getNumEnds()191         public int getNumEnds() {
192             return mNumEnds;
193         }
194 
getNumCancels()195         public int getNumCancels() {
196             return mNumCancels;
197         }
198 
reset()199         public void reset() {
200             mNumStarts = 0;
201             mNumEnds = 0;
202             mNumCancels = 0;
203         }
204     }
205 
206     private AnimatorListener mAnimatorListener = new AnimatorListener();
207 
208     private int mSurfaceColor = 0x112233;
209 
finishAnimationsImmediately()210     private void finishAnimationsImmediately() {
211         // Execute code that will trigger animations.
212         mScrimController.onPreDraw();
213         // Force finish all animations.
214         mLooper.processAllMessages();
215         endAnimation(mNotificationsScrim);
216         endAnimation(mScrimBehind);
217         endAnimation(mScrimInFront);
218 
219         assertEquals("Animators did not finish",
220                 mAnimatorListener.getNumStarts(), mAnimatorListener.getNumEnds());
221     }
222 
endAnimation(View scrimView)223     private void endAnimation(View scrimView) {
224         Animator animator = getAnimator(scrimView);
225         if (animator != null) {
226             animator.end();
227         }
228     }
229 
getAnimator(View scrimView)230     private Animator getAnimator(View scrimView) {
231         return (Animator) scrimView.getTag(ScrimController.TAG_KEY_ANIM);
232     }
233 
234     @Before
setup()235     public void setup() {
236         MockitoAnnotations.initMocks(this);
237         mContext = spy(getContext());
238         when(mContext.obtainStyledAttributes(
239                 new int[]{com.android.internal.R.attr.materialColorSurface}))
240                 .thenReturn(mMockTypedArray);
241 
242         when(mMockTypedArray.getColorStateList(anyInt()))
243                 .thenAnswer((invocation) -> ColorStateList.valueOf(mSurfaceColor));
244 
245         mScrimBehind = spy(new ScrimView(mContext));
246         mScrimInFront = new ScrimView(mContext);
247         mNotificationsScrim = new ScrimView(mContext);
248         mAlwaysOnEnabled = true;
249         mLooper = TestableLooper.get(this);
250         DejankUtils.setImmediate(true);
251 
252         // ScrimController uses mScrimBehind to delay some callbacks that we should run immediately.
253         doAnswer(invocation -> {
254             ((Runnable) invocation.getArgument(0)).run();
255             return null;
256         }).when(mScrimBehind).postOnAnimationDelayed(any(Runnable.class), anyLong());
257 
258         when(mDozeParameters.getAlwaysOn()).thenAnswer(invocation -> mAlwaysOnEnabled);
259         when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(true);
260 
261         doAnswer((Answer<Void>) invocation -> {
262             mScrimState = invocation.getArgument(0);
263             mScrimBehindAlpha = invocation.getArgument(1);
264             mScrimInFrontColor = invocation.getArgument(2);
265             return null;
266         }).when(mLightBarController).setScrimState(
267                 any(ScrimState.class), anyFloat(), any(GradientColors.class));
268 
269         when(mDelayedWakeLockFactory.create(any(String.class))).thenReturn(mWakeLock);
270         when(mDockManager.isDocked()).thenReturn(false);
271 
272         when(mPrimaryBouncerToGoneTransitionViewModel.getScrimAlpha())
273                 .thenReturn(emptyFlow());
274         when(mAlternateBouncerToGoneTransitionViewModel.getScrimAlpha())
275                 .thenReturn(emptyFlow());
276 
277         mScrimController = new ScrimController(
278                 mLightBarController,
279                 mDozeParameters,
280                 mAlarmManager,
281                 mKeyguardStateController,
282                 mDelayedWakeLockFactory,
283                 new FakeHandler(mLooper.getLooper()),
284                 mKeyguardUpdateMonitor,
285                 mDockManager,
286                 mConfigurationController,
287                 new FakeExecutor(new FakeSystemClock()),
288                 mJavaAdapter,
289                 mScreenOffAnimationController,
290                 mKeyguardUnlockAnimationController,
291                 mStatusBarKeyguardViewManager,
292                 mPrimaryBouncerToGoneTransitionViewModel,
293                 mAlternateBouncerToGoneTransitionViewModel,
294                 mKeyguardTransitionInteractor,
295                 mKeyguardInteractor,
296                 mWallpaperRepository,
297                 mKosmos.getTestDispatcher(),
298                 mLinearLargeScreenShadeInterpolator);
299         mScrimController.start();
300         mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
301         mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
302         mScrimController.setAnimatorListener(mAnimatorListener);
303 
304         // Attach behind scrim so flows that are collecting on it start running.
305         ViewUtils.attachView(mScrimBehind);
306 
307         mScrimController.setHasBackdrop(false);
308 
309         mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(false);
310         mTestScope.getTestScheduler().runCurrent();
311 
312         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
313         finishAnimationsImmediately();
314     }
315 
316     @After
tearDown()317     public void tearDown() {
318         // Detaching view stops flow collection and prevents memory leak.
319         ViewUtils.detachView(mScrimBehind);
320         finishAnimationsImmediately();
321         Arrays.stream(ScrimState.values()).forEach((scrim) -> {
322             scrim.setAodFrontScrimAlpha(0f);
323             scrim.setClipQsScrim(false);
324         });
325         DejankUtils.setImmediate(false);
326     }
327 
328     @Test
transitionToKeyguard()329     public void transitionToKeyguard() {
330         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
331         finishAnimationsImmediately();
332 
333         assertScrimAlpha(Map.of(
334                 mScrimInFront, TRANSPARENT,
335                 mScrimBehind, SEMI_TRANSPARENT));
336 
337         assertScrimTinted(Map.of(
338                 mScrimInFront, true,
339                 mScrimBehind, true
340         ));
341     }
342 
343     @Test
transitionToShadeLocked()344     public void transitionToShadeLocked() {
345         mScrimController.legacyTransitionTo(SHADE_LOCKED);
346         mScrimController.setQsPosition(1f, 0);
347         finishAnimationsImmediately();
348 
349         assertScrimAlpha(Map.of(
350                 mNotificationsScrim, OPAQUE,
351                 mScrimInFront, TRANSPARENT,
352                 mScrimBehind, OPAQUE));
353 
354         assertScrimTinted(Map.of(
355                 mScrimInFront, false,
356                 mScrimBehind, true
357         ));
358     }
359 
360     @Test
transitionToShadeLocked_clippingQs()361     public void transitionToShadeLocked_clippingQs() {
362         mScrimController.setClipsQsScrim(true);
363         mScrimController.legacyTransitionTo(SHADE_LOCKED);
364         mScrimController.setQsPosition(1f, 0);
365         finishAnimationsImmediately();
366 
367         assertScrimAlpha(Map.of(
368                 mNotificationsScrim, OPAQUE,
369                 mScrimInFront, TRANSPARENT,
370                 mScrimBehind, OPAQUE));
371 
372         assertScrimTinted(Map.of(
373                 mScrimInFront, false,
374                 mScrimBehind, true
375         ));
376     }
377 
378     @Test
transitionToOff()379     public void transitionToOff() {
380         mScrimController.legacyTransitionTo(ScrimState.OFF);
381         finishAnimationsImmediately();
382 
383         assertScrimAlpha(Map.of(
384                 mScrimInFront, OPAQUE,
385                 mScrimBehind, OPAQUE));
386 
387         assertScrimTinted(Map.of(
388                 mScrimInFront, true,
389                 mScrimBehind, true
390         ));
391 
392         assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
393     }
394 
395     @Test
transitionToAod_withRegularWallpaper()396     public void transitionToAod_withRegularWallpaper() {
397         mScrimController.legacyTransitionTo(ScrimState.AOD);
398         finishAnimationsImmediately();
399 
400         assertScrimAlpha(Map.of(
401                 mScrimInFront, TRANSPARENT,
402                 mScrimBehind, TRANSPARENT,
403                 mNotificationsScrim, TRANSPARENT));
404         assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
405 
406         assertScrimTinted(Map.of(
407                 mScrimInFront, true,
408                 mScrimBehind, true
409         ));
410     }
411 
412     @Test
transitionToAod_withAodWallpaper()413     public void transitionToAod_withAodWallpaper() {
414         mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(true);
415         mTestScope.getTestScheduler().runCurrent();
416 
417         mScrimController.legacyTransitionTo(ScrimState.AOD);
418         finishAnimationsImmediately();
419 
420         assertScrimAlpha(Map.of(
421                 mScrimInFront, TRANSPARENT,
422                 mScrimBehind, TRANSPARENT));
423         assertEquals(0f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
424 
425         // Pulsing notification should conserve AOD wallpaper.
426         mScrimController.legacyTransitionTo(ScrimState.PULSING);
427         finishAnimationsImmediately();
428 
429         assertScrimAlpha(Map.of(
430                 mScrimInFront, TRANSPARENT,
431                 mScrimBehind, TRANSPARENT));
432         assertEquals(0f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
433     }
434 
435     @Test
transitionToAod_withAodWallpaperAndLockScreenWallpaper()436     public void transitionToAod_withAodWallpaperAndLockScreenWallpaper() {
437         mScrimController.setHasBackdrop(true);
438         mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(true);
439         mTestScope.getTestScheduler().runCurrent();
440 
441         mScrimController.legacyTransitionTo(ScrimState.AOD);
442         finishAnimationsImmediately();
443 
444         assertScrimAlpha(Map.of(
445                 mScrimInFront, TRANSPARENT,
446                 mScrimBehind, TRANSPARENT));
447         assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
448 
449         assertScrimTinted(Map.of(
450                 mScrimInFront, true,
451                 mScrimBehind, true
452         ));
453     }
454 
455     @Test
setHasBackdrop_withAodWallpaperAndAlbumArt()456     public void setHasBackdrop_withAodWallpaperAndAlbumArt() {
457         mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(true);
458         mTestScope.getTestScheduler().runCurrent();
459 
460         mScrimController.legacyTransitionTo(ScrimState.AOD);
461         finishAnimationsImmediately();
462         mScrimController.setHasBackdrop(true);
463         finishAnimationsImmediately();
464 
465         assertScrimAlpha(Map.of(
466                 mScrimInFront, TRANSPARENT,
467                 mScrimBehind, TRANSPARENT));
468         assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
469 
470         assertScrimTinted(Map.of(
471                 mScrimInFront, true,
472                 mScrimBehind, true
473         ));
474     }
475 
476     @Test
transitionToAod_withFrontAlphaUpdates()477     public void transitionToAod_withFrontAlphaUpdates() {
478         // Assert that setting the AOD front scrim alpha doesn't take effect in a non-AOD state.
479         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
480         mScrimController.setAodFrontScrimAlpha(0.5f);
481         finishAnimationsImmediately();
482 
483         assertScrimAlpha(Map.of(
484                 mScrimInFront, TRANSPARENT,
485                 mScrimBehind, SEMI_TRANSPARENT));
486 
487         // ... but that it does take effect once we enter the AOD state.
488         mScrimController.legacyTransitionTo(ScrimState.AOD);
489         finishAnimationsImmediately();
490         assertScrimAlpha(Map.of(
491                 mScrimInFront, SEMI_TRANSPARENT,
492                 mScrimBehind, TRANSPARENT));
493         assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
494 
495         // ... and that if we set it while we're in AOD, it does take immediate effect.
496         mScrimController.setAodFrontScrimAlpha(1f);
497         assertScrimAlpha(Map.of(
498                 mScrimInFront, OPAQUE,
499                 mScrimBehind, TRANSPARENT));
500         assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
501 
502         // ... and make sure we recall the previous front scrim alpha even if we transition away
503         // for a bit.
504         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
505         mScrimController.legacyTransitionTo(ScrimState.AOD);
506         finishAnimationsImmediately();
507         assertScrimAlpha(Map.of(
508                 mScrimInFront, OPAQUE,
509                 mScrimBehind, TRANSPARENT));
510         assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
511 
512         // ... and alpha updates should be completely ignored if always_on is off.
513         // Passing it forward would mess up the wake-up transition.
514         mAlwaysOnEnabled = false;
515         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
516         mScrimController.legacyTransitionTo(ScrimState.AOD);
517         finishAnimationsImmediately();
518         mScrimController.setAodFrontScrimAlpha(0.3f);
519         assertEquals(ScrimState.AOD.getFrontAlpha(), mScrimInFront.getViewAlpha(), 0.001f);
520         Assert.assertNotEquals(0.3f, mScrimInFront.getViewAlpha(), 0.001f);
521     }
522 
523     @Test
transitionToAod_afterDocked_ignoresAlwaysOnAndUpdatesFrontAlpha()524     public void transitionToAod_afterDocked_ignoresAlwaysOnAndUpdatesFrontAlpha() {
525         // Assert that setting the AOD front scrim alpha doesn't take effect in a non-AOD state.
526         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
527         mScrimController.setAodFrontScrimAlpha(0.5f);
528         finishAnimationsImmediately();
529 
530         assertScrimAlpha(Map.of(
531                 mScrimInFront, TRANSPARENT,
532                 mScrimBehind, SEMI_TRANSPARENT));
533 
534         // ... and doesn't take effect when disabled always_on
535         mAlwaysOnEnabled = false;
536         mScrimController.legacyTransitionTo(ScrimState.AOD);
537         finishAnimationsImmediately();
538         assertScrimAlpha(Map.of(
539                 mScrimInFront, OPAQUE,
540                 mScrimBehind, TRANSPARENT));
541         assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
542 
543         // ... but will take effect after docked
544         when(mDockManager.isDocked()).thenReturn(true);
545         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
546         mScrimController.setAodFrontScrimAlpha(0.5f);
547         mScrimController.legacyTransitionTo(ScrimState.AOD);
548         finishAnimationsImmediately();
549 
550         assertScrimAlpha(Map.of(
551                 mScrimInFront, SEMI_TRANSPARENT,
552                 mScrimBehind, TRANSPARENT));
553         assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
554 
555         // ... and that if we set it while we're in AOD, it does take immediate effect after docked.
556         mScrimController.setAodFrontScrimAlpha(1f);
557         finishAnimationsImmediately();
558         assertScrimAlpha(Map.of(
559                 mScrimInFront, OPAQUE,
560                 mScrimBehind, TRANSPARENT));
561         assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
562 
563         // Reset value since enums are static.
564         mScrimController.setAodFrontScrimAlpha(0f);
565     }
566 
567     @Test
transitionToPulsing_withFrontAlphaUpdates()568     public void transitionToPulsing_withFrontAlphaUpdates() {
569         // Pre-condition
570         // Need to go to AoD first because PULSING doesn't change
571         // the back scrim opacity - otherwise it would hide AoD wallpapers.
572         mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(false);
573         mTestScope.getTestScheduler().runCurrent();
574 
575         mScrimController.legacyTransitionTo(ScrimState.AOD);
576         finishAnimationsImmediately();
577         assertScrimAlpha(Map.of(
578                 mScrimInFront, TRANSPARENT,
579                 mScrimBehind, TRANSPARENT));
580         assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
581 
582         mScrimController.legacyTransitionTo(ScrimState.PULSING);
583         finishAnimationsImmediately();
584         // Front scrim should be transparent, but tinted
585         // Back scrim should be semi-transparent so the user can see the wallpaper
586         // Pulse callback should have been invoked
587         assertScrimAlpha(Map.of(
588                 mScrimInFront, TRANSPARENT,
589                 mScrimBehind, TRANSPARENT));
590         assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
591 
592         assertScrimTinted(Map.of(
593                 mScrimInFront, true,
594                 mScrimBehind, true
595         ));
596 
597         // ... and when ambient goes dark, front scrim should be semi-transparent
598         mScrimController.setAodFrontScrimAlpha(0.5f);
599         finishAnimationsImmediately();
600         // Front scrim should be semi-transparent
601         assertScrimAlpha(Map.of(
602                 mScrimInFront, SEMI_TRANSPARENT,
603                 mScrimBehind, TRANSPARENT));
604         assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
605 
606         mScrimController.setWakeLockScreenSensorActive(true);
607         finishAnimationsImmediately();
608         assertScrimAlpha(Map.of(
609                 mScrimInFront, SEMI_TRANSPARENT,
610                 mScrimBehind, TRANSPARENT));
611         assertEquals(ScrimController.WAKE_SENSOR_SCRIM_ALPHA,
612                 mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
613 
614         // Reset value since enums are static.
615         mScrimController.setAodFrontScrimAlpha(0f);
616     }
617 
618     @Test
transitionToKeyguardBouncer()619     public void transitionToKeyguardBouncer() {
620         mScrimController.legacyTransitionTo(BOUNCER);
621         finishAnimationsImmediately();
622         // Front scrim should be transparent
623         // Back scrim should be visible and tinted to the surface color
624         assertScrimAlpha(Map.of(
625                 mScrimInFront, TRANSPARENT,
626                 mNotificationsScrim, TRANSPARENT,
627                 mScrimBehind, OPAQUE));
628 
629         assertScrimTinted(Map.of(
630                 mScrimInFront, false,
631                 mScrimBehind, true,
632                 mNotificationsScrim, false
633         ));
634 
635         assertScrimTint(mScrimBehind, mSurfaceColor);
636     }
637 
638     @Test
lockscreenToHubTransition_setsBehindScrimAlpha()639     public void lockscreenToHubTransition_setsBehindScrimAlpha() {
640         // Start on lockscreen.
641         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
642         finishAnimationsImmediately();
643 
644         // Behind scrim starts at default alpha.
645         final float transitionProgress = 0f;
646         float expectedAlpha = ScrimState.KEYGUARD.getBehindAlpha();
647         mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
648                 new TransitionStep(
649                         KeyguardState.LOCKSCREEN,
650                         KeyguardState.GLANCEABLE_HUB,
651                         transitionProgress,
652                         TransitionState.STARTED
653                 ), true);
654         mTestScope.getTestScheduler().runCurrent();
655         assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
656 
657         // Scrim fades out as transition runs.
658         final float runningProgress = 0.2f;
659         expectedAlpha = (1 - runningProgress) * ScrimState.KEYGUARD.getBehindAlpha();
660         mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
661                 new TransitionStep(
662                         KeyguardState.LOCKSCREEN,
663                         KeyguardState.GLANCEABLE_HUB,
664                         runningProgress,
665                         TransitionState.RUNNING
666                 ), true);
667         mTestScope.getTestScheduler().runCurrent();
668         assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
669 
670         // Scrim invisible at end of transition.
671         final float finishedProgress = 1f;
672         expectedAlpha = 0f;
673         mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
674                 new TransitionStep(
675                         KeyguardState.LOCKSCREEN,
676                         KeyguardState.GLANCEABLE_HUB,
677                         finishedProgress,
678                         TransitionState.FINISHED
679                 ), true);
680         mTestScope.getTestScheduler().runCurrent();
681         assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
682     }
683 
684     @Test
hubToLockscreenTransition_setsViewAlpha()685     public void hubToLockscreenTransition_setsViewAlpha() {
686         // Start on glanceable hub.
687         mScrimController.legacyTransitionTo(ScrimState.GLANCEABLE_HUB);
688         finishAnimationsImmediately();
689 
690         // Behind scrim starts at 0 alpha.
691         final float transitionProgress = 0f;
692         float expectedAlpha = 0f;
693         mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
694                 new TransitionStep(
695                         KeyguardState.GLANCEABLE_HUB,
696                         KeyguardState.LOCKSCREEN,
697                         transitionProgress,
698                         TransitionState.STARTED
699                 ), true);
700         mTestScope.getTestScheduler().runCurrent();
701         assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
702 
703         // Scrim fades in as transition runs.
704         final float runningProgress = 0.2f;
705         expectedAlpha = runningProgress * ScrimState.KEYGUARD.getBehindAlpha();
706         mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
707                 new TransitionStep(
708                         KeyguardState.GLANCEABLE_HUB,
709                         KeyguardState.LOCKSCREEN,
710                         runningProgress,
711                         TransitionState.RUNNING
712                 ), true);
713         mTestScope.getTestScheduler().runCurrent();
714         assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
715 
716         // Scrim at default visibility at end of transition.
717         final float finishedProgress = 1f;
718         expectedAlpha = finishedProgress * ScrimState.KEYGUARD.getBehindAlpha();
719         mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
720                 new TransitionStep(
721                         KeyguardState.GLANCEABLE_HUB,
722                         KeyguardState.LOCKSCREEN,
723                         finishedProgress,
724                         TransitionState.FINISHED
725                 ), true);
726         mTestScope.getTestScheduler().runCurrent();
727         assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
728     }
729 
730     @Test
transitionToHub()731     public void transitionToHub() {
732         mScrimController.setRawPanelExpansionFraction(0f);
733         mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_HIDDEN);
734         mScrimController.legacyTransitionTo(ScrimState.GLANCEABLE_HUB);
735         finishAnimationsImmediately();
736 
737         // All scrims transparent on the hub.
738         assertScrimAlpha(Map.of(
739                 mScrimInFront, TRANSPARENT,
740                 mNotificationsScrim, TRANSPARENT,
741                 mScrimBehind, TRANSPARENT));
742     }
743 
744     @Test
openBouncerOnHub()745     public void openBouncerOnHub() {
746         mScrimController.legacyTransitionTo(ScrimState.GLANCEABLE_HUB);
747 
748         // Open the bouncer.
749         mScrimController.setRawPanelExpansionFraction(0f);
750         when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(true);
751         mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_VISIBLE);
752         finishAnimationsImmediately();
753 
754         // Only behind scrim is visible.
755         assertScrimAlpha(Map.of(
756                 mScrimInFront, TRANSPARENT,
757                 mNotificationsScrim, TRANSPARENT,
758                 mScrimBehind, OPAQUE));
759         assertScrimTint(mScrimBehind, mSurfaceColor);
760 
761         // Bouncer is closed.
762         mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_HIDDEN);
763         mScrimController.legacyTransitionTo(ScrimState.GLANCEABLE_HUB);
764         finishAnimationsImmediately();
765 
766         // All scrims are transparent.
767         assertScrimAlpha(Map.of(
768                 mScrimInFront, TRANSPARENT,
769                 mNotificationsScrim, TRANSPARENT,
770                 mScrimBehind, TRANSPARENT));
771     }
772 
773     @Test
openShadeOnHub()774     public void openShadeOnHub() {
775         mScrimController.legacyTransitionTo(ScrimState.GLANCEABLE_HUB);
776 
777         // Open the shade.
778         mScrimController.setQsPosition(1f, 0);
779         mScrimController.setRawPanelExpansionFraction(1);
780         mScrimController.setTransitionToFullShadeProgress(1, 0);
781         finishAnimationsImmediately();
782 
783         // Shade scrims are visible.
784         assertScrimAlpha(Map.of(
785                 mNotificationsScrim, OPAQUE,
786                 mScrimInFront, TRANSPARENT,
787                 mScrimBehind, OPAQUE));
788         assertScrimTint(mScrimBehind, Color.BLACK);
789         assertScrimTint(mNotificationsScrim, Color.TRANSPARENT);
790 
791         mScrimController.setTransitionToFullShadeProgress(0, 0);
792         finishAnimationsImmediately();
793 
794         // All scrims are transparent.
795         assertScrimAlpha(Map.of(
796                 mScrimInFront, TRANSPARENT,
797                 mNotificationsScrim, TRANSPARENT,
798                 mScrimBehind, TRANSPARENT));
799     }
800 
801     @Test
transitionToHubOverDream()802     public void transitionToHubOverDream() {
803         mScrimController.setRawPanelExpansionFraction(0f);
804         mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_HIDDEN);
805         mScrimController.legacyTransitionTo(ScrimState.GLANCEABLE_HUB_OVER_DREAM);
806         finishAnimationsImmediately();
807 
808         // All scrims transparent on the hub.
809         assertScrimAlpha(Map.of(
810                 mScrimInFront, TRANSPARENT,
811                 mNotificationsScrim, TRANSPARENT,
812                 mScrimBehind, TRANSPARENT));
813     }
814 
815     @Test
openBouncerOnHubOverDream()816     public void openBouncerOnHubOverDream() {
817         mScrimController.legacyTransitionTo(ScrimState.GLANCEABLE_HUB_OVER_DREAM);
818 
819         // Open the bouncer.
820         mScrimController.setRawPanelExpansionFraction(0f);
821         when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(true);
822         mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_VISIBLE);
823         finishAnimationsImmediately();
824 
825         // Only behind scrim is visible.
826         assertScrimAlpha(Map.of(
827                 mScrimInFront, TRANSPARENT,
828                 mNotificationsScrim, TRANSPARENT,
829                 mScrimBehind, OPAQUE));
830         assertScrimTint(mScrimBehind, mSurfaceColor);
831 
832         // Bouncer is closed.
833         mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_HIDDEN);
834         mScrimController.legacyTransitionTo(ScrimState.GLANCEABLE_HUB_OVER_DREAM);
835         finishAnimationsImmediately();
836 
837         // All scrims are transparent.
838         assertScrimAlpha(Map.of(
839                 mScrimInFront, TRANSPARENT,
840                 mNotificationsScrim, TRANSPARENT,
841                 mScrimBehind, TRANSPARENT));
842     }
843 
844     @Test
openShadeOnHubOverDream()845     public void openShadeOnHubOverDream() {
846         mScrimController.legacyTransitionTo(ScrimState.GLANCEABLE_HUB_OVER_DREAM);
847 
848         // Open the shade.
849         mScrimController.setQsPosition(1f, 0);
850         mScrimController.setRawPanelExpansionFraction(1f);
851         finishAnimationsImmediately();
852 
853         // Shade scrims are visible.
854         assertScrimAlpha(Map.of(
855                 mNotificationsScrim, OPAQUE,
856                 mScrimInFront, TRANSPARENT,
857                 mScrimBehind, OPAQUE));
858         assertScrimTint(mScrimBehind, Color.BLACK);
859         assertScrimTint(mNotificationsScrim, Color.TRANSPARENT);
860 
861         mScrimController.setQsPosition(0f, 0);
862         mScrimController.setRawPanelExpansionFraction(0f);
863         finishAnimationsImmediately();
864 
865         // All scrims are transparent.
866         assertScrimAlpha(Map.of(
867                 mScrimInFront, TRANSPARENT,
868                 mNotificationsScrim, TRANSPARENT,
869                 mScrimBehind, TRANSPARENT));
870     }
871 
872     @Test
onThemeChange_bouncerBehindTint_isUpdatedToSurfaceColor()873     public void onThemeChange_bouncerBehindTint_isUpdatedToSurfaceColor() {
874         assertEquals(BOUNCER.getBehindTint(), 0x112233);
875         mSurfaceColor = 0x223344;
876         mConfigurationController.notifyThemeChanged();
877         assertEquals(BOUNCER.getBehindTint(), 0x223344);
878     }
879 
880     @Test
onThemeChangeWhileClipQsScrim_bouncerBehindTint_remainsBlack()881     public void onThemeChangeWhileClipQsScrim_bouncerBehindTint_remainsBlack() {
882         mScrimController.setClipsQsScrim(true);
883         mScrimController.legacyTransitionTo(BOUNCER);
884         finishAnimationsImmediately();
885 
886         assertEquals(BOUNCER.getBehindTint(), Color.BLACK);
887         mSurfaceColor = 0x223344;
888         mConfigurationController.notifyThemeChanged();
889         assertEquals(BOUNCER.getBehindTint(), Color.BLACK);
890     }
891 
892     @Test
transitionToKeyguardBouncer_clippingQs()893     public void transitionToKeyguardBouncer_clippingQs() {
894         mScrimController.setClipsQsScrim(true);
895         mScrimController.legacyTransitionTo(BOUNCER);
896         finishAnimationsImmediately();
897         // Front scrim should be transparent
898         // Back scrim should be clipping QS
899         // Notif scrim should be visible without tint
900         assertScrimAlpha(Map.of(
901                 mScrimInFront, TRANSPARENT,
902                 mNotificationsScrim, OPAQUE,
903                 mScrimBehind, OPAQUE));
904 
905         assertScrimTinted(Map.of(
906                 mScrimInFront, false,
907                 mScrimBehind, true,
908                 mNotificationsScrim, false
909         ));
910     }
911 
912     @Test
disableClipQsScrimWithoutStateTransition_updatesTintAndAlpha()913     public void disableClipQsScrimWithoutStateTransition_updatesTintAndAlpha() {
914         mScrimController.setClipsQsScrim(true);
915         mScrimController.legacyTransitionTo(BOUNCER);
916 
917         mScrimController.setClipsQsScrim(false);
918 
919         finishAnimationsImmediately();
920         // Front scrim should be transparent
921         // Back scrim should be visible and has a tint of surfaceColor
922         assertScrimAlpha(Map.of(
923                 mScrimInFront, TRANSPARENT,
924                 mNotificationsScrim, TRANSPARENT,
925                 mScrimBehind, OPAQUE));
926         assertScrimTinted(Map.of(
927                 mScrimInFront, false,
928                 mScrimBehind, true,
929                 mNotificationsScrim, false
930         ));
931         assertScrimTint(mScrimBehind, mSurfaceColor);
932     }
933 
934     @Test
enableClipQsScrimWithoutStateTransition_updatesTintAndAlpha()935     public void enableClipQsScrimWithoutStateTransition_updatesTintAndAlpha() {
936         mScrimController.setClipsQsScrim(false);
937         mScrimController.legacyTransitionTo(BOUNCER);
938 
939         mScrimController.setClipsQsScrim(true);
940 
941         finishAnimationsImmediately();
942         // Front scrim should be transparent
943         // Back scrim should be clipping QS
944         // Notif scrim should be visible without tint
945         assertScrimAlpha(Map.of(
946                 mScrimInFront, TRANSPARENT,
947                 mNotificationsScrim, OPAQUE,
948                 mScrimBehind, OPAQUE));
949         assertScrimTinted(Map.of(
950                 mScrimInFront, false,
951                 mScrimBehind, true,
952                 mNotificationsScrim, false
953         ));
954     }
955 
956     @Test
transitionToBouncer()957     public void transitionToBouncer() {
958         mScrimController.legacyTransitionTo(ScrimState.BOUNCER_SCRIMMED);
959         finishAnimationsImmediately();
960         assertScrimAlpha(Map.of(
961                 mScrimInFront, OPAQUE,
962                 mScrimBehind, TRANSPARENT));
963         assertScrimTinted(Map.of(
964                 mScrimInFront, false,
965                 mScrimBehind, false
966         ));
967     }
968 
969     @Test
transitionToUnlocked_clippedQs()970     public void transitionToUnlocked_clippedQs() {
971         mScrimController.setClipsQsScrim(true);
972         mScrimController.setRawPanelExpansionFraction(0f);
973         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
974         finishAnimationsImmediately();
975 
976         assertScrimTinted(Map.of(
977                 mNotificationsScrim, false,
978                 mScrimInFront, false,
979                 mScrimBehind, true
980         ));
981         assertScrimAlpha(Map.of(
982                 mScrimInFront, TRANSPARENT,
983                 mNotificationsScrim, TRANSPARENT,
984                 mScrimBehind, OPAQUE));
985 
986         mScrimController.setRawPanelExpansionFraction(0.25f);
987         assertScrimAlpha(Map.of(
988                 mScrimInFront, TRANSPARENT,
989                 mNotificationsScrim, SEMI_TRANSPARENT,
990                 mScrimBehind, OPAQUE));
991 
992         mScrimController.setRawPanelExpansionFraction(0.5f);
993         assertScrimAlpha(Map.of(
994                 mScrimInFront, TRANSPARENT,
995                 mNotificationsScrim, OPAQUE,
996                 mScrimBehind, OPAQUE));
997     }
998 
999     @Test
transitionToUnlocked_nonClippedQs_followsLargeScreensInterpolator()1000     public void transitionToUnlocked_nonClippedQs_followsLargeScreensInterpolator() {
1001         mScrimController.setClipsQsScrim(false);
1002         mScrimController.setRawPanelExpansionFraction(0f);
1003         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
1004         finishAnimationsImmediately();
1005 
1006         assertScrimTinted(Map.of(
1007                 mNotificationsScrim, false,
1008                 mScrimInFront, false,
1009                 mScrimBehind, true
1010         ));
1011         // The large screens interpolator used in this test is a linear one, just for tests.
1012         // Assertions below are based on this assumption, and that the code uses that interpolator
1013         // when on a large screen (QS not clipped).
1014         assertScrimAlpha(Map.of(
1015                 mScrimInFront, TRANSPARENT,
1016                 mNotificationsScrim, TRANSPARENT,
1017                 mScrimBehind, TRANSPARENT));
1018 
1019         mScrimController.setRawPanelExpansionFraction(0.5f);
1020         assertScrimAlpha(Map.of(
1021                 mScrimInFront, TRANSPARENT,
1022                 mNotificationsScrim, SEMI_TRANSPARENT,
1023                 mScrimBehind, SEMI_TRANSPARENT));
1024 
1025         mScrimController.setRawPanelExpansionFraction(0.99f);
1026         assertScrimAlpha(Map.of(
1027                 mScrimInFront, TRANSPARENT,
1028                 mNotificationsScrim, SEMI_TRANSPARENT,
1029                 mScrimBehind, SEMI_TRANSPARENT));
1030 
1031         mScrimController.setRawPanelExpansionFraction(1f);
1032         assertScrimAlpha(Map.of(
1033                 mScrimInFront, TRANSPARENT,
1034                 mNotificationsScrim, OPAQUE,
1035                 mScrimBehind, OPAQUE));
1036     }
1037 
1038     @Test
scrimStateCallback()1039     public void scrimStateCallback() {
1040         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
1041         finishAnimationsImmediately();
1042         assertEquals(mScrimState, ScrimState.UNLOCKED);
1043 
1044         mScrimController.legacyTransitionTo(BOUNCER);
1045         finishAnimationsImmediately();
1046         assertEquals(mScrimState, BOUNCER);
1047 
1048         mScrimController.legacyTransitionTo(ScrimState.BOUNCER_SCRIMMED);
1049         finishAnimationsImmediately();
1050         assertEquals(mScrimState, ScrimState.BOUNCER_SCRIMMED);
1051     }
1052 
1053     @Test
panelExpansion()1054     public void panelExpansion() {
1055         mScrimController.setRawPanelExpansionFraction(0f);
1056         mScrimController.setRawPanelExpansionFraction(0.5f);
1057         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
1058         finishAnimationsImmediately();
1059 
1060         reset(mScrimBehind);
1061         mScrimController.setRawPanelExpansionFraction(0f);
1062         mScrimController.setRawPanelExpansionFraction(1.0f);
1063         finishAnimationsImmediately();
1064 
1065         assertEquals("Scrim alpha should change after setPanelExpansion",
1066                 mScrimBehindAlpha, mScrimBehind.getViewAlpha(), 0.01f);
1067 
1068         mScrimController.setRawPanelExpansionFraction(0f);
1069         finishAnimationsImmediately();
1070 
1071         assertEquals("Scrim alpha should change after setPanelExpansion",
1072                 mScrimBehindAlpha, mScrimBehind.getViewAlpha(), 0.01f);
1073     }
1074 
1075     @Test
qsExpansion()1076     public void qsExpansion() {
1077         reset(mScrimBehind);
1078         mScrimController.setQsPosition(1f, 999 /* value doesn't matter */);
1079         finishAnimationsImmediately();
1080 
1081         assertScrimAlpha(Map.of(
1082                 mScrimInFront, TRANSPARENT,
1083                 mScrimBehind, OPAQUE,
1084                 mNotificationsScrim, OPAQUE));
1085     }
1086 
1087     @Test
qsExpansion_clippingQs()1088     public void qsExpansion_clippingQs() {
1089         reset(mScrimBehind);
1090         mScrimController.setClipsQsScrim(true);
1091         mScrimController.setQsPosition(1f, 999 /* value doesn't matter */);
1092         finishAnimationsImmediately();
1093 
1094         assertScrimAlpha(Map.of(
1095                 mScrimInFront, TRANSPARENT,
1096                 mScrimBehind, OPAQUE,
1097                 mNotificationsScrim, OPAQUE));
1098     }
1099 
1100     @Test
qsExpansion_half_clippingQs()1101     public void qsExpansion_half_clippingQs() {
1102         reset(mScrimBehind);
1103         mScrimController.setClipsQsScrim(true);
1104         mScrimController.setQsPosition(0.25f, 999 /* value doesn't matter */);
1105         finishAnimationsImmediately();
1106 
1107         assertScrimAlpha(Map.of(
1108                 mScrimInFront, TRANSPARENT,
1109                 mScrimBehind, OPAQUE,
1110                 mNotificationsScrim, SEMI_TRANSPARENT));
1111     }
1112 
1113     @Test
panelExpansionAffectsAlpha()1114     public void panelExpansionAffectsAlpha() {
1115         mScrimController.setRawPanelExpansionFraction(0f);
1116         mScrimController.setRawPanelExpansionFraction(0.5f);
1117         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
1118         finishAnimationsImmediately();
1119 
1120         final float scrimAlpha = mScrimBehind.getViewAlpha();
1121         reset(mScrimBehind);
1122         mScrimController.setExpansionAffectsAlpha(false);
1123         mScrimController.setRawPanelExpansionFraction(0.8f);
1124         verifyZeroInteractions(mScrimBehind);
1125         assertEquals("Scrim opacity shouldn't change when setExpansionAffectsAlpha "
1126                 + "is false", scrimAlpha, mScrimBehind.getViewAlpha(), 0.01f);
1127 
1128         mScrimController.setExpansionAffectsAlpha(true);
1129         mScrimController.setRawPanelExpansionFraction(0.1f);
1130         finishAnimationsImmediately();
1131         Assert.assertNotEquals("Scrim opacity should change when setExpansionAffectsAlpha "
1132                 + "is true", scrimAlpha, mScrimBehind.getViewAlpha(), 0.01f);
1133     }
1134 
1135     @Test
transitionToUnlockedFromOff()1136     public void transitionToUnlockedFromOff() {
1137         // Simulate unlock with fingerprint without AOD
1138         mScrimController.legacyTransitionTo(ScrimState.OFF);
1139         mScrimController.setRawPanelExpansionFraction(0f);
1140         finishAnimationsImmediately();
1141         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
1142 
1143         finishAnimationsImmediately();
1144 
1145         // All scrims should be transparent at the end of fade transition.
1146         assertScrimAlpha(Map.of(
1147                 mScrimInFront, TRANSPARENT,
1148                 mScrimBehind, TRANSPARENT));
1149 
1150         // Make sure at the very end of the animation, we're reset to transparent
1151         assertScrimTinted(Map.of(
1152                 mScrimInFront, false,
1153                 mScrimBehind, true
1154         ));
1155     }
1156 
1157     @Test
transitionToUnlockedFromAod()1158     public void transitionToUnlockedFromAod() {
1159         // Simulate unlock with fingerprint
1160         mScrimController.legacyTransitionTo(ScrimState.AOD);
1161         mScrimController.setRawPanelExpansionFraction(0f);
1162         finishAnimationsImmediately();
1163         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
1164 
1165         finishAnimationsImmediately();
1166 
1167         // All scrims should be transparent at the end of fade transition.
1168         assertScrimAlpha(Map.of(
1169                 mScrimInFront, TRANSPARENT,
1170                 mScrimBehind, TRANSPARENT));
1171 
1172         // Make sure at the very end of the animation, we're reset to transparent
1173         assertScrimTinted(Map.of(
1174                 mScrimInFront, false,
1175                 mScrimBehind, true
1176         ));
1177     }
1178 
1179     @Test
scrimBlanksBeforeLeavingAod()1180     public void scrimBlanksBeforeLeavingAod() {
1181         // Simulate unlock with fingerprint
1182         mScrimController.legacyTransitionTo(ScrimState.AOD);
1183         finishAnimationsImmediately();
1184         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED,
1185                 new ScrimController.Callback() {
1186                     @Override
1187                     public void onDisplayBlanked() {
1188                         // Front scrim should be black in the middle of the transition
1189                         Assert.assertTrue("Scrim should be visible during transition. Alpha: "
1190                                 + mScrimInFront.getViewAlpha(), mScrimInFront.getViewAlpha() > 0);
1191                         assertScrimTinted(Map.of(
1192                                 mScrimInFront, true,
1193                                 mScrimBehind, true
1194                         ));
1195                         Assert.assertSame("Scrim should be visible during transition.",
1196                                 mScrimVisibility, OPAQUE);
1197                     }
1198                 });
1199         finishAnimationsImmediately();
1200     }
1201 
1202     @Test
scrimBlankCallbackWhenUnlockingFromPulse()1203     public void scrimBlankCallbackWhenUnlockingFromPulse() {
1204         boolean[] blanked = {false};
1205         // Simulate unlock with fingerprint
1206         mScrimController.legacyTransitionTo(ScrimState.PULSING);
1207         finishAnimationsImmediately();
1208         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED,
1209                 new ScrimController.Callback() {
1210                     @Override
1211                     public void onDisplayBlanked() {
1212                         blanked[0] = true;
1213                     }
1214                 });
1215         finishAnimationsImmediately();
1216         Assert.assertTrue("Scrim should send display blanked callback when unlocking "
1217                 + "from pulse.", blanked[0]);
1218     }
1219 
1220     @Test
blankingNotRequired_leavingAoD()1221     public void blankingNotRequired_leavingAoD() {
1222         // GIVEN display does NOT need blanking
1223         when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(false);
1224 
1225         mScrimController = new ScrimController(
1226                 mLightBarController,
1227                 mDozeParameters,
1228                 mAlarmManager,
1229                 mKeyguardStateController,
1230                 mDelayedWakeLockFactory,
1231                 new FakeHandler(mLooper.getLooper()),
1232                 mKeyguardUpdateMonitor,
1233                 mDockManager,
1234                 mConfigurationController,
1235                 new FakeExecutor(new FakeSystemClock()),
1236                 mJavaAdapter,
1237                 mScreenOffAnimationController,
1238                 mKeyguardUnlockAnimationController,
1239                 mStatusBarKeyguardViewManager,
1240                 mPrimaryBouncerToGoneTransitionViewModel,
1241                 mAlternateBouncerToGoneTransitionViewModel,
1242                 mKeyguardTransitionInteractor,
1243                 mKeyguardInteractor,
1244                 mWallpaperRepository,
1245                 mKosmos.getTestDispatcher(),
1246                 mLinearLargeScreenShadeInterpolator);
1247         mScrimController.start();
1248         mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
1249         mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
1250         mScrimController.setAnimatorListener(mAnimatorListener);
1251         mScrimController.setHasBackdrop(false);
1252         mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(false);
1253         mTestScope.getTestScheduler().runCurrent();
1254         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
1255         finishAnimationsImmediately();
1256 
1257         // WHEN Simulate unlock with fingerprint
1258         mScrimController.legacyTransitionTo(ScrimState.AOD);
1259         finishAnimationsImmediately();
1260 
1261         // WHEN transitioning to UNLOCKED, onDisplayCallbackBlanked callback called to continue
1262         // the transition but the scrim was not actually blanked
1263         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED,
1264                 new ScrimController.Callback() {
1265                     @Override
1266                     public void onDisplayBlanked() {
1267                         // Front scrim should not be black nor opaque
1268                         Assert.assertTrue("Scrim should NOT be visible during transition."
1269                                 + " Alpha: " + mScrimInFront.getViewAlpha(),
1270                                 mScrimInFront.getViewAlpha() == 0f);
1271                         Assert.assertSame("Scrim should not be visible during transition.",
1272                                 mScrimVisibility, TRANSPARENT);
1273                     }
1274                 });
1275         finishAnimationsImmediately();
1276     }
1277 
1278     @Test
testScrimCallback()1279     public void testScrimCallback() {
1280         int[] callOrder = {0, 0, 0};
1281         int[] currentCall = {0};
1282         mScrimController.legacyTransitionTo(ScrimState.AOD, new ScrimController.Callback() {
1283             @Override
1284             public void onStart() {
1285                 callOrder[0] = ++currentCall[0];
1286             }
1287 
1288             @Override
1289             public void onDisplayBlanked() {
1290                 callOrder[1] = ++currentCall[0];
1291             }
1292 
1293             @Override
1294             public void onFinished() {
1295                 callOrder[2] = ++currentCall[0];
1296             }
1297         });
1298         finishAnimationsImmediately();
1299         assertEquals("onStart called in wrong order", 1, callOrder[0]);
1300         assertEquals("onDisplayBlanked called in wrong order", 2, callOrder[1]);
1301         assertEquals("onFinished called in wrong order", 3, callOrder[2]);
1302     }
1303 
1304     @Test
testScrimCallbacksWithoutAmbientDisplay()1305     public void testScrimCallbacksWithoutAmbientDisplay() {
1306         mAlwaysOnEnabled = false;
1307         testScrimCallback();
1308     }
1309 
1310     @Test
testScrimCallbackCancelled()1311     public void testScrimCallbackCancelled() {
1312         boolean[] cancelledCalled = {false};
1313         mScrimController.legacyTransitionTo(ScrimState.AOD, new ScrimController.Callback() {
1314             @Override
1315             public void onCancelled() {
1316                 cancelledCalled[0] = true;
1317             }
1318         });
1319         mScrimController.legacyTransitionTo(ScrimState.PULSING);
1320         Assert.assertTrue("onCancelled should have been called", cancelledCalled[0]);
1321     }
1322 
1323     @Test
testHoldsWakeLock_whenAOD()1324     public void testHoldsWakeLock_whenAOD() {
1325         mScrimController.legacyTransitionTo(ScrimState.AOD);
1326         verify(mWakeLock).acquire(anyString());
1327         verify(mWakeLock, never()).release(anyString());
1328         finishAnimationsImmediately();
1329         verify(mWakeLock).release(anyString());
1330     }
1331 
1332     @Test
testDoesNotHoldWakeLock_whenUnlocking()1333     public void testDoesNotHoldWakeLock_whenUnlocking() {
1334         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
1335         finishAnimationsImmediately();
1336         verifyZeroInteractions(mWakeLock);
1337     }
1338 
1339     @Test
testCallbackInvokedOnSameStateTransition()1340     public void testCallbackInvokedOnSameStateTransition() {
1341         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
1342         finishAnimationsImmediately();
1343         ScrimController.Callback callback = mock(ScrimController.Callback.class);
1344         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED, callback);
1345         verify(callback).onFinished();
1346     }
1347 
1348     @Test
testHoldsAodWallpaperAnimationLock()1349     public void testHoldsAodWallpaperAnimationLock() {
1350         // Pre-conditions
1351         mScrimController.legacyTransitionTo(ScrimState.AOD);
1352         finishAnimationsImmediately();
1353         reset(mWakeLock);
1354 
1355         mScrimController.onHideWallpaperTimeout();
1356         verify(mWakeLock).acquire(anyString());
1357         verify(mWakeLock, never()).release(anyString());
1358         finishAnimationsImmediately();
1359         verify(mWakeLock).release(anyString());
1360     }
1361 
1362     @Test
testHoldsPulsingWallpaperAnimationLock()1363     public void testHoldsPulsingWallpaperAnimationLock() {
1364         // Pre-conditions
1365         mScrimController.legacyTransitionTo(ScrimState.PULSING);
1366         finishAnimationsImmediately();
1367         reset(mWakeLock);
1368 
1369         mScrimController.onHideWallpaperTimeout();
1370         verify(mWakeLock).acquire(anyString());
1371         verify(mWakeLock, never()).release(anyString());
1372         finishAnimationsImmediately();
1373         verify(mWakeLock).release(anyString());
1374     }
1375 
1376     @Test
testWillHideAodWallpaper()1377     public void testWillHideAodWallpaper() {
1378         mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(true);
1379         mTestScope.getTestScheduler().runCurrent();
1380 
1381         mScrimController.legacyTransitionTo(ScrimState.AOD);
1382         verify(mAlarmManager).setExact(anyInt(), anyLong(), any(), any(), any());
1383         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
1384         verify(mAlarmManager).cancel(any(AlarmManager.OnAlarmListener.class));
1385     }
1386 
1387     @Test
testWillHideDockedWallpaper()1388     public void testWillHideDockedWallpaper() {
1389         mAlwaysOnEnabled = false;
1390         when(mDockManager.isDocked()).thenReturn(true);
1391         mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(true);
1392         mTestScope.getTestScheduler().runCurrent();
1393 
1394         mScrimController.legacyTransitionTo(ScrimState.AOD);
1395 
1396         verify(mAlarmManager).setExact(anyInt(), anyLong(), any(), any(), any());
1397     }
1398 
1399     @Test
testConservesExpansionOpacityAfterTransition()1400     public void testConservesExpansionOpacityAfterTransition() {
1401         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
1402         mScrimController.setRawPanelExpansionFraction(0.5f);
1403         finishAnimationsImmediately();
1404 
1405         final float expandedAlpha = mScrimBehind.getViewAlpha();
1406 
1407         mScrimController.legacyTransitionTo(ScrimState.BRIGHTNESS_MIRROR);
1408         finishAnimationsImmediately();
1409         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
1410         finishAnimationsImmediately();
1411 
1412         assertEquals("Scrim expansion opacity wasn't conserved when transitioning back",
1413                 expandedAlpha, mScrimBehind.getViewAlpha(), 0.01f);
1414     }
1415 
1416     @Test
testCancelsOldAnimationBeforeBlanking()1417     public void testCancelsOldAnimationBeforeBlanking() {
1418         mScrimController.legacyTransitionTo(ScrimState.AOD);
1419         finishAnimationsImmediately();
1420         // Consume whatever value we had before
1421         mAnimatorListener.reset();
1422 
1423         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
1424         finishAnimationsImmediately();
1425         Assert.assertTrue("Animators not canceled", mAnimatorListener.getNumCancels() != 0);
1426     }
1427 
1428     @Test
testScrimsAreNotFocusable()1429     public void testScrimsAreNotFocusable() {
1430         assertFalse("Behind scrim should not be focusable", mScrimBehind.isFocusable());
1431         assertFalse("Front scrim should not be focusable", mScrimInFront.isFocusable());
1432         assertFalse("Notifications scrim should not be focusable",
1433                 mNotificationsScrim.isFocusable());
1434     }
1435 
1436     @Test
testHidesShowWhenLockedActivity()1437     public void testHidesShowWhenLockedActivity() {
1438         mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(true);
1439         mTestScope.getTestScheduler().runCurrent();
1440 
1441         mScrimController.setKeyguardOccluded(true);
1442         mScrimController.legacyTransitionTo(ScrimState.AOD);
1443         finishAnimationsImmediately();
1444         assertScrimAlpha(Map.of(
1445                 mScrimInFront, TRANSPARENT,
1446                 mScrimBehind, OPAQUE));
1447 
1448         mScrimController.legacyTransitionTo(ScrimState.PULSING);
1449         finishAnimationsImmediately();
1450         assertScrimAlpha(Map.of(
1451                 mScrimInFront, TRANSPARENT,
1452                 mScrimBehind, OPAQUE));
1453     }
1454 
1455     @Test
testHidesShowWhenLockedActivity_whenAlreadyInAod()1456     public void testHidesShowWhenLockedActivity_whenAlreadyInAod() {
1457         mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(true);
1458         mTestScope.getTestScheduler().runCurrent();
1459 
1460         mScrimController.legacyTransitionTo(ScrimState.AOD);
1461         finishAnimationsImmediately();
1462         assertScrimAlpha(Map.of(
1463                 mScrimInFront, TRANSPARENT,
1464                 mScrimBehind, TRANSPARENT));
1465 
1466         mScrimController.setKeyguardOccluded(true);
1467         finishAnimationsImmediately();
1468         assertScrimAlpha(Map.of(
1469                 mScrimInFront, TRANSPARENT,
1470                 mScrimBehind, OPAQUE));
1471     }
1472 
1473     @Test
testEatsTouchEvent()1474     public void testEatsTouchEvent() {
1475         HashSet<ScrimState> eatsTouches =
1476                 new HashSet<>(Collections.singletonList(ScrimState.AOD));
1477         for (ScrimState state : ScrimState.values()) {
1478             if (state == ScrimState.UNINITIALIZED) {
1479                 continue;
1480             }
1481             mScrimController.legacyTransitionTo(state);
1482             finishAnimationsImmediately();
1483             assertEquals("Should be clickable unless AOD or PULSING, was: " + state,
1484                     mScrimBehind.getViewAlpha() != 0 && !eatsTouches.contains(state),
1485                     mScrimBehind.isClickable());
1486         }
1487     }
1488 
1489     @Test
testAnimatesTransitionToAod()1490     public void testAnimatesTransitionToAod() {
1491         when(mDozeParameters.shouldControlScreenOff()).thenReturn(false);
1492         ScrimState.AOD.prepare(ScrimState.KEYGUARD);
1493         assertFalse("No animation when ColorFade kicks in",
1494                 ScrimState.AOD.getAnimateChange());
1495 
1496         reset(mDozeParameters);
1497         when(mDozeParameters.shouldControlScreenOff()).thenReturn(true);
1498         ScrimState.AOD.prepare(ScrimState.KEYGUARD);
1499         Assert.assertTrue("Animate scrims when ColorFade won't be triggered",
1500                 ScrimState.AOD.getAnimateChange());
1501     }
1502 
1503     @Test
testIsLowPowerMode()1504     public void testIsLowPowerMode() {
1505         HashSet<ScrimState> lowPowerModeStates = new HashSet<>(Arrays.asList(
1506                 ScrimState.OFF, ScrimState.AOD, ScrimState.PULSING));
1507         HashSet<ScrimState> regularStates = new HashSet<>(Arrays.asList(
1508                 ScrimState.UNINITIALIZED, ScrimState.KEYGUARD, BOUNCER,
1509                 ScrimState.DREAMING, ScrimState.BOUNCER_SCRIMMED, ScrimState.BRIGHTNESS_MIRROR,
1510                 ScrimState.UNLOCKED, SHADE_LOCKED, ScrimState.AUTH_SCRIMMED,
1511                 ScrimState.AUTH_SCRIMMED_SHADE, ScrimState.GLANCEABLE_HUB,
1512                 ScrimState.GLANCEABLE_HUB_OVER_DREAM));
1513 
1514         for (ScrimState state : ScrimState.values()) {
1515             if (!lowPowerModeStates.contains(state) && !regularStates.contains(state)) {
1516                 Assert.fail("Scrim state isn't categorized as a low power or regular state.");
1517             }
1518         }
1519     }
1520 
1521     @Test
testScrimsOpaque_whenShadeFullyExpanded()1522     public void testScrimsOpaque_whenShadeFullyExpanded() {
1523         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
1524         mScrimController.setRawPanelExpansionFraction(1);
1525         // notifications scrim alpha change require calling setQsPosition
1526         mScrimController.setQsPosition(0, 300);
1527         finishAnimationsImmediately();
1528 
1529         assertEquals("Behind scrim should be opaque",
1530                 mScrimBehind.getViewAlpha(), 1, 0.0);
1531         assertEquals("Notifications scrim should be opaque",
1532                 mNotificationsScrim.getViewAlpha(), 1, 0.0);
1533     }
1534 
1535     @Test
testAuthScrim_setClipQSScrimTrue_notifScrimOpaque_whenShadeFullyExpanded()1536     public void testAuthScrim_setClipQSScrimTrue_notifScrimOpaque_whenShadeFullyExpanded() {
1537         // GIVEN device has an activity showing ('UNLOCKED' state can occur on the lock screen
1538         // with the camera app occluding the keyguard)
1539         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
1540         mScrimController.setClipsQsScrim(true);
1541         mScrimController.setRawPanelExpansionFraction(1);
1542         // notifications scrim alpha change require calling setQsPosition
1543         mScrimController.setQsPosition(0, 300);
1544         finishAnimationsImmediately();
1545 
1546         // WHEN the user triggers the auth bouncer
1547         mScrimController.legacyTransitionTo(ScrimState.AUTH_SCRIMMED_SHADE);
1548         finishAnimationsImmediately();
1549 
1550         assertEquals("Behind scrim should be opaque",
1551                 mScrimBehind.getViewAlpha(), 1, 0.0);
1552         assertEquals("Notifications scrim should be opaque",
1553                 mNotificationsScrim.getViewAlpha(), 1, 0.0);
1554 
1555         assertScrimTinted(Map.of(
1556                 mScrimInFront, true,
1557                 mScrimBehind, true,
1558                 mNotificationsScrim, false
1559         ));
1560     }
1561 
1562 
1563     @Test
testAuthScrim_setClipQSScrimFalse_notifScrimOpaque_whenShadeFullyExpanded()1564     public void testAuthScrim_setClipQSScrimFalse_notifScrimOpaque_whenShadeFullyExpanded() {
1565         // GIVEN device has an activity showing ('UNLOCKED' state can occur on the lock screen
1566         // with the camera app occluding the keyguard)
1567         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
1568         mScrimController.setClipsQsScrim(false);
1569         mScrimController.setRawPanelExpansionFraction(1);
1570         // notifications scrim alpha change require calling setQsPosition
1571         mScrimController.setQsPosition(0, 300);
1572         finishAnimationsImmediately();
1573 
1574         // WHEN the user triggers the auth bouncer
1575         mScrimController.legacyTransitionTo(ScrimState.AUTH_SCRIMMED_SHADE);
1576         finishAnimationsImmediately();
1577 
1578         assertEquals("Behind scrim should be opaque",
1579                 mScrimBehind.getViewAlpha(), 1, 0.0);
1580         assertEquals("Notifications scrim should be opaque",
1581                 mNotificationsScrim.getViewAlpha(), 1, 0.0);
1582 
1583         assertScrimTinted(Map.of(
1584                 mScrimInFront, true,
1585                 mScrimBehind, true,
1586                 mNotificationsScrim, false
1587         ));
1588     }
1589 
1590     @Test
testAuthScrimKeyguard()1591     public void testAuthScrimKeyguard() {
1592         // GIVEN device is on the keyguard
1593         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
1594         finishAnimationsImmediately();
1595 
1596         // WHEN the user triggers the auth bouncer
1597         mScrimController.legacyTransitionTo(ScrimState.AUTH_SCRIMMED);
1598         finishAnimationsImmediately();
1599 
1600         // THEN the front scrim is updated and the KEYGUARD scrims are the same as the
1601         // KEYGUARD scrim state
1602         assertScrimAlpha(Map.of(
1603                 mScrimInFront, SEMI_TRANSPARENT,
1604                 mScrimBehind, SEMI_TRANSPARENT,
1605                 mNotificationsScrim, TRANSPARENT));
1606     }
1607 
1608     @Test
testScrimsVisible_whenShadeVisible()1609     public void testScrimsVisible_whenShadeVisible() {
1610         mScrimController.setClipsQsScrim(true);
1611         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
1612         mScrimController.setRawPanelExpansionFraction(0.3f);
1613         // notifications scrim alpha change require calling setQsPosition
1614         mScrimController.setQsPosition(0, 300);
1615         finishAnimationsImmediately();
1616 
1617         assertScrimAlpha(Map.of(
1618                 mScrimBehind, SEMI_TRANSPARENT,
1619                 mNotificationsScrim, SEMI_TRANSPARENT,
1620                 mScrimInFront, TRANSPARENT));
1621     }
1622 
1623     @Test
testDoesntAnimate_whenUnlocking()1624     public void testDoesntAnimate_whenUnlocking() {
1625         // LightRevealScrim will animate the transition, we should only hide the keyguard scrims.
1626         ScrimState.UNLOCKED.prepare(ScrimState.KEYGUARD);
1627         assertThat(ScrimState.UNLOCKED.getAnimateChange()).isTrue();
1628         ScrimState.UNLOCKED.prepare(ScrimState.PULSING);
1629         assertThat(ScrimState.UNLOCKED.getAnimateChange()).isFalse();
1630 
1631         ScrimState.UNLOCKED.prepare(ScrimState.KEYGUARD);
1632         assertThat(ScrimState.UNLOCKED.getAnimateChange()).isTrue();
1633         ScrimState.UNLOCKED.prepare(ScrimState.AOD);
1634         assertThat(ScrimState.UNLOCKED.getAnimateChange()).isFalse();
1635 
1636         // LightRevealScrim doesn't animate when AOD is disabled. We need to use the legacy anim.
1637         ScrimState.UNLOCKED.prepare(ScrimState.KEYGUARD);
1638         assertThat(ScrimState.UNLOCKED.getAnimateChange()).isTrue();
1639         ScrimState.UNLOCKED.prepare(ScrimState.OFF);
1640         assertThat(ScrimState.UNLOCKED.getAnimateChange()).isTrue();
1641     }
1642 
1643     @Test
testScrimsVisible_whenShadeVisible_clippingQs()1644     public void testScrimsVisible_whenShadeVisible_clippingQs() {
1645         mScrimController.setClipsQsScrim(true);
1646         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
1647         mScrimController.setRawPanelExpansionFraction(0.3f);
1648         // notifications scrim alpha change require calling setQsPosition
1649         mScrimController.setQsPosition(0.5f, 300);
1650         finishAnimationsImmediately();
1651 
1652         assertScrimAlpha(Map.of(
1653                 mScrimBehind, OPAQUE,
1654                 mNotificationsScrim, SEMI_TRANSPARENT,
1655                 mScrimInFront, TRANSPARENT));
1656     }
1657 
1658     @Test
testScrimsVisible_whenShadeVisibleOnLockscreen()1659     public void testScrimsVisible_whenShadeVisibleOnLockscreen() {
1660         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
1661         mScrimController.setQsPosition(0.25f, 300);
1662 
1663         assertScrimAlpha(Map.of(
1664                 mScrimBehind, SEMI_TRANSPARENT,
1665                 mNotificationsScrim, SEMI_TRANSPARENT,
1666                 mScrimInFront, TRANSPARENT));
1667     }
1668 
1669     @Test
testNotificationScrimTransparent_whenOnLockscreen()1670     public void testNotificationScrimTransparent_whenOnLockscreen() {
1671         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
1672         // even if shade is not pulled down, panel has expansion of 1 on the lockscreen
1673         mScrimController.setRawPanelExpansionFraction(1);
1674         mScrimController.setQsPosition(0f, /*qs panel bottom*/ 0);
1675 
1676         assertScrimAlpha(Map.of(
1677                 mScrimBehind, SEMI_TRANSPARENT,
1678                 mNotificationsScrim, TRANSPARENT));
1679     }
1680 
1681     @Test
testNotificationScrimVisible_afterOpeningShadeFromLockscreen()1682     public void testNotificationScrimVisible_afterOpeningShadeFromLockscreen() {
1683         mScrimController.setRawPanelExpansionFraction(1);
1684         mScrimController.legacyTransitionTo(SHADE_LOCKED);
1685         finishAnimationsImmediately();
1686 
1687         assertScrimAlpha(Map.of(
1688                 mScrimBehind, OPAQUE,
1689                 mNotificationsScrim, OPAQUE));
1690     }
1691 
1692     @Test
qsExpansion_BehindTint_shadeLocked_bouncerActive_usesBouncerProgress()1693     public void qsExpansion_BehindTint_shadeLocked_bouncerActive_usesBouncerProgress() {
1694         when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(true);
1695         // clipping doesn't change tested logic but allows to assert scrims more in line with
1696         // their expected large screen behaviour
1697         mScrimController.setClipsQsScrim(false);
1698         mScrimController.legacyTransitionTo(SHADE_LOCKED);
1699 
1700         mScrimController.setQsPosition(1f, 100 /* value doesn't matter */);
1701         assertTintAfterExpansion(mScrimBehind, SHADE_LOCKED.getBehindTint(), /* expansion= */ 1f);
1702 
1703         mScrimController.setQsPosition(0.8f, 100 /* value doesn't matter */);
1704         // panel expansion of 0.6 means its fully transitioned with bouncer progress interpolation
1705         assertTintAfterExpansion(mScrimBehind, BOUNCER.getBehindTint(), /* expansion= */ 0.6f);
1706     }
1707 
1708     @Test
expansionNotificationAlpha_shadeLocked_bouncerActive_usesBouncerInterpolator()1709     public void expansionNotificationAlpha_shadeLocked_bouncerActive_usesBouncerInterpolator() {
1710         when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(true);
1711 
1712         mScrimController.legacyTransitionTo(SHADE_LOCKED);
1713 
1714         float expansion = 0.8f;
1715         float expectedAlpha =
1716                 BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(expansion);
1717         assertAlphaAfterExpansion(mNotificationsScrim, expectedAlpha, expansion);
1718 
1719         expansion = 0.2f;
1720         expectedAlpha = BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(expansion);
1721         assertAlphaAfterExpansion(mNotificationsScrim, expectedAlpha, expansion);
1722     }
1723 
1724     @Test
expansionNotificationAlpha_shadeLocked_bouncerNotActive_usesShadeInterpolator()1725     public void expansionNotificationAlpha_shadeLocked_bouncerNotActive_usesShadeInterpolator() {
1726         when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false);
1727 
1728         mScrimController.legacyTransitionTo(SHADE_LOCKED);
1729 
1730         float expansion = 0.8f;
1731         float expectedAlpha = ShadeInterpolation.getNotificationScrimAlpha(expansion);
1732         assertAlphaAfterExpansion(mNotificationsScrim, expectedAlpha, expansion);
1733 
1734         expansion = 0.2f;
1735         expectedAlpha = ShadeInterpolation.getNotificationScrimAlpha(expansion);
1736         assertAlphaAfterExpansion(mNotificationsScrim, expectedAlpha, expansion);
1737     }
1738 
1739     @Test
notificationAlpha_unnocclusionAnimating_bouncerNotActive_usesKeyguardNotifAlpha()1740     public void notificationAlpha_unnocclusionAnimating_bouncerNotActive_usesKeyguardNotifAlpha() {
1741         when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false);
1742 
1743         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
1744 
1745         assertAlphaAfterExpansion(
1746                 mNotificationsScrim, ScrimState.KEYGUARD.getNotifAlpha(), /* expansion */ 0f);
1747         assertAlphaAfterExpansion(
1748                 mNotificationsScrim, ScrimState.KEYGUARD.getNotifAlpha(), /* expansion */ 0.4f);
1749         assertAlphaAfterExpansion(
1750                 mNotificationsScrim, ScrimState.KEYGUARD.getNotifAlpha(), /* expansion */ 1.0f);
1751 
1752         // Verify normal behavior after
1753         float expansion = 0.4f;
1754         float alpha = 1 - ShadeInterpolation.getNotificationScrimAlpha(expansion);
1755         assertAlphaAfterExpansion(mNotificationsScrim, alpha, expansion);
1756     }
1757 
1758     @Test
notificationAlpha_inKeyguardState_bouncerActive_usesInvertedBouncerInterpolator()1759     public void notificationAlpha_inKeyguardState_bouncerActive_usesInvertedBouncerInterpolator() {
1760         when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(true);
1761         mScrimController.setClipsQsScrim(true);
1762 
1763         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
1764 
1765         float expansion = 0.8f;
1766         float alpha = 1 - BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(expansion);
1767         assertAlphaAfterExpansion(mNotificationsScrim, alpha, expansion);
1768 
1769         expansion = 0.4f;
1770         alpha = 1 - BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(expansion);
1771         assertAlphaAfterExpansion(mNotificationsScrim, alpha, expansion);
1772 
1773         expansion = 0.2f;
1774         alpha = 1 - BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(expansion);
1775         assertAlphaAfterExpansion(mNotificationsScrim, alpha, expansion);
1776     }
1777 
1778     @Test
notificationAlpha_inKeyguardState_bouncerNotActive_usesInvertedShadeInterpolator()1779     public void notificationAlpha_inKeyguardState_bouncerNotActive_usesInvertedShadeInterpolator() {
1780         when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false);
1781         mScrimController.setClipsQsScrim(true);
1782 
1783         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
1784 
1785         float expansion = 0.8f;
1786         float alpha = 1 - ShadeInterpolation.getNotificationScrimAlpha(expansion);
1787         assertAlphaAfterExpansion(mNotificationsScrim, alpha, expansion);
1788 
1789         expansion = 0.4f;
1790         alpha = 1 - ShadeInterpolation.getNotificationScrimAlpha(expansion);
1791         assertAlphaAfterExpansion(mNotificationsScrim, alpha, expansion);
1792 
1793         expansion = 0.2f;
1794         alpha = 1 - ShadeInterpolation.getNotificationScrimAlpha(expansion);
1795         assertAlphaAfterExpansion(mNotificationsScrim, alpha, expansion);
1796     }
1797 
1798     @Test
behindTint_inKeyguardState_bouncerNotActive_usesKeyguardBehindTint()1799     public void behindTint_inKeyguardState_bouncerNotActive_usesKeyguardBehindTint() {
1800         when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false);
1801         mScrimController.setClipsQsScrim(false);
1802 
1803         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
1804         finishAnimationsImmediately();
1805         assertThat(mScrimBehind.getTint())
1806                 .isEqualTo(ScrimState.KEYGUARD.getBehindTint());
1807     }
1808 
1809     @Test
testNotificationTransparency_followsTransitionToFullShade()1810     public void testNotificationTransparency_followsTransitionToFullShade() {
1811         mScrimController.setClipsQsScrim(true);
1812 
1813         mScrimController.legacyTransitionTo(SHADE_LOCKED);
1814         mScrimController.setRawPanelExpansionFraction(1.0f);
1815         finishAnimationsImmediately();
1816 
1817         assertScrimTinted(Map.of(
1818                 mScrimInFront, false,
1819                 mScrimBehind, true,
1820                 mNotificationsScrim, false
1821         ));
1822 
1823         float shadeLockedAlpha = mNotificationsScrim.getViewAlpha();
1824         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
1825         mScrimController.setRawPanelExpansionFraction(1.0f);
1826         finishAnimationsImmediately();
1827         float keyguardAlpha = mNotificationsScrim.getViewAlpha();
1828 
1829         assertScrimTinted(Map.of(
1830                 mScrimInFront, true,
1831                 mScrimBehind, true,
1832                 mNotificationsScrim, true
1833         ));
1834 
1835         float progress = 0.5f;
1836         float lsNotifProgress = 0.3f;
1837         mScrimController.setTransitionToFullShadeProgress(progress, lsNotifProgress);
1838         assertEquals(MathUtils.lerp(keyguardAlpha, shadeLockedAlpha, progress),
1839                 mNotificationsScrim.getViewAlpha(), 0.2);
1840         progress = 0.0f;
1841         mScrimController.setTransitionToFullShadeProgress(progress, lsNotifProgress);
1842         assertEquals(MathUtils.lerp(keyguardAlpha, shadeLockedAlpha, progress),
1843                 mNotificationsScrim.getViewAlpha(), 0.2);
1844         progress = 1.0f;
1845         mScrimController.setTransitionToFullShadeProgress(progress, lsNotifProgress);
1846         assertEquals(MathUtils.lerp(keyguardAlpha, shadeLockedAlpha, progress),
1847                 mNotificationsScrim.getViewAlpha(), 0.2);
1848     }
1849 
1850     @Test
notificationTransparency_followsNotificationScrimProgress()1851     public void notificationTransparency_followsNotificationScrimProgress() {
1852         mScrimController.legacyTransitionTo(SHADE_LOCKED);
1853         mScrimController.setRawPanelExpansionFraction(1.0f);
1854         finishAnimationsImmediately();
1855         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
1856         mScrimController.setRawPanelExpansionFraction(1.0f);
1857         finishAnimationsImmediately();
1858 
1859         float progress = 0.5f;
1860         float notifProgress = 0.3f;
1861         mScrimController.setTransitionToFullShadeProgress(progress, notifProgress);
1862 
1863         assertThat(mNotificationsScrim.getViewAlpha()).isEqualTo(notifProgress);
1864     }
1865 
1866     @Test
notificationAlpha_qsNotClipped_alphaMatchesNotificationExpansionProgress()1867     public void notificationAlpha_qsNotClipped_alphaMatchesNotificationExpansionProgress() {
1868         mScrimController.setClipsQsScrim(false);
1869         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
1870         // RawPanelExpansion and QsExpansion are usually used for the notification alpha
1871         // calculation.
1872         // Here we set them to non-zero values explicitly to make sure that in not clipped mode,
1873         // they are not being used even when set.
1874         mScrimController.setRawPanelExpansionFraction(0.5f);
1875         mScrimController.setQsPosition(/* expansionFraction= */ 0.5f, /* qsPanelBottomY= */ 500);
1876         finishAnimationsImmediately();
1877 
1878         float progress = 0.5f;
1879 
1880         float notificationExpansionProgress = 0f;
1881         mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress);
1882         mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress);
1883 
1884         notificationExpansionProgress = 0.25f;
1885         mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress);
1886         mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress);
1887 
1888         notificationExpansionProgress = 0.5f;
1889         mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress);
1890         mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress);
1891 
1892         notificationExpansionProgress = 0.75f;
1893         mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress);
1894         mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress);
1895 
1896         notificationExpansionProgress = 1f;
1897         mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress);
1898         mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress);
1899     }
1900 
1901     @Test
setNotificationsOverScrollAmount_setsTranslationYOnNotificationsScrim()1902     public void setNotificationsOverScrollAmount_setsTranslationYOnNotificationsScrim() {
1903         int overScrollAmount = 10;
1904 
1905         mScrimController.setNotificationsOverScrollAmount(overScrollAmount);
1906 
1907         assertThat(mNotificationsScrim.getTranslationY()).isEqualTo(overScrollAmount);
1908     }
1909 
1910     @Test
setNotificationsOverScrollAmount_doesNotSetTranslationYOnBehindScrim()1911     public void setNotificationsOverScrollAmount_doesNotSetTranslationYOnBehindScrim() {
1912         int overScrollAmount = 10;
1913 
1914         mScrimController.setNotificationsOverScrollAmount(overScrollAmount);
1915 
1916         assertThat(mScrimBehind.getTranslationY()).isEqualTo(0);
1917     }
1918 
1919     @Test
setNotificationsOverScrollAmount_doesNotSetTranslationYOnFrontScrim()1920     public void setNotificationsOverScrollAmount_doesNotSetTranslationYOnFrontScrim() {
1921         int overScrollAmount = 10;
1922 
1923         mScrimController.setNotificationsOverScrollAmount(overScrollAmount);
1924 
1925         assertThat(mScrimInFront.getTranslationY()).isEqualTo(0);
1926     }
1927 
1928     @Test
notificationBoundsTopGetsPassedToKeyguard()1929     public void notificationBoundsTopGetsPassedToKeyguard() {
1930         mScrimController.legacyTransitionTo(SHADE_LOCKED);
1931         mScrimController.setQsPosition(1f, 0);
1932         finishAnimationsImmediately();
1933 
1934         mScrimController.setNotificationsBounds(0f, 100f, 0f, 0f);
1935         verify(mKeyguardInteractor).setTopClippingBounds(eq(100));
1936     }
1937 
1938     @Test
notificationBoundsTopDoesNotGetPassedToKeyguardWhenNotifScrimIsNotVisible()1939     public void notificationBoundsTopDoesNotGetPassedToKeyguardWhenNotifScrimIsNotVisible() {
1940         mScrimController.setKeyguardOccluded(true);
1941         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
1942         finishAnimationsImmediately();
1943 
1944         mScrimController.setNotificationsBounds(0f, 100f, 0f, 0f);
1945         verify(mKeyguardInteractor).setTopClippingBounds(eq(null));
1946     }
1947 
1948     @Test
transitionToDreaming()1949     public void transitionToDreaming() {
1950         mScrimController.setRawPanelExpansionFraction(0f);
1951         mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_HIDDEN);
1952         mScrimController.legacyTransitionTo(ScrimState.DREAMING);
1953         finishAnimationsImmediately();
1954 
1955         assertScrimAlpha(Map.of(
1956                 mScrimInFront, TRANSPARENT,
1957                 mNotificationsScrim, TRANSPARENT,
1958                 mScrimBehind, TRANSPARENT));
1959 
1960         assertScrimTinted(Map.of(
1961                 mScrimInFront, false,
1962                 mScrimBehind, true,
1963                 mNotificationsScrim, false
1964         ));
1965     }
1966 
1967     @Test
keyguardGoingAwayUpdateScrims()1968     public void keyguardGoingAwayUpdateScrims() {
1969         when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(true);
1970         mScrimController.updateScrims();
1971         finishAnimationsImmediately();
1972         assertThat(mNotificationsScrim.getViewAlpha()).isEqualTo(TRANSPARENT);
1973     }
1974 
1975 
1976     @Test
setUnOccludingAnimationKeyguard()1977     public void setUnOccludingAnimationKeyguard() {
1978         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
1979         finishAnimationsImmediately();
1980         assertThat(mNotificationsScrim.getViewAlpha())
1981                 .isWithin(0.01f).of(ScrimState.KEYGUARD.getNotifAlpha());
1982         assertThat(mNotificationsScrim.getTint())
1983                 .isEqualTo(ScrimState.KEYGUARD.getNotifTint());
1984         assertThat(mScrimBehind.getViewAlpha())
1985                 .isWithin(0.01f).of(ScrimState.KEYGUARD.getBehindAlpha());
1986         assertThat(mScrimBehind.getTint())
1987                 .isEqualTo(ScrimState.KEYGUARD.getBehindTint());
1988     }
1989 
1990     @Test
testHidesScrimFlickerInActivity()1991     public void testHidesScrimFlickerInActivity() {
1992         mScrimController.setKeyguardOccluded(true);
1993         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
1994         finishAnimationsImmediately();
1995         assertScrimAlpha(Map.of(
1996                 mScrimInFront, TRANSPARENT,
1997                 mScrimBehind, TRANSPARENT,
1998                 mNotificationsScrim, TRANSPARENT));
1999 
2000         mScrimController.legacyTransitionTo(SHADE_LOCKED);
2001         finishAnimationsImmediately();
2002         assertScrimAlpha(Map.of(
2003                 mScrimInFront, TRANSPARENT,
2004                 mScrimBehind, TRANSPARENT,
2005                 mNotificationsScrim, TRANSPARENT));
2006     }
2007 
2008     @Test
notificationAlpha_inKeyguardState_bouncerNotActive_clipsQsScrimFalse()2009     public void notificationAlpha_inKeyguardState_bouncerNotActive_clipsQsScrimFalse() {
2010         mScrimController.setClipsQsScrim(false);
2011         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
2012 
2013         float expansion = 0.8f;
2014         assertAlphaAfterExpansion(mNotificationsScrim, 0f, expansion);
2015     }
2016 
2017     @Test
aodStateSetsFrontScrimToNotBlend()2018     public void aodStateSetsFrontScrimToNotBlend() {
2019         mScrimController.legacyTransitionTo(ScrimState.AOD);
2020         assertFalse("Front scrim should not blend with main color",
2021                 mScrimInFront.shouldBlendWithMainColor());
2022     }
2023 
2024     @Test
applyState_unlocked_bouncerShowing()2025     public void applyState_unlocked_bouncerShowing() {
2026         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
2027         mScrimController.setBouncerHiddenFraction(0.99f);
2028         mScrimController.setRawPanelExpansionFraction(0f);
2029         finishAnimationsImmediately();
2030         assertScrimAlpha(mScrimBehind, 0);
2031     }
2032 
2033     @Test
ignoreTransitionRequestWhileKeyguardTransitionRunning()2034     public void ignoreTransitionRequestWhileKeyguardTransitionRunning() {
2035         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
2036         mScrimController.mBouncerToGoneTransition.accept(
2037                 new TransitionStep(KeyguardState.PRIMARY_BOUNCER, KeyguardState.GONE, 0f,
2038                         TransitionState.RUNNING, "ScrimControllerTest"));
2039 
2040         // This request should not happen
2041         mScrimController.legacyTransitionTo(ScrimState.BOUNCER);
2042         assertThat(mScrimController.getState()).isEqualTo(ScrimState.UNLOCKED);
2043     }
2044 
2045     @Test
primaryBouncerToGoneOnFinishCallsKeyguardFadedAway()2046     public void primaryBouncerToGoneOnFinishCallsKeyguardFadedAway() {
2047         when(mKeyguardStateController.isKeyguardFadingAway()).thenReturn(true);
2048         mScrimController.mBouncerToGoneTransition.accept(
2049                 new TransitionStep(KeyguardState.PRIMARY_BOUNCER, KeyguardState.GONE, 0f,
2050                         TransitionState.FINISHED, "ScrimControllerTest"));
2051 
2052         verify(mStatusBarKeyguardViewManager).onKeyguardFadedAway();
2053     }
2054 
2055     @Test
testDoNotAnimateChangeIfOccludeAnimationPlaying()2056     public void testDoNotAnimateChangeIfOccludeAnimationPlaying() {
2057         mScrimController.setOccludeAnimationPlaying(true);
2058         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
2059 
2060         assertFalse(ScrimState.UNLOCKED.mAnimateChange);
2061     }
2062 
2063     @Test
testNotifScrimAlpha_1f_afterUnlockFinishedAndExpanded()2064     public void testNotifScrimAlpha_1f_afterUnlockFinishedAndExpanded() {
2065         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
2066         when(mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()).thenReturn(true);
2067         mScrimController.legacyTransitionTo(ScrimState.UNLOCKED);
2068         mScrimController.onUnlockAnimationFinished();
2069         assertAlphaAfterExpansion(mNotificationsScrim, 1f, 1f);
2070     }
2071 
assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion)2072     private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
2073         mScrimController.setRawPanelExpansionFraction(expansion);
2074         finishAnimationsImmediately();
2075         // alpha is not changing linearly thus 0.2 of leeway when asserting
2076         assertEquals(expectedAlpha, scrim.getViewAlpha(), 0.2);
2077     }
2078 
assertTintAfterExpansion(ScrimView scrim, int expectedTint, float expansion)2079     private void assertTintAfterExpansion(ScrimView scrim, int expectedTint, float expansion) {
2080         String message = "Tint test failed with expected scrim tint: "
2081                 + Integer.toHexString(expectedTint) + " and actual tint: "
2082                 + Integer.toHexString(scrim.getTint()) + " for scrim: " + getScrimName(scrim);
2083         mScrimController.setRawPanelExpansionFraction(expansion);
2084         finishAnimationsImmediately();
2085         assertEquals(message, expectedTint, scrim.getTint(), 0.1);
2086     }
2087 
assertScrimTinted(Map<ScrimView, Boolean> scrimToTint)2088     private void assertScrimTinted(Map<ScrimView, Boolean> scrimToTint) {
2089         scrimToTint.forEach((scrim, hasTint) -> assertScrimTint(scrim, hasTint));
2090     }
2091 
assertScrimTint(ScrimView scrim, boolean hasTint)2092     private void assertScrimTint(ScrimView scrim, boolean hasTint) {
2093         String message = "Tint test failed at state " + mScrimController.getState()
2094                 + " with scrim: " + getScrimName(scrim) + " and tint: "
2095                 + Integer.toHexString(scrim.getTint());
2096         assertEquals(message, hasTint, scrim.getTint() != Color.TRANSPARENT);
2097     }
2098 
assertScrimTint(ScrimView scrim, int expectedTint)2099     private void assertScrimTint(ScrimView scrim, int expectedTint) {
2100         String message = "Tint test failed with expected scrim tint: "
2101                 + Integer.toHexString(expectedTint) + " and actual tint: "
2102                 + Integer.toHexString(scrim.getTint()) + " for scrim: " + getScrimName(scrim);
2103         assertEquals(message, expectedTint, scrim.getTint(), 0.1);
2104     }
2105 
getScrimName(ScrimView scrim)2106     private String getScrimName(ScrimView scrim) {
2107         if (scrim == mScrimInFront) {
2108             return "front";
2109         } else if (scrim == mScrimBehind) {
2110             return "behind";
2111         } else if (scrim == mNotificationsScrim) {
2112             return "notifications";
2113         }
2114         return "unknown_scrim";
2115     }
2116 
2117     /**
2118      * If {@link #mNotificationsScrim} is not passed in the map
2119      * we assume it must be transparent
2120      */
assertScrimAlpha(Map<ScrimView, Integer> scrimToAlpha)2121     private void assertScrimAlpha(Map<ScrimView, Integer> scrimToAlpha) {
2122         // Check single scrim visibility.
2123         if (!scrimToAlpha.containsKey(mNotificationsScrim)) {
2124             assertScrimAlpha(mNotificationsScrim, TRANSPARENT);
2125         }
2126         scrimToAlpha.forEach((scrimView, alpha) -> assertScrimAlpha(scrimView, alpha));
2127 
2128         // When clipping, QS scrim should not affect combined visibility.
2129         if (mScrimController.getClipQsScrim() && scrimToAlpha.get(mScrimBehind) == OPAQUE) {
2130             scrimToAlpha = new HashMap<>(scrimToAlpha);
2131             scrimToAlpha.remove(mScrimBehind);
2132         }
2133 
2134         // Check combined scrim visibility.
2135         final int visibility;
2136         if (scrimToAlpha.values().contains(OPAQUE)) {
2137             visibility = OPAQUE;
2138         } else if (scrimToAlpha.values().contains(SEMI_TRANSPARENT)) {
2139             visibility = SEMI_TRANSPARENT;
2140         } else {
2141             visibility = TRANSPARENT;
2142         }
2143         assertEquals("Invalid visibility.",
2144                 visibility /* expected */,
2145                 mScrimVisibility);
2146     }
2147 
assertScrimAlpha(ScrimView scrim, int expectedAlpha)2148     private void assertScrimAlpha(ScrimView scrim, int expectedAlpha) {
2149         assertEquals("Unexpected " + getScrimName(scrim) + " scrim alpha: "
2150                         + scrim.getViewAlpha(),
2151                 expectedAlpha != TRANSPARENT /* expected */,
2152                 scrim.getViewAlpha() > TRANSPARENT /* actual */);
2153     }
2154 }
2155