blob: 8d05e6693e3348be53332a604894c6e46082e385 [file] [log] [blame]
/*
* Copyright (C) 2021 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;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.LayoutInflater;
import android.view.View;
import androidx.test.filters.SmallTest;
import com.android.keyguard.CarrierTextController;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.battery.BatteryMeterViewController;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserInfoController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
@Mock
private CarrierTextController mCarrierTextController;
@Mock
private ConfigurationController mConfigurationController;
@Mock
private SystemStatusAnimationScheduler mAnimationScheduler;
@Mock
private BatteryController mBatteryController;
@Mock
private UserInfoController mUserInfoController;
@Mock
private StatusBarIconController mStatusBarIconController;
@Mock
private FeatureFlags mFeatureFlags;
@Mock
private BatteryMeterViewController mBatteryMeterViewController;
@Mock
private KeyguardStateController mKeyguardStateController;
@Mock
private KeyguardBypassController mKeyguardBypassController;
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
private BiometricUnlockController mBiometricUnlockController;
@Mock
private SysuiStatusBarStateController mStatusBarStateController;
@Mock
private StatusBarContentInsetsProvider mStatusBarContentInsetsProvider;
private TestNotificationPanelViewStateProvider mNotificationPanelViewStateProvider;
private KeyguardStatusBarView mKeyguardStatusBarView;
private KeyguardStatusBarViewController mController;
@Before
public void setup() throws Exception {
mNotificationPanelViewStateProvider = new TestNotificationPanelViewStateProvider();
MockitoAnnotations.initMocks(this);
allowTestableLooperAsMainThread();
TestableLooper.get(this).runWithLooper(() -> {
mKeyguardStatusBarView =
(KeyguardStatusBarView) LayoutInflater.from(mContext)
.inflate(R.layout.keyguard_status_bar, null);
});
mController = new KeyguardStatusBarViewController(
mKeyguardStatusBarView,
mCarrierTextController,
mConfigurationController,
mAnimationScheduler,
mBatteryController,
mUserInfoController,
mStatusBarIconController,
new StatusBarIconController.TintedIconManager.Factory(mFeatureFlags),
mBatteryMeterViewController,
mNotificationPanelViewStateProvider,
mKeyguardStateController,
mKeyguardBypassController,
mKeyguardUpdateMonitor,
mBiometricUnlockController,
mStatusBarStateController,
mStatusBarContentInsetsProvider
);
}
@Test
public void onViewAttached_callbacksRegistered() {
mController.onViewAttached();
verify(mConfigurationController).addCallback(any());
verify(mAnimationScheduler).addCallback(any());
verify(mUserInfoController).addCallback(any());
verify(mStatusBarIconController).addIconGroup(any());
}
@Test
public void onViewDetached_callbacksUnregistered() {
// Set everything up first.
mController.onViewAttached();
mController.onViewDetached();
verify(mConfigurationController).removeCallback(any());
verify(mAnimationScheduler).removeCallback(any());
verify(mUserInfoController).removeCallback(any());
verify(mStatusBarIconController).removeIconGroup(any());
}
@Test
public void setBatteryListening_true_callbackAdded() {
mController.setBatteryListening(true);
verify(mBatteryController).addCallback(any());
}
@Test
public void setBatteryListening_false_callbackRemoved() {
// First set to true so that we know setting to false is a change in state.
mController.setBatteryListening(true);
mController.setBatteryListening(false);
verify(mBatteryController).removeCallback(any());
}
@Test
public void setBatteryListening_trueThenTrue_callbackAddedOnce() {
mController.setBatteryListening(true);
mController.setBatteryListening(true);
verify(mBatteryController).addCallback(any());
}
@Test
public void updateTopClipping_viewClippingUpdated() {
int viewTop = 20;
mKeyguardStatusBarView.setTop(viewTop);
int notificationPanelTop = 30;
mController.updateTopClipping(notificationPanelTop);
assertThat(mKeyguardStatusBarView.getClipBounds().top).isEqualTo(
notificationPanelTop - viewTop);
}
@Test
public void setNotTopClipping_viewClippingUpdatedToZero() {
// Start out with some amount of top clipping.
mController.updateTopClipping(50);
assertThat(mKeyguardStatusBarView.getClipBounds().top).isGreaterThan(0);
mController.setNoTopClipping();
assertThat(mKeyguardStatusBarView.getClipBounds().top).isEqualTo(0);
}
@Test
public void updateViewState_alphaAndVisibilityGiven_viewUpdated() {
// Verify the initial values so we know the method triggers changes.
assertThat(mKeyguardStatusBarView.getAlpha()).isEqualTo(1f);
assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE);
float newAlpha = 0.5f;
int newVisibility = View.INVISIBLE;
mController.updateViewState(newAlpha, newVisibility);
assertThat(mKeyguardStatusBarView.getAlpha()).isEqualTo(newAlpha);
assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(newVisibility);
}
@Test
public void updateViewState_notKeyguardState_nothingUpdated() {
mController.onViewAttached();
updateStateToNotKeyguard();
float oldAlpha = mKeyguardStatusBarView.getAlpha();
mController.updateViewState();
assertThat(mKeyguardStatusBarView.getAlpha()).isEqualTo(oldAlpha);
}
@Test
public void updateViewState_bypassEnabledAndShouldListenForFace_viewHidden() {
mController.onViewAttached();
updateStateToKeyguard();
assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE);
when(mKeyguardUpdateMonitor.shouldListenForFace()).thenReturn(true);
when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
onFinishedGoingToSleep();
mController.updateViewState();
assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE);
}
@Test
public void updateViewState_bypassNotEnabled_viewShown() {
mController.onViewAttached();
updateStateToKeyguard();
when(mKeyguardUpdateMonitor.shouldListenForFace()).thenReturn(true);
when(mKeyguardBypassController.getBypassEnabled()).thenReturn(false);
onFinishedGoingToSleep();
mController.updateViewState();
assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
public void updateViewState_shouldNotListenForFace_viewShown() {
mController.onViewAttached();
updateStateToKeyguard();
when(mKeyguardUpdateMonitor.shouldListenForFace()).thenReturn(false);
when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
onFinishedGoingToSleep();
mController.updateViewState();
assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
public void updateViewState_panelExpandedHeightZero_viewHidden() {
mController.onViewAttached();
updateStateToKeyguard();
mNotificationPanelViewStateProvider.setPanelViewExpandedHeight(0);
mController.updateViewState();
assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE);
}
@Test
public void updateViewState_qsExpansionOne_viewHidden() {
mController.onViewAttached();
updateStateToKeyguard();
mNotificationPanelViewStateProvider.setQsExpansionFraction(1f);
mController.updateViewState();
assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE);
}
// TODO(b/195442899): Add more tests for #updateViewState once CLs are finalized.
@Test
public void updateForHeadsUp_headsUpShouldBeVisible_viewHidden() {
mController.onViewAttached();
updateStateToKeyguard();
mKeyguardStatusBarView.setVisibility(View.VISIBLE);
mNotificationPanelViewStateProvider.setShouldHeadsUpBeVisible(true);
mController.updateForHeadsUp(/* animate= */ false);
assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE);
}
@Test
public void updateForHeadsUp_headsUpShouldNotBeVisible_viewShown() {
mController.onViewAttached();
updateStateToKeyguard();
// Start with the opposite state.
mNotificationPanelViewStateProvider.setShouldHeadsUpBeVisible(true);
mController.updateForHeadsUp(/* animate= */ false);
mNotificationPanelViewStateProvider.setShouldHeadsUpBeVisible(false);
mController.updateForHeadsUp(/* animate= */ false);
assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE);
}
private void updateStateToNotKeyguard() {
updateStatusBarState(SHADE);
}
private void updateStateToKeyguard() {
updateStatusBarState(KEYGUARD);
}
private void updateStatusBarState(int state) {
ArgumentCaptor<StatusBarStateController.StateListener> statusBarStateListenerCaptor =
ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
verify(mStatusBarStateController).addCallback(statusBarStateListenerCaptor.capture());
StatusBarStateController.StateListener callback = statusBarStateListenerCaptor.getValue();
callback.onStateChanged(state);
}
/**
* Calls {@link com.android.keyguard.KeyguardUpdateMonitorCallback#onFinishedGoingToSleep(int)}
* to ensure values are updated properly.
*/
private void onFinishedGoingToSleep() {
ArgumentCaptor<KeyguardUpdateMonitorCallback> keyguardUpdateCallbackCaptor =
ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
verify(mKeyguardUpdateMonitor).registerCallback(keyguardUpdateCallbackCaptor.capture());
KeyguardUpdateMonitorCallback callback = keyguardUpdateCallbackCaptor.getValue();
callback.onFinishedGoingToSleep(0);
}
private static class TestNotificationPanelViewStateProvider
implements NotificationPanelViewController.NotificationPanelViewStateProvider {
TestNotificationPanelViewStateProvider() {}
private float mPanelViewExpandedHeight = 100f;
private float mQsExpansionFraction = 0f;
private boolean mShouldHeadsUpBeVisible = false;
@Override
public float getPanelViewExpandedHeight() {
return mPanelViewExpandedHeight;
}
@Override
public float getQsExpansionFraction() {
return mQsExpansionFraction;
}
@Override
public boolean shouldHeadsUpBeVisible() {
return mShouldHeadsUpBeVisible;
}
public void setPanelViewExpandedHeight(float panelViewExpandedHeight) {
this.mPanelViewExpandedHeight = panelViewExpandedHeight;
}
public void setQsExpansionFraction(float qsExpansionFraction) {
this.mQsExpansionFraction = qsExpansionFraction;
}
public void setShouldHeadsUpBeVisible(boolean shouldHeadsUpBeVisible) {
this.mShouldHeadsUpBeVisible = shouldHeadsUpBeVisible;
}
}
}