diff options
author | 2020-10-20 13:30:41 +0000 | |
---|---|---|
committer | 2020-10-20 13:30:41 +0000 | |
commit | f4c81035208d3f8e7798b84fb48daedd480de680 (patch) | |
tree | 372b5447d5e2c2cea0527964d3763fc2118d1944 | |
parent | ae31181f133dba251225d95169d95ee1574599af (diff) | |
parent | 3834b11c62b2b396b4516480408373379b7889c5 (diff) |
Merge changes from topic "b168904199-qs-injection"
* changes:
5/N Move QS Tile tracking logic into QSPanelControllerBase.
4/N Add QSPanelControllerBase
3/N Remove UserTracker from QSPanel
2/N Remove BroadcastDispatcher from QSPanel
1/N Add QSFragmentComponent
31 files changed, 1224 insertions, 613 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardRootViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardRootViewController.java index 5c125fcc95cb..4e375c2d1227 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardRootViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardRootViewController.java @@ -19,7 +19,7 @@ package com.android.keyguard; import android.view.ViewGroup; import com.android.keyguard.dagger.KeyguardBouncerScope; -import com.android.keyguard.dagger.RootView; +import com.android.systemui.dagger.qualifiers.RootView; import com.android.systemui.statusbar.phone.KeyguardBouncer; import com.android.systemui.util.ViewController; diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java index 881108858b51..4fad9a916d0d 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java @@ -24,6 +24,7 @@ import com.android.keyguard.KeyguardMessageArea; import com.android.keyguard.KeyguardSecurityContainer; import com.android.keyguard.KeyguardSecurityViewFlipper; import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.RootView; import com.android.systemui.statusbar.phone.KeyguardBouncer; import dagger.Module; diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/RootView.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/RootView.java index 5ebff097604b..e6c46c07fff8 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/RootView.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/RootView.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.keyguard.dagger; +package com.android.systemui.dagger.qualifiers; import static java.lang.annotation.RetentionPolicy.RUNTIME; diff --git a/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt index dc157a8dd257..81076475c5ce 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt @@ -33,7 +33,7 @@ class DoubleLineTileLayout( private const val NUM_LINES = 2 } - protected val mRecords = ArrayList<QSPanel.TileRecord>() + protected val mRecords = ArrayList<QSPanelControllerBase.TileRecord>() private var _listening = false private var smallTileSize = 0 private val twoLineHeight @@ -50,17 +50,17 @@ class DoubleLineTileLayout( updateResources() } - override fun addTile(tile: QSPanel.TileRecord) { + override fun addTile(tile: QSPanelControllerBase.TileRecord) { mRecords.add(tile) tile.tile.setListening(this, _listening) addTileView(tile) } - protected fun addTileView(tile: QSPanel.TileRecord) { + protected fun addTileView(tile: QSPanelControllerBase.TileRecord) { addView(tile.tileView) } - override fun removeTile(tile: QSPanel.TileRecord) { + override fun removeTile(tile: QSPanelControllerBase.TileRecord) { mRecords.remove(tile) tile.tile.setListening(this, false) removeView(tile.tileView) @@ -72,7 +72,7 @@ class DoubleLineTileLayout( super.removeAllViews() } - override fun getOffsetTop(tile: QSPanel.TileRecord?) = top + override fun getOffsetTop(tile: QSPanelControllerBase.TileRecord?) = top override fun updateResources(): Boolean { with(mContext.resources) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java index 04f379ef35ea..3062a77bcbe1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java @@ -26,7 +26,7 @@ import com.android.internal.logging.UiEventLogger; import com.android.systemui.R; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.qs.QSPanel.QSTileLayout; -import com.android.systemui.qs.QSPanel.TileRecord; +import com.android.systemui.qs.QSPanelControllerBase.TileRecord; import java.util.ArrayList; import java.util.Set; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java index 9dcc924f161e..4d4195063227 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java @@ -28,12 +28,17 @@ import com.android.systemui.qs.QSHost.Callback; import com.android.systemui.qs.QSPanel.QSTileLayout; import com.android.systemui.qs.TouchAnimator.Builder; import com.android.systemui.qs.TouchAnimator.Listener; +import com.android.systemui.qs.dagger.QSScope; import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; import java.util.ArrayList; import java.util.Collection; +import javax.inject.Inject; + +/** */ +@QSScope public class QSAnimator implements Callback, PageListener, Listener, OnLayoutChangeListener, OnAttachStateChangeListener, Tunable { @@ -53,6 +58,9 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha private final ArrayList<View> mQuickQsViews = new ArrayList<>(); private final QuickQSPanel mQuickQsPanel; private final QSPanel mQsPanel; + private final QSPanelController mQsPanelController; + private final QuickQSPanelController mQuickQSPanelController; + private final QSSecurityFooter mSecurityFooter; private final QS mQs; private PagedTileLayout mPagedLayout; @@ -78,10 +86,19 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha private QSTileHost mHost; private boolean mShowCollapsedOnKeyguard; - public QSAnimator(QS qs, QuickQSPanel quickPanel, QSPanel panel) { + @Inject + public QSAnimator(QS qs, QuickQSPanel quickPanel, QSPanel panel, + QSPanelController qsPanelController, QuickQSPanelController quickQSPanelController, + QSTileHost qsTileHost, + QSSecurityFooter securityFooter) { mQs = qs; mQuickQsPanel = quickPanel; mQsPanel = panel; + mQsPanelController = qsPanelController; + mQuickQSPanelController = quickQSPanelController; + mSecurityFooter = securityFooter; + mHost = qsTileHost; + mHost.addCallback(this); mQsPanel.addOnAttachStateChangeListener(this); qs.getView().addOnLayoutChangeListener(this); if (mQsPanel.isAttachedToWindow()) { @@ -134,12 +151,6 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha && !mShowCollapsedOnKeyguard ? View.INVISIBLE : View.VISIBLE); } - public void setHost(QSTileHost qsh) { - mHost = qsh; - qsh.addCallback(this); - updateAnimators(); - } - @Override public void onViewAttachedToWindow(View v) { Dependency.get(TunerService.class).addTunable(this, ALLOW_FANCY_ANIMATION, @@ -148,9 +159,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha @Override public void onViewDetachedFromWindow(View v) { - if (mHost != null) { - mHost.removeCallback(this); - } + mHost.removeCallback(this); Dependency.get(TunerService.class).removeTunable(this); } @@ -185,8 +194,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha TouchAnimator.Builder translationXBuilder = new Builder(); TouchAnimator.Builder translationYBuilder = new Builder(); - if (mQsPanel.getHost() == null) return; - Collection<QSTile> tiles = mQsPanel.getHost().getTiles(); + Collection<QSTile> tiles = mHost.getTiles(); int count = 0; int[] loc1 = new int[2]; int[] loc2 = new int[2]; @@ -206,7 +214,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha firstPageBuilder.addFloat(tileLayout, "translationY", heightDiff, 0); for (QSTile tile : tiles) { - QSTileView tileView = mQsPanel.getTileView(tile); + QSTileView tileView = mQsPanelController.getTileView(tile); if (tileView == null) { Log.e(TAG, "tileView is null " + tile.getTileSpec()); continue; @@ -217,7 +225,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha // This case: less tiles to animate in small displays. if (count < mQuickQsPanel.getTileLayout().getNumVisibleTiles() && mAllowFancy) { // Quick tiles. - QSTileView quickTileView = mQuickQsPanel.getTileView(tile); + QSTileView quickTileView = mQuickQSPanelController.getTileView(tile); if (quickTileView == null) continue; lastX = loc1[0]; @@ -302,16 +310,12 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha // Fade in the security footer and the divider as we reach the final position builder = new Builder().setStartDelay(EXPANDED_TILE_DELAY); - if (mQsPanel.getSecurityFooter() != null) { - builder.addFloat(mQsPanel.getSecurityFooter().getView(), "alpha", 0, 1); - } + builder.addFloat(mSecurityFooter.getView(), "alpha", 0, 1); if (mQsPanel.getDivider() != null) { builder.addFloat(mQsPanel.getDivider(), "alpha", 0, 1); } mAllPagesDelayedAnimator = builder.build(); - if (mQsPanel.getSecurityFooter() != null) { - mAllViews.add(mQsPanel.getSecurityFooter().getView()); - } + mAllViews.add(mSecurityFooter.getView()); if (mQsPanel.getDivider() != null) { mAllViews.add(mQsPanel.getDivider()); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java index 1e239b1e9ec9..acead987a06a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java @@ -16,19 +16,21 @@ package com.android.systemui.qs; -import com.android.systemui.R; +import com.android.systemui.qs.dagger.QSScope; import com.android.systemui.util.ViewController; import javax.inject.Inject; -class QSContainerImplController extends ViewController<QSContainerImpl> { +/** */ +@QSScope +public class QSContainerImplController extends ViewController<QSContainerImpl> { private final QuickStatusBarHeaderController mQuickStatusBarHeaderController; - private QSContainerImplController(QSContainerImpl view, - QuickStatusBarHeaderController.Builder quickStatusBarHeaderControllerBuilder) { + @Inject + QSContainerImplController(QSContainerImpl view, + QuickStatusBarHeaderController quickStatusBarHeaderController) { super(view); - mQuickStatusBarHeaderController = quickStatusBarHeaderControllerBuilder - .setQuickStatusBarHeader(mView.findViewById(R.id.header)).build(); + mQuickStatusBarHeaderController = quickStatusBarHeaderController; } @Override @@ -49,23 +51,7 @@ class QSContainerImplController extends ViewController<QSContainerImpl> { protected void onViewDetached() { } - static class Builder { - private final QuickStatusBarHeaderController.Builder mQuickStatusBarHeaderControllerBuilder; - private QSContainerImpl mView; - - @Inject - Builder( - QuickStatusBarHeaderController.Builder quickStatusBarHeaderControllerBuilder) { - mQuickStatusBarHeaderControllerBuilder = quickStatusBarHeaderControllerBuilder; - } - - public Builder setQSContainerImpl(QSContainerImpl view) { - mView = view; - return this; - } - - public QSContainerImplController build() { - return new QSContainerImplController(mView, mQuickStatusBarHeaderControllerBuilder); - } + public QSContainerImpl getView() { + return mView; } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java index 3a783653a2d8..4ea600ab5e25 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java @@ -35,11 +35,11 @@ import androidx.annotation.VisibleForTesting; import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.R.id; import com.android.systemui.media.MediaHost; import com.android.systemui.plugins.qs.QS; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.customize.QSCustomizer; +import com.android.systemui.qs.dagger.QSFragmentComponent; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; @@ -70,7 +70,6 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca private HeightListener mPanelView; protected QuickStatusBarHeader mHeader; private QSCustomizer mQSCustomizer; - protected QSPanel mQSPanel; protected NonInterceptingScrollView mQSPanelScrollView; private QSDetail mQSDetail; private boolean mListening; @@ -82,7 +81,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler; private final InjectionInflationController mInjectionInflater; - private final QSContainerImplController.Builder mQSContainerImplControllerBuilder; + private final QSFragmentComponent.Factory mQsComponentFactory; private final QSTileHost mHost; private boolean mShowCollapsedOnKeyguard; private boolean mLastKeyguardAndExpanded; @@ -96,15 +95,17 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca private int[] mTmpLocation = new int[2]; private int mLastViewHeight; private float mLastHeaderTranslation; + private QSPanelController mQSPanelController; + private QuickQSPanelController mQuickQSPanelController; @Inject public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler, InjectionInflationController injectionInflater, QSTileHost qsTileHost, StatusBarStateController statusBarStateController, CommandQueue commandQueue, - QSContainerImplController.Builder qsContainerImplControllerBuilder) { + QSFragmentComponent.Factory qsComponentFactory) { mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler; mInjectionInflater = injectionInflater; - mQSContainerImplControllerBuilder = qsContainerImplControllerBuilder; + mQsComponentFactory = qsComponentFactory; commandQueue.observe(getLifecycle(), this); mHost = qsTileHost; mStatusBarStateController = statusBarStateController; @@ -120,8 +121,13 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - mQSPanel = view.findViewById(R.id.quick_settings_panel); + QSFragmentComponent qsFragmentComponent = mQsComponentFactory.create(this); + mQSPanelController = qsFragmentComponent.getQSPanelController(); + mQuickQSPanelController = qsFragmentComponent.getQuickQSPanelController(); + + mQSPanelController.init(); + mQuickQSPanelController.init(); + mQSPanelScrollView = view.findViewById(R.id.expanded_qs_scroll_view); mQSPanelScrollView.addOnLayoutChangeListener( (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { @@ -135,18 +141,15 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca }); mQSDetail = view.findViewById(R.id.qs_detail); mHeader = view.findViewById(R.id.header); - mQSPanel.setHeaderContainer(view.findViewById(R.id.header_text_container)); + mQSPanelController.setHeaderContainer(view.findViewById(R.id.header_text_container)); mFooter = view.findViewById(R.id.qs_footer); - mContainer = view.findViewById(id.quick_settings_container); - mQSContainerImplController = mQSContainerImplControllerBuilder - .setQSContainerImpl((QSContainerImpl) view) - .build(); + mQSContainerImplController = qsFragmentComponent.getQSContainerImplController(); mQSContainerImplController.init(); + mContainer = mQSContainerImplController.getView(); - mQSDetail.setQsPanel(mQSPanel, mHeader, (View) mFooter); - mQSAnimator = new QSAnimator(this, mHeader.findViewById(R.id.quick_qs_panel), mQSPanel); - + mQSDetail.setQsPanel(mQSPanelController.getView(), mHeader, (View) mFooter); + mQSAnimator = qsFragmentComponent.getQSAnimator(); mQSCustomizer = view.findViewById(R.id.qs_customize); mQSCustomizer.setQs(this); @@ -156,7 +159,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca setEditLocation(view); mQSCustomizer.restoreInstanceState(savedInstanceState); if (mQsExpanded) { - mQSPanel.getTileLayout().restoreInstanceState(savedInstanceState); + mQSPanelController.getTileLayout().restoreInstanceState(savedInstanceState); } } setHost(mHost); @@ -188,7 +191,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca outState.putBoolean(EXTRA_LISTENING, mListening); mQSCustomizer.saveInstanceState(outState); if (mQsExpanded) { - mQSPanel.getTileLayout().saveInstanceState(outState); + mQSPanelController.getTileLayout().saveInstanceState(outState); } } @@ -249,14 +252,10 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca } public void setHost(QSTileHost qsh) { - mQSPanel.setHost(qsh, mQSCustomizer); - mHeader.setQSPanel(mQSPanel); - mFooter.setQSPanel(mQSPanel); + mQSPanelController.setCustomizer(mQSCustomizer); + mHeader.setQSPanel(mQSPanelController.getView()); + mFooter.setQSPanel(mQSPanelController.getView()); mQSDetail.setHost(qsh); - - if (mQSAnimator != null) { - mQSAnimator.setHost(qsh); - } } @Override @@ -278,7 +277,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca private void updateQsState() { final boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling || mHeaderAnimating; - mQSPanel.setExpanded(mQsExpanded); + mQSPanelController.setExpanded(mQsExpanded); mQSDetail.setExpanded(mQsExpanded); boolean keyguardShowing = isKeyguardShowing(); mHeader.setVisibility((mQsExpanded || !keyguardShowing || mHeaderAnimating @@ -294,7 +293,8 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca : View.INVISIBLE); mFooter.setExpanded((keyguardShowing && !mHeaderAnimating && !mShowCollapsedOnKeyguard) || (mQsExpanded && !mStackScrollerOverscrolling)); - mQSPanel.setVisibility(!mQsDisabled && expandVisually ? View.VISIBLE : View.INVISIBLE); + mQSPanelController.setVisibility( + !mQsDisabled && expandVisually ? View.VISIBLE : View.INVISIBLE); } private boolean isKeyguardShowing() { @@ -317,8 +317,12 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca } } + public QSPanelController getQSPanelController() { + return mQSPanelController; + } + public QSPanel getQsPanel() { - return mQSPanel; + return mQSPanelController.getView(); } public QSCustomizer getCustomizer() { @@ -327,7 +331,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca @Override public boolean isShowingDetail() { - return mQSPanel.isShowingCustomize() || mQSDetail.isShowingDetail(); + return mQSPanelController.isShowingCustomize() || mQSDetail.isShowingDetail(); } @Override @@ -339,7 +343,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca public void setExpanded(boolean expanded) { if (DEBUG) Log.d(TAG, "setExpanded " + expanded); mQsExpanded = expanded; - mQSPanel.setListening(mListening, mQsExpanded); + mQSPanelController.setListening(mListening, mQsExpanded); updateQsState(); } @@ -368,7 +372,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca mListening = listening; mQSContainerImplController.setListening(listening); mFooter.setListening(listening); - mQSPanel.setListening(mListening, mQsExpanded); + mQSPanelController.setListening(mListening, mQsExpanded); } @Override @@ -406,11 +410,15 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca float panelTranslationY = translationScaleY * heightDiff; // Let the views animate their contents correctly by giving them the necessary context. - mHeader.setExpansion(onKeyguardAndExpanded, expansion, - panelTranslationY); + mHeader.setExpansion(onKeyguardAndExpanded, expansion, panelTranslationY); + if (expansion < 1 && expansion > 0.99) { + if (mQuickQSPanelController.switchTileLayout(false)) { + mHeader.updateResources(); + } + } mFooter.setExpansion(onKeyguardAndExpanded ? 1 : expansion); - mQSPanel.getQsTileRevealController().setExpansion(expansion); - mQSPanel.getTileLayout().setExpansion(expansion); + mQSPanelController.getQsTileRevealController().setExpansion(expansion); + mQSPanelController.getTileLayout().setExpansion(expansion); mQSPanelScrollView.setTranslationY(translationScaleY * heightDiff); if (fullyCollapsed) { mQSPanelScrollView.setScrollY(0); @@ -448,7 +456,8 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca float expandedMediaPosition = absoluteBottomPosition - mQSPanelScrollView.getScrollY() + mQSPanelScrollView.getScrollRange(); // The expanded media host should never move below the laid out position - pinToBottom(expandedMediaPosition, mQSPanel.getMediaHost(), true /* expanded */); + pinToBottom( + expandedMediaPosition, mQSPanelController.getMediaHost(), true /* expanded */); // The expanded media host should never move above the laid out position pinToBottom(absoluteBottomPosition, mHeader.getHeaderQsPanel().getMediaHost(), false /* expanded */); @@ -538,7 +547,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca @Override public void closeDetail() { - mQSPanel.closeDetail(); + mQSPanelController.closeDetail(); } public void notifyCustomizeChanged() { @@ -553,8 +562,8 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca } /** - * The height this view wants to be. This is different from {@link #getMeasuredHeight} such that - * during closing the detail panel, this already returns the smaller height. + * The height this view wants to be. This is different from {@link View#getMeasuredHeight} such + * that during closing the detail panel, this already returns the smaller height. */ @Override public int getDesiredHeight() { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index efe46096239f..1b17a2a277f2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -22,11 +22,9 @@ import static com.android.systemui.util.Utils.useQsMediaPlayer; import android.annotation.NonNull; import android.annotation.Nullable; -import android.content.ComponentName; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; -import android.metrics.LogMaker; import android.os.Bundle; import android.os.Handler; import android.os.Message; @@ -43,41 +41,30 @@ import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.widget.RemeasuringLinearLayout; import com.android.systemui.Dependency; -import com.android.systemui.Dumpable; import com.android.systemui.R; -import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.dump.DumpManager; import com.android.systemui.media.MediaHierarchyManager; import com.android.systemui.media.MediaHost; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSTile; -import com.android.systemui.plugins.qs.QSTileView; -import com.android.systemui.qs.QSHost.Callback; import com.android.systemui.qs.customize.QSCustomizer; -import com.android.systemui.qs.external.CustomTile; import com.android.systemui.qs.logging.QSLogger; -import com.android.systemui.settings.BrightnessController; import com.android.systemui.settings.ToggleSliderView; -import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.policy.BrightnessMirrorController; import com.android.systemui.statusbar.policy.BrightnessMirrorController.BrightnessMirrorListener; import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; import com.android.systemui.util.animation.DisappearParameters; -import java.io.FileDescriptor; -import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collection; +import java.util.List; import java.util.function.Consumer; -import java.util.stream.Collectors; import javax.inject.Inject; import javax.inject.Named; /** View that represents the quick settings tile panel (when expanded/pulled down). **/ -public class QSPanel extends LinearLayout implements Tunable, Callback, BrightnessMirrorListener, - Dumpable { +public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorListener { public static final String QS_SHOW_BRIGHTNESS = "qs_show_brightness"; public static final String QS_SHOW_HEADER = "qs_show_header"; @@ -85,20 +72,15 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne private static final String TAG = "QSPanel"; protected final Context mContext; - protected final ArrayList<TileRecord> mRecords = new ArrayList<>(); - private final BroadcastDispatcher mBroadcastDispatcher; protected final MediaHost mMediaHost; /** * The index where the content starts that needs to be moved between parents */ private final int mMovableContentStartIndex; - private String mCachedSpecs = ""; @Nullable protected View mBrightnessView; - @Nullable - private BrightnessController mBrightnessController; private final H mHandler = new H(); private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class); @@ -112,14 +94,14 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne protected boolean mListening; private QSDetail.Callback mCallback; - private final DumpManager mDumpManager; private final QSLogger mQSLogger; protected final UiEventLogger mUiEventLogger; protected QSTileHost mHost; - private final UserTracker mUserTracker; + private final List<OnConfigurationChangedListener> mOnConfigurationChangedListeners = + new ArrayList<>(); @Nullable - protected QSSecurityFooter mSecurityFooter; + protected View mSecurityFooter; @Nullable protected View mFooter; @@ -156,12 +138,9 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne public QSPanel( @Named(VIEW_CONTEXT) Context context, AttributeSet attrs, - DumpManager dumpManager, - BroadcastDispatcher broadcastDispatcher, QSLogger qsLogger, @Named(QS_PANEL) MediaHost mediaHost, - UiEventLogger uiEventLogger, - UserTracker userTracker + UiEventLogger uiEventLogger ) { super(context, attrs); mUsingMediaPlayer = useQsMediaPlayer(context); @@ -174,16 +153,14 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne }); mContext = context; mQSLogger = qsLogger; - mDumpManager = dumpManager; - mBroadcastDispatcher = broadcastDispatcher; mUiEventLogger = uiEventLogger; - mUserTracker = userTracker; setOrientation(VERTICAL); addViewsAboveTiles(); mMovableContentStartIndex = getChildCount(); mRegularTileLayout = createRegularTileLayout(); + mTileLayout = mRegularTileLayout; if (mUsingMediaPlayer) { mHorizontalLinearLayout = new RemeasuringLinearLayout(mContext); @@ -209,35 +186,27 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne initMediaHostState(); } - addSecurityFooter(); if (mRegularTileLayout instanceof PagedTileLayout) { mQsTileRevealController = new QSTileRevealController(mContext, this, (PagedTileLayout) mRegularTileLayout); } - mQSLogger.logAllTilesChangeListening(mListening, getDumpableTag(), mCachedSpecs); - updateResources(); + mQSLogger.logAllTilesChangeListening(mListening, getDumpableTag(), ""); } protected void onMediaVisibilityChanged(Boolean visible) { - switchTileLayout(); if (mMediaVisibilityChangedListener != null) { mMediaVisibilityChangedListener.accept(visible); } } - protected void addSecurityFooter() { - mSecurityFooter = new QSSecurityFooter(this, mContext, mUserTracker); - } - protected void addViewsAboveTiles() { mBrightnessView = LayoutInflater.from(mContext).inflate( R.layout.quick_settings_brightness_dialog, this, false); addView(mBrightnessView); - mBrightnessController = new BrightnessController(getContext(), - findViewById(R.id.brightness_slider), mBroadcastDispatcher); } - protected QSTileLayout createRegularTileLayout() { + /** */ + public QSTileLayout createRegularTileLayout() { if (mRegularTileLayout == null) { mRegularTileLayout = (QSTileLayout) LayoutInflater.from(mContext).inflate( R.layout.qs_paged_tile_layout, this, false); @@ -337,37 +306,10 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne } @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - final TunerService tunerService = Dependency.get(TunerService.class); - tunerService.addTunable(this, QS_SHOW_BRIGHTNESS); - - if (mHost != null) { - setTiles(mHost.getTiles()); - } - if (mBrightnessMirrorController != null) { - mBrightnessMirrorController.addCallback(this); - } - mDumpManager.registerDumpable(getDumpableTag(), this); - } - - @Override protected void onDetachedFromWindow() { - Dependency.get(TunerService.class).removeTunable(this); - if (mHost != null) { - mHost.removeCallback(this); - } if (mTileLayout != null) { mTileLayout.setListening(false); } - for (TileRecord record : mRecords) { - record.tile.removeCallbacks(); - } - mRecords.clear(); - if (mBrightnessMirrorController != null) { - mBrightnessMirrorController.removeCallback(this); - } - mDumpManager.unregisterDumpable(getDumpableTag()); super.onDetachedFromWindow(); } @@ -376,11 +318,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne } @Override - public void onTilesChanged() { - setTiles(mHost.getTiles()); - } - - @Override public void onTuningChanged(String key, String newValue) { if (QS_SHOW_BRIGHTNESS.equals(key) && mBrightnessView != null) { updateViewVisibilityForTuningValue(mBrightnessView, newValue); @@ -391,8 +328,8 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne view.setVisibility(TunerService.parseIntegerSwitch(newValue, true) ? VISIBLE : GONE); } - public void openDetails(String subPanel) { - QSTile tile = getTile(subPanel); + /** */ + public void openDetails(QSTile tile) { // If there's no tile with that name (as defined in QSFactoryImpl or other QSFactory), // QSFactory will not be able to create a tile and getTile will return null if (tile != null) { @@ -400,15 +337,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne } } - private QSTile getTile(String subPanel) { - for (int i = 0; i < mRecords.size(); i++) { - if (subPanel.equals(mRecords.get(i).tile.getTileSpec())) { - return mRecords.get(i).tile; - } - } - return mHost.createTile(subPanel); - } - public void setBrightnessMirror(BrightnessMirrorController c) { if (mBrightnessMirrorController != null) { mBrightnessMirrorController.removeCallback(this); @@ -434,17 +362,8 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne mCallback = callback; } - public void setHost(QSTileHost host, QSCustomizer customizer) { - mHost = host; - mHost.addCallback(this); - setTiles(mHost.getTiles()); - if (mSecurityFooter != null) { - mSecurityFooter.setHostEnvironment(host); - } + void setCustomizer(QSCustomizer customizer) { mCustomizePanel = customizer; - if (mCustomizePanel != null) { - mCustomizePanel.setHost(mHost); - } } /** @@ -483,9 +402,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne updatePageIndicator(); - if (mListening) { - refreshAllTiles(); - } if (mTileLayout != null) { mTileLayout.updateResources(); } @@ -506,20 +422,21 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom)); } + void addOnConfigurationChangedListener(OnConfigurationChangedListener listener) { + mOnConfigurationChangedListeners.add(listener); + } + + void removeOnConfigurationChangedListener(OnConfigurationChangedListener listener) { + mOnConfigurationChangedListeners.remove(listener); + } + @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - if (mSecurityFooter != null) { - mSecurityFooter.onConfigurationChanged(); - } - updateResources(); + mOnConfigurationChangedListeners.forEach( + listener -> listener.onConfigurationChange(newConfig)); updateBrightnessMirror(); - - if (newConfig.orientation != mLastOrientation) { - mLastOrientation = newConfig.orientation; - switchTileLayout(); - } } @Override @@ -527,14 +444,9 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne super.onFinishInflate(); mFooter = findViewById(R.id.qs_footer); mDivider = findViewById(R.id.divider); - switchTileLayout(true /* force */); - } - - boolean switchTileLayout() { - return switchTileLayout(false /* force */); } - private boolean switchTileLayout(boolean force) { + boolean switchTileLayout(boolean force, List<QSPanelControllerBase.TileRecord> records) { /** Whether or not the QuickQSPanel currently contains a media player. */ boolean horizontal = shouldUseHorizontalLayout(); if (mDivider != null) { @@ -562,13 +474,12 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne reAttachMediaHost(); if (mTileLayout != null) { mTileLayout.setListening(false); - for (TileRecord record : mRecords) { + for (QSPanelControllerBase.TileRecord record : records) { mTileLayout.removeTile(record); record.tile.removeCallback(record.callback); } } mTileLayout = newLayout; - if (mHost != null) setTiles(mHost.getTiles()); newLayout.setListening(mListening); if (needsDynamicRowsAndColumns()) { newLayout.setMinRows(horizontal ? 2 : 1); @@ -617,20 +528,20 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne index++; if (mSecurityFooter != null) { - View view = mSecurityFooter.getView(); - LinearLayout.LayoutParams layoutParams = (LayoutParams) view.getLayoutParams(); + LinearLayout.LayoutParams layoutParams = + (LayoutParams) mSecurityFooter.getLayoutParams(); if (mUsingHorizontalLayout && mHeaderContainer != null) { // Adding the security view to the header, that enables us to avoid scrolling layoutParams.width = 0; layoutParams.weight = 1.6f; - switchToParent(view, mHeaderContainer, 1 /* always in second place */); + switchToParent(mSecurityFooter, mHeaderContainer, 1 /* always in second place */); } else { layoutParams.width = LayoutParams.WRAP_CONTENT; layoutParams.weight = 0; - switchToParent(view, parent, index); + switchToParent(mSecurityFooter, parent, index); index++; } - view.setLayoutParams(layoutParams); + mSecurityFooter.setLayoutParams(layoutParams); } if (mFooter != null) { @@ -703,14 +614,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne if (!mExpanded && mTileLayout instanceof PagedTileLayout) { ((PagedTileLayout) mTileLayout).setCurrentItem(0, false); } - mMetricsLogger.visibility(MetricsEvent.QS_PANEL, mExpanded); - if (!mExpanded) { - mUiEventLogger.log(closePanelEvent()); - closeDetail(); - } else { - mUiEventLogger.log(openPanelEvent()); - logTiles(); - } } public void setPageListener(final PagedTileLayout.PageListener pageListener) { @@ -723,56 +626,16 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne return mExpanded; } - public void setListening(boolean listening) { + /** */ + public void setListening(boolean listening, String cachedSpecs) { if (mListening == listening) return; mListening = listening; if (mTileLayout != null) { - mQSLogger.logAllTilesChangeListening(listening, getDumpableTag(), mCachedSpecs); + mQSLogger.logAllTilesChangeListening(listening, getDumpableTag(), cachedSpecs); mTileLayout.setListening(listening); } - if (mListening) { - refreshAllTiles(); - } } - private String getTilesSpecs() { - return mRecords.stream() - .map(tileRecord -> tileRecord.tile.getTileSpec()) - .collect(Collectors.joining(",")); - } - - public void setListening(boolean listening, boolean expanded) { - setListening(listening && expanded); - if (mSecurityFooter != null) { - mSecurityFooter.setListening(listening); - } - // Set the listening as soon as the QS fragment starts listening regardless of the expansion, - // so it will update the current brightness before the slider is visible. - setBrightnessListening(listening); - } - - public void setBrightnessListening(boolean listening) { - if (mBrightnessController == null) { - return; - } - if (listening) { - mBrightnessController.registerCallbacks(); - } else { - mBrightnessController.unregisterCallbacks(); - } - } - - public void refreshAllTiles() { - if (mBrightnessController != null) { - mBrightnessController.checkRestrictionAndSetEnabled(); - } - for (TileRecord r : mRecords) { - r.tile.refreshState(); - } - if (mSecurityFooter != null) { - mSecurityFooter.refreshState(); - } - } public void showDetailAdapter(boolean show, DetailAdapter adapter, int[] locationInWindow) { int xInWindow = locationInWindow[0]; @@ -794,33 +657,10 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne mHandler.obtainMessage(H.SHOW_DETAIL, show ? 1 : 0, 0, r).sendToTarget(); } - public void setTiles(Collection<QSTile> tiles) { - setTiles(tiles, false); - } - - public void setTiles(Collection<QSTile> tiles, boolean collapsedView) { - if (!collapsedView) { - mQsTileRevealController.updateRevealedTiles(tiles); - } - for (TileRecord record : mRecords) { - mTileLayout.removeTile(record); - record.tile.removeCallback(record.callback); - } - mRecords.clear(); - mCachedSpecs = ""; - for (QSTile tile : tiles) { - addTile(tile, collapsedView); - } - } - - protected void drawTile(TileRecord r, QSTile.State state) { + protected void drawTile(QSPanelControllerBase.TileRecord r, QSTile.State state) { r.tileView.onStateChanged(state); } - protected QSTileView createTileView(QSTile tile, boolean collapsedView) { - return mHost.createTileView(tile, collapsedView); - } - protected QSEvent openPanelEvent() { return QSEvent.QS_PANEL_EXPANDED; } @@ -837,14 +677,15 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne return mExpanded; } - protected TileRecord addTile(final QSTile tile, boolean collapsedView) { - final TileRecord r = new TileRecord(); - r.tile = tile; - r.tileView = createTileView(tile, collapsedView); + void updateRevealedTiles(Collection<QSTile> tiles) { + mQsTileRevealController.updateRevealedTiles(tiles); + } + + void addTile(QSPanelControllerBase.TileRecord tileRecord) { final QSTile.Callback callback = new QSTile.Callback() { @Override public void onStateChanged(QSTile.State state) { - drawTile(r, state); + drawTile(tileRecord, state); } @Override @@ -852,22 +693,22 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne // Both the collapsed and full QS panels get this callback, this check determines // which one should handle showing the detail. if (shouldShowDetail()) { - QSPanel.this.showDetail(show, r); + QSPanel.this.showDetail(show, tileRecord); } } @Override public void onToggleStateChanged(boolean state) { - if (mDetailRecord == r) { + if (mDetailRecord == tileRecord) { fireToggleStateChanged(state); } } @Override public void onScanStateChanged(boolean state) { - r.scanState = state; - if (mDetailRecord == r) { - fireScanStateChanged(r.scanState); + tileRecord.scanState = state; + if (mDetailRecord == tileRecord) { + fireScanStateChanged(tileRecord.scanState); } } @@ -879,20 +720,20 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne } } }; - r.tile.addCallback(callback); - r.callback = callback; - r.tileView.init(r.tile); - r.tile.refreshState(); - mRecords.add(r); - mCachedSpecs = getTilesSpecs(); + + tileRecord.tile.addCallback(callback); + tileRecord.callback = callback; + tileRecord.tileView.init(tileRecord.tile); + tileRecord.tile.refreshState(); if (mTileLayout != null) { - mTileLayout.addTile(r); + mTileLayout.addTile(tileRecord); } - - return r; } + void removeTile(QSPanelControllerBase.TileRecord tileRecord) { + mTileLayout.removeTile(tileRecord); + } public void showEdit(final View v) { v.post(new Runnable() { @@ -925,8 +766,8 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne } protected void handleShowDetail(Record r, boolean show) { - if (r instanceof TileRecord) { - handleShowDetailTile((TileRecord) r, show); + if (r instanceof QSPanelControllerBase.TileRecord) { + handleShowDetailTile((QSPanelControllerBase.TileRecord) r, show); } else { int x = 0; int y = 0; @@ -938,7 +779,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne } } - private void handleShowDetailTile(TileRecord r, boolean show) { + private void handleShowDetailTile(QSPanelControllerBase.TileRecord r, boolean show) { if ((mDetailRecord != null) == show && mDetailRecord == r) return; if (show) { @@ -959,8 +800,8 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne protected void setDetailRecord(Record r) { if (r == mDetailRecord) return; mDetailRecord = r; - final boolean scanState = mDetailRecord instanceof TileRecord - && ((TileRecord) mDetailRecord).scanState; + final boolean scanState = mDetailRecord instanceof QSPanelControllerBase.TileRecord + && ((QSPanelControllerBase.TileRecord) mDetailRecord).scanState; fireScanStateChanged(scanState); } @@ -972,15 +813,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne } mGridContentVisible = visible; } - - private void logTiles() { - for (int i = 0; i < mRecords.size(); i++) { - QSTile tile = mRecords.get(i).tile; - mMetricsLogger.write(tile.populate(new LogMaker(tile.getMetricsCategory()) - .setType(MetricsEvent.TYPE_OPEN))); - } - } - private void fireShowingDetail(DetailAdapter detail, int x, int y) { if (mCallback != null) { mCallback.onShowingDetail(detail, x, y); @@ -999,46 +831,15 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne } } - public void clickTile(ComponentName tile) { - final String spec = CustomTile.toSpec(tile); - final int N = mRecords.size(); - for (int i = 0; i < N; i++) { - if (mRecords.get(i).tile.getTileSpec().equals(spec)) { - mRecords.get(i).tile.click(); - break; - } - } - } - QSTileLayout getTileLayout() { return mTileLayout; } - QSTileView getTileView(QSTile tile) { - for (TileRecord r : mRecords) { - if (r.tile == tile) { - return r.tileView; - } - } - return null; - } - - @Nullable - public QSSecurityFooter getSecurityFooter() { - return mSecurityFooter; - } - @Nullable public View getDivider() { return mDivider; } - public void showDeviceMonitoringDialog() { - if (mSecurityFooter != null) { - mSecurityFooter.showDeviceMonitoringDialog(); - } - } - public void setContentMargins(int startMargin, int endMargin) { // Only some views actually want this content padding, others want to go all the way // to the edge like the brightness slider @@ -1121,9 +922,11 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne */ protected void updateMargins(View view, int start, int end) { LayoutParams lp = (LayoutParams) view.getLayoutParams(); - lp.setMarginStart(start); - lp.setMarginEnd(end); - view.setLayoutParams(lp); + if (lp != null) { + lp.setMarginStart(start); + lp.setMarginEnd(end); + view.setLayoutParams(lp); + } } public MediaHost getMediaHost() { @@ -1141,6 +944,14 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne mMediaVisibilityChangedListener = visibilityChangedListener; } + public boolean isListening() { + return mListening; + } + + public void setSecurityFooter(View view) { + mSecurityFooter = view; + } + private class H extends Handler { private static final int SHOW_DETAIL = 1; private static final int SET_TILE_VISIBILITY = 2; @@ -1156,46 +967,32 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne } } - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println(getClass().getSimpleName() + ":"); - pw.println(" Tile records:"); - for (TileRecord record : mRecords) { - if (record.tile instanceof Dumpable) { - pw.print(" "); ((Dumpable) record.tile).dump(fd, pw, args); - pw.print(" "); pw.println(record.tileView.toString()); - } - } - } - - protected static class Record { DetailAdapter detailAdapter; int x; int y; } - public static final class TileRecord extends Record { - public QSTile tile; - public com.android.systemui.plugins.qs.QSTileView tileView; - public boolean scanState; - public QSTile.Callback callback; - } - public interface QSTileLayout { - + /** */ default void saveInstanceState(Bundle outState) {} + /** */ default void restoreInstanceState(Bundle savedInstanceState) {} - void addTile(TileRecord tile); + /** */ + void addTile(QSPanelControllerBase.TileRecord tile); - void removeTile(TileRecord tile); + /** */ + void removeTile(QSPanelControllerBase.TileRecord tile); - int getOffsetTop(TileRecord tile); + /** */ + int getOffsetTop(QSPanelControllerBase.TileRecord tile); + /** */ boolean updateResources(); + /** */ void setListening(boolean listening); /** @@ -1222,4 +1019,8 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne int getNumVisibleTiles(); } + + interface OnConfigurationChangedListener { + void onConfigurationChange(Configuration newConfig); + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java new file mode 100644 index 000000000000..4e2351f66ca2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java @@ -0,0 +1,195 @@ +/* + * 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.android.systemui.qs.QSPanel.QS_SHOW_BRIGHTNESS; + +import android.annotation.NonNull; +import android.content.res.Configuration; +import android.view.ViewGroup; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.UiEventLogger; +import com.android.systemui.R; +import com.android.systemui.dump.DumpManager; +import com.android.systemui.media.MediaHost; +import com.android.systemui.plugins.qs.QSTile; +import com.android.systemui.qs.customize.QSCustomizer; +import com.android.systemui.qs.dagger.QSScope; +import com.android.systemui.settings.BrightnessController; +import com.android.systemui.statusbar.policy.BrightnessMirrorController; +import com.android.systemui.tuner.TunerService; + +import javax.inject.Inject; + +/** + * Controller for {@link QSPanel}. + */ +@QSScope +public class QSPanelController extends QSPanelControllerBase<QSPanel> { + private final QSSecurityFooter mQsSecurityFooter; + private final TunerService mTunerService; + private final BrightnessController mBrightnessController; + + private final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener = + new QSPanel.OnConfigurationChangedListener() { + @Override + public void onConfigurationChange(Configuration newConfig) { + mView.updateResources(); + mQsSecurityFooter.onConfigurationChanged(); + if (mView.isListening()) { + refreshAllTiles(); + } + } + }; + private BrightnessMirrorController mBrightnessMirrorController; + + @Inject + QSPanelController(QSPanel view, QSSecurityFooter qsSecurityFooter, TunerService tunerService, + QSTileHost qstileHost, DumpManager dumpManager, + MetricsLogger metricsLogger, UiEventLogger uiEventLogger, + BrightnessController.Factory brightnessControllerFactory) { + super(view, qstileHost, metricsLogger, uiEventLogger, dumpManager); + mQsSecurityFooter = qsSecurityFooter; + mTunerService = tunerService; + mQsSecurityFooter.setHostEnvironment(qstileHost); + mBrightnessController = brightnessControllerFactory.create( + mView.findViewById(R.id.brightness_slider)); + } + + @Override + protected void onViewAttached() { + super.onViewAttached(); + mTunerService.addTunable(mView, QS_SHOW_BRIGHTNESS); + mView.updateResources(); + if (mView.isListening()) { + refreshAllTiles(); + } + mView.addOnConfigurationChangedListener(mOnConfigurationChangedListener); + mView.setSecurityFooter(mQsSecurityFooter.getView()); + switchTileLayout(true); + if (mBrightnessMirrorController != null) { + mBrightnessMirrorController.addCallback(mView); + } + } + + @Override + protected void onViewDetached() { + mTunerService.removeTunable(mView); + mView.removeOnConfigurationChangedListener(mOnConfigurationChangedListener); + if (mBrightnessMirrorController != null) { + mBrightnessMirrorController.removeCallback(mView); + } + super.onViewDetached(); + } + + /** TODO(b/168904199): Remove this method once view is controllerized. */ + QSPanel getView() { + return mView; + } + + /** + * Set the header container of quick settings. + */ + public void setHeaderContainer(@NonNull ViewGroup headerContainer) { + mView.setHeaderContainer(headerContainer); + } + + public QSPanel.QSTileLayout getTileLayout() { + return mView.getTileLayout(); + } + + /** */ + public void setCustomizer(QSCustomizer customizer) { + mView.setCustomizer(customizer); + } + + /** */ + public boolean isShowingCustomize() { + return mView.isShowingCustomize(); + } + + /** */ + public void setVisibility(int visibility) { + mView.setVisibility(visibility); + } + + /** */ + public void setListening(boolean listening, boolean expanded) { + setListening(listening && expanded); + if (mView.isListening()) { + refreshAllTiles(); + } + + mQsSecurityFooter.setListening(listening); + + // Set the listening as soon as the QS fragment starts listening regardless of the + //expansion, so it will update the current brightness before the slider is visible. + if (listening) { + mBrightnessController.registerCallbacks(); + } else { + mBrightnessController.unregisterCallbacks(); + } + } + + /** */ + public QSTileRevealController getQsTileRevealController() { + return mView.getQsTileRevealController(); + } + + /** */ + public MediaHost getMediaHost() { + return mView.getMediaHost(); + } + + /** */ + public void setBrightnessMirror(BrightnessMirrorController brightnessMirrorController) { + mBrightnessMirrorController = brightnessMirrorController; + mView.setBrightnessMirror(brightnessMirrorController); + } + + /** Get the QSTileHost this panel uses. */ + public QSTileHost getHost() { + return mHost; + } + + + /** Open the details for a specific tile.. */ + public void openDetails(String subPanel) { + QSTile tile = getTile(subPanel); + if (tile != null) { + mView.openDetails(tile); + } + } + + /** Show the device monitoring dialog. */ + public void showDeviceMonitoringDialog() { + mQsSecurityFooter.showDeviceMonitoringDialog(); + } + + /** Update appearance of QSPanel. */ + public void updateResources() { + mView.updateResources(); + } + + /** Update state of all tiles. */ + public void refreshAllTiles() { + mBrightnessController.checkRestrictionAndSetEnabled(); + super.refreshAllTiles(); + mQsSecurityFooter.refreshState(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java new file mode 100644 index 000000000000..fe92827806c6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java @@ -0,0 +1,250 @@ +/* + * 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.android.internal.logging.nano.MetricsProto.MetricsEvent; + +import android.content.ComponentName; +import android.content.res.Configuration; +import android.metrics.LogMaker; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.UiEventLogger; +import com.android.systemui.Dumpable; +import com.android.systemui.dump.DumpManager; +import com.android.systemui.media.MediaHost; +import com.android.systemui.plugins.qs.QSTile; +import com.android.systemui.plugins.qs.QSTileView; +import com.android.systemui.qs.external.CustomTile; +import com.android.systemui.util.ViewController; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.stream.Collectors; + +/** + * Controller for QSPanel views. + * + * @param <T> Type of QSPanel. + */ +public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewController<T> + implements Dumpable{ + protected final QSTileHost mHost; + private final MediaHost mMediaHost; + private final MetricsLogger mMetricsLogger; + private final UiEventLogger mUiEventLogger; + private final DumpManager mDumpManager; + protected final ArrayList<TileRecord> mRecords = new ArrayList<>(); + + private int mLastOrientation; + + private final QSHost.Callback mQSHostCallback = this::setTiles; + + private final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener = + new QSPanel.OnConfigurationChangedListener() { + @Override + public void onConfigurationChange(Configuration newConfig) { + if (newConfig.orientation != mLastOrientation) { + mLastOrientation = newConfig.orientation; + switchTileLayout(false); + } + } + }; + private String mCachedSpecs = ""; + + protected QSPanelControllerBase(T view, QSTileHost host, + MetricsLogger metricsLogger, UiEventLogger uiEventLogger, DumpManager dumpManager) { + super(view); + mHost = host; + mMediaHost = mView.getMediaHost(); + mMetricsLogger = metricsLogger; + mUiEventLogger = uiEventLogger; + mDumpManager = dumpManager; + } + + @Override + protected void onViewAttached() { + mView.addOnConfigurationChangedListener(mOnConfigurationChangedListener); + mHost.addCallback(mQSHostCallback); + mMediaHost.addVisibilityChangeListener(aBoolean -> { + switchTileLayout(false); + return null; + }); + setTiles(); + switchTileLayout(true); + mDumpManager.registerDumpable(mView.getDumpableTag(), this); + } + + @Override + protected void onViewDetached() { + mView.removeOnConfigurationChangedListener(mOnConfigurationChangedListener); + mHost.removeCallback(mQSHostCallback); + + for (TileRecord record : mRecords) { + record.tile.removeCallbacks(); + } + mRecords.clear(); + mDumpManager.unregisterDumpable(mView.getDumpableTag()); + } + + /** */ + public void setTiles() { + setTiles(mHost.getTiles(), false); + } + + /** */ + public void setTiles(Collection<QSTile> tiles, boolean collapsedView) { + if (!collapsedView) { + mView.updateRevealedTiles(tiles); + } + for (QSPanelControllerBase.TileRecord record : mRecords) { + mView.removeTile(record); + record.tile.removeCallback(record.callback); + } + mRecords.clear(); + mCachedSpecs = ""; + for (QSTile tile : tiles) { + addTile(tile, collapsedView); + } + } + + /** */ + public void refreshAllTiles() { + for (QSPanelControllerBase.TileRecord r : mRecords) { + r.tile.refreshState(); + } + } + + private void addTile(final QSTile tile, boolean collapsedView) { + final TileRecord r = new TileRecord(); + r.tile = tile; + r.tileView = mHost.createTileView(tile, collapsedView); + mView.addTile(r); + mRecords.add(r); + mCachedSpecs = getTilesSpecs(); + + } + + /** */ + public void clickTile(ComponentName tile) { + final String spec = CustomTile.toSpec(tile); + for (TileRecord record : mRecords) { + if (record.tile.getTileSpec().equals(spec)) { + record.tile.click(); + break; + } + } + } + protected QSTile getTile(String subPanel) { + for (int i = 0; i < mRecords.size(); i++) { + if (subPanel.equals(mRecords.get(i).tile.getTileSpec())) { + return mRecords.get(i).tile; + } + } + return mHost.createTile(subPanel); + } + + + QSTileView getTileView(QSTile tile) { + for (QSPanelControllerBase.TileRecord r : mRecords) { + if (r.tile == tile) { + return r.tileView; + } + } + return null; + } + + private String getTilesSpecs() { + return mRecords.stream() + .map(tileRecord -> tileRecord.tile.getTileSpec()) + .collect(Collectors.joining(",")); + } + + + /** */ + public void setExpanded(boolean expanded) { + mView.setExpanded(expanded); + mMetricsLogger.visibility(MetricsEvent.QS_PANEL, expanded); + if (!expanded) { + mUiEventLogger.log(mView.closePanelEvent()); + closeDetail(); + } else { + mUiEventLogger.log(mView.openPanelEvent()); + logTiles(); + } + } + + /** */ + public void closeDetail() { + mView.closeDetail(); + } + + /** */ + public void openDetails(String subPanel) { + QSTile tile = getTile(subPanel); + // If there's no tile with that name (as defined in QSFactoryImpl or other QSFactory), + // QSFactory will not be able to create a tile and getTile will return null + if (tile != null) { + mView.showDetailAdapter( + true, tile.getDetailAdapter(), new int[]{mView.getWidth() / 2, 0}); + } + } + + + void setListening(boolean listening) { + mView.setListening(listening, mCachedSpecs); + } + + boolean switchTileLayout(boolean force) { + if (mView.switchTileLayout(force, mRecords)) { + setTiles(); + return true; + } + return false; + } + + private void logTiles() { + for (int i = 0; i < mRecords.size(); i++) { + QSTile tile = mRecords.get(i).tile; + mMetricsLogger.write(tile.populate(new LogMaker(tile.getMetricsCategory()) + .setType(MetricsEvent.TYPE_OPEN))); + } + } + + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println(getClass().getSimpleName() + ":"); + pw.println(" Tile records:"); + for (QSPanelControllerBase.TileRecord record : mRecords) { + if (record.tile instanceof Dumpable) { + pw.print(" "); ((Dumpable) record.tile).dump(fd, pw, args); + pw.print(" "); pw.println(record.tileView.toString()); + } + } + } + + /** */ + public static final class TileRecord extends QSPanel.Record { + public QSTile tile; + public com.android.systemui.plugins.qs.QSTileView tileView; + public boolean scanState; + public QSTile.Callback callback; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java index 0891972c11d2..c90182b15da6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java @@ -44,11 +44,15 @@ import com.android.systemui.Dependency; import com.android.systemui.FontSizeUtils; import com.android.systemui.R; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.qs.dagger.QSScope; import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.SecurityController; -public class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListener { +import javax.inject.Inject; + +@QSScope +class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListener { protected static final String TAG = "QSSecurityFooter"; protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final boolean DEBUG_FORCE_VISIBLE = false; @@ -72,12 +76,13 @@ public class QSSecurityFooter implements OnClickListener, DialogInterface.OnClic private int mFooterTextId; private int mFooterIconId; + @Inject public QSSecurityFooter(QSPanel qsPanel, Context context, UserTracker userTracker) { mRootView = LayoutInflater.from(context) .inflate(R.layout.quick_settings_footer, qsPanel, false); mRootView.setOnClickListener(this); - mFooterText = (TextView) mRootView.findViewById(R.id.footer_text); - mFooterIcon = (ImageView) mRootView.findViewById(R.id.footer_icon); + mFooterText = mRootView.findViewById(R.id.footer_text); + mFooterIcon = mRootView.findViewById(R.id.footer_icon); mFooterIconId = R.drawable.ic_info_outline; mContext = context; mMainHandler = new Handler(Looper.myLooper()); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java index 2f012e6e608e..3d4a417abf2e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java @@ -8,11 +8,16 @@ import android.util.ArraySet; import com.android.systemui.Prefs; import com.android.systemui.plugins.qs.QSTile; +import com.android.systemui.qs.dagger.QSScope; import java.util.Collection; import java.util.Collections; import java.util.Set; +import javax.inject.Inject; + +/** */ +@QSScope public class QSTileRevealController { private static final long QS_REVEAL_TILES_DELAY = 500L; @@ -34,6 +39,7 @@ public class QSTileRevealController { } }; + @Inject QSTileRevealController(Context context, QSPanel qsPanel, PagedTileLayout pagedTileLayout) { mContext = context; mQSPanel = qsPanel; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java index 82cb8639e9ee..84a5b6f0538d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java @@ -28,23 +28,13 @@ import android.view.View; import android.widget.LinearLayout; import com.android.internal.logging.UiEventLogger; -import com.android.systemui.Dependency; import com.android.systemui.R; -import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.dump.DumpManager; import com.android.systemui.media.MediaHierarchyManager; import com.android.systemui.media.MediaHost; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.qs.QSTile.SignalState; import com.android.systemui.plugins.qs.QSTile.State; -import com.android.systemui.qs.customize.QSCustomizer; import com.android.systemui.qs.logging.QSLogger; -import com.android.systemui.settings.UserTracker; -import com.android.systemui.tuner.TunerService; -import com.android.systemui.tuner.TunerService.Tunable; - -import java.util.ArrayList; -import java.util.Collection; import javax.inject.Inject; import javax.inject.Named; @@ -68,15 +58,10 @@ public class QuickQSPanel extends QSPanel { public QuickQSPanel( @Named(VIEW_CONTEXT) Context context, AttributeSet attrs, - DumpManager dumpManager, - BroadcastDispatcher broadcastDispatcher, QSLogger qsLogger, @Named(QUICK_QS_PANEL) MediaHost mediaHost, - UiEventLogger uiEventLogger, - UserTracker userTracker - ) { - super(context, attrs, dumpManager, broadcastDispatcher, qsLogger, mediaHost, uiEventLogger, - userTracker); + UiEventLogger uiEventLogger) { + super(context, attrs, qsLogger, mediaHost, uiEventLogger); sDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns); applyBottomMargin((View) mRegularTileLayout); } @@ -89,17 +74,12 @@ public class QuickQSPanel extends QSPanel { } @Override - protected void addSecurityFooter() { - // No footer needed - } - - @Override protected void addViewsAboveTiles() { // Nothing to add above the tiles } @Override - protected TileLayout createRegularTileLayout() { + public TileLayout createRegularTileLayout() { return new QuickQSPanel.HeaderTileLayout(mContext, mUiEventLogger); } @@ -133,18 +113,6 @@ public class QuickQSPanel extends QSPanel { } @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - Dependency.get(TunerService.class).addTunable(mNumTiles, NUM_QUICK_TILES); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - Dependency.get(TunerService.class).removeTunable(mNumTiles); - } - - @Override protected String getDumpableTag() { return TAG; } @@ -159,7 +127,7 @@ public class QuickQSPanel extends QSPanel { } @Override - protected void drawTile(TileRecord r, State state) { + protected void drawTile(QSPanelControllerBase.TileRecord r, State state) { if (state instanceof SignalState) { SignalState copy = new SignalState(); state.copyTo(copy); @@ -171,17 +139,8 @@ public class QuickQSPanel extends QSPanel { super.drawTile(r, state); } - @Override - public void setHost(QSTileHost host, QSCustomizer customizer) { - super.setHost(host, customizer); - setTiles(mHost.getTiles()); - } - public void setMaxTiles(int maxTiles) { mMaxTiles = maxTiles; - if (mHost != null) { - setTiles(mHost.getTiles()); - } } @Override @@ -192,25 +151,6 @@ public class QuickQSPanel extends QSPanel { } } - @Override - public void setTiles(Collection<QSTile> tiles) { - ArrayList<QSTile> quickTiles = new ArrayList<>(); - for (QSTile tile : tiles) { - quickTiles.add(tile); - if (quickTiles.size() == mMaxTiles) { - break; - } - } - super.setTiles(quickTiles, true); - } - - private final Tunable mNumTiles = new Tunable() { - @Override - public void onTuningChanged(String key, String newValue) { - setMaxTiles(parseNumTiles(newValue)); - } - }; - public int getNumQuickTiles() { return mMaxTiles; } @@ -308,7 +248,7 @@ public class QuickQSPanel extends QSPanel { } @Override - protected void addTileView(TileRecord tile) { + protected void addTileView(QSPanelControllerBase.TileRecord tile) { addView(tile.tileView, getChildCount(), generateTileLayoutParams()); } @@ -371,7 +311,7 @@ public class QuickQSPanel extends QSPanel { private void setAccessibilityOrder() { if (mRecords != null && mRecords.size() > 0) { View previousView = this; - for (TileRecord record : mRecords) { + for (QSPanelControllerBase.TileRecord record : mRecords) { if (record.tileView.getVisibility() == GONE) continue; previousView = record.tileView.updateAccessibilityOrder(previousView); } @@ -383,7 +323,7 @@ public class QuickQSPanel extends QSPanel { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // Measure each QS tile. - for (TileRecord record : mRecords) { + for (QSPanelControllerBase.TileRecord record : mRecords) { if (record.tileView.getVisibility() == GONE) continue; record.tileView.measure(exactly(mCellWidth), exactly(mCellHeight)); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java new file mode 100644 index 000000000000..97b6e99a0390 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java @@ -0,0 +1,83 @@ +/* + * 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.android.systemui.qs.QuickQSPanel.NUM_QUICK_TILES; +import static com.android.systemui.qs.QuickQSPanel.parseNumTiles; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.UiEventLogger; +import com.android.systemui.dump.DumpManager; +import com.android.systemui.plugins.qs.QSTile; +import com.android.systemui.qs.dagger.QSScope; +import com.android.systemui.tuner.TunerService; +import com.android.systemui.tuner.TunerService.Tunable; + +import java.util.ArrayList; + +import javax.inject.Inject; + +/** Controller for {@link QuickQSPanel}. */ +@QSScope +public class QuickQSPanelController extends QSPanelControllerBase<QuickQSPanel> { + private final Tunable mNumTiles = + (key, newValue) -> setMaxTiles(parseNumTiles(newValue)); + + private final TunerService mTunerService; + + @Inject + QuickQSPanelController(QuickQSPanel view, TunerService tunerService, QSTileHost qsTileHost, + MetricsLogger metricsLogger, UiEventLogger uiEventLogger, + DumpManager dumpManager) { + super(view, qsTileHost, metricsLogger, uiEventLogger, dumpManager); + mTunerService = tunerService; + } + + @Override + protected void onViewAttached() { + super.onViewAttached(); + mTunerService.addTunable(mNumTiles, NUM_QUICK_TILES); + + } + + @Override + protected void onViewDetached() { + super.onViewDetached(); + mTunerService.removeTunable(mNumTiles); + } + + public boolean isListening() { + return mView.isListening(); + } + + private void setMaxTiles(int parseNumTiles) { + mView.setMaxTiles(parseNumTiles); + setTiles(); + } + + @Override + public void setTiles() { + ArrayList<QSTile> quickTiles = new ArrayList<>(); + for (QSTile tile : mHost.getTiles()) { + quickTiles.add(tile); + if (quickTiles.size() == mView.getNumQuickTiles()) { + break; + } + } + super.setTiles(quickTiles, true); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index a9fbc744b38e..5757602b9d0f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -353,11 +353,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwn mPrivacyChip.setExpanded(expansionFraction > 0.5); mPrivacyChipAlphaAnimator.setPosition(keyguardExpansionFraction); } - if (expansionFraction < 1 && expansionFraction > 0.99) { - if (mHeaderQsPanel.switchTileLayout()) { - updateResources(); - } - } + mKeyguardExpansionFraction = keyguardExpansionFraction; } @@ -446,7 +442,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwn public void setQSPanel(final QSPanel qsPanel) { //host.setHeaderView(mExpandIndicator); mHeaderQsPanel.setQSPanelAndHeader(qsPanel, this); - mHeaderQsPanel.setHost(qsPanel.getHost(), null /* No customization in header */); Rect tintArea = new Rect(0, 0, 0, 0); int colorForeground = Utils.getColorAttrDefaultColor(getContext(), diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java index 398edd7002ee..febb71c3223b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java @@ -44,6 +44,7 @@ import com.android.systemui.privacy.PrivacyChipEvent; import com.android.systemui.privacy.PrivacyItem; import com.android.systemui.privacy.PrivacyItemController; import com.android.systemui.qs.carrier.QSCarrierGroupController; +import com.android.systemui.qs.dagger.QSScope; import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.StatusBarIconController; @@ -64,6 +65,7 @@ import javax.inject.Inject; /** * Controller for {@link QuickStatusBarHeader}. */ +@QSScope class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader> { private static final String TAG = "QuickStatusBarHeader"; @@ -74,7 +76,7 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader private final ActivityStarter mActivityStarter; private final UiEventLogger mUiEventLogger; private final QSCarrierGroupController mQSCarrierGroupController; - private final QuickQSPanel mHeaderQsPanel; + private final QuickQSPanelController mHeaderQsPanelController; private final LifecycleRegistry mLifecycle; private final OngoingPrivacyChip mPrivacyChip; private final Clock mClockView; @@ -203,13 +205,14 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader } }; - private QuickStatusBarHeaderController(QuickStatusBarHeader view, + @Inject + QuickStatusBarHeaderController(QuickStatusBarHeader view, ZenModeController zenModeController, NextAlarmController nextAlarmController, PrivacyItemController privacyItemController, RingerModeTracker ringerModeTracker, ActivityStarter activityStarter, UiEventLogger uiEventLogger, QSTileHost qsTileHost, StatusBarIconController statusBarIconController, CommandQueue commandQueue, DemoModeController demoModeController, - UserTracker userTracker, + UserTracker userTracker, QuickQSPanelController quickQSPanelController, QSCarrierGroupController.Builder qsCarrierGroupControllerBuilder) { super(view); mZenModeController = zenModeController; @@ -224,6 +227,7 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader mDemoModeController = demoModeController; mUserTracker = userTracker; mLifecycle = new LifecycleRegistry(mLifecycleOwner); + mHeaderQsPanelController = quickQSPanelController; mQSCarrierGroupController = qsCarrierGroupControllerBuilder .setQSCarrierGroup(mView.findViewById(R.id.carrier_group)) @@ -231,7 +235,6 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader mPrivacyChip = mView.findViewById(R.id.privacy_chip); - mHeaderQsPanel = mView.findViewById(R.id.quick_qs_panel); mNextAlarmContainer = mView.findViewById(R.id.alarm_container); mClockView = mView.findViewById(R.id.clock); mRingerContainer = mView.findViewById(R.id.ringer_container); @@ -290,8 +293,12 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader } mListening = listening; - mHeaderQsPanel.setListening(listening); - if (mHeaderQsPanel.switchTileLayout()) { + mHeaderQsPanelController.setListening(listening); + if (mHeaderQsPanelController.isListening()) { + mHeaderQsPanelController.refreshAllTiles(); + } + + if (mHeaderQsPanelController.switchTileLayout(false)) { mView.updateResources(); } @@ -380,55 +387,4 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader mClockView.onDemoModeFinished(); } } - - static class Builder { - private final ZenModeController mZenModeController; - private final NextAlarmController mNextAlarmController; - private final PrivacyItemController mPrivacyItemController; - private final RingerModeTracker mRingerModeTracker; - private final ActivityStarter mActivityStarter; - private final UiEventLogger mUiEventLogger; - private final QSTileHost mQsTileHost; - private final StatusBarIconController mStatusBarIconController; - private final CommandQueue mCommandQueue; - private final DemoModeController mDemoModeController; - private final UserTracker mUserTracker; - private final QSCarrierGroupController.Builder mQSCarrierGroupControllerBuilder; - private QuickStatusBarHeader mView; - - @Inject - Builder(ZenModeController zenModeController, NextAlarmController nextAlarmController, - PrivacyItemController privacyItemController, RingerModeTracker ringerModeTracker, - ActivityStarter activityStarter, UiEventLogger uiEventLogger, QSTileHost qsTileHost, - StatusBarIconController statusBarIconController, CommandQueue commandQueue, - DemoModeController demoModeController, UserTracker userTracker, - QSCarrierGroupController.Builder qsCarrierGroupControllerBuilder) { - mZenModeController = zenModeController; - mNextAlarmController = nextAlarmController; - mPrivacyItemController = privacyItemController; - mRingerModeTracker = ringerModeTracker; - mActivityStarter = activityStarter; - mUiEventLogger = uiEventLogger; - mQsTileHost = qsTileHost; - mStatusBarIconController = statusBarIconController; - mCommandQueue = commandQueue; - mDemoModeController = demoModeController; - mUserTracker = userTracker; - mQSCarrierGroupControllerBuilder = qsCarrierGroupControllerBuilder; - } - - public Builder setQuickStatusBarHeader(QuickStatusBarHeader view) { - mView = view; - return this; - } - - - QuickStatusBarHeaderController build() { - return new QuickStatusBarHeaderController(mView, mZenModeController, - mNextAlarmController, mPrivacyItemController, mRingerModeTracker, - mActivityStarter, mUiEventLogger, mQsTileHost, mStatusBarIconController, - mCommandQueue, mDemoModeController, mUserTracker, - mQSCarrierGroupControllerBuilder); - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java index 694492a33524..4ab7afd46602 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java @@ -11,7 +11,7 @@ import android.view.ViewGroup; import com.android.systemui.R; import com.android.systemui.qs.QSPanel.QSTileLayout; -import com.android.systemui.qs.QSPanel.TileRecord; +import com.android.systemui.qs.QSPanelControllerBase.TileRecord; import java.util.ArrayList; diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java index 55b67e061c13..8097958fac39 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java @@ -74,9 +74,9 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene private final ScreenLifecycle mScreenLifecycle; private final TileQueryHelper mTileQueryHelper; private final View mTransparentView; + private final QSTileHost mHost; private boolean isShown; - private QSTileHost mHost; private RecyclerView mRecyclerView; private TileAdapter mTileAdapter; private Toolbar mToolbar; @@ -95,6 +95,7 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene KeyguardStateController keyguardStateController, ScreenLifecycle screenLifecycle, TileQueryHelper tileQueryHelper, + QSTileHost qsTileHost, UiEventLogger uiEventLogger) { super(new ContextThemeWrapper(context, R.style.edit_theme), attrs); @@ -139,6 +140,8 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene mLightBarController = lightBarController; mKeyguardStateController = keyguardStateController; mScreenLifecycle = screenLifecycle; + mHost = qsTileHost; + mTileAdapter.setHost(mHost); updateNavBackDrop(getResources().getConfiguration()); } @@ -170,11 +173,6 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene mLightBarController.setQsCustomizing(mIsShowingNavBackdrop && isShown); } - public void setHost(QSTileHost host) { - mHost = host; - mTileAdapter.setHost(host); - } - public void setContainer(NotificationsQuickSettingsContainer notificationsQsContainer) { mNotifQsContainer = notificationsQsContainer; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java new file mode 100644 index 000000000000..7ba3563f3b20 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java @@ -0,0 +1,51 @@ +/* + * 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.dagger; + +import com.android.systemui.qs.QSAnimator; +import com.android.systemui.qs.QSContainerImplController; +import com.android.systemui.qs.QSFragment; +import com.android.systemui.qs.QSPanelController; +import com.android.systemui.qs.QuickQSPanelController; + +import dagger.BindsInstance; +import dagger.Subcomponent; + +/** + * Dagger Subcomponent for {@link QSFragment}. + */ +@Subcomponent(modules = {QSFragmentModule.class}) +@QSScope +public interface QSFragmentComponent { + /** Factory for building a {@link QSFragmentComponent}. */ + @Subcomponent.Factory + interface Factory { + QSFragmentComponent create(@BindsInstance QSFragment qsFragment); + } + + /** Construct a {@link QSPanelController}. */ + QSPanelController getQSPanelController(); + + /** Construct a {@link QuickQSPanelController}. */ + QuickQSPanelController getQuickQSPanelController(); + + /** Construct a {@link QSAnimator}. */ + QSAnimator getQSAnimator(); + + /** Construct a {@link QSContainerImplController}. */ + QSContainerImplController getQSContainerImplController(); +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java new file mode 100644 index 000000000000..ee3f2f60fccc --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java @@ -0,0 +1,73 @@ +/* + * 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.dagger; + +import android.view.View; + +import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.RootView; +import com.android.systemui.plugins.qs.QS; +import com.android.systemui.qs.QSContainerImpl; +import com.android.systemui.qs.QSFragment; +import com.android.systemui.qs.QSPanel; +import com.android.systemui.qs.QuickQSPanel; +import com.android.systemui.qs.QuickStatusBarHeader; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; + +/** + * Dagger Module for {@link QSFragmentComponent}. + */ +@Module +public interface QSFragmentModule { + /** */ + @Provides + @RootView + static View provideRootView(QSFragment qsFragment) { + return qsFragment.getView(); + } + + /** */ + @Provides + static QSPanel provideQSPanel(@RootView View view) { + return view.findViewById(R.id.quick_settings_panel); + } + + /** */ + @Provides + static QSContainerImpl providesQSContainerImpl(@RootView View view) { + return view.findViewById(R.id.quick_settings_container); + } + + /** */ + @Binds + QS bindQS(QSFragment qsFragment); + + /** */ + @Provides + static QuickStatusBarHeader providesQuickStatusBarHeader(@RootView View view) { + return view.findViewById(R.id.header); + } + + /** */ + @Provides + static QuickQSPanel providesQuickQSPanel(QuickStatusBarHeader quickStatusBarHeader) { + return quickStatusBarHeader.findViewById(R.id.quick_qs_panel); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java index 953de6086ac7..7c799aefe90d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java +++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java @@ -38,8 +38,8 @@ import dagger.Provides; /** * Module for QS dependencies */ -// TODO: Add other QS classes -@Module(includes = {MediaModule.class}) +@Module(subcomponents = {QSFragmentComponent.class}, + includes = {MediaModule.class}) public interface QSModule { @Provides @@ -60,7 +60,6 @@ public interface QSModule { return manager; } - /** */ @Binds QSHost provideQsHost(QSTileHost controllerImpl); diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSScope.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSScope.java new file mode 100644 index 000000000000..f615eabb67dc --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSScope.java @@ -0,0 +1,32 @@ +/* + * 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.dagger; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import javax.inject.Scope; + +/** + * Scope annotation for singleton items within the {@link QSFragmentComponent}. + */ +@Documented +@Retention(RUNTIME) +@Scope +public @interface QSScope {} diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java index 1bea72aea2ba..72034f84fd30 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java +++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java @@ -50,6 +50,8 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import java.util.ArrayList; +import javax.inject.Inject; + public class BrightnessController implements ToggleSlider.Listener { private static final String TAG = "StatusBar.BrightnessController"; private static final int SLIDER_ANIMATION_DURATION = 3000; @@ -475,4 +477,20 @@ public class BrightnessController implements ToggleSlider.Listener { mSliderAnimator.start(); } + /** Factory for creating a {@link BrightnessController}. */ + public static class Factory { + private final Context mContext; + private final BroadcastDispatcher mBroadcastDispatcher; + + @Inject + public Factory(Context context, BroadcastDispatcher broadcastDispatcher) { + mContext = context; + mBroadcastDispatcher = broadcastDispatcher; + } + + /** Create a {@link BrightnessController} */ + public BrightnessController create(ToggleSlider toggleSlider) { + return new BrightnessController(mContext, toggleSlider, mBroadcastDispatcher); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index af6ac223ada1..2767b7e1627d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -38,9 +38,9 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.ViewMediatorCallback; import com.android.keyguard.dagger.KeyguardBouncerComponent; -import com.android.keyguard.dagger.RootView; import com.android.systemui.DejankUtils; import com.android.systemui.biometrics.AuthController; +import com.android.systemui.dagger.qualifiers.RootView; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.shared.system.SysUiStatsLog; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index f55c93580210..c7932bb44cf4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -172,7 +172,7 @@ import com.android.systemui.plugins.qs.QS; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSFragment; -import com.android.systemui.qs.QSPanel; +import com.android.systemui.qs.QSPanelController; import com.android.systemui.recents.ScreenPinningRequest; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.shared.system.WindowManagerWrapper; @@ -408,7 +408,7 @@ public class StatusBar extends SystemUI implements DemoMode, protected NotificationPanelViewController mNotificationPanelViewController; // settings - private QSPanel mQSPanel; + private QSPanelController mQSPanelController; KeyguardIndicationController mKeyguardIndicationController; @@ -1200,8 +1200,8 @@ public class StatusBar extends SystemUI implements DemoMode, fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> { QS qs = (QS) f; if (qs instanceof QSFragment) { - mQSPanel = ((QSFragment) qs).getQsPanel(); - mQSPanel.setBrightnessMirror(mBrightnessMirrorController); + mQSPanelController = ((QSFragment) qs).getQSPanelController(); + mQSPanelController.setBrightnessMirror(mBrightnessMirrorController); } }); } @@ -1593,19 +1593,19 @@ public class StatusBar extends SystemUI implements DemoMode, } public void addQsTile(ComponentName tile) { - if (mQSPanel != null && mQSPanel.getHost() != null) { - mQSPanel.getHost().addTile(tile); + if (mQSPanelController != null && mQSPanelController.getHost() != null) { + mQSPanelController.getHost().addTile(tile); } } public void remQsTile(ComponentName tile) { - if (mQSPanel != null && mQSPanel.getHost() != null) { - mQSPanel.getHost().removeTile(tile); + if (mQSPanelController != null && mQSPanelController.getHost() != null) { + mQSPanelController.getHost().removeTile(tile); } } public void clickTile(ComponentName tile) { - mQSPanel.clickTile(tile); + mQSPanelController.clickTile(tile); } /** @@ -2197,7 +2197,7 @@ public class StatusBar extends SystemUI implements DemoMode, if (!mUserSetup) return; if (subPanel != null) { - mQSPanel.openDetails(subPanel); + mQSPanelController.openDetails(subPanel); } mNotificationPanelViewController.expandWithQs(); @@ -2845,7 +2845,7 @@ public class StatusBar extends SystemUI implements DemoMode, resetUserExpandedStates(); } else if (DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG.equals(action)) { - mQSPanel.showDeviceMonitoringDialog(); + mQSPanelController.showDeviceMonitoringDialog(); } Trace.endSection(); } @@ -2936,8 +2936,8 @@ public class StatusBar extends SystemUI implements DemoMode, */ void updateResources() { // Update the quick setting tiles - if (mQSPanel != null) { - mQSPanel.updateResources(); + if (mQSPanelController != null) { + mQSPanelController.updateResources(); } if (mStatusBarWindowController != null) { @@ -3402,8 +3402,8 @@ public class StatusBar extends SystemUI implements DemoMode, // Keyguard state has changed, but QS is not listening anymore. Make sure to update the tile // visibilities so next time we open the panel we know the correct height already. - if (mQSPanel != null) { - mQSPanel.refreshAllTiles(); + if (mQSPanelController != null) { + mQSPanelController.refreshAllTiles(); } mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT); releaseGestureWakeLock(); 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 e472cb22ed6b..90609ccb48d6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -16,7 +16,9 @@ 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.Mockito.mock; +import static org.mockito.Mockito.when; import android.app.Fragment; import android.content.Context; @@ -42,6 +44,7 @@ import com.android.systemui.SysuiBaseFragmentTest; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.qs.dagger.QSFragmentComponent; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSFactoryImpl; import com.android.systemui.settings.UserTracker; @@ -61,6 +64,8 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import java.util.Optional; @@ -71,6 +76,12 @@ import java.util.Optional; public class QSFragmentTest extends SysuiBaseFragmentTest { private MetricsLogger mMockMetricsLogger; + @Mock + private QSFragmentComponent.Factory mQsComponentFactory; + @Mock + private QSFragmentComponent mQsFragmentComponent; + @Mock + private QSPanelController mQSPanelController; public QSFragmentTest() { super(QSFragment.class); @@ -80,6 +91,10 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { @Before @Ignore("failing") public void addLeakCheckDependencies() { + MockitoAnnotations.initMocks(this); + when(mQsComponentFactory.create(any(QSFragment.class))).thenReturn(mQsFragmentComponent); + when(mQsFragmentComponent.getQSPanelController()).thenReturn(mQSPanelController); + mMockMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class); mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE, new LayoutInflaterBuilder(mContext) @@ -152,6 +167,6 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { mock(QSTileHost.class), mock(StatusBarStateController.class), commandQueue, - mock(QSContainerImplController.Builder.class)); + mQsComponentFactory); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java new file mode 100644 index 000000000000..bf0e0841de9a --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java @@ -0,0 +1,141 @@ +/* + * 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 org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +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.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.tileimpl.QSTileImpl; + +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 MediaHost mMediaHost; + @Mock + private MetricsLogger mMetricsLogger; + private UiEventLoggerFake mUiEventLogger = new UiEventLoggerFake(); + private DumpManager mDumpManager = new DumpManager(); + @Mock + QSTileImpl mQSTile; + @Mock + QSTileView mQSTileView; + + private QSPanelControllerBase<QSPanel> mController; + + /** Implementation needed to ensure we have a reflectively-available class name. */ + private static class TestableQSPanelControllerBase extends QSPanelControllerBase<QSPanel> { + protected TestableQSPanelControllerBase(QSPanel view, QSTileHost host, + MetricsLogger metricsLogger, + UiEventLogger uiEventLogger, DumpManager dumpManager) { + super(view, host, metricsLogger, uiEventLogger, dumpManager); + } + } + + @Before + public void setup() throws Exception { + MockitoAnnotations.initMocks(this); + + when(mQSPanel.getMediaHost()).thenReturn(mMediaHost); + 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(mQSTileHost.getTiles()).thenReturn(Collections.singleton(mQSTile)); + when(mQSTileHost.createTileView(eq(mQSTile), anyBoolean())).thenReturn(mQSTileView); + + mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost, + mMetricsLogger, mUiEventLogger, mDumpManager); + + mController.init(); + } + + @Test + public void testSetExpanded_Metrics() { + mController.setExpanded(true); + verify(mMetricsLogger).visibility(eq(MetricsEvent.QS_PANEL), eq(true)); + assertEquals(1, mUiEventLogger.numLogs()); + assertEquals(QSEvent.QS_PANEL_EXPANDED.getId(), mUiEventLogger.eventId(0)); + mUiEventLogger.getLogs().clear(); + + mController.setExpanded(false); + verify(mMetricsLogger).visibility(eq(MetricsEvent.QS_PANEL), eq(false)); + 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()); + } + +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java new file mode 100644 index 000000000000..0ba0214d2173 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java @@ -0,0 +1,106 @@ +/* + * 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 org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +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.testing.UiEventLoggerFake; +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.tileimpl.QSTileImpl; +import com.android.systemui.settings.BrightnessController; +import com.android.systemui.settings.ToggleSlider; +import com.android.systemui.tuner.TunerService; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Collections; + +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +@SmallTest +public class QSPanelControllerTest extends SysuiTestCase { + + @Mock + private QSPanel mQSPanel; + @Mock + private QSTileHost mQSTileHost; + @Mock + private MediaHost mMediaHost; + @Mock + private MetricsLogger mMetricsLogger; + private UiEventLogger mUiEventLogger = new UiEventLoggerFake(); + private DumpManager mDumpManager = new DumpManager(); + @Mock + private TunerService mTunerService; + @Mock + private QSSecurityFooter mQSSecurityFooter; + @Mock + private BrightnessController.Factory mBrightnessControllerFactory; + @Mock + private BrightnessController mBrightnessController; + @Mock + QSTileImpl mQSTile; + @Mock + QSTileView mQSTileView; + + private QSPanelController mController; + + @Before + public void setup() throws Exception { + MockitoAnnotations.initMocks(this); + + when(mQSPanel.getMediaHost()).thenReturn(mMediaHost); + when(mQSPanel.isAttachedToWindow()).thenReturn(true); + when(mQSPanel.getDumpableTag()).thenReturn("QSPanel"); + when(mQSTileHost.getTiles()).thenReturn(Collections.singleton(mQSTile)); + when(mQSTileHost.createTileView(eq(mQSTile), anyBoolean())).thenReturn(mQSTileView); + when(mBrightnessControllerFactory.create(any(ToggleSlider.class))) + .thenReturn(mBrightnessController); + + mController = new QSPanelController(mQSPanel, mQSSecurityFooter, mTunerService, + mQSTileHost, mDumpManager, mMetricsLogger, mUiEventLogger, + mBrightnessControllerFactory); + + mController.init(); + } + + @Test + public void testOpenDetailsWithNonExistingTile_NoException() { + mController.openDetails("none"); + + verify(mQSPanel, never()).openDetails(any()); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java index 4b7a26870308..e38d54b90f69 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java @@ -14,12 +14,9 @@ package com.android.systemui.qs; -import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; -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.verify; @@ -36,19 +33,15 @@ import android.widget.FrameLayout; import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; -import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.dump.DumpManager; import com.android.systemui.media.MediaHost; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTileView; import com.android.systemui.qs.customize.QSCustomizer; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; -import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.policy.SecurityController; import com.android.systemui.util.animation.DisappearParameters; import com.android.systemui.util.animation.UniqueObjectHostView; @@ -59,9 +52,6 @@ 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) @@ -79,9 +69,9 @@ public class QSPanelTest extends SysuiTestCase { @Mock private QSTileImpl dndTile; @Mock - private BroadcastDispatcher mBroadcastDispatcher; + private QSTileImpl mNonTile; @Mock - private DumpManager mDumpManager; + private QSPanelControllerBase.TileRecord mDndTileRecord; @Mock private QSLogger mQSLogger; private ViewGroup mParentView; @@ -93,9 +83,8 @@ public class QSPanelTest extends SysuiTestCase { private MediaHost mMediaHost; @Mock private ActivityStarter mActivityStarter; - @Mock(stubOnly = true) - private UserTracker mUserTracker; private UiEventLoggerFake mUiEventLogger; + private String mCachedSpecs = ""; @Before public void setup() throws Exception { @@ -109,12 +98,13 @@ public class QSPanelTest extends SysuiTestCase { mContext.addMockSystemService(Context.USER_SERVICE, mock(UserManager.class)); when(mMediaHost.getHostView()).thenReturn(new UniqueObjectHostView(getContext())); when(mMediaHost.getDisappearParameters()).thenReturn(new DisappearParameters()); + mDndTileRecord.tile = dndTile; + mDndTileRecord.tileView = mQSTileView; mUiEventLogger = new UiEventLoggerFake(); mTestableLooper.runWithLooper(() -> { mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class); - mQsPanel = new QSPanel(mContext, null, mDumpManager, mBroadcastDispatcher, - mQSLogger, mMediaHost, mUiEventLogger, mUserTracker); + mQsPanel = new QSPanel(mContext, null, mQSLogger, mMediaHost, mUiEventLogger); mQsPanel.onFinishInflate(); // Provides a parent with non-zero size for QSPanel mParentView = new FrameLayout(mContext); @@ -124,8 +114,8 @@ public class QSPanelTest extends SysuiTestCase { when(mHost.getTiles()).thenReturn(Collections.emptyList()); when(mHost.createTileView(any(), anyBoolean())).thenReturn(mQSTileView); - mQsPanel.setHost(mHost, mCustomizer); - mQsPanel.addTile(dndTile, true); + mQsPanel.setCustomizer(mCustomizer); + mQsPanel.addTile(mDndTileRecord); mQsPanel.setCallback(mCallback); }); } @@ -133,25 +123,16 @@ public class QSPanelTest extends SysuiTestCase { @Test public void testSetExpanded_Metrics() { mQsPanel.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(); mQsPanel.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 testOpenDetailsWithExistingTile_NoException() { mTestableLooper.processAllMessages(); - mQsPanel.openDetails("dnd"); + mQsPanel.openDetails(dndTile); mTestableLooper.processAllMessages(); verify(mCallback).onShowingDetail(any(), anyInt(), anyInt()); @@ -159,53 +140,19 @@ public class QSPanelTest extends SysuiTestCase { @Test public void setListening() { - when(dndTile.getTileSpec()).thenReturn("dnd"); - - mQsPanel.setListening(true); + mQsPanel.setListening(true, "dnd"); verify(mQSLogger).logAllTilesChangeListening(true, mQsPanel.getDumpableTag(), "dnd"); - mQsPanel.setListening(false); + mQsPanel.setListening(false, "dnd"); verify(mQSLogger).logAllTilesChangeListening(false, mQsPanel.getDumpableTag(), "dnd"); } -/* @Test + @Test public void testOpenDetailsWithNullParameter_NoException() { mTestableLooper.processAllMessages(); mQsPanel.openDetails(null); mTestableLooper.processAllMessages(); verify(mCallback, never()).onShowingDetail(any(), anyInt(), anyInt()); - }*/ - - @Test - public void testOpenDetailsWithNonExistingTile_NoException() { - mTestableLooper.processAllMessages(); - mQsPanel.openDetails("invalid-name"); - mTestableLooper.processAllMessages(); - - verify(mCallback, never()).onShowingDetail(any(), anyInt(), anyInt()); - } - - @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(dndTile).dump(any(FileDescriptor.class), any(PrintWriter.class), - any(String[].class)); - when(mQSTileView.toString()).thenReturn(mockTileViewString); - - StringWriter w = new StringWriter(); - PrintWriter pw = new PrintWriter(w); - mQsPanel.dump(mock(FileDescriptor.class), pw, new String[]{}); - String expected = "QSPanel:\n" - + " Tile records:\n" - + " " + mockTileString + "\n" - + " " + mockTileViewString + "\n"; - assertEquals(expected, w.getBuffer().toString()); } - } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java index fef47bd6a392..6c7c20a15140 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java @@ -57,8 +57,8 @@ public class TileLayoutTest extends SysuiTestCase { mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal) * 3; } - private QSPanel.TileRecord createTileRecord() { - QSPanel.TileRecord tileRecord = new QSPanel.TileRecord(); + private QSPanelControllerBase.TileRecord createTileRecord() { + QSPanelControllerBase.TileRecord tileRecord = new QSPanelControllerBase.TileRecord(); tileRecord.tile = mock(QSTile.class); tileRecord.tileView = spy(new QSTileView(mContext, new QSIconViewImpl(mContext))); return tileRecord; @@ -66,14 +66,14 @@ public class TileLayoutTest extends SysuiTestCase { @Test public void testAddTile_CallsSetListeningOnTile() { - QSPanel.TileRecord tileRecord = createTileRecord(); + QSPanelControllerBase.TileRecord tileRecord = createTileRecord(); mTileLayout.addTile(tileRecord); verify(tileRecord.tile, times(1)).setListening(mTileLayout, false); } @Test public void testSetListening_CallsSetListeningOnTile() { - QSPanel.TileRecord tileRecord = createTileRecord(); + QSPanelControllerBase.TileRecord tileRecord = createTileRecord(); mTileLayout.addTile(tileRecord); mTileLayout.setListening(true); verify(tileRecord.tile, times(1)).setListening(mTileLayout, true); @@ -81,7 +81,7 @@ public class TileLayoutTest extends SysuiTestCase { @Test public void testSetListening_SameValueIsNoOp() { - QSPanel.TileRecord tileRecord = createTileRecord(); + QSPanelControllerBase.TileRecord tileRecord = createTileRecord(); mTileLayout.addTile(tileRecord); mTileLayout.setListening(false); verify(tileRecord.tile, times(1)).setListening(any(), anyBoolean()); @@ -89,7 +89,7 @@ public class TileLayoutTest extends SysuiTestCase { @Test public void testSetListening_ChangesValueForAddingFutureTiles() { - QSPanel.TileRecord tileRecord = createTileRecord(); + QSPanelControllerBase.TileRecord tileRecord = createTileRecord(); mTileLayout.setListening(true); mTileLayout.addTile(tileRecord); verify(tileRecord.tile, times(1)).setListening(mTileLayout, true); @@ -97,7 +97,7 @@ public class TileLayoutTest extends SysuiTestCase { @Test public void testRemoveTile_CallsSetListeningFalseOnTile() { - QSPanel.TileRecord tileRecord = createTileRecord(); + QSPanelControllerBase.TileRecord tileRecord = createTileRecord(); mTileLayout.setListening(true); mTileLayout.addTile(tileRecord); mTileLayout.removeTile(tileRecord); @@ -106,8 +106,8 @@ public class TileLayoutTest extends SysuiTestCase { @Test public void testRemoveAllViews_CallsSetListeningFalseOnAllTiles() { - QSPanel.TileRecord tileRecord1 = createTileRecord(); - QSPanel.TileRecord tileRecord2 = createTileRecord(); + QSPanelControllerBase.TileRecord tileRecord1 = createTileRecord(); + QSPanelControllerBase.TileRecord tileRecord2 = createTileRecord(); mTileLayout.setListening(true); mTileLayout.addTile(tileRecord1); mTileLayout.addTile(tileRecord2); @@ -118,7 +118,7 @@ public class TileLayoutTest extends SysuiTestCase { @Test public void testMeasureLayout_CallsLayoutOnTile() { - QSPanel.TileRecord tileRecord = createTileRecord(); + QSPanelControllerBase.TileRecord tileRecord = createTileRecord(); mTileLayout.addTile(tileRecord); mTileLayout.measure(mLayoutSizeForOneTile, mLayoutSizeForOneTile); mTileLayout.layout(0, 0, mLayoutSizeForOneTile, mLayoutSizeForOneTile); @@ -127,8 +127,8 @@ public class TileLayoutTest extends SysuiTestCase { @Test public void testMeasureLayout_CallsLayoutOnTilesWithNeighboredBounds() { - QSPanel.TileRecord tileRecord1 = createTileRecord(); - QSPanel.TileRecord tileRecord2 = createTileRecord(); + QSPanelControllerBase.TileRecord tileRecord1 = createTileRecord(); + QSPanelControllerBase.TileRecord tileRecord2 = createTileRecord(); mTileLayout.addTile(tileRecord1); mTileLayout.addTile(tileRecord2); mTileLayout.measure(mLayoutSizeForOneTile * 2, mLayoutSizeForOneTile * 2); |