1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.qs;
18 
19 import static com.android.systemui.classifier.Classifier.QS_SWIPE;
20 import static com.android.systemui.media.dagger.MediaModule.QS_PANEL;
21 import static com.android.systemui.qs.QSPanel.QS_SHOW_BRIGHTNESS;
22 import static com.android.systemui.qs.dagger.QSFragmentModule.QS_USING_MEDIA_PLAYER;
23 
24 import android.annotation.NonNull;
25 import android.content.res.Configuration;
26 import android.view.MotionEvent;
27 import android.view.View;
28 import android.view.ViewGroup;
29 
30 import com.android.internal.logging.MetricsLogger;
31 import com.android.internal.logging.UiEventLogger;
32 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
33 import com.android.systemui.dump.DumpManager;
34 import com.android.systemui.media.MediaHierarchyManager;
35 import com.android.systemui.media.MediaHost;
36 import com.android.systemui.plugins.FalsingManager;
37 import com.android.systemui.plugins.qs.DetailAdapter;
38 import com.android.systemui.plugins.qs.QSTile;
39 import com.android.systemui.qs.customize.QSCustomizerController;
40 import com.android.systemui.qs.dagger.QSScope;
41 import com.android.systemui.qs.logging.QSLogger;
42 import com.android.systemui.settings.brightness.BrightnessController;
43 import com.android.systemui.settings.brightness.BrightnessMirrorHandler;
44 import com.android.systemui.settings.brightness.BrightnessSliderController;
45 import com.android.systemui.statusbar.CommandQueue;
46 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
47 import com.android.systemui.tuner.TunerService;
48 import com.android.systemui.util.Utils;
49 
50 import javax.inject.Inject;
51 import javax.inject.Named;
52 
53 /**
54  * Controller for {@link QSPanel}.
55  */
56 @QSScope
57 public class QSPanelController extends QSPanelControllerBase<QSPanel> {
58     public static final String QS_REMOVE_LABELS = "sysui_remove_labels";
59 
60     private final QSSecurityFooter mQsSecurityFooter;
61     private final TunerService mTunerService;
62     private final QSCustomizerController mQsCustomizerController;
63     private final QSTileRevealController.Factory mQsTileRevealControllerFactory;
64     private final FalsingManager mFalsingManager;
65     private final CommandQueue mCommandQueue;
66     private final BrightnessController mBrightnessController;
67     private final BrightnessSliderController mBrightnessSliderController;
68     private final BrightnessMirrorHandler mBrightnessMirrorHandler;
69 
70     private boolean mGridContentVisible = true;
71 
72     private final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener =
73             new QSPanel.OnConfigurationChangedListener() {
74         @Override
75         public void onConfigurationChange(Configuration newConfig) {
76             updateMediaExpansion();
77             mView.updateResources();
78             mQsSecurityFooter.onConfigurationChanged();
79             if (mView.isListening()) {
80                 refreshAllTiles();
81             }
82             mView.switchSecurityFooter(mShouldUseSplitNotificationShade);
83         }
84     };
85 
86     private View.OnTouchListener mTileLayoutTouchListener = new View.OnTouchListener() {
87         @Override
88         public boolean onTouch(View v, MotionEvent event) {
89             if (event.getActionMasked() == MotionEvent.ACTION_UP) {
90                 mFalsingManager.isFalseTouch(QS_SWIPE);
91             }
92             return false;
93         }
94     };
95 
96     @Inject
QSPanelController(QSPanel view, QSSecurityFooter qsSecurityFooter, TunerService tunerService, QSTileHost qstileHost, QSCustomizerController qsCustomizerController, @Named(QS_USING_MEDIA_PLAYER) boolean usingMediaPlayer, @Named(QS_PANEL) MediaHost mediaHost, QSTileRevealController.Factory qsTileRevealControllerFactory, DumpManager dumpManager, MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger, BrightnessController.Factory brightnessControllerFactory, BrightnessSliderController.Factory brightnessSliderFactory, FalsingManager falsingManager, CommandQueue commandQueue)97     QSPanelController(QSPanel view, QSSecurityFooter qsSecurityFooter, TunerService tunerService,
98             QSTileHost qstileHost, QSCustomizerController qsCustomizerController,
99             @Named(QS_USING_MEDIA_PLAYER) boolean usingMediaPlayer,
100             @Named(QS_PANEL) MediaHost mediaHost,
101             QSTileRevealController.Factory qsTileRevealControllerFactory,
102             DumpManager dumpManager, MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
103             QSLogger qsLogger, BrightnessController.Factory brightnessControllerFactory,
104             BrightnessSliderController.Factory brightnessSliderFactory,
105             FalsingManager falsingManager, CommandQueue commandQueue) {
106         super(view, qstileHost, qsCustomizerController, usingMediaPlayer, mediaHost,
107                 metricsLogger, uiEventLogger, qsLogger, dumpManager);
108         mQsSecurityFooter = qsSecurityFooter;
109         mTunerService = tunerService;
110         mQsCustomizerController = qsCustomizerController;
111         mQsTileRevealControllerFactory = qsTileRevealControllerFactory;
112         mFalsingManager = falsingManager;
113         mCommandQueue = commandQueue;
114         mQsSecurityFooter.setHostEnvironment(qstileHost);
115 
116         mBrightnessSliderController = brightnessSliderFactory.create(getContext(), mView);
117         mView.setBrightnessView(mBrightnessSliderController.getRootView());
118 
119         mBrightnessController = brightnessControllerFactory.create(mBrightnessSliderController);
120         mBrightnessMirrorHandler = new BrightnessMirrorHandler(mBrightnessController);
121     }
122 
123     @Override
onInit()124     public void onInit() {
125         super.onInit();
126         updateMediaExpansion();
127         mMediaHost.setShowsOnlyActiveMedia(false);
128         mMediaHost.init(MediaHierarchyManager.LOCATION_QS);
129         mQsCustomizerController.init();
130         mBrightnessSliderController.init();
131     }
132 
updateMediaExpansion()133     private void updateMediaExpansion() {
134         mMediaHost.setExpansion(Utils.shouldUseSplitNotificationShade(getResources()) ? 0 : 1);
135     }
136 
137     @Override
onViewAttached()138     protected void onViewAttached() {
139         super.onViewAttached();
140 
141         updateMediaDisappearParameters();
142 
143         mTunerService.addTunable(mView, QS_SHOW_BRIGHTNESS);
144         mView.updateResources();
145         if (mView.isListening()) {
146             refreshAllTiles();
147         }
148         mView.addOnConfigurationChangedListener(mOnConfigurationChangedListener);
149         mView.setSecurityFooter(mQsSecurityFooter.getView(), mShouldUseSplitNotificationShade);
150         switchTileLayout(true);
151         mBrightnessMirrorHandler.onQsPanelAttached();
152 
153         ((PagedTileLayout) mView.getOrCreateTileLayout())
154                 .setOnTouchListener(mTileLayoutTouchListener);
155     }
156 
157     @Override
createTileRevealController()158     protected QSTileRevealController createTileRevealController() {
159         return mQsTileRevealControllerFactory.create(
160                 this, (PagedTileLayout) mView.getOrCreateTileLayout());
161     }
162 
163     @Override
onViewDetached()164     protected void onViewDetached() {
165         mTunerService.removeTunable(mView);
166         mView.removeOnConfigurationChangedListener(mOnConfigurationChangedListener);
167         mBrightnessMirrorHandler.onQsPanelDettached();
168         super.onViewDetached();
169     }
170 
171     /**
172      * Set the header container of quick settings.
173      */
setHeaderContainer(@onNull ViewGroup headerContainer)174     public void setHeaderContainer(@NonNull ViewGroup headerContainer) {
175         mView.setHeaderContainer(headerContainer);
176     }
177 
178     /** */
setVisibility(int visibility)179     public void setVisibility(int visibility) {
180         mView.setVisibility(visibility);
181     }
182 
183     /** */
setListening(boolean listening, boolean expanded)184     public void setListening(boolean listening, boolean expanded) {
185         setListening(listening && expanded);
186         if (mView.isListening()) {
187             refreshAllTiles();
188         }
189 
190         mQsSecurityFooter.setListening(listening);
191 
192         // Set the listening as soon as the QS fragment starts listening regardless of the
193         //expansion, so it will update the current brightness before the slider is visible.
194         if (listening) {
195             mBrightnessController.registerCallbacks();
196         } else {
197             mBrightnessController.unregisterCallbacks();
198         }
199     }
200 
setBrightnessMirror(BrightnessMirrorController brightnessMirrorController)201     public void setBrightnessMirror(BrightnessMirrorController brightnessMirrorController) {
202         mBrightnessMirrorHandler.setController(brightnessMirrorController);
203     }
204 
205     /** Get the QSTileHost this panel uses. */
getHost()206     public QSTileHost getHost() {
207         return mHost;
208     }
209 
210 
211     /** Open the details for a specific tile.. */
openDetails(String subPanel)212     public void openDetails(String subPanel) {
213         QSTile tile = getTile(subPanel);
214         if (tile != null) {
215             mView.openDetails(tile);
216         }
217     }
218 
219     /** Show the device monitoring dialog. */
showDeviceMonitoringDialog()220     public void showDeviceMonitoringDialog() {
221         mQsSecurityFooter.showDeviceMonitoringDialog();
222     }
223 
224     /** Update appearance of QSPanel. */
updateResources()225     public void updateResources() {
226         mView.updateResources();
227     }
228 
229     /** Update state of all tiles. */
refreshAllTiles()230     public void refreshAllTiles() {
231         mBrightnessController.checkRestrictionAndSetEnabled();
232         super.refreshAllTiles();
233         mQsSecurityFooter.refreshState();
234     }
235 
236     /** Start customizing the Quick Settings. */
showEdit(View view)237     public void showEdit(View view) {
238         view.post(() -> {
239             if (!mQsCustomizerController.isCustomizing()) {
240                 int[] loc = view.getLocationOnScreen();
241                 int x = loc[0] + view.getWidth() / 2;
242                 int y = loc[1] + view.getHeight() / 2;
243                 mQsCustomizerController.show(x, y, false);
244             }
245         });
246     }
247 
248     /** */
setCallback(QSDetail.Callback qsPanelCallback)249     public void setCallback(QSDetail.Callback qsPanelCallback) {
250         mView.setCallback(qsPanelCallback);
251     }
252 
253     /** */
setGridContentVisibility(boolean visible)254     public void setGridContentVisibility(boolean visible) {
255         int newVis = visible ? View.VISIBLE : View.INVISIBLE;
256         setVisibility(newVis);
257         if (mGridContentVisible != visible) {
258             mMetricsLogger.visibility(MetricsEvent.QS_PANEL, newVis);
259         }
260         mGridContentVisible = visible;
261     }
262 
isLayoutRtl()263     public boolean isLayoutRtl() {
264         return mView.isLayoutRtl();
265     }
266 
267     /** */
setPageListener(PagedTileLayout.PageListener listener)268     public void setPageListener(PagedTileLayout.PageListener listener) {
269         mView.setPageListener(listener);
270     }
271 
isShown()272     public boolean isShown() {
273         return mView.isShown();
274     }
275 
276     /** */
setContentMargins(int startMargin, int endMargin)277     public void setContentMargins(int startMargin, int endMargin) {
278         mView.setContentMargins(startMargin, endMargin, mMediaHost.getHostView());
279     }
280 
281     /** */
showDetailAdapter(DetailAdapter detailAdapter, int x, int y)282     public void showDetailAdapter(DetailAdapter detailAdapter, int x, int y) {
283         // TODO(b/199296365)
284         // Workaround for opening detail from QQS, when there might not be enough space to
285         // display e.g. in case of multiuser detail from split shade. Currently showing detail works
286         // only for QS (mView below) and that's why expanding panel (thus showing QS instead of QQS)
287         // makes it displayed correctly.
288         if (!isExpanded()) {
289             mCommandQueue.animateExpandSettingsPanel(null);
290         }
291         mView.showDetailAdapter(true, detailAdapter, new int[]{x, y});
292     }
293 
294     /** */
setFooterPageIndicator(PageIndicator pageIndicator)295     public void setFooterPageIndicator(PageIndicator pageIndicator) {
296         mView.setFooterPageIndicator(pageIndicator);
297     }
298 
299     /** */
isExpanded()300     public boolean isExpanded() {
301         return mView.isExpanded();
302     }
303 
setPageMargin(int pageMargin)304     void setPageMargin(int pageMargin) {
305         mView.setPageMargin(pageMargin);
306     }
307 }
308 
309