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