1 /* 2 * Copyright (C) 2023 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.qs; 18 19 import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS; 20 21 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; 22 import static com.android.systemui.statusbar.StatusBarState.SHADE; 23 import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED; 24 25 import static com.google.common.truth.Truth.assertThat; 26 27 import static org.junit.Assert.assertEquals; 28 import static org.junit.Assert.assertTrue; 29 import static org.mockito.ArgumentMatchers.any; 30 import static org.mockito.ArgumentMatchers.anyBoolean; 31 import static org.mockito.ArgumentMatchers.anyInt; 32 import static org.mockito.ArgumentMatchers.eq; 33 import static org.mockito.ArgumentMatchers.nullable; 34 import static org.mockito.Mockito.clearInvocations; 35 import static org.mockito.Mockito.doAnswer; 36 import static org.mockito.Mockito.mock; 37 import static org.mockito.Mockito.spy; 38 import static org.mockito.Mockito.verify; 39 import static org.mockito.Mockito.verifyZeroInteractions; 40 import static org.mockito.Mockito.when; 41 42 import android.content.Context; 43 import android.graphics.Rect; 44 import android.os.Bundle; 45 import android.testing.TestableLooper.RunWithLooper; 46 import android.view.Display; 47 import android.view.LayoutInflater; 48 import android.view.View; 49 import android.view.ViewGroup; 50 import android.widget.FrameLayout; 51 52 import androidx.compose.ui.platform.ComposeView; 53 import androidx.lifecycle.Lifecycle; 54 import androidx.test.ext.junit.runners.AndroidJUnit4; 55 import androidx.test.filters.SmallTest; 56 57 import com.android.keyguard.BouncerPanelExpansionCalculator; 58 import com.android.systemui.SysuiTestCase; 59 import com.android.systemui.dump.DumpManager; 60 import com.android.systemui.flags.EnableSceneContainer; 61 import com.android.systemui.media.controls.ui.view.MediaHost; 62 import com.android.systemui.qs.customize.QSCustomizerController; 63 import com.android.systemui.qs.dagger.QSComponent; 64 import com.android.systemui.qs.external.TileServiceRequestController; 65 import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel; 66 import com.android.systemui.qs.logging.QSLogger; 67 import com.android.systemui.res.R; 68 import com.android.systemui.settings.FakeDisplayTracker; 69 import com.android.systemui.shade.transition.LargeScreenShadeInterpolator; 70 import com.android.systemui.statusbar.CommandQueue; 71 import com.android.systemui.statusbar.StatusBarState; 72 import com.android.systemui.statusbar.SysuiStatusBarStateController; 73 import com.android.systemui.statusbar.phone.KeyguardBypassController; 74 import com.android.systemui.statusbar.policy.ConfigurationController; 75 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; 76 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController; 77 import com.android.systemui.util.animation.UniqueObjectHostView; 78 79 import org.junit.Before; 80 import org.junit.Test; 81 import org.junit.runner.RunWith; 82 import org.mockito.Mock; 83 import org.mockito.MockitoAnnotations; 84 85 @RunWith(AndroidJUnit4.class) 86 @RunWithLooper(setAsMainLooper = true) 87 @SmallTest 88 public class QSImplTest extends SysuiTestCase { 89 90 @Mock private QSComponent mQsComponent; 91 @Mock private QSPanelController mQSPanelController; 92 @Mock private MediaHost mQSMediaHost; 93 @Mock private MediaHost mQQSMediaHost; 94 @Mock private KeyguardBypassController mBypassController; 95 @Mock private TileServiceRequestController.Builder mTileServiceRequestControllerBuilder; 96 @Mock private TileServiceRequestController mTileServiceRequestController; 97 @Mock private QSCustomizerController mQsCustomizerController; 98 @Mock private QuickQSPanelController mQuickQSPanelController; 99 @Mock private FooterActionsController mQSFooterActionController; 100 @Mock private QSContainerImplController mQSContainerImplController; 101 @Mock private QSContainerImpl mContainer; 102 @Mock private QSFooter mFooter; 103 @Mock private LayoutInflater mLayoutInflater; 104 @Mock private NonInterceptingScrollView mQSPanelScrollView; 105 @Mock private QuickStatusBarHeader mHeader; 106 @Mock private QSPanel.QSTileLayout mQsTileLayout; 107 @Mock private QSPanel.QSTileLayout mQQsTileLayout; 108 @Mock private QSAnimator mQSAnimator; 109 @Mock private SysuiStatusBarStateController mStatusBarStateController; 110 @Mock private QSSquishinessController mSquishinessController; 111 @Mock private FooterActionsViewModel mFooterActionsViewModel; 112 @Mock private FooterActionsViewModel.Factory mFooterActionsViewModelFactory; 113 @Mock private LargeScreenShadeInterpolator mLargeScreenShadeInterpolator; 114 private ViewGroup mQsView; 115 116 private final CommandQueue mCommandQueue = 117 new CommandQueue(mContext, new FakeDisplayTracker(mContext)); 118 119 private QSImpl mUnderTest; 120 121 122 @Before setup()123 public void setup() { 124 MockitoAnnotations.initMocks(this); 125 126 mUnderTest = instantiate(); 127 128 mUnderTest.onComponentCreated(mQsComponent, null); 129 } 130 131 /* 132 * Regression test for b/303180152. 133 */ 134 @Test testDisableCallbackOnDisabledQuickSettingsUponCreationDoesntCrash()135 public void testDisableCallbackOnDisabledQuickSettingsUponCreationDoesntCrash() { 136 QSImpl other = instantiate(); 137 mCommandQueue.disable(Display.DEFAULT_DISPLAY, 0, DISABLE2_QUICK_SETTINGS); 138 139 other.onComponentCreated(mQsComponent, null); 140 } 141 142 @Test testSaveState()143 public void testSaveState() { 144 mUnderTest.setListening(true); 145 mUnderTest.setExpanded(true); 146 mUnderTest.setQsVisible(true); 147 148 Bundle bundle = new Bundle(); 149 mUnderTest.onSaveInstanceState(bundle); 150 151 // Get a new instance 152 QSImpl other = instantiate(); 153 other.onComponentCreated(mQsComponent, bundle); 154 155 assertTrue(other.isListening()); 156 assertTrue(other.isExpanded()); 157 assertTrue(other.isQsVisible()); 158 } 159 160 @Test transitionToFullShade_smallScreen_alphaAlways1()161 public void transitionToFullShade_smallScreen_alphaAlways1() { 162 setIsSmallScreen(); 163 setStatusBarCurrentAndUpcomingState(StatusBarState.SHADE); 164 boolean isTransitioningToFullShade = true; 165 float transitionProgress = 0.5f; 166 float squishinessFraction = 0.5f; 167 168 mUnderTest.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress, 169 squishinessFraction); 170 171 assertThat(mQsView.getAlpha()).isEqualTo(1f); 172 } 173 174 @Test transitionToFullShade_largeScreen_alphaLargeScreenShadeInterpolator()175 public void transitionToFullShade_largeScreen_alphaLargeScreenShadeInterpolator() { 176 setIsLargeScreen(); 177 setStatusBarCurrentAndUpcomingState(StatusBarState.SHADE); 178 boolean isTransitioningToFullShade = true; 179 float transitionProgress = 0.5f; 180 float squishinessFraction = 0.5f; 181 when(mLargeScreenShadeInterpolator.getQsAlpha(transitionProgress)).thenReturn(123f); 182 183 mUnderTest.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress, 184 squishinessFraction); 185 186 assertThat(mQsView.getAlpha()).isEqualTo(123f); 187 } 188 189 @Test 190 public void transitionToFullShade_onKeyguard_noBouncer_setsAlphaUsingLinearInterpolator()191 transitionToFullShade_onKeyguard_noBouncer_setsAlphaUsingLinearInterpolator() { 192 setStatusBarCurrentAndUpcomingState(KEYGUARD); 193 when(mQSPanelController.isBouncerInTransit()).thenReturn(false); 194 boolean isTransitioningToFullShade = true; 195 float transitionProgress = 0.5f; 196 float squishinessFraction = 0.5f; 197 198 mUnderTest.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress, 199 squishinessFraction); 200 201 assertThat(mQsView.getAlpha()).isEqualTo(transitionProgress); 202 } 203 204 @Test 205 public void transitionToFullShade_onKeyguard_bouncerActive_setsAlphaUsingBouncerInterpolator()206 transitionToFullShade_onKeyguard_bouncerActive_setsAlphaUsingBouncerInterpolator() { 207 setStatusBarCurrentAndUpcomingState(KEYGUARD); 208 when(mQSPanelController.isBouncerInTransit()).thenReturn(true); 209 boolean isTransitioningToFullShade = true; 210 float transitionProgress = 0.5f; 211 float squishinessFraction = 0.5f; 212 213 mUnderTest.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress, 214 squishinessFraction); 215 216 assertThat(mQsView.getAlpha()) 217 .isEqualTo( 218 BouncerPanelExpansionCalculator.aboutToShowBouncerProgress( 219 transitionProgress)); 220 } 221 222 @Test transitionToFullShade_inFullWidth_alwaysSetsAlphaTo1()223 public void transitionToFullShade_inFullWidth_alwaysSetsAlphaTo1() { 224 mUnderTest.setIsNotificationPanelFullWidth(true); 225 226 boolean isTransitioningToFullShade = true; 227 float transitionProgress = 0.1f; 228 float squishinessFraction = 0.5f; 229 mUnderTest.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress, 230 squishinessFraction); 231 assertThat(mQsView.getAlpha()).isEqualTo(1); 232 233 transitionProgress = 0.5f; 234 mUnderTest.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress, 235 squishinessFraction); 236 assertThat(mQsView.getAlpha()).isEqualTo(1); 237 assertThat(mQsView.getAlpha()).isEqualTo(1); 238 239 transitionProgress = 0.7f; 240 mUnderTest.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress, 241 squishinessFraction); 242 assertThat(mQsView.getAlpha()).isEqualTo(1); 243 } 244 245 @Test transitionToFullShade_setsSquishinessOnController()246 public void transitionToFullShade_setsSquishinessOnController() { 247 boolean isTransitioningToFullShade = true; 248 float transitionProgress = 0.123f; 249 float squishinessFraction = 0.456f; 250 251 mUnderTest.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress, 252 squishinessFraction); 253 254 verify(mQsComponent.getQSSquishinessController()).setSquishiness(squishinessFraction); 255 } 256 257 @Test setQsExpansion_whenShouldUpdateSquishinessTrue_setsSquishinessBasedOnFraction()258 public void setQsExpansion_whenShouldUpdateSquishinessTrue_setsSquishinessBasedOnFraction() { 259 enableSplitShade(); 260 when(mStatusBarStateController.getState()).thenReturn(KEYGUARD); 261 float expansion = 0.456f; 262 float panelExpansionFraction = 0.678f; 263 float proposedTranslation = 567f; 264 float squishinessFraction = 0.789f; 265 266 mUnderTest.setShouldUpdateSquishinessOnMedia(true); 267 mUnderTest.setQsExpansion(expansion, panelExpansionFraction, proposedTranslation, 268 squishinessFraction); 269 270 verify(mQSMediaHost).setSquishFraction(squishinessFraction); 271 } 272 273 @Test setQsExpansion_whenOnKeyguardAndShouldUpdateSquishinessFalse_setsSquishiness()274 public void setQsExpansion_whenOnKeyguardAndShouldUpdateSquishinessFalse_setsSquishiness() { 275 // Random test values without any meaning. They just have to be different from each other. 276 float expansion = 0.123f; 277 float panelExpansionFraction = 0.321f; 278 float proposedTranslation = 456f; 279 float squishinessFraction = 0.567f; 280 281 enableSplitShade(); 282 setStatusBarCurrentAndUpcomingState(KEYGUARD); 283 mUnderTest.setShouldUpdateSquishinessOnMedia(false); 284 mUnderTest.setQsExpansion(expansion, panelExpansionFraction, proposedTranslation, 285 squishinessFraction); 286 287 verify(mQSMediaHost).setSquishFraction(1.0f); 288 } 289 290 @Test setQsExpansion_inSplitShade_setsFooterActionsExpansion_basedOnPanelExpFraction()291 public void setQsExpansion_inSplitShade_setsFooterActionsExpansion_basedOnPanelExpFraction() { 292 // Random test values without any meaning. They just have to be different from each other. 293 float expansion = 0.123f; 294 float panelExpansionFraction = 0.321f; 295 float proposedTranslation = 456f; 296 float squishinessFraction = 0.987f; 297 298 enableSplitShade(); 299 300 mUnderTest.setQsExpansion(expansion, panelExpansionFraction, proposedTranslation, 301 squishinessFraction); 302 303 verify(mFooterActionsViewModel).onQuickSettingsExpansionChanged( 304 panelExpansionFraction, /* isInSplitShade= */ true); 305 } 306 307 @Test setQsExpansion_notInSplitShade_setsFooterActionsExpansion_basedOnExpansion()308 public void setQsExpansion_notInSplitShade_setsFooterActionsExpansion_basedOnExpansion() { 309 // Random test values without any meaning. They just have to be different from each other. 310 float expansion = 0.123f; 311 float panelExpansionFraction = 0.321f; 312 float proposedTranslation = 456f; 313 float squishinessFraction = 0.987f; 314 315 disableSplitShade(); 316 317 mUnderTest.setQsExpansion(expansion, panelExpansionFraction, proposedTranslation, 318 squishinessFraction); 319 320 verify(mFooterActionsViewModel).onQuickSettingsExpansionChanged( 321 expansion, /* isInSplitShade= */ false); 322 } 323 324 @Test setQsExpansion_inSplitShade_whenTransitioningToKeyguard_setsAlphaBasedOnShadeTransitionProgress()325 public void setQsExpansion_inSplitShade_whenTransitioningToKeyguard_setsAlphaBasedOnShadeTransitionProgress() { 326 enableSplitShade(); 327 when(mStatusBarStateController.getState()).thenReturn(SHADE); 328 when(mStatusBarStateController.getCurrentOrUpcomingState()).thenReturn(KEYGUARD); 329 boolean isTransitioningToFullShade = false; 330 float transitionProgress = 0; 331 float squishinessFraction = 0f; 332 333 mUnderTest.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress, 334 squishinessFraction); 335 336 // trigger alpha refresh with non-zero expansion and fraction values 337 mUnderTest.setQsExpansion(/* expansion= */ 1, /* panelExpansionFraction= */1, 338 /* proposedTranslation= */ 0, /* squishinessFraction= */ 1); 339 340 // alpha should follow lockscreen to shade progress, not panel expansion fraction 341 assertThat(mQsView.getAlpha()).isEqualTo(transitionProgress); 342 } 343 344 @Test getQsMinExpansionHeight_notInSplitShade_returnsHeaderHeight()345 public void getQsMinExpansionHeight_notInSplitShade_returnsHeaderHeight() { 346 disableSplitShade(); 347 when(mHeader.getHeight()).thenReturn(1234); 348 349 int height = mUnderTest.getQsMinExpansionHeight(); 350 351 assertThat(height).isEqualTo(mHeader.getHeight()); 352 } 353 354 @Test getQsMinExpansionHeight_inSplitShade_returnsAbsoluteBottomOfQSContainer()355 public void getQsMinExpansionHeight_inSplitShade_returnsAbsoluteBottomOfQSContainer() { 356 int top = 1234; 357 int height = 9876; 358 enableSplitShade(); 359 setLocationOnScreen(mQsView, top); 360 when(mQsView.getHeight()).thenReturn(height); 361 362 int expectedHeight = top + height; 363 assertThat(mUnderTest.getQsMinExpansionHeight()).isEqualTo(expectedHeight); 364 } 365 366 @Test getQsMinExpansionHeight_inSplitShade_returnsAbsoluteBottomExcludingTranslation()367 public void getQsMinExpansionHeight_inSplitShade_returnsAbsoluteBottomExcludingTranslation() { 368 int top = 1234; 369 int height = 9876; 370 float translationY = -600f; 371 enableSplitShade(); 372 setLocationOnScreen(mQsView, (int) (top + translationY)); 373 when(mQsView.getHeight()).thenReturn(height); 374 when(mQsView.getTranslationY()).thenReturn(translationY); 375 376 int expectedHeight = top + height; 377 assertThat(mUnderTest.getQsMinExpansionHeight()).isEqualTo(expectedHeight); 378 } 379 380 @Test hideImmediately_notInSplitShade_movesViewUpByHeaderHeight()381 public void hideImmediately_notInSplitShade_movesViewUpByHeaderHeight() { 382 disableSplitShade(); 383 when(mHeader.getHeight()).thenReturn(555); 384 385 mUnderTest.hideImmediately(); 386 387 assertThat(mQsView.getY()).isEqualTo(-mHeader.getHeight()); 388 } 389 390 @Test hideImmediately_inSplitShade_movesViewUpByQSAbsoluteBottom()391 public void hideImmediately_inSplitShade_movesViewUpByQSAbsoluteBottom() { 392 enableSplitShade(); 393 int top = 1234; 394 int height = 9876; 395 setLocationOnScreen(mQsView, top); 396 when(mQsView.getHeight()).thenReturn(height); 397 398 mUnderTest.hideImmediately(); 399 400 int qsAbsoluteBottom = top + height; 401 assertThat(mQsView.getY()).isEqualTo(-qsAbsoluteBottom); 402 } 403 404 @Test setCollapseExpandAction_passedToControllers()405 public void setCollapseExpandAction_passedToControllers() { 406 Runnable action = () -> {}; 407 mUnderTest.setCollapseExpandAction(action); 408 409 verify(mQSPanelController).setCollapseExpandAction(action); 410 verify(mQuickQSPanelController).setCollapseExpandAction(action); 411 } 412 413 @Test setOverScrollAmount_setsTranslationOnView()414 public void setOverScrollAmount_setsTranslationOnView() { 415 mUnderTest.setOverScrollAmount(123); 416 417 assertThat(mQsView.getTranslationY()).isEqualTo(123); 418 } 419 420 @Test setOverScrollAmount_beforeViewCreated_translationIsNotSet()421 public void setOverScrollAmount_beforeViewCreated_translationIsNotSet() { 422 QSImpl other = instantiate(); 423 other.setOverScrollAmount(123); 424 425 assertThat(mQsView.getTranslationY()).isEqualTo(0); 426 } 427 getListeningAndVisibilityLifecycleState()428 private Lifecycle.State getListeningAndVisibilityLifecycleState() { 429 return mUnderTest 430 .getListeningAndVisibilityLifecycleOwner() 431 .getLifecycle() 432 .getCurrentState(); 433 } 434 435 @Test setListeningFalse_notVisible()436 public void setListeningFalse_notVisible() { 437 mUnderTest.setQsVisible(false); 438 clearInvocations(mQSContainerImplController, mQSPanelController, mQSFooterActionController); 439 440 mUnderTest.setListening(false); 441 verify(mQSContainerImplController).setListening(false); 442 assertThat(getListeningAndVisibilityLifecycleState()).isEqualTo(Lifecycle.State.CREATED); 443 verify(mQSPanelController).setListening(eq(false), anyBoolean()); 444 } 445 446 @Test setListeningTrue_notVisible()447 public void setListeningTrue_notVisible() { 448 mUnderTest.setQsVisible(false); 449 clearInvocations(mQSContainerImplController, mQSPanelController, mQSFooterActionController); 450 451 mUnderTest.setListening(true); 452 verify(mQSContainerImplController).setListening(false); 453 assertThat(getListeningAndVisibilityLifecycleState()).isEqualTo(Lifecycle.State.STARTED); 454 verify(mQSPanelController).setListening(eq(false), anyBoolean()); 455 } 456 457 @Test setListeningFalse_visible()458 public void setListeningFalse_visible() { 459 mUnderTest.setQsVisible(true); 460 clearInvocations(mQSContainerImplController, mQSPanelController, mQSFooterActionController); 461 462 mUnderTest.setListening(false); 463 verify(mQSContainerImplController).setListening(false); 464 assertThat(getListeningAndVisibilityLifecycleState()).isEqualTo(Lifecycle.State.CREATED); 465 verify(mQSPanelController).setListening(eq(false), anyBoolean()); 466 } 467 468 @Test setListeningTrue_visible()469 public void setListeningTrue_visible() { 470 mUnderTest.setQsVisible(true); 471 clearInvocations(mQSContainerImplController, mQSPanelController, mQSFooterActionController); 472 473 mUnderTest.setListening(true); 474 verify(mQSContainerImplController).setListening(true); 475 assertThat(getListeningAndVisibilityLifecycleState()).isEqualTo(Lifecycle.State.RESUMED); 476 verify(mQSPanelController).setListening(eq(true), anyBoolean()); 477 } 478 479 @Test passCorrectExpansionState_inSplitShade()480 public void passCorrectExpansionState_inSplitShade() { 481 enableSplitShade(); 482 clearInvocations(mQSPanelController); 483 484 mUnderTest.setExpanded(true); 485 verify(mQSPanelController).setExpanded(true); 486 487 mUnderTest.setExpanded(false); 488 verify(mQSPanelController).setExpanded(false); 489 } 490 491 @Test startsListeningAfterStateChangeToExpanded_inSplitShade()492 public void startsListeningAfterStateChangeToExpanded_inSplitShade() { 493 enableSplitShade(); 494 mUnderTest.setQsVisible(true); 495 clearInvocations(mQSPanelController); 496 497 mUnderTest.setExpanded(true); 498 verify(mQSPanelController).setListening(true, true); 499 } 500 501 @Test testUpdateQSBounds_setMediaClipCorrectly()502 public void testUpdateQSBounds_setMediaClipCorrectly() { 503 disableSplitShade(); 504 505 Rect mediaHostClip = new Rect(); 506 when(mQSPanelController.getPaddingBottom()).thenReturn(50); 507 setLocationOnScreen(mQSPanelScrollView, 25); 508 when(mQSPanelScrollView.getMeasuredHeight()).thenReturn(200); 509 when(mQSMediaHost.getCurrentClipping()).thenReturn(mediaHostClip); 510 511 mUnderTest.updateQsBounds(); 512 513 assertEquals(25, mediaHostClip.top); 514 assertEquals(175, mediaHostClip.bottom); 515 } 516 517 @Test testQsUpdatesQsAnimatorWithUpcomingState()518 public void testQsUpdatesQsAnimatorWithUpcomingState() { 519 setStatusBarCurrentAndUpcomingState(SHADE); 520 mUnderTest.onUpcomingStateChanged(KEYGUARD); 521 522 verify(mQSAnimator).setOnKeyguard(true); 523 } 524 525 @Test 526 @EnableSceneContainer testSceneContainerFlagsEnabled_FooterActionsRemoved_controllerNotStarted()527 public void testSceneContainerFlagsEnabled_FooterActionsRemoved_controllerNotStarted() { 528 clearInvocations(mFooterActionsViewModel, mFooterActionsViewModelFactory); 529 QSImpl other = instantiate(); 530 531 other.onComponentCreated(mQsComponent, null); 532 533 assertThat((View) other.getView().findViewById(R.id.qs_footer_actions)).isNull(); 534 verifyZeroInteractions(mFooterActionsViewModel, mFooterActionsViewModelFactory); 535 } 536 537 @Test 538 @EnableSceneContainer testSceneContainerFlagsEnabled_statusBarStateIsShade()539 public void testSceneContainerFlagsEnabled_statusBarStateIsShade() { 540 mUnderTest.onStateChanged(KEYGUARD); 541 assertThat(mUnderTest.getStatusBarState()).isEqualTo(SHADE); 542 543 mUnderTest.onStateChanged(SHADE_LOCKED); 544 assertThat(mUnderTest.getStatusBarState()).isEqualTo(SHADE); 545 } 546 547 @Test 548 @EnableSceneContainer testSceneContainerFlagsEnabled_isKeyguardState_alwaysFalse()549 public void testSceneContainerFlagsEnabled_isKeyguardState_alwaysFalse() { 550 mUnderTest.onStateChanged(KEYGUARD); 551 assertThat(mUnderTest.isKeyguardState()).isFalse(); 552 553 when(mStatusBarStateController.getCurrentOrUpcomingState()).thenReturn(KEYGUARD); 554 assertThat(mUnderTest.isKeyguardState()).isFalse(); 555 } 556 instantiate()557 private QSImpl instantiate() { 558 setupQsComponent(); 559 setUpViews(); 560 setUpInflater(); 561 setUpMedia(); 562 setUpOther(); 563 564 return new QSImpl( 565 new RemoteInputQuickSettingsDisabler( 566 mContext, 567 mCommandQueue, 568 new ResourcesSplitShadeStateController(), 569 mock(ConfigurationController.class)), 570 mStatusBarStateController, 571 mCommandQueue, 572 mQSMediaHost, 573 mQQSMediaHost, 574 mBypassController, 575 mock(QSDisableFlagsLogger.class), 576 mock(DumpManager.class), 577 mock(QSLogger.class), 578 mock(FooterActionsController.class), 579 mFooterActionsViewModelFactory, 580 mLargeScreenShadeInterpolator 581 ); 582 } 583 setUpOther()584 private void setUpOther() { 585 when(mTileServiceRequestControllerBuilder.create(any())) 586 .thenReturn(mTileServiceRequestController); 587 when(mQSContainerImplController.getView()).thenReturn(mContainer); 588 when(mQSPanelController.getTileLayout()).thenReturn(mQQsTileLayout); 589 when(mQuickQSPanelController.getTileLayout()).thenReturn(mQsTileLayout); 590 when(mFooterActionsViewModelFactory.create(any())).thenReturn(mFooterActionsViewModel); 591 } 592 setUpMedia()593 private void setUpMedia() { 594 when(mQSMediaHost.getCurrentClipping()).thenReturn(new Rect()); 595 when(mQSMediaHost.getHostView()).thenReturn(new UniqueObjectHostView(mContext)); 596 when(mQQSMediaHost.getHostView()).thenReturn(new UniqueObjectHostView(mContext)); 597 } 598 setUpViews()599 private void setUpViews() { 600 mQsView = spy(new FrameLayout(mContext)); 601 when(mQsComponent.getRootView()).thenReturn(mQsView); 602 603 when(mQSPanelScrollView.findViewById(R.id.expanded_qs_scroll_view)) 604 .thenReturn(mQSPanelScrollView); 605 mQsView.addView(mQSPanelScrollView); 606 607 when(mHeader.findViewById(R.id.header)).thenReturn(mHeader); 608 mQsView.addView(mHeader); 609 610 View customizer = new View(mContext); 611 customizer.setId(android.R.id.edit); 612 mQsView.addView(customizer); 613 614 ComposeView footerActionsView = new ComposeView(mContext); 615 footerActionsView.setId(R.id.qs_footer_actions); 616 mQsView.addView(footerActionsView); 617 } 618 setUpInflater()619 private void setUpInflater() { 620 when(mLayoutInflater.cloneInContext(any(Context.class))).thenReturn(mLayoutInflater); 621 when(mLayoutInflater.inflate(anyInt(), nullable(ViewGroup.class), anyBoolean())) 622 .thenAnswer((invocation) -> mQsView); 623 when(mLayoutInflater.inflate(anyInt(), nullable(ViewGroup.class))) 624 .thenAnswer((invocation) -> mQsView); 625 mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE, mLayoutInflater); 626 } 627 setupQsComponent()628 private void setupQsComponent() { 629 when(mQsComponent.getQSPanelController()).thenReturn(mQSPanelController); 630 when(mQsComponent.getQuickQSPanelController()).thenReturn(mQuickQSPanelController); 631 when(mQsComponent.getQSCustomizerController()).thenReturn(mQsCustomizerController); 632 when(mQsComponent.getQSContainerImplController()) 633 .thenReturn(mQSContainerImplController); 634 when(mQsComponent.getQSFooter()).thenReturn(mFooter); 635 when(mQsComponent.getQSFooterActionController()) 636 .thenReturn(mQSFooterActionController); 637 when(mQsComponent.getQSAnimator()).thenReturn(mQSAnimator); 638 when(mQsComponent.getQSSquishinessController()).thenReturn(mSquishinessController); 639 } 640 setStatusBarCurrentAndUpcomingState(int statusBarState)641 private void setStatusBarCurrentAndUpcomingState(int statusBarState) { 642 when(mStatusBarStateController.getState()).thenReturn(statusBarState); 643 when(mStatusBarStateController.getCurrentOrUpcomingState()).thenReturn(statusBarState); 644 mUnderTest.onStateChanged(statusBarState); 645 } 646 enableSplitShade()647 private void enableSplitShade() { 648 setSplitShadeEnabled(true); 649 } 650 disableSplitShade()651 private void disableSplitShade() { 652 setSplitShadeEnabled(false); 653 } 654 setSplitShadeEnabled(boolean enabled)655 private void setSplitShadeEnabled(boolean enabled) { 656 mUnderTest.setInSplitShade(enabled); 657 } 658 setLocationOnScreen(View view, int top)659 private void setLocationOnScreen(View view, int top) { 660 doAnswer(invocation -> { 661 int[] locationOnScreen = invocation.getArgument(/* index= */ 0); 662 locationOnScreen[0] = 0; 663 locationOnScreen[1] = top; 664 return null; 665 }).when(view).getLocationOnScreen(any(int[].class)); 666 } 667 setIsLargeScreen()668 private void setIsLargeScreen() { 669 mUnderTest.setIsNotificationPanelFullWidth(false); 670 } 671 setIsSmallScreen()672 private void setIsSmallScreen() { 673 mUnderTest.setIsNotificationPanelFullWidth(true); 674 } 675 } 676