1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 15 package com.android.systemui.statusbar.phone.fragment; 16 17 import static android.view.Display.DEFAULT_DISPLAY; 18 19 import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_CLOSED; 20 import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_OPEN; 21 22 import static org.junit.Assert.assertEquals; 23 import static org.junit.Assert.assertFalse; 24 import static org.junit.Assert.assertNotEquals; 25 import static org.junit.Assert.assertTrue; 26 import static org.mockito.ArgumentMatchers.any; 27 import static org.mockito.ArgumentMatchers.anyFloat; 28 import static org.mockito.ArgumentMatchers.anyLong; 29 import static org.mockito.Matchers.eq; 30 import static org.mockito.Mockito.atLeast; 31 import static org.mockito.Mockito.doAnswer; 32 import static org.mockito.Mockito.mock; 33 import static org.mockito.Mockito.verify; 34 import static org.mockito.Mockito.when; 35 36 import android.app.Fragment; 37 import android.app.StatusBarManager; 38 import android.content.Context; 39 import android.os.Bundle; 40 import android.os.UserHandle; 41 import android.provider.Settings; 42 import android.testing.AndroidTestingRunner; 43 import android.testing.TestableLooper.RunWithLooper; 44 import android.view.View; 45 import android.view.ViewPropertyAnimator; 46 import android.widget.FrameLayout; 47 48 import androidx.test.filters.SmallTest; 49 50 import com.android.keyguard.KeyguardUpdateMonitor; 51 import com.android.systemui.R; 52 import com.android.systemui.SysuiBaseFragmentTest; 53 import com.android.systemui.animation.AnimatorTestRule; 54 import com.android.systemui.dump.DumpManager; 55 import com.android.systemui.flags.FeatureFlags; 56 import com.android.systemui.log.LogBuffer; 57 import com.android.systemui.log.LogcatEchoTracker; 58 import com.android.systemui.plugins.DarkIconDispatcher; 59 import com.android.systemui.plugins.statusbar.StatusBarStateController; 60 import com.android.systemui.shade.ShadeExpansionStateManager; 61 import com.android.systemui.shade.ShadeViewController; 62 import com.android.systemui.statusbar.CommandQueue; 63 import com.android.systemui.statusbar.OperatorNameViewController; 64 import com.android.systemui.statusbar.disableflags.DisableFlagsLogger; 65 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler; 66 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController; 67 import com.android.systemui.statusbar.phone.NotificationIconAreaController; 68 import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager; 69 import com.android.systemui.statusbar.phone.StatusBarIconController; 70 import com.android.systemui.statusbar.phone.StatusBarLocationPublisher; 71 import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent; 72 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController; 73 import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.FakeCollapsedStatusBarViewBinder; 74 import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.FakeCollapsedStatusBarViewModel; 75 import com.android.systemui.statusbar.policy.KeyguardStateController; 76 import com.android.systemui.statusbar.window.StatusBarWindowStateController; 77 import com.android.systemui.statusbar.window.StatusBarWindowStateListener; 78 import com.android.systemui.util.CarrierConfigTracker; 79 import com.android.systemui.util.concurrency.FakeExecutor; 80 import com.android.systemui.util.settings.SecureSettings; 81 import com.android.systemui.util.time.FakeSystemClock; 82 83 import org.junit.Before; 84 import org.junit.Rule; 85 import org.junit.Test; 86 import org.junit.runner.RunWith; 87 import org.mockito.Mock; 88 import org.mockito.MockitoAnnotations; 89 90 import java.util.ArrayList; 91 import java.util.List; 92 93 @RunWith(AndroidTestingRunner.class) 94 @RunWithLooper(setAsMainLooper = true) 95 @SmallTest 96 public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { 97 98 private NotificationIconAreaController mMockNotificationAreaController; 99 private ShadeExpansionStateManager mShadeExpansionStateManager; 100 private View mNotificationAreaInner; 101 private OngoingCallController mOngoingCallController; 102 private SystemStatusAnimationScheduler mAnimationScheduler; 103 private StatusBarLocationPublisher mLocationPublisher; 104 // Set in instantiate() 105 private StatusBarIconController mStatusBarIconController; 106 private KeyguardStateController mKeyguardStateController; 107 108 private final CommandQueue mCommandQueue = mock(CommandQueue.class); 109 private OperatorNameViewController.Factory mOperatorNameViewControllerFactory; 110 private OperatorNameViewController mOperatorNameViewController; 111 private SecureSettings mSecureSettings; 112 private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); 113 private final CarrierConfigTracker mCarrierConfigTracker = mock(CarrierConfigTracker.class); 114 115 @Mock 116 private StatusBarFragmentComponent.Factory mStatusBarFragmentComponentFactory; 117 @Mock 118 private StatusBarFragmentComponent mStatusBarFragmentComponent; 119 @Mock 120 private StatusBarStateController mStatusBarStateController; 121 @Mock 122 private HeadsUpAppearanceController mHeadsUpAppearanceController; 123 @Mock 124 private ShadeViewController mShadeViewController; 125 @Mock 126 private StatusBarIconController.DarkIconManager.Factory mIconManagerFactory; 127 @Mock 128 private StatusBarIconController.DarkIconManager mIconManager; 129 private FakeCollapsedStatusBarViewModel mCollapsedStatusBarViewModel; 130 private FakeCollapsedStatusBarViewBinder mCollapsedStatusBarViewBinder; 131 @Mock 132 private StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager; 133 @Mock 134 private DumpManager mDumpManager; 135 @Mock 136 private StatusBarWindowStateController mStatusBarWindowStateController; 137 @Mock 138 private KeyguardUpdateMonitor mKeyguardUpdateMonitor; 139 @Rule 140 public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule(); 141 142 private List<StatusBarWindowStateListener> mStatusBarWindowStateListeners = new ArrayList<>(); 143 CollapsedStatusBarFragmentTest()144 public CollapsedStatusBarFragmentTest() { 145 super(CollapsedStatusBarFragment.class); 146 } 147 148 @Before setup()149 public void setup() { 150 injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES); 151 mDependency.injectMockDependency(DarkIconDispatcher.class); 152 153 // Keep the window state listeners so we can dispatch to them to test the status bar 154 // fragment's response. 155 doAnswer(invocation -> { 156 mStatusBarWindowStateListeners.add(invocation.getArgument(0)); 157 return null; 158 }).when(mStatusBarWindowStateController).addListener( 159 any(StatusBarWindowStateListener.class)); 160 } 161 162 @Test testDisableNone()163 public void testDisableNone() { 164 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 165 166 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 167 168 assertEquals(View.VISIBLE, getEndSideContentView().getVisibility()); 169 assertEquals(View.VISIBLE, getClockView().getVisibility()); 170 } 171 172 @Test testDisableSystemInfo_systemAnimationIdle_doesHide()173 public void testDisableSystemInfo_systemAnimationIdle_doesHide() { 174 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 175 176 fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_SYSTEM_INFO, 0, false); 177 178 assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility()); 179 180 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 181 182 assertEquals(View.VISIBLE, getEndSideContentView().getVisibility()); 183 184 fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_SYSTEM_INFO, 0, false); 185 186 assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility()); 187 } 188 189 @Test testSystemStatusAnimation_startedDisabled_finishedWithAnimator_showsSystemInfo()190 public void testSystemStatusAnimation_startedDisabled_finishedWithAnimator_showsSystemInfo() { 191 // GIVEN the status bar hides the system info via disable flags, while there is no event 192 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 193 fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_SYSTEM_INFO, 0, false); 194 assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility()); 195 196 // WHEN the system event animation starts 197 fragment.onSystemEventAnimationBegin().start(); 198 199 // THEN the view remains invisible during the animation 200 assertEquals(0f, getEndSideContentView().getAlpha(), 0.01); 201 mAnimatorTestRule.advanceTimeBy(500); 202 assertEquals(0f, getEndSideContentView().getAlpha(), 0.01); 203 204 // WHEN the disable flags are cleared during a system event animation 205 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 206 207 // THEN the view remains invisible 208 assertEquals(0, getEndSideContentView().getAlpha(), 0.01); 209 210 // WHEN the system event animation finishes 211 fragment.onSystemEventAnimationFinish(false).start(); 212 mAnimatorTestRule.advanceTimeBy(500); 213 214 // THEN the system info is full alpha 215 assertEquals(1, getEndSideContentView().getAlpha(), 0.01); 216 } 217 218 @Test testSystemStatusAnimation_systemInfoDisabled_staysInvisible()219 public void testSystemStatusAnimation_systemInfoDisabled_staysInvisible() { 220 // GIVEN the status bar hides the system info via disable flags, while there is no event 221 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 222 fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_SYSTEM_INFO, 0, false); 223 assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility()); 224 225 // WHEN the system event animation finishes 226 fragment.onSystemEventAnimationFinish(false).start(); 227 mAnimatorTestRule.advanceTimeBy(500); 228 229 // THEN the system info remains invisible (since the disable flag is still set) 230 assertEquals(0, getEndSideContentView().getAlpha(), 0.01); 231 assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility()); 232 } 233 234 235 @Test testSystemStatusAnimation_notDisabled_animatesAlphaZero()236 public void testSystemStatusAnimation_notDisabled_animatesAlphaZero() { 237 // GIVEN the status bar is not disabled 238 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 239 assertEquals(1, getEndSideContentView().getAlpha(), 0.01); 240 241 // WHEN the system event animation begins 242 fragment.onSystemEventAnimationBegin().start(); 243 mAnimatorTestRule.advanceTimeBy(500); 244 245 // THEN the system info is invisible 246 assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility()); 247 assertEquals(0, getEndSideContentView().getAlpha(), 0.01); 248 } 249 250 @Test testSystemStatusAnimation_notDisabled_animatesBackToAlphaOne()251 public void testSystemStatusAnimation_notDisabled_animatesBackToAlphaOne() { 252 // GIVEN the status bar is not disabled 253 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 254 assertEquals(1, getEndSideContentView().getAlpha(), 0.01); 255 256 // WHEN the system event animation begins 257 fragment.onSystemEventAnimationBegin().start(); 258 mAnimatorTestRule.advanceTimeBy(500); 259 260 // THEN the system info is invisible 261 assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility()); 262 assertEquals(0, getEndSideContentView().getAlpha(), 0.01); 263 264 // WHEN the system event animation finishes 265 fragment.onSystemEventAnimationFinish(false).start(); 266 mAnimatorTestRule.advanceTimeBy(500); 267 268 // THEN the system info is full alpha and VISIBLE 269 assertEquals(View.VISIBLE, getEndSideContentView().getVisibility()); 270 assertEquals(1, getEndSideContentView().getAlpha(), 0.01); 271 } 272 273 @Test testDisableNotifications()274 public void testDisableNotifications() { 275 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 276 277 fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false); 278 279 verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.INVISIBLE)); 280 281 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 282 283 verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.VISIBLE)); 284 285 fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false); 286 287 verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.INVISIBLE)); 288 } 289 290 @Test testDisableClock()291 public void testDisableClock() { 292 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 293 294 fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_CLOCK, 0, false); 295 296 assertEquals(View.GONE, getClockView().getVisibility()); 297 298 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 299 300 assertEquals(View.VISIBLE, getClockView().getVisibility()); 301 302 fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_CLOCK, 0, false); 303 304 assertEquals(View.GONE, getClockView().getVisibility()); 305 } 306 307 @Test disable_shadeOpenAndShouldHide_everythingHidden()308 public void disable_shadeOpenAndShouldHide_everythingHidden() { 309 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 310 311 // WHEN the shade is open and configured to hide the status bar icons 312 mShadeExpansionStateManager.updateState(STATE_OPEN); 313 when(mShadeViewController.shouldHideStatusBarIconsWhenExpanded()).thenReturn(true); 314 315 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 316 317 // THEN all views are hidden 318 assertEquals(View.INVISIBLE, getClockView().getVisibility()); 319 verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.INVISIBLE)); 320 assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility()); 321 } 322 323 @Test disable_shadeOpenButNotShouldHide_everythingShown()324 public void disable_shadeOpenButNotShouldHide_everythingShown() { 325 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 326 327 // WHEN the shade is open but *not* configured to hide the status bar icons 328 mShadeExpansionStateManager.updateState(STATE_OPEN); 329 when(mShadeViewController.shouldHideStatusBarIconsWhenExpanded()).thenReturn(false); 330 331 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 332 333 // THEN all views are shown 334 assertEquals(View.VISIBLE, getClockView().getVisibility()); 335 verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.VISIBLE)); 336 assertEquals(View.VISIBLE, getEndSideContentView().getVisibility()); 337 } 338 339 /** Regression test for b/279790651. */ 340 @Test disable_shadeOpenAndShouldHide_thenShadeNotOpenAndDozingUpdate_everythingShown()341 public void disable_shadeOpenAndShouldHide_thenShadeNotOpenAndDozingUpdate_everythingShown() { 342 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 343 344 // WHEN the shade is open and configured to hide the status bar icons 345 mShadeExpansionStateManager.updateState(STATE_OPEN); 346 when(mShadeViewController.shouldHideStatusBarIconsWhenExpanded()).thenReturn(true); 347 348 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 349 350 // THEN all views are hidden 351 assertEquals(View.INVISIBLE, getClockView().getVisibility()); 352 verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.INVISIBLE)); 353 assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility()); 354 355 // WHEN the shade is updated to no longer be open 356 mShadeExpansionStateManager.updateState(STATE_CLOSED); 357 358 // AND we internally request an update via dozing change 359 fragment.onDozingChanged(true); 360 361 // THEN all views are shown 362 assertEquals(View.VISIBLE, getClockView().getVisibility()); 363 verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.VISIBLE)); 364 assertEquals(View.VISIBLE, getEndSideContentView().getVisibility()); 365 } 366 367 @Test disable_notTransitioningToOccluded_everythingShown()368 public void disable_notTransitioningToOccluded_everythingShown() { 369 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 370 371 mCollapsedStatusBarViewModel.isTransitioningFromLockscreenToOccluded().setValue(false); 372 373 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 374 375 // THEN all views are shown 376 assertEquals(View.VISIBLE, getClockView().getVisibility()); 377 verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.VISIBLE)); 378 assertEquals(View.VISIBLE, getEndSideContentView().getVisibility()); 379 } 380 381 @Test disable_isTransitioningToOccluded_everythingHidden()382 public void disable_isTransitioningToOccluded_everythingHidden() { 383 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 384 385 mCollapsedStatusBarViewModel.isTransitioningFromLockscreenToOccluded().setValue(true); 386 387 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 388 389 // THEN all views are hidden 390 assertEquals(View.GONE, getClockView().getVisibility()); 391 verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.INVISIBLE)); 392 assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility()); 393 } 394 395 @Test disable_wasTransitioningToOccluded_transitionFinished_everythingShown()396 public void disable_wasTransitioningToOccluded_transitionFinished_everythingShown() { 397 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 398 399 // WHEN the transition is occurring 400 mCollapsedStatusBarViewModel.isTransitioningFromLockscreenToOccluded().setValue(true); 401 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 402 403 // THEN all views are hidden 404 assertEquals(View.GONE, getClockView().getVisibility()); 405 verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.INVISIBLE)); 406 assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility()); 407 408 // WHEN the transition has finished 409 mCollapsedStatusBarViewModel.isTransitioningFromLockscreenToOccluded().setValue(false); 410 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 411 412 // THEN all views are shown 413 assertEquals(View.VISIBLE, getClockView().getVisibility()); 414 verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.VISIBLE)); 415 assertEquals(View.VISIBLE, getEndSideContentView().getVisibility()); 416 } 417 418 @Test userChip_defaultVisibilityIsGone()419 public void userChip_defaultVisibilityIsGone() { 420 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 421 422 assertEquals(View.GONE, getUserChipView().getVisibility()); 423 } 424 425 @Test disable_noOngoingCall_chipHidden()426 public void disable_noOngoingCall_chipHidden() { 427 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 428 429 when(mOngoingCallController.hasOngoingCall()).thenReturn(false); 430 431 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 432 433 assertEquals(View.GONE, 434 mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility()); 435 } 436 437 @Test disable_hasOngoingCall_chipDisplayedAndNotificationIconsHidden()438 public void disable_hasOngoingCall_chipDisplayedAndNotificationIconsHidden() { 439 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 440 441 when(mOngoingCallController.hasOngoingCall()).thenReturn(true); 442 443 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 444 445 assertEquals(View.VISIBLE, 446 mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility()); 447 verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.INVISIBLE)); 448 } 449 450 @Test disable_hasOngoingCallButNotificationIconsDisabled_chipHidden()451 public void disable_hasOngoingCallButNotificationIconsDisabled_chipHidden() { 452 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 453 454 when(mOngoingCallController.hasOngoingCall()).thenReturn(true); 455 456 fragment.disable(DEFAULT_DISPLAY, 457 StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false); 458 459 assertEquals(View.GONE, 460 mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility()); 461 } 462 463 @Test disable_hasOngoingCallButAlsoHun_chipHidden()464 public void disable_hasOngoingCallButAlsoHun_chipHidden() { 465 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 466 467 when(mOngoingCallController.hasOngoingCall()).thenReturn(true); 468 when(mHeadsUpAppearanceController.shouldBeVisible()).thenReturn(true); 469 470 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 471 472 assertEquals(View.GONE, 473 mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility()); 474 } 475 476 @Test disable_ongoingCallEnded_chipHidden()477 public void disable_ongoingCallEnded_chipHidden() { 478 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 479 480 // Ongoing call started 481 when(mOngoingCallController.hasOngoingCall()).thenReturn(true); 482 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 483 484 assertEquals(View.VISIBLE, 485 mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility()); 486 487 // Ongoing call ended 488 when(mOngoingCallController.hasOngoingCall()).thenReturn(false); 489 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 490 491 assertEquals(View.GONE, 492 mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility()); 493 494 // Ongoing call started 495 when(mOngoingCallController.hasOngoingCall()).thenReturn(true); 496 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 497 498 assertEquals(View.VISIBLE, 499 mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility()); 500 } 501 502 @Test disable_isDozing_clockAndSystemInfoVisible()503 public void disable_isDozing_clockAndSystemInfoVisible() { 504 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 505 when(mStatusBarStateController.isDozing()).thenReturn(true); 506 507 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 508 509 assertEquals(View.VISIBLE, getEndSideContentView().getVisibility()); 510 assertEquals(View.VISIBLE, getClockView().getVisibility()); 511 } 512 513 @Test disable_NotDozing_clockAndSystemInfoVisible()514 public void disable_NotDozing_clockAndSystemInfoVisible() { 515 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 516 when(mStatusBarStateController.isDozing()).thenReturn(false); 517 518 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 519 520 assertEquals(View.VISIBLE, getEndSideContentView().getVisibility()); 521 assertEquals(View.VISIBLE, getClockView().getVisibility()); 522 } 523 524 @Test disable_headsUpShouldBeVisibleTrue_clockDisabled()525 public void disable_headsUpShouldBeVisibleTrue_clockDisabled() { 526 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 527 when(mHeadsUpAppearanceController.shouldBeVisible()).thenReturn(true); 528 529 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 530 531 assertEquals(View.GONE, getClockView().getVisibility()); 532 } 533 534 @Test disable_headsUpShouldBeVisibleFalse_clockNotDisabled()535 public void disable_headsUpShouldBeVisibleFalse_clockNotDisabled() { 536 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 537 when(mHeadsUpAppearanceController.shouldBeVisible()).thenReturn(false); 538 539 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 540 541 assertEquals(View.VISIBLE, getClockView().getVisibility()); 542 } 543 544 @Test setUp_fragmentCreatesDaggerComponent()545 public void setUp_fragmentCreatesDaggerComponent() { 546 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 547 548 assertEquals(mStatusBarFragmentComponent, fragment.getStatusBarFragmentComponent()); 549 } 550 551 @Test testBlockedIcons_obeysSettingForVibrateIcon_settingOff()552 public void testBlockedIcons_obeysSettingForVibrateIcon_settingOff() { 553 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 554 String str = mContext.getString(com.android.internal.R.string.status_bar_volume); 555 556 // GIVEN the setting is off 557 when(mSecureSettings.getInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0)) 558 .thenReturn(0); 559 560 // WHEN CollapsedStatusBarFragment builds the blocklist 561 fragment.updateBlockedIcons(); 562 563 // THEN status_bar_volume SHOULD be present in the list 564 boolean contains = fragment.getBlockedIcons().contains(str); 565 assertTrue(contains); 566 } 567 568 @Test testBlockedIcons_obeysSettingForVibrateIcon_settingOn()569 public void testBlockedIcons_obeysSettingForVibrateIcon_settingOn() { 570 CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 571 String str = mContext.getString(com.android.internal.R.string.status_bar_volume); 572 573 // GIVEN the setting is ON 574 when(mSecureSettings.getIntForUser(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0, 575 UserHandle.USER_CURRENT)) 576 .thenReturn(1); 577 578 // WHEN CollapsedStatusBarFragment builds the blocklist 579 fragment.updateBlockedIcons(); 580 581 // THEN status_bar_volume SHOULD NOT be present in the list 582 boolean contains = fragment.getBlockedIcons().contains(str); 583 assertFalse(contains); 584 } 585 586 @Test testStatusBarIcons_hiddenThroughoutCameraLaunch()587 public void testStatusBarIcons_hiddenThroughoutCameraLaunch() { 588 final CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 589 590 mockSecureCameraLaunch(fragment, true /* launched */); 591 592 // Status icons should be invisible or gone, but certainly not VISIBLE. 593 assertNotEquals(View.VISIBLE, getEndSideContentView().getVisibility()); 594 assertNotEquals(View.VISIBLE, getClockView().getVisibility()); 595 596 mockSecureCameraLaunchFinished(); 597 598 assertNotEquals(View.VISIBLE, getEndSideContentView().getVisibility()); 599 assertNotEquals(View.VISIBLE, getClockView().getVisibility()); 600 601 mockSecureCameraLaunch(fragment, false /* launched */); 602 603 assertEquals(View.VISIBLE, getEndSideContentView().getVisibility()); 604 assertEquals(View.VISIBLE, getClockView().getVisibility()); 605 } 606 607 @Test testStatusBarIcons_hiddenThroughoutLockscreenToDreamTransition()608 public void testStatusBarIcons_hiddenThroughoutLockscreenToDreamTransition() { 609 final CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 610 611 // WHEN a transition to dream has started 612 mCollapsedStatusBarViewBinder.getListener().onTransitionFromLockscreenToDreamStarted(); 613 when(mKeyguardUpdateMonitor.isDreaming()).thenReturn(true); 614 when(mKeyguardStateController.isOccluded()).thenReturn(true); 615 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 616 617 // THEN status icons should be invisible or gone, but certainly not VISIBLE. 618 assertNotEquals(View.VISIBLE, getEndSideContentView().getVisibility()); 619 assertNotEquals(View.VISIBLE, getClockView().getVisibility()); 620 621 // WHEN the transition has finished and dream is displaying 622 mockLockscreenToDreamTransitionFinished(); 623 // (This approximates "dream is displaying") 624 when(mStatusBarHideIconsForBouncerManager.getShouldHideStatusBarIconsForBouncer()) 625 .thenReturn(true); 626 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 627 628 // THEN the views still aren't visible because dream is hiding them 629 assertNotEquals(View.VISIBLE, getEndSideContentView().getVisibility()); 630 assertNotEquals(View.VISIBLE, getClockView().getVisibility()); 631 632 // WHEN dream has ended 633 when(mStatusBarHideIconsForBouncerManager.getShouldHideStatusBarIconsForBouncer()) 634 .thenReturn(false); 635 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 636 637 // THEN the views can be visible again 638 assertEquals(View.VISIBLE, getEndSideContentView().getVisibility()); 639 assertEquals(View.VISIBLE, getClockView().getVisibility()); 640 } 641 642 @Test testStatusBarIcons_lockscreenToDreamTransitionButNotDreaming_iconsVisible()643 public void testStatusBarIcons_lockscreenToDreamTransitionButNotDreaming_iconsVisible() { 644 final CollapsedStatusBarFragment fragment = resumeAndGetFragment(); 645 646 // WHEN a transition to dream has started but we're *not* dreaming 647 mCollapsedStatusBarViewBinder.getListener().onTransitionFromLockscreenToDreamStarted(); 648 when(mKeyguardUpdateMonitor.isDreaming()).thenReturn(false); 649 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 650 651 // THEN the views are still visible 652 assertEquals(View.VISIBLE, getEndSideContentView().getVisibility()); 653 assertEquals(View.VISIBLE, getClockView().getVisibility()); 654 } 655 656 @Override instantiate(Context context, String className, Bundle arguments)657 protected Fragment instantiate(Context context, String className, Bundle arguments) { 658 MockitoAnnotations.initMocks(this); 659 setUpDaggerComponent(); 660 mOngoingCallController = mock(OngoingCallController.class); 661 mAnimationScheduler = mock(SystemStatusAnimationScheduler.class); 662 mLocationPublisher = mock(StatusBarLocationPublisher.class); 663 mStatusBarIconController = mock(StatusBarIconController.class); 664 mStatusBarStateController = mock(StatusBarStateController.class); 665 mKeyguardStateController = mock(KeyguardStateController.class); 666 mOperatorNameViewController = mock(OperatorNameViewController.class); 667 mOperatorNameViewControllerFactory = mock(OperatorNameViewController.Factory.class); 668 when(mOperatorNameViewControllerFactory.create(any())) 669 .thenReturn(mOperatorNameViewController); 670 when(mIconManagerFactory.create(any(), any())).thenReturn(mIconManager); 671 mSecureSettings = mock(SecureSettings.class); 672 673 mShadeExpansionStateManager = new ShadeExpansionStateManager(); 674 mCollapsedStatusBarViewModel = new FakeCollapsedStatusBarViewModel(); 675 mCollapsedStatusBarViewBinder = new FakeCollapsedStatusBarViewBinder(); 676 677 setUpNotificationIconAreaController(); 678 return new CollapsedStatusBarFragment( 679 mStatusBarFragmentComponentFactory, 680 mOngoingCallController, 681 mAnimationScheduler, 682 mLocationPublisher, 683 mMockNotificationAreaController, 684 mShadeExpansionStateManager, 685 mock(FeatureFlags.class), 686 mStatusBarIconController, 687 mIconManagerFactory, 688 mCollapsedStatusBarViewModel, 689 mCollapsedStatusBarViewBinder, 690 mStatusBarHideIconsForBouncerManager, 691 mKeyguardStateController, 692 mShadeViewController, 693 mStatusBarStateController, 694 mCommandQueue, 695 mCarrierConfigTracker, 696 new CollapsedStatusBarFragmentLogger( 697 new LogBuffer("TEST", 1, mock(LogcatEchoTracker.class)), 698 new DisableFlagsLogger() 699 ), 700 mOperatorNameViewControllerFactory, 701 mSecureSettings, 702 mExecutor, 703 mDumpManager, 704 mStatusBarWindowStateController, 705 mKeyguardUpdateMonitor); 706 } 707 setUpDaggerComponent()708 private void setUpDaggerComponent() { 709 when(mStatusBarFragmentComponentFactory.create(any())) 710 .thenReturn(mStatusBarFragmentComponent); 711 when(mStatusBarFragmentComponent.getHeadsUpAppearanceController()) 712 .thenReturn(mHeadsUpAppearanceController); 713 } 714 setUpNotificationIconAreaController()715 private void setUpNotificationIconAreaController() { 716 mMockNotificationAreaController = mock(NotificationIconAreaController.class); 717 718 mNotificationAreaInner = mock(View.class); 719 720 when(mNotificationAreaInner.getLayoutParams()).thenReturn( 721 new FrameLayout.LayoutParams(100, 100)); 722 // We should probably start using a real view so that we don't need to mock these methods. 723 ViewPropertyAnimator viewPropertyAnimator = mock(ViewPropertyAnimator.class); 724 when(mNotificationAreaInner.animate()).thenReturn(viewPropertyAnimator); 725 when(viewPropertyAnimator.alpha(anyFloat())).thenReturn(viewPropertyAnimator); 726 when(viewPropertyAnimator.setDuration(anyLong())).thenReturn(viewPropertyAnimator); 727 when(viewPropertyAnimator.setInterpolator(any())).thenReturn(viewPropertyAnimator); 728 when(viewPropertyAnimator.setStartDelay(anyLong())).thenReturn(viewPropertyAnimator); 729 when(viewPropertyAnimator.withEndAction(any())).thenReturn(viewPropertyAnimator); 730 731 when(mMockNotificationAreaController.getNotificationInnerAreaView()).thenReturn( 732 mNotificationAreaInner); 733 } 734 735 /** 736 * Configure mocks to return values consistent with the secure camera animating itself launched 737 * over the keyguard. 738 */ mockSecureCameraLaunch(CollapsedStatusBarFragment fragment, boolean launched)739 private void mockSecureCameraLaunch(CollapsedStatusBarFragment fragment, boolean launched) { 740 when(mKeyguardUpdateMonitor.isSecureCameraLaunchedOverKeyguard()).thenReturn(launched); 741 when(mKeyguardStateController.isOccluded()).thenReturn(launched); 742 743 if (launched) { 744 fragment.onCameraLaunchGestureDetected(0 /* source */); 745 } else { 746 for (StatusBarWindowStateListener listener : mStatusBarWindowStateListeners) { 747 listener.onStatusBarWindowStateChanged(StatusBarManager.WINDOW_STATE_SHOWING); 748 } 749 } 750 751 fragment.disable(DEFAULT_DISPLAY, 0, 0, false); 752 } 753 754 /** 755 * Configure mocks to return values consistent with the secure camera showing over the keyguard 756 * with its launch animation finished. 757 */ mockSecureCameraLaunchFinished()758 private void mockSecureCameraLaunchFinished() { 759 for (StatusBarWindowStateListener listener : mStatusBarWindowStateListeners) { 760 listener.onStatusBarWindowStateChanged(StatusBarManager.WINDOW_STATE_HIDDEN); 761 } 762 } 763 mockLockscreenToDreamTransitionFinished()764 private void mockLockscreenToDreamTransitionFinished() { 765 for (StatusBarWindowStateListener listener : mStatusBarWindowStateListeners) { 766 listener.onStatusBarWindowStateChanged(StatusBarManager.WINDOW_STATE_HIDDEN); 767 } 768 } 769 resumeAndGetFragment()770 private CollapsedStatusBarFragment resumeAndGetFragment() { 771 mFragments.dispatchResume(); 772 processAllMessages(); 773 return (CollapsedStatusBarFragment) mFragment; 774 } 775 getUserChipView()776 private View getUserChipView() { 777 return mFragment.getView().findViewById(R.id.user_switcher_container); 778 } 779 getClockView()780 private View getClockView() { 781 return mFragment.getView().findViewById(R.id.clock); 782 } 783 getEndSideContentView()784 private View getEndSideContentView() { 785 return mFragment.getView().findViewById(R.id.status_bar_end_side_content); 786 } 787 } 788