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