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