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