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.VISIBILITY_FULLY_OPAQUE; 20 import static com.android.systemui.statusbar.phone.ScrimController.VISIBILITY_FULLY_TRANSPARENT; 21 import static com.android.systemui.statusbar.phone.ScrimController.VISIBILITY_SEMI_TRANSPARENT; 22 23 import static org.mockito.ArgumentMatchers.any; 24 import static org.mockito.ArgumentMatchers.anyInt; 25 import static org.mockito.ArgumentMatchers.anyLong; 26 import static org.mockito.Mockito.mock; 27 import static org.mockito.Mockito.never; 28 import static org.mockito.Mockito.reset; 29 import static org.mockito.Mockito.spy; 30 import static org.mockito.Mockito.verify; 31 import static org.mockito.Mockito.verifyZeroInteractions; 32 import static org.mockito.Mockito.when; 33 34 import android.animation.Animator; 35 import android.animation.ValueAnimator; 36 import android.app.AlarmManager; 37 import android.graphics.Color; 38 import android.os.Handler; 39 import android.os.Looper; 40 import android.support.test.filters.SmallTest; 41 import android.testing.AndroidTestingRunner; 42 import android.testing.TestableLooper; 43 import android.view.View; 44 45 import com.android.internal.colorextraction.ColorExtractor.GradientColors; 46 import com.android.internal.util.function.TriConsumer; 47 import com.android.keyguard.KeyguardUpdateMonitor; 48 import com.android.systemui.SysuiTestCase; 49 import com.android.systemui.statusbar.ScrimView; 50 import com.android.systemui.util.wakelock.WakeLock; 51 import com.android.systemui.utils.os.FakeHandler; 52 53 import org.junit.Assert; 54 import org.junit.Before; 55 import org.junit.Test; 56 import org.junit.runner.RunWith; 57 58 import java.util.Arrays; 59 import java.util.HashSet; 60 import java.util.function.Consumer; 61 62 @RunWith(AndroidTestingRunner.class) 63 @TestableLooper.RunWithLooper 64 @SmallTest 65 public class ScrimControllerTest extends SysuiTestCase { 66 67 private SynchronousScrimController mScrimController; 68 private ScrimView mScrimBehind; 69 private ScrimView mScrimInFront; 70 private ScrimState mScrimState; 71 private float mScrimBehindAlpha; 72 private GradientColors mScrimInFrontColor; 73 private int mScrimVisibility; 74 private DozeParameters mDozeParamenters; 75 private WakeLock mWakeLock; 76 private boolean mAlwaysOnEnabled; 77 private AlarmManager mAlarmManager; 78 79 80 @Before 81 public void setup() { 82 mScrimBehind = spy(new ScrimView(getContext())); 83 mScrimInFront = new ScrimView(getContext()); 84 mWakeLock = mock(WakeLock.class); 85 mAlarmManager = mock(AlarmManager.class); 86 mAlwaysOnEnabled = true; 87 mDozeParamenters = mock(DozeParameters.class); 88 when(mDozeParamenters.getAlwaysOn()).thenAnswer(invocation -> mAlwaysOnEnabled); 89 when(mDozeParamenters.getDisplayNeedsBlanking()).thenReturn(true); 90 mScrimController = new SynchronousScrimController(mScrimBehind, mScrimInFront, 91 (scrimState, scrimBehindAlpha, scrimInFrontColor) -> { 92 mScrimState = scrimState; 93 mScrimBehindAlpha = scrimBehindAlpha; 94 mScrimInFrontColor = scrimInFrontColor; 95 }, 96 visible -> mScrimVisibility = visible, mDozeParamenters, mAlarmManager); 97 } 98 99 @Test 100 public void initialState() { 101 Assert.assertEquals("ScrimController should start initialized", 102 mScrimController.getState(), ScrimState.UNINITIALIZED); 103 } 104 105 @Test 106 public void transitionToKeyguard() { 107 mScrimController.transitionTo(ScrimState.KEYGUARD); 108 mScrimController.finishAnimationsImmediately(); 109 // Front scrim should be transparent 110 // Back scrim should be visible without tint 111 assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_SEMI_TRANSPARENT); 112 assertScrimTint(mScrimBehind, false /* tinted */); 113 } 114 115 @Test 116 public void transitionToAod_withRegularWallpaper() { 117 mScrimController.transitionTo(ScrimState.AOD); 118 mScrimController.finishAnimationsImmediately(); 119 // Front scrim should be transparent 120 // Back scrim should be visible with tint 121 assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE); 122 assertScrimTint(mScrimBehind, true /* tinted */); 123 assertScrimTint(mScrimInFront, true /* tinted */); 124 } 125 126 @Test 127 public void transitionToAod_withAodWallpaper() { 128 mScrimController.setWallpaperSupportsAmbientMode(true); 129 mScrimController.transitionTo(ScrimState.AOD); 130 mScrimController.finishAnimationsImmediately(); 131 // Front scrim should be transparent 132 // Back scrim should be transparent 133 assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_TRANSPARENT); 134 135 // Move on to PULSING and check if the back scrim is still transparent 136 mScrimController.transitionTo(ScrimState.PULSING); 137 mScrimController.finishAnimationsImmediately(); 138 assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_TRANSPARENT); 139 } 140 141 @Test 142 public void transitionToAod_withAodWallpaperAndLockScreenWallpaper() { 143 ScrimState.AOD.mKeyguardUpdateMonitor = new KeyguardUpdateMonitor(getContext()) { 144 @Override 145 public boolean hasLockscreenWallpaper() { 146 return true; 147 } 148 }; 149 mScrimController.setWallpaperSupportsAmbientMode(true); 150 mScrimController.transitionTo(ScrimState.AOD); 151 mScrimController.finishAnimationsImmediately(); 152 // Front scrim should be transparent 153 // Back scrim should be visible with tint 154 assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE); 155 assertScrimTint(mScrimBehind, true /* tinted */); 156 assertScrimTint(mScrimInFront, true /* tinted */); 157 } 158 159 @Test 160 public void transitionToAod_withFrontAlphaUpdates() { 161 // Assert that setting the AOD front scrim alpha doesn't take effect in a non-AOD state. 162 mScrimController.transitionTo(ScrimState.KEYGUARD); 163 mScrimController.setAodFrontScrimAlpha(0.5f); 164 mScrimController.finishAnimationsImmediately(); 165 // Front scrim should be transparent 166 // Back scrim should be visible without tint 167 assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_SEMI_TRANSPARENT); 168 169 // ... but that it does take effect once we enter the AOD state. 170 mScrimController.transitionTo(ScrimState.AOD); 171 mScrimController.finishAnimationsImmediately(); 172 // Front scrim should be semi-transparent 173 // Back scrim should be visible 174 assertScrimVisibility(VISIBILITY_SEMI_TRANSPARENT, VISIBILITY_FULLY_OPAQUE); 175 176 // ... and that if we set it while we're in AOD, it does take immediate effect. 177 mScrimController.setAodFrontScrimAlpha(1f); 178 assertScrimVisibility(VISIBILITY_FULLY_OPAQUE, VISIBILITY_FULLY_OPAQUE); 179 180 // ... and make sure we recall the previous front scrim alpha even if we transition away 181 // for a bit. 182 mScrimController.transitionTo(ScrimState.UNLOCKED); 183 mScrimController.transitionTo(ScrimState.AOD); 184 mScrimController.finishAnimationsImmediately(); 185 assertScrimVisibility(VISIBILITY_FULLY_OPAQUE, VISIBILITY_FULLY_OPAQUE); 186 187 // ... and alpha updates should be completely ignored if always_on is off. 188 // Passing it forward would mess up the wake-up transition. 189 mAlwaysOnEnabled = false; 190 mScrimController.transitionTo(ScrimState.UNLOCKED); 191 mScrimController.transitionTo(ScrimState.AOD); 192 mScrimController.finishAnimationsImmediately(); 193 mScrimController.setAodFrontScrimAlpha(0.3f); 194 Assert.assertEquals(ScrimState.AOD.getFrontAlpha(), mScrimInFront.getViewAlpha(), 0.001f); 195 Assert.assertNotEquals(0.3f, mScrimInFront.getViewAlpha(), 0.001f); 196 197 // Reset value since enums are static. 198 mScrimController.setAodFrontScrimAlpha(0f); 199 } 200 201 @Test 202 public void transitionToPulsing() { 203 // Pre-condition 204 // Need to go to AoD first because PULSING doesn't change 205 // the back scrim opacity - otherwise it would hide AoD wallpapers. 206 mScrimController.setWallpaperSupportsAmbientMode(false); 207 mScrimController.transitionTo(ScrimState.AOD); 208 mScrimController.finishAnimationsImmediately(); 209 assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE); 210 211 mScrimController.transitionTo(ScrimState.PULSING); 212 mScrimController.finishAnimationsImmediately(); 213 // Front scrim should be transparent 214 // Back scrim should be visible with tint 215 // Pulse callback should have been invoked 216 assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE); 217 assertScrimTint(mScrimBehind, true /* tinted */); 218 } 219 220 @Test 221 public void transitionToKeyguardBouncer() { 222 mScrimController.transitionTo(ScrimState.BOUNCER); 223 mScrimController.finishAnimationsImmediately(); 224 // Front scrim should be transparent 225 // Back scrim should be visible without tint 226 assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_SEMI_TRANSPARENT); 227 assertScrimTint(mScrimBehind, false /* tinted */); 228 } 229 230 @Test 231 public void transitionToBouncer() { 232 mScrimController.transitionTo(ScrimState.BOUNCER_SCRIMMED); 233 mScrimController.finishAnimationsImmediately(); 234 // Front scrim should be transparent 235 // Back scrim should be visible without tint 236 assertScrimVisibility(VISIBILITY_SEMI_TRANSPARENT, VISIBILITY_FULLY_TRANSPARENT); 237 assertScrimTint(mScrimBehind, false /* tinted */); 238 } 239 240 @Test 241 public void transitionToUnlocked() { 242 mScrimController.setPanelExpansion(0f); 243 mScrimController.transitionTo(ScrimState.UNLOCKED); 244 mScrimController.finishAnimationsImmediately(); 245 // Front scrim should be transparent 246 // Back scrim should be transparent 247 assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_TRANSPARENT); 248 assertScrimTint(mScrimBehind, false /* tinted */); 249 assertScrimTint(mScrimInFront, false /* tinted */); 250 251 // Back scrim should be visible after start dragging 252 mScrimController.setPanelExpansion(0.5f); 253 assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_SEMI_TRANSPARENT); 254 } 255 256 @Test 257 public void scrimStateCallback() { 258 mScrimController.transitionTo(ScrimState.UNLOCKED); 259 mScrimController.finishAnimationsImmediately(); 260 Assert.assertEquals(mScrimState, ScrimState.UNLOCKED); 261 262 mScrimController.transitionTo(ScrimState.BOUNCER); 263 mScrimController.finishAnimationsImmediately(); 264 Assert.assertEquals(mScrimState, ScrimState.BOUNCER); 265 266 mScrimController.transitionTo(ScrimState.BOUNCER_SCRIMMED); 267 mScrimController.finishAnimationsImmediately(); 268 Assert.assertEquals(mScrimState, ScrimState.BOUNCER_SCRIMMED); 269 } 270 271 @Test 272 public void panelExpansion() { 273 mScrimController.setPanelExpansion(0f); 274 mScrimController.setPanelExpansion(0.5f); 275 mScrimController.transitionTo(ScrimState.UNLOCKED); 276 mScrimController.finishAnimationsImmediately(); 277 278 reset(mScrimBehind); 279 mScrimController.setPanelExpansion(0f); 280 mScrimController.setPanelExpansion(1.0f); 281 mScrimController.onPreDraw(); 282 283 Assert.assertEquals("Scrim alpha should change after setPanelExpansion", 284 mScrimBehindAlpha, mScrimBehind.getViewAlpha(), 0.01f); 285 286 mScrimController.setPanelExpansion(0f); 287 mScrimController.onPreDraw(); 288 289 Assert.assertEquals("Scrim alpha should change after setPanelExpansion", 290 mScrimBehindAlpha, mScrimBehind.getViewAlpha(), 0.01f); 291 } 292 293 @Test 294 public void panelExpansionAffectsAlpha() { 295 mScrimController.setPanelExpansion(0f); 296 mScrimController.setPanelExpansion(0.5f); 297 mScrimController.transitionTo(ScrimState.UNLOCKED); 298 mScrimController.finishAnimationsImmediately(); 299 300 final float scrimAlpha = mScrimBehind.getViewAlpha(); 301 reset(mScrimBehind); 302 mScrimController.setExpansionAffectsAlpha(false); 303 mScrimController.setPanelExpansion(0.8f); 304 verifyZeroInteractions(mScrimBehind); 305 Assert.assertEquals("Scrim opacity shouldn't change when setExpansionAffectsAlpha " 306 + "is false", scrimAlpha, mScrimBehind.getViewAlpha(), 0.01f); 307 308 mScrimController.setExpansionAffectsAlpha(true); 309 mScrimController.setPanelExpansion(0.1f); 310 Assert.assertNotEquals("Scrim opacity should change when setExpansionAffectsAlpha " 311 + "is true", scrimAlpha, mScrimBehind.getViewAlpha(), 0.01f); 312 } 313 314 @Test 315 public void transitionToUnlockedFromAod() { 316 // Simulate unlock with fingerprint 317 mScrimController.transitionTo(ScrimState.AOD); 318 mScrimController.setPanelExpansion(0f); 319 mScrimController.finishAnimationsImmediately(); 320 mScrimController.transitionTo(ScrimState.UNLOCKED); 321 // Immediately tinted after the transition starts 322 assertScrimTint(mScrimInFront, true /* tinted */); 323 assertScrimTint(mScrimBehind, true /* tinted */); 324 mScrimController.finishAnimationsImmediately(); 325 // Front scrim should be transparent 326 // Back scrim should be transparent 327 // Neither scrims should be tinted anymore after the animation. 328 assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_TRANSPARENT); 329 assertScrimTint(mScrimInFront, false /* tinted */); 330 assertScrimTint(mScrimBehind, false /* tinted */); 331 } 332 333 @Test 334 public void scrimBlanksBeforeLeavingAod() { 335 // Simulate unlock with fingerprint 336 mScrimController.transitionTo(ScrimState.AOD); 337 mScrimController.finishAnimationsImmediately(); 338 mScrimController.transitionTo(ScrimState.UNLOCKED, 339 new ScrimController.Callback() { 340 @Override 341 public void onDisplayBlanked() { 342 // Front scrim should be black in the middle of the transition 343 Assert.assertTrue("Scrim should be visible during transition. Alpha: " 344 + mScrimInFront.getViewAlpha(), mScrimInFront.getViewAlpha() > 0); 345 assertScrimTint(mScrimInFront, true /* tinted */); 346 Assert.assertSame("Scrim should be visible during transition.", 347 mScrimVisibility, VISIBILITY_FULLY_OPAQUE); 348 } 349 }); 350 mScrimController.finishAnimationsImmediately(); 351 } 352 353 @Test 354 public void scrimBlanksWhenUnlockingFromPulse() { 355 boolean[] blanked = {false}; 356 // Simulate unlock with fingerprint 357 mScrimController.transitionTo(ScrimState.PULSING); 358 mScrimController.finishAnimationsImmediately(); 359 mScrimController.transitionTo(ScrimState.UNLOCKED, 360 new ScrimController.Callback() { 361 @Override 362 public void onDisplayBlanked() { 363 blanked[0] = true; 364 } 365 }); 366 mScrimController.finishAnimationsImmediately(); 367 Assert.assertTrue("Scrim should blank when unlocking from pulse.", blanked[0]); 368 } 369 370 @Test 371 public void testScrimCallback() { 372 int[] callOrder = {0, 0, 0}; 373 int[] currentCall = {0}; 374 mScrimController.transitionTo(ScrimState.AOD, new ScrimController.Callback() { 375 @Override 376 public void onStart() { 377 callOrder[0] = ++currentCall[0]; 378 } 379 380 @Override 381 public void onDisplayBlanked() { 382 callOrder[1] = ++currentCall[0]; 383 } 384 385 @Override 386 public void onFinished() { 387 callOrder[2] = ++currentCall[0]; 388 } 389 }); 390 mScrimController.finishAnimationsImmediately(); 391 Assert.assertEquals("onStart called in wrong order", 1, callOrder[0]); 392 Assert.assertEquals("onDisplayBlanked called in wrong order", 2, callOrder[1]); 393 Assert.assertEquals("onFinished called in wrong order", 3, callOrder[2]); 394 } 395 396 @Test 397 public void testScrimCallbacksWithoutAmbientDisplay() { 398 mAlwaysOnEnabled = false; 399 testScrimCallback(); 400 } 401 402 @Test 403 public void testScrimCallbackCancelled() { 404 boolean[] cancelledCalled = {false}; 405 mScrimController.transitionTo(ScrimState.AOD, new ScrimController.Callback() { 406 @Override 407 public void onCancelled() { 408 cancelledCalled[0] = true; 409 } 410 }); 411 mScrimController.transitionTo(ScrimState.PULSING); 412 Assert.assertTrue("onCancelled should have been called", cancelledCalled[0]); 413 } 414 415 @Test 416 public void testHoldsWakeLock_whenAOD() { 417 mScrimController.transitionTo(ScrimState.AOD); 418 verify(mWakeLock).acquire(); 419 verify(mWakeLock, never()).release(); 420 mScrimController.finishAnimationsImmediately(); 421 verify(mWakeLock).release(); 422 } 423 424 @Test 425 public void testDoesNotHoldWakeLock_whenUnlocking() { 426 mScrimController.transitionTo(ScrimState.UNLOCKED); 427 mScrimController.finishAnimationsImmediately(); 428 verifyZeroInteractions(mWakeLock); 429 } 430 431 @Test 432 public void testCallbackInvokedOnSameStateTransition() { 433 mScrimController.transitionTo(ScrimState.UNLOCKED); 434 mScrimController.finishAnimationsImmediately(); 435 ScrimController.Callback callback = mock(ScrimController.Callback.class); 436 mScrimController.transitionTo(ScrimState.UNLOCKED, callback); 437 verify(callback).onFinished(); 438 } 439 440 @Test 441 public void testHoldsAodWallpaperAnimationLock() { 442 // Pre-conditions 443 mScrimController.transitionTo(ScrimState.AOD); 444 mScrimController.finishAnimationsImmediately(); 445 reset(mWakeLock); 446 447 mScrimController.onHideWallpaperTimeout(); 448 verify(mWakeLock).acquire(); 449 verify(mWakeLock, never()).release(); 450 mScrimController.finishAnimationsImmediately(); 451 verify(mWakeLock).release(); 452 } 453 454 @Test 455 public void testWillHideAodWallpaper() { 456 mScrimController.setWallpaperSupportsAmbientMode(true); 457 mScrimController.transitionTo(ScrimState.AOD); 458 verify(mAlarmManager).setExact(anyInt(), anyLong(), any(), any(), any()); 459 mScrimController.transitionTo(ScrimState.KEYGUARD); 460 verify(mAlarmManager).cancel(any(AlarmManager.OnAlarmListener.class)); 461 } 462 463 @Test 464 public void testConservesExpansionOpacityAfterTransition() { 465 mScrimController.transitionTo(ScrimState.UNLOCKED); 466 mScrimController.setPanelExpansion(0.5f); 467 mScrimController.finishAnimationsImmediately(); 468 469 final float expandedAlpha = mScrimBehind.getViewAlpha(); 470 471 mScrimController.transitionTo(ScrimState.BRIGHTNESS_MIRROR); 472 mScrimController.finishAnimationsImmediately(); 473 mScrimController.transitionTo(ScrimState.UNLOCKED); 474 mScrimController.finishAnimationsImmediately(); 475 476 Assert.assertEquals("Scrim expansion opacity wasn't conserved when transitioning back", 477 expandedAlpha, mScrimBehind.getViewAlpha(), 0.01f); 478 } 479 480 @Test 481 public void cancelsOldAnimationBeforeBlanking() { 482 mScrimController.transitionTo(ScrimState.AOD); 483 mScrimController.finishAnimationsImmediately(); 484 // Consume whatever value we had before 485 mScrimController.wasAnimationJustCancelled(); 486 487 mScrimController.transitionTo(ScrimState.KEYGUARD); 488 mScrimController.finishAnimationsImmediately(); 489 Assert.assertTrue(mScrimController.wasAnimationJustCancelled()); 490 } 491 492 /** 493 * Number of visible notifications affects scrim opacity. 494 */ 495 @Test 496 public void testNotificationDensity() { 497 mScrimController.transitionTo(ScrimState.KEYGUARD); 498 mScrimController.finishAnimationsImmediately(); 499 500 mScrimController.setNotificationCount(0); 501 mScrimController.finishAnimationsImmediately(); 502 Assert.assertEquals("lower density when no notifications", 503 ScrimController.GRADIENT_SCRIM_ALPHA, mScrimBehind.getViewAlpha(), 0.01f); 504 505 mScrimController.setNotificationCount(3); 506 mScrimController.finishAnimationsImmediately(); 507 Assert.assertEquals("stronger density when notifications are visible", 508 ScrimController.GRADIENT_SCRIM_ALPHA_BUSY, mScrimBehind.getViewAlpha(), 0.01f); 509 } 510 511 /** 512 * Moving from/to states conserves old notification density. 513 */ 514 @Test 515 public void testConservesNotificationDensity() { 516 testConservesNotificationDensity(0 /* count */, ScrimController.GRADIENT_SCRIM_ALPHA); 517 testConservesNotificationDensity(3 /* count */, ScrimController.GRADIENT_SCRIM_ALPHA_BUSY); 518 } 519 520 @Test 521 public void testScrimFocus() { 522 mScrimController.transitionTo(ScrimState.AOD); 523 Assert.assertFalse("Should not be focusable on AOD", mScrimBehind.isFocusable()); 524 Assert.assertFalse("Should not be focusable on AOD", mScrimInFront.isFocusable()); 525 526 mScrimController.transitionTo(ScrimState.KEYGUARD); 527 Assert.assertTrue("Should be focusable on keyguard", mScrimBehind.isFocusable()); 528 Assert.assertTrue("Should be focusable on keyguard", mScrimInFront.isFocusable()); 529 } 530 531 @Test 532 public void testHidesShowWhenLockedActivity() { 533 mScrimController.setWallpaperSupportsAmbientMode(true); 534 mScrimController.setKeyguardOccluded(true); 535 mScrimController.transitionTo(ScrimState.AOD); 536 mScrimController.finishAnimationsImmediately(); 537 assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE); 538 539 mScrimController.transitionTo(ScrimState.PULSING); 540 mScrimController.finishAnimationsImmediately(); 541 assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE); 542 } 543 544 @Test 545 public void testHidesShowWhenLockedActivity_whenAlreadyInAod() { 546 mScrimController.setWallpaperSupportsAmbientMode(true); 547 mScrimController.transitionTo(ScrimState.AOD); 548 mScrimController.finishAnimationsImmediately(); 549 assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_TRANSPARENT); 550 551 mScrimController.setKeyguardOccluded(true); 552 mScrimController.finishAnimationsImmediately(); 553 assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE); 554 } 555 556 @Test 557 public void testEatsTouchEvent() { 558 HashSet<ScrimState> eatsTouches = 559 new HashSet<>(Arrays.asList(ScrimState.AOD, ScrimState.PULSING)); 560 for (ScrimState state : ScrimState.values()) { 561 if (state == ScrimState.UNINITIALIZED) { 562 continue; 563 } 564 mScrimController.transitionTo(state); 565 mScrimController.finishAnimationsImmediately(); 566 Assert.assertEquals("Should be clickable unless AOD or PULSING, was: " + state, 567 mScrimBehind.getViewAlpha() != 0 && !eatsTouches.contains(state), 568 mScrimBehind.isClickable()); 569 } 570 } 571 572 @Test 573 public void testAnimatesTransitionToAod() { 574 when(mDozeParamenters.shouldControlScreenOff()).thenReturn(false); 575 ScrimState.AOD.prepare(ScrimState.KEYGUARD); 576 Assert.assertFalse("No animation when ColorFade kicks in", 577 ScrimState.AOD.getAnimateChange()); 578 579 reset(mDozeParamenters); 580 when(mDozeParamenters.shouldControlScreenOff()).thenReturn(true); 581 ScrimState.AOD.prepare(ScrimState.KEYGUARD); 582 Assert.assertTrue("Animate scrims when ColorFade won't be triggered", 583 ScrimState.AOD.getAnimateChange()); 584 } 585 586 @Test 587 public void testViewsDontHaveFocusHighlight() { 588 Assert.assertFalse("Scrim shouldn't have focus highlight", 589 mScrimInFront.getDefaultFocusHighlightEnabled()); 590 Assert.assertFalse("Scrim shouldn't have focus highlight", 591 mScrimBehind.getDefaultFocusHighlightEnabled()); 592 } 593 594 /** 595 * Conserves old notification density after leaving state and coming back. 596 * 597 * @param count How many notification. 598 * @param expectedAlpha Expected alpha. 599 */ 600 private void testConservesNotificationDensity(int count, float expectedAlpha) { 601 mScrimController.setNotificationCount(count); 602 mScrimController.transitionTo(ScrimState.UNLOCKED); 603 mScrimController.finishAnimationsImmediately(); 604 605 mScrimController.transitionTo(ScrimState.KEYGUARD); 606 mScrimController.finishAnimationsImmediately(); 607 608 Assert.assertEquals("Doesn't respect notification busyness after transition", 609 expectedAlpha, mScrimBehind.getViewAlpha(), 0.01f); 610 } 611 612 private void assertScrimTint(ScrimView scrimView, boolean tinted) { 613 final boolean viewIsTinted = scrimView.getTint() != Color.TRANSPARENT; 614 final String name = scrimView == mScrimInFront ? "front" : "back"; 615 Assert.assertEquals("Tint test failed at state " + mScrimController.getState() 616 +" with scrim: " + name + " and tint: " + Integer.toHexString(scrimView.getTint()), 617 tinted, viewIsTinted); 618 } 619 620 private void assertScrimVisibility(int inFront, int behind) { 621 boolean inFrontVisible = inFront != ScrimController.VISIBILITY_FULLY_TRANSPARENT; 622 boolean behindVisible = behind != ScrimController.VISIBILITY_FULLY_TRANSPARENT; 623 Assert.assertEquals("Unexpected front scrim visibility. Alpha is " 624 + mScrimInFront.getViewAlpha(), inFrontVisible, mScrimInFront.getViewAlpha() > 0); 625 Assert.assertEquals("Unexpected back scrim visibility. Alpha is " 626 + mScrimBehind.getViewAlpha(), behindVisible, mScrimBehind.getViewAlpha() > 0); 627 628 final int visibility; 629 if (inFront == VISIBILITY_FULLY_OPAQUE || behind == VISIBILITY_FULLY_OPAQUE) { 630 visibility = VISIBILITY_FULLY_OPAQUE; 631 } else if (inFront > VISIBILITY_FULLY_TRANSPARENT || behind > VISIBILITY_FULLY_TRANSPARENT) { 632 visibility = VISIBILITY_SEMI_TRANSPARENT; 633 } else { 634 visibility = VISIBILITY_FULLY_TRANSPARENT; 635 } 636 Assert.assertEquals("Invalid visibility.", visibility, mScrimVisibility); 637 } 638 639 /** 640 * Special version of ScrimController where animations have 0 duration for test purposes. 641 */ 642 private class SynchronousScrimController extends ScrimController { 643 644 private FakeHandler mHandler; 645 private boolean mAnimationCancelled; 646 boolean mOnPreDrawCalled; 647 648 SynchronousScrimController(ScrimView scrimBehind, ScrimView scrimInFront, 649 TriConsumer<ScrimState, Float, GradientColors> scrimStateListener, 650 Consumer<Integer> scrimVisibleListener, DozeParameters dozeParameters, 651 AlarmManager alarmManager) { 652 super(scrimBehind, scrimInFront, scrimStateListener, scrimVisibleListener, 653 dozeParameters, alarmManager); 654 mHandler = new FakeHandler(Looper.myLooper()); 655 } 656 657 @Override 658 public boolean onPreDraw() { 659 mOnPreDrawCalled = true; 660 return super.onPreDraw(); 661 } 662 663 void finishAnimationsImmediately() { 664 boolean[] animationFinished = {false}; 665 setOnAnimationFinished(()-> animationFinished[0] = true); 666 667 // Execute code that will trigger animations. 668 onPreDraw(); 669 670 // Force finish screen blanking. 671 mHandler.dispatchQueuedMessages(); 672 // Force finish all animations. 673 endAnimation(mScrimBehind, TAG_KEY_ANIM); 674 endAnimation(mScrimInFront, TAG_KEY_ANIM); 675 676 if (!animationFinished[0]) { 677 throw new IllegalStateException("Animation never finished"); 678 } 679 } 680 681 boolean wasAnimationJustCancelled() { 682 final boolean wasCancelled = mAnimationCancelled; 683 mAnimationCancelled = false; 684 return wasCancelled; 685 } 686 687 private void endAnimation(View scrimView, int tag) { 688 Animator animator = (Animator) scrimView.getTag(tag); 689 if (animator != null) { 690 animator.end(); 691 } 692 } 693 694 @Override 695 protected void cancelAnimator(ValueAnimator previousAnimator) { 696 super.cancelAnimator(previousAnimator); 697 mAnimationCancelled = true; 698 } 699 700 @Override 701 protected Handler getHandler() { 702 return mHandler; 703 } 704 705 @Override 706 protected WakeLock createWakeLock() { 707 return mWakeLock; 708 } 709 710 /** 711 * Do not wait for a frame since we're in a test environment. 712 * @param callback What to execute. 713 */ 714 @Override 715 protected void doOnTheNextFrame(Runnable callback) { 716 callback.run(); 717 } 718 } 719 720 } 721