blob: 37c8f6285970c22338dacc7ace5dc70bc1099313 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.android.systemui.statusbar.phone.fragment;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_IN;
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_OUT;
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.IDLE;
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.RUNNING_CHIP_ANIM;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.animation.Animator;
import android.app.Fragment;
import android.app.StatusBarManager;
import android.content.Context;
import android.os.Bundle;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.view.View;
import android.view.ViewPropertyAnimator;
import android.widget.FrameLayout;
import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiBaseFragmentTest;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.LogcatEchoTracker;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DisableFlagsLogger;
import com.android.systemui.statusbar.OperatorNameViewController;
import com.android.systemui.statusbar.connectivity.NetworkController;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarLocationPublisher;
import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.CarrierConfigTracker;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
@RunWithLooper(setAsMainLooper = true)
@SmallTest
public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
private NotificationIconAreaController mMockNotificationAreaController;
private View mNotificationAreaInner;
private OngoingCallController mOngoingCallController;
private SystemStatusAnimationScheduler mAnimationScheduler;
private StatusBarLocationPublisher mLocationPublisher;
// Set in instantiate()
private StatusBarIconController mStatusBarIconController;
private NetworkController mNetworkController;
private KeyguardStateController mKeyguardStateController;
private final CommandQueue mCommandQueue = mock(CommandQueue.class);
private OperatorNameViewController.Factory mOperatorNameViewControllerFactory;
private OperatorNameViewController mOperatorNameViewController;
private SecureSettings mSecureSettings;
private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
private final CarrierConfigTracker mCarrierConfigTracker = mock(CarrierConfigTracker.class);
@Mock
private StatusBarFragmentComponent.Factory mStatusBarFragmentComponentFactory;
@Mock
private StatusBarFragmentComponent mStatusBarFragmentComponent;
@Mock
private StatusBarStateController mStatusBarStateController;
@Mock
private HeadsUpAppearanceController mHeadsUpAppearanceController;
@Mock
private NotificationPanelViewController mNotificationPanelViewController;
@Mock
private StatusBarIconController.DarkIconManager.Factory mIconManagerFactory;
@Mock
private StatusBarIconController.DarkIconManager mIconManager;
@Mock
private StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager;
@Mock
private DumpManager mDumpManager;
public CollapsedStatusBarFragmentTest() {
super(CollapsedStatusBarFragment.class);
}
@Before
public void setup() {
injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
mDependency.injectMockDependency(DarkIconDispatcher.class);
}
@Test
public void testDisableNone() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
assertEquals(View.VISIBLE, getClockView().getVisibility());
}
@Test
public void testDisableSystemInfo_systemAnimationIdle_doesHide() {
when(mAnimationScheduler.getAnimationState()).thenReturn(IDLE);
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_SYSTEM_INFO, 0, false);
assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
}
@Test
public void testSystemStatusAnimation_startedDisabled_finishedWithAnimator_showsSystemInfo() {
// GIVEN the status bar hides the system info via disable flags, while there is no event
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mAnimationScheduler.getAnimationState()).thenReturn(IDLE);
fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_SYSTEM_INFO, 0, false);
assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
// WHEN the disable flags are cleared during a system event animation
when(mAnimationScheduler.getAnimationState()).thenReturn(RUNNING_CHIP_ANIM);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
// THEN the view is made visible again, but still low alpha
assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
assertEquals(0, getEndSideContentView().getAlpha(), 0.01);
// WHEN the system event animation finishes
when(mAnimationScheduler.getAnimationState()).thenReturn(ANIMATING_OUT);
Animator anim = fragment.onSystemEventAnimationFinish(false);
anim.start();
processAllMessages();
anim.end();
// THEN the system info is full alpha
assertEquals(1, getEndSideContentView().getAlpha(), 0.01);
}
@Test
public void testSystemStatusAnimation_systemInfoDisabled_staysInvisible() {
// GIVEN the status bar hides the system info via disable flags, while there is no event
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mAnimationScheduler.getAnimationState()).thenReturn(IDLE);
fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_SYSTEM_INFO, 0, false);
assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
// WHEN the system event animation finishes
when(mAnimationScheduler.getAnimationState()).thenReturn(ANIMATING_OUT);
Animator anim = fragment.onSystemEventAnimationFinish(false);
anim.start();
processAllMessages();
anim.end();
// THEN the system info is at full alpha, but still INVISIBLE (since the disable flag is
// still set)
assertEquals(1, getEndSideContentView().getAlpha(), 0.01);
assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
}
@Test
public void testSystemStatusAnimation_notDisabled_animatesAlphaZero() {
// GIVEN the status bar is not disabled
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mAnimationScheduler.getAnimationState()).thenReturn(ANIMATING_IN);
// WHEN the system event animation begins
Animator anim = fragment.onSystemEventAnimationBegin();
anim.start();
processAllMessages();
anim.end();
// THEN the system info is visible but alpha 0
assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
assertEquals(0, getEndSideContentView().getAlpha(), 0.01);
}
@Test
public void testSystemStatusAnimation_notDisabled_animatesBackToAlphaOne() {
// GIVEN the status bar is not disabled
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mAnimationScheduler.getAnimationState()).thenReturn(ANIMATING_IN);
// WHEN the system event animation begins
Animator anim = fragment.onSystemEventAnimationBegin();
anim.start();
processAllMessages();
anim.end();
// THEN the system info is visible but alpha 0
assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
assertEquals(0, getEndSideContentView().getAlpha(), 0.01);
// WHEN the system event animation finishes
when(mAnimationScheduler.getAnimationState()).thenReturn(ANIMATING_OUT);
anim = fragment.onSystemEventAnimationFinish(false);
anim.start();
processAllMessages();
anim.end();
// THEN the syste info is full alpha and VISIBLE
assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
assertEquals(1, getEndSideContentView().getAlpha(), 0.01);
}
@Test
public void testDisableNotifications() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.INVISIBLE));
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.VISIBLE));
}
@Test
public void testDisableClock() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_CLOCK, 0, false);
assertEquals(View.GONE, getClockView().getVisibility());
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.VISIBLE, getClockView().getVisibility());
}
@Test
public void disable_noOngoingCall_chipHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mOngoingCallController.hasOngoingCall()).thenReturn(false);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.GONE,
mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
}
@Test
public void disable_hasOngoingCall_chipDisplayedAndNotificationIconsHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.VISIBLE,
mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.INVISIBLE));
}
@Test
public void disable_hasOngoingCallButNotificationIconsDisabled_chipHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
fragment.disable(DEFAULT_DISPLAY,
StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
assertEquals(View.GONE,
mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
}
@Test
public void disable_ongoingCallEnded_chipHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
// Ongoing call started
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.VISIBLE,
mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
// Ongoing call ended
when(mOngoingCallController.hasOngoingCall()).thenReturn(false);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.GONE,
mFragment.getView().findViewById(R.id.ongoing_call_chip).getVisibility());
}
@Test
public void disable_isDozing_clockAndSystemInfoVisible() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mStatusBarStateController.isDozing()).thenReturn(true);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
assertEquals(View.VISIBLE, getClockView().getVisibility());
}
@Test
public void disable_NotDozing_clockAndSystemInfoVisible() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mStatusBarStateController.isDozing()).thenReturn(false);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
assertEquals(View.VISIBLE, getClockView().getVisibility());
}
@Test
public void disable_headsUpShouldBeVisibleTrue_clockDisabled() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mHeadsUpAppearanceController.shouldBeVisible()).thenReturn(true);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.GONE, getClockView().getVisibility());
}
@Test
public void disable_headsUpShouldBeVisibleFalse_clockNotDisabled() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mHeadsUpAppearanceController.shouldBeVisible()).thenReturn(false);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.VISIBLE, getClockView().getVisibility());
}
@Test
public void setUp_fragmentCreatesDaggerComponent() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
assertEquals(mStatusBarFragmentComponent, fragment.getStatusBarFragmentComponent());
}
@Test
public void testBlockedIcons_obeysSettingForVibrateIcon_settingOff() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
String str = mContext.getString(com.android.internal.R.string.status_bar_volume);
// GIVEN the setting is off
when(mSecureSettings.getInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0))
.thenReturn(0);
// WHEN CollapsedStatusBarFragment builds the blocklist
fragment.updateBlockedIcons();
// THEN status_bar_volume SHOULD be present in the list
boolean contains = fragment.getBlockedIcons().contains(str);
assertTrue(contains);
}
@Test
public void testBlockedIcons_obeysSettingForVibrateIcon_settingOn() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
String str = mContext.getString(com.android.internal.R.string.status_bar_volume);
// GIVEN the setting is ON
when(mSecureSettings.getIntForUser(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0,
UserHandle.USER_CURRENT))
.thenReturn(1);
// WHEN CollapsedStatusBarFragment builds the blocklist
fragment.updateBlockedIcons();
// THEN status_bar_volume SHOULD NOT be present in the list
boolean contains = fragment.getBlockedIcons().contains(str);
assertFalse(contains);
}
@Override
protected Fragment instantiate(Context context, String className, Bundle arguments) {
MockitoAnnotations.initMocks(this);
setUpDaggerComponent();
mOngoingCallController = mock(OngoingCallController.class);
mAnimationScheduler = mock(SystemStatusAnimationScheduler.class);
mLocationPublisher = mock(StatusBarLocationPublisher.class);
mStatusBarIconController = mock(StatusBarIconController.class);
mNetworkController = mock(NetworkController.class);
mStatusBarStateController = mock(StatusBarStateController.class);
mKeyguardStateController = mock(KeyguardStateController.class);
mOperatorNameViewController = mock(OperatorNameViewController.class);
mOperatorNameViewControllerFactory = mock(OperatorNameViewController.Factory.class);
when(mOperatorNameViewControllerFactory.create(any()))
.thenReturn(mOperatorNameViewController);
when(mIconManagerFactory.create(any())).thenReturn(mIconManager);
mSecureSettings = mock(SecureSettings.class);
setUpNotificationIconAreaController();
return new CollapsedStatusBarFragment(
mStatusBarFragmentComponentFactory,
mOngoingCallController,
mAnimationScheduler,
mLocationPublisher,
mMockNotificationAreaController,
new PanelExpansionStateManager(),
mock(FeatureFlags.class),
mStatusBarIconController,
mIconManagerFactory,
mStatusBarHideIconsForBouncerManager,
mKeyguardStateController,
mNotificationPanelViewController,
mNetworkController,
mStatusBarStateController,
mCommandQueue,
mCarrierConfigTracker,
new CollapsedStatusBarFragmentLogger(
new LogBuffer("TEST", 1, mock(LogcatEchoTracker.class)),
new DisableFlagsLogger()
),
mOperatorNameViewControllerFactory,
mSecureSettings,
mExecutor,
mDumpManager);
}
private void setUpDaggerComponent() {
when(mStatusBarFragmentComponentFactory.create(any()))
.thenReturn(mStatusBarFragmentComponent);
when(mStatusBarFragmentComponent.getHeadsUpAppearanceController())
.thenReturn(mHeadsUpAppearanceController);
}
private void setUpNotificationIconAreaController() {
mMockNotificationAreaController = mock(NotificationIconAreaController.class);
mNotificationAreaInner = mock(View.class);
when(mNotificationAreaInner.getLayoutParams()).thenReturn(
new FrameLayout.LayoutParams(100, 100));
when(mNotificationAreaInner.animate()).thenReturn(mock(ViewPropertyAnimator.class));
when(mMockNotificationAreaController.getNotificationInnerAreaView()).thenReturn(
mNotificationAreaInner);
}
private CollapsedStatusBarFragment resumeAndGetFragment() {
mFragments.dispatchResume();
processAllMessages();
return (CollapsedStatusBarFragment) mFragment;
}
private View getClockView() {
return mFragment.getView().findViewById(R.id.clock);
}
private View getEndSideContentView() {
return mFragment.getView().findViewById(R.id.status_bar_end_side_content);
}
}