blob: faef8706908418e6431165b08ee9a4543ebca68a [file] [log] [blame]
/*
* Copyright (C) 2020 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.qs;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QSTileView;
import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.util.animation.DisappearParameters;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collections;
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@SmallTest
public class QSPanelControllerBaseTest extends SysuiTestCase {
@Mock
private QSPanel mQSPanel;
@Mock
private QSTileHost mQSTileHost;
@Mock
private QSCustomizerController mQSCustomizerController;
@Mock
private QSTileRevealController.Factory mQSTileRevealControllerFactory;
@Mock
private QSTileRevealController mQSTileRevealController;
@Mock
private MediaHost mMediaHost;
@Mock
private MetricsLogger mMetricsLogger;
private UiEventLoggerFake mUiEventLogger = new UiEventLoggerFake();
@Mock
private QSLogger mQSLogger;
private DumpManager mDumpManager = new DumpManager();
@Mock
QSTileImpl mQSTile;
@Mock
QSTileView mQSTileView;
@Mock
PagedTileLayout mPagedTileLayout;
@Mock
FeatureFlags mFeatureFlags;
@Mock
Resources mResources;
@Mock
Configuration mConfiguration;
@Mock
Runnable mHorizontalLayoutListener;
private QSPanelControllerBase<QSPanel> mController;
/** Implementation needed to ensure we have a reflectively-available class name. */
private class TestableQSPanelControllerBase extends QSPanelControllerBase<QSPanel> {
protected TestableQSPanelControllerBase(QSPanel view, QSTileHost host,
QSCustomizerController qsCustomizerController, MediaHost mediaHost,
MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
DumpManager dumpManager, FeatureFlags featureFlags) {
super(view, host, qsCustomizerController, true, mediaHost, metricsLogger, uiEventLogger,
qsLogger, dumpManager, featureFlags);
}
@Override
protected QSTileRevealController createTileRevealController() {
return mQSTileRevealController;
}
}
@Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
when(mQSPanel.isAttachedToWindow()).thenReturn(true);
when(mQSPanel.getDumpableTag()).thenReturn("QSPanel");
when(mQSPanel.openPanelEvent()).thenReturn(QSEvent.QS_PANEL_EXPANDED);
when(mQSPanel.closePanelEvent()).thenReturn(QSEvent.QS_PANEL_COLLAPSED);
when(mQSPanel.getOrCreateTileLayout()).thenReturn(mPagedTileLayout);
when(mQSPanel.getTileLayout()).thenReturn(mPagedTileLayout);
when(mQSTile.getTileSpec()).thenReturn("dnd");
when(mQSTileHost.getTiles()).thenReturn(Collections.singleton(mQSTile));
when(mQSTileHost.createTileView(any(), eq(mQSTile), anyBoolean())).thenReturn(mQSTileView);
when(mQSTileRevealControllerFactory.create(any(), any()))
.thenReturn(mQSTileRevealController);
when(mMediaHost.getDisappearParameters()).thenReturn(new DisappearParameters());
when(mQSPanel.getResources()).thenReturn(mResources);
when(mResources.getConfiguration()).thenReturn(mConfiguration);
mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
mQSCustomizerController, mMediaHost,
mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mFeatureFlags);
mController.init();
reset(mQSTileRevealController);
}
@Test
public void testSetRevealExpansion_preAttach() {
mController.onViewDetached();
QSPanelControllerBase<QSPanel> controller = new TestableQSPanelControllerBase(mQSPanel,
mQSTileHost, mQSCustomizerController, mMediaHost,
mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mFeatureFlags) {
@Override
protected QSTileRevealController createTileRevealController() {
return mQSTileRevealController;
}
};
// Nothing happens until attached
controller.setRevealExpansion(0);
verify(mQSTileRevealController, never()).setExpansion(anyFloat());
controller.setRevealExpansion(0.5f);
verify(mQSTileRevealController, never()).setExpansion(anyFloat());
controller.setRevealExpansion(1);
verify(mQSTileRevealController, never()).setExpansion(anyFloat());
controller.init();
verify(mQSTileRevealController).setExpansion(1);
}
@Test
public void testSetRevealExpansion_postAttach() {
mController.setRevealExpansion(0);
verify(mQSTileRevealController).setExpansion(0);
mController.setRevealExpansion(0.5f);
verify(mQSTileRevealController).setExpansion(0.5f);
mController.setRevealExpansion(1);
verify(mQSTileRevealController).setExpansion(1);
}
@Test
public void testSetExpanded_Metrics() {
when(mQSPanel.isExpanded()).thenReturn(false);
mController.setExpanded(true);
verify(mMetricsLogger).visibility(eq(MetricsEvent.QS_PANEL), eq(true));
verify(mQSLogger).logPanelExpanded(true, mQSPanel.getDumpableTag());
assertEquals(1, mUiEventLogger.numLogs());
assertEquals(QSEvent.QS_PANEL_EXPANDED.getId(), mUiEventLogger.eventId(0));
mUiEventLogger.getLogs().clear();
when(mQSPanel.isExpanded()).thenReturn(true);
mController.setExpanded(false);
verify(mMetricsLogger).visibility(eq(MetricsEvent.QS_PANEL), eq(false));
verify(mQSLogger).logPanelExpanded(false, mQSPanel.getDumpableTag());
assertEquals(1, mUiEventLogger.numLogs());
assertEquals(QSEvent.QS_PANEL_COLLAPSED.getId(), mUiEventLogger.eventId(0));
mUiEventLogger.getLogs().clear();
}
@Test
public void testDump() {
String mockTileViewString = "Mock Tile View";
String mockTileString = "Mock Tile";
doAnswer(invocation -> {
PrintWriter pw = invocation.getArgument(1);
pw.println(mockTileString);
return null;
}).when(mQSTile).dump(any(FileDescriptor.class), any(PrintWriter.class),
any(String[].class));
when(mQSTileView.toString()).thenReturn(mockTileViewString);
StringWriter w = new StringWriter();
PrintWriter pw = new PrintWriter(w);
mController.dump(mock(FileDescriptor.class), pw, new String[]{});
String expected = "TestableQSPanelControllerBase:\n"
+ " Tile records:\n"
+ " " + mockTileString + "\n"
+ " " + mockTileViewString + "\n";
assertEquals(expected, w.getBuffer().toString());
}
@Test
public void setListening() {
mController.setListening(true);
verify(mQSLogger).logAllTilesChangeListening(true, "QSPanel", "dnd");
verify(mPagedTileLayout).setListening(true, mUiEventLogger);
mController.setListening(false);
verify(mQSLogger).logAllTilesChangeListening(false, "QSPanel", "dnd");
verify(mPagedTileLayout).setListening(false, mUiEventLogger);
}
@Test
public void testShouldUzeHorizontalLayout_falseForSplitShade() {
mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE;
when(mMediaHost.getVisible()).thenReturn(true);
when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(false);
when(mQSPanel.getDumpableTag()).thenReturn("QSPanelLandscape");
mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
mQSCustomizerController, mMediaHost,
mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mFeatureFlags);
mController.init();
assertThat(mController.shouldUseHorizontalLayout()).isTrue();
when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(true);
when(mResources.getBoolean(R.bool.config_use_split_notification_shade)).thenReturn(true);
when(mQSPanel.getDumpableTag()).thenReturn("QSPanelPortrait");
mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
mQSCustomizerController, mMediaHost,
mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mFeatureFlags);
mController.init();
assertThat(mController.shouldUseHorizontalLayout()).isFalse();
}
@Test
public void testChangeConfiguration_shouldUseHorizontalLayout() {
when(mMediaHost.getVisible()).thenReturn(true);
mController.setUsingHorizontalLayoutChangeListener(mHorizontalLayoutListener);
// When device is rotated to landscape
mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE;
mController.mOnConfigurationChangedListener.onConfigurationChange(mConfiguration);
// Then the layout changes
assertThat(mController.shouldUseHorizontalLayout()).isTrue();
verify(mHorizontalLayoutListener).run(); // not invoked
// When it is rotated back to portrait
mConfiguration.orientation = Configuration.ORIENTATION_PORTRAIT;
mController.mOnConfigurationChangedListener.onConfigurationChange(mConfiguration);
// Then the layout changes back
assertThat(mController.shouldUseHorizontalLayout()).isFalse();
verify(mHorizontalLayoutListener, times(2)).run();
}
}