From cf36d22dad1bf62c5a3d57fa7a6c8730d9926c08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6llner?= Date: Mon, 28 Mar 2022 15:16:59 +0200 Subject: [PATCH] Fix and re-enable QSFragmentTest QSFragmentTest has been disabled for a long time, as it is failing. QSFragment is a crucial component of SysUI and should have tests. The fix was to make sure all dependencies are correctly set up. This also applied to the layout inflater and views. By default the code was inflating the real view, and some of the sub-views have dependencies that were not there. Fixes: 227167398 Test: QSFragmentTest passes Change-Id: I0a0a23c4e5b023d1178d9f96a561730051cd98aa --- .../com/android/systemui/qs/QSFragment.java | 12 +- .../android/systemui/qs/QSFragmentTest.java | 130 ++++++++++++------ 2 files changed, 96 insertions(+), 46 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java index 8d0494afbb897..c6a114e430380 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java @@ -262,9 +262,13 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca if (mListening) { setListening(false); } - mQSCustomizerController.setQs(null); + if (mQSCustomizerController != null) { + mQSCustomizerController.setQs(null); + } mScrollListener = null; - mDumpManager.unregisterDumpable(mContainer.getClass().getName()); + if (mContainer != null) { + mDumpManager.unregisterDumpable(mContainer.getClass().getName()); + } } @Override @@ -272,7 +276,9 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca super.onSaveInstanceState(outState); outState.putBoolean(EXTRA_EXPANDED, mQsExpanded); outState.putBoolean(EXTRA_LISTENING, mListening); - mQSCustomizerController.saveInstanceState(outState); + if (mQSCustomizerController != null) { + mQSCustomizerController.saveInstanceState(outState); + } if (mQsExpanded) { mQSPanelController.getTileLayout().saveInstanceState(outState); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java index 534c7e7f20298..def1d4183158d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -14,37 +14,37 @@ package com.android.systemui.qs; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.app.Fragment; import android.content.Context; +import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.testing.AndroidTestingRunner; -import android.testing.LayoutInflaterBuilder; -import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; +import android.view.LayoutInflater; import android.view.View; -import android.widget.FrameLayout; +import android.view.ViewGroup; import androidx.test.filters.SmallTest; -import androidx.test.filters.Suppress; -import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; -import com.android.keyguard.CarrierText; -import com.android.systemui.Dependency; +import com.android.systemui.R; import com.android.systemui.SysuiBaseFragmentTest; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; import com.android.systemui.media.MediaHost; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.qs.customize.QSCustomizerController; import com.android.systemui.qs.dagger.QSFragmentComponent; import com.android.systemui.qs.external.CustomTileStatePersister; import com.android.systemui.qs.external.TileLifecycleManager; @@ -55,18 +55,16 @@ import com.android.systemui.settings.UserTracker; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.AutoTileManager; -import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.CentralSurfaces; +import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.StatusBarIconController; -import com.android.systemui.statusbar.policy.Clock; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; -import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.tuner.TunerService; +import com.android.systemui.util.animation.UniqueObjectHostView; import com.android.systemui.util.settings.SecureSettings; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -75,12 +73,10 @@ import org.mockito.MockitoAnnotations; import java.util.Optional; @RunWith(AndroidTestingRunner.class) -@RunWithLooper +@RunWithLooper(setAsMainLooper = true) @SmallTest -@Suppress public class QSFragmentTest extends SysuiBaseFragmentTest { - private MetricsLogger mMockMetricsLogger; @Mock private QSFragmentComponent.Factory mQsComponentFactory; @Mock @@ -99,41 +95,41 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { private TileServiceRequestController.Builder mTileServiceRequestControllerBuilder; @Mock private TileServiceRequestController mTileServiceRequestController; + @Mock + private QSCustomizerController mQsCustomizerController; + @Mock + private QuickQSPanelController mQuickQSPanelController; + @Mock + private FooterActionsController mQSFooterActionController; + @Mock + private QSContainerImplController mQSContainerImplController; + @Mock + private QSContainerImpl mContainer; + @Mock + private QSFooter mFooter; + @Mock + private LayoutInflater mLayoutInflater; + @Mock + private NonInterceptingScrollView mQSPanelScrollView; + @Mock + private QuickStatusBarHeader mHeader; + @Mock + private QSPanel.QSTileLayout mQsTileLayout; + @Mock + private QSPanel.QSTileLayout mQQsTileLayout; + private View mQsFragmentView; public QSFragmentTest() { super(QSFragment.class); - injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES); } @Before - @Ignore("failing") - public void addLeakCheckDependencies() { - MockitoAnnotations.initMocks(this); - when(mQsComponentFactory.create(any(QSFragment.class))).thenReturn(mQsFragmentComponent); - when(mQsFragmentComponent.getQSPanelController()).thenReturn(mQSPanelController); - - when(mTileServiceRequestControllerBuilder.create(any())) - .thenReturn(mTileServiceRequestController); - - mMockMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class); - mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE, - new LayoutInflaterBuilder(mContext) - .replace("com.android.systemui.statusbar.policy.SplitClockView", - FrameLayout.class) - .replace("TextClock", View.class) - .replace(CarrierText.class, View.class) - .replace(Clock.class, View.class) - .build()); - - mDependency.injectTestDependency(Dependency.BG_LOOPER, - TestableLooper.get(this).getLooper()); - mDependency.injectMockDependency(UserSwitcherController.class); + public void setup() { + injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES); } @Test - @Ignore("failing") public void testListening() { - assertEquals(Looper.myLooper(), Looper.getMainLooper()); QSFragment qs = (QSFragment) mFragment; mFragments.dispatchResume(); processAllMessages(); @@ -157,13 +153,11 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { } @Test - @Ignore("failing") public void testSaveState() { - QSFragment qs = (QSFragment) mFragment; - mFragments.dispatchResume(); processAllMessages(); + QSFragment qs = (QSFragment) mFragment; qs.setListening(true); qs.setExpanded(true); processAllMessages(); @@ -178,7 +172,15 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { @Override protected Fragment instantiate(Context context, String className, Bundle arguments) { + MockitoAnnotations.initMocks(this); CommandQueue commandQueue = new CommandQueue(context); + + setupQsComponent(); + setUpViews(); + setUpInflater(); + setUpMedia(); + setUpOther(); + return new QSFragment( new RemoteInputQuickSettingsDisabler(context, commandQueue, mock(ConfigurationController.class)), @@ -193,4 +195,46 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { mFalsingManager, mock(DumpManager.class)); } + + private void setUpOther() { + when(mTileServiceRequestControllerBuilder.create(any())) + .thenReturn(mTileServiceRequestController); + when(mQSContainerImplController.getView()).thenReturn(mContainer); + when(mQSPanelController.getTileLayout()).thenReturn(mQQsTileLayout); + when(mQuickQSPanelController.getTileLayout()).thenReturn(mQsTileLayout); + } + + private void setUpMedia() { + when(mQSMediaHost.getCurrentClipping()).thenReturn(new Rect()); + when(mQSMediaHost.getHostView()).thenReturn(new UniqueObjectHostView(mContext)); + when(mQQSMediaHost.getHostView()).thenReturn(new UniqueObjectHostView(mContext)); + } + + private void setUpViews() { + mQsFragmentView = spy(new View(mContext)); + when(mQsFragmentView.findViewById(R.id.expanded_qs_scroll_view)).thenReturn( + mQSPanelScrollView); + when(mQsFragmentView.findViewById(R.id.header)).thenReturn(mHeader); + when(mQsFragmentView.findViewById(android.R.id.edit)).thenReturn(new View(mContext)); + } + + private void setUpInflater() { + when(mLayoutInflater.cloneInContext(any(Context.class))).thenReturn(mLayoutInflater); + when(mLayoutInflater.inflate(anyInt(), any(ViewGroup.class), anyBoolean())) + .thenReturn(mQsFragmentView); + mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE, + mLayoutInflater); + } + + private void setupQsComponent() { + when(mQsComponentFactory.create(any(QSFragment.class))).thenReturn(mQsFragmentComponent); + when(mQsFragmentComponent.getQSPanelController()).thenReturn(mQSPanelController); + when(mQsFragmentComponent.getQuickQSPanelController()).thenReturn(mQuickQSPanelController); + when(mQsFragmentComponent.getQSCustomizerController()).thenReturn(mQsCustomizerController); + when(mQsFragmentComponent.getQSContainerImplController()).thenReturn( + mQSContainerImplController); + when(mQsFragmentComponent.getQSFooter()).thenReturn(mFooter); + when(mQsFragmentComponent.getQSFooterActionController()).thenReturn( + mQSFooterActionController); + } }