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_SIDE; 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.QSScopeModule.QS_USING_MEDIA_PLAYER; 23 24 import android.view.MotionEvent; 25 import android.view.View; 26 27 import androidx.annotation.Nullable; 28 29 import com.android.internal.logging.MetricsLogger; 30 import com.android.internal.logging.UiEventLogger; 31 import com.android.systemui.dump.DumpManager; 32 import com.android.systemui.haptics.qs.QSLongPressEffect; 33 import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor; 34 import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager; 35 import com.android.systemui.media.controls.ui.view.MediaHost; 36 import com.android.systemui.media.controls.ui.view.MediaHostState; 37 import com.android.systemui.plugins.FalsingManager; 38 import com.android.systemui.qs.customize.QSCustomizerController; 39 import com.android.systemui.qs.dagger.QSScope; 40 import com.android.systemui.qs.logging.QSLogger; 41 import com.android.systemui.scene.shared.flag.SceneContainerFlag; 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.settings.brightness.MirrorController; 46 import com.android.systemui.shade.ShadeDisplayAware; 47 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; 48 import com.android.systemui.statusbar.policy.ConfigurationController; 49 import com.android.systemui.statusbar.policy.SplitShadeStateController; 50 import com.android.systemui.tuner.TunerService; 51 52 import kotlinx.coroutines.flow.StateFlow; 53 54 import javax.inject.Inject; 55 import javax.inject.Named; 56 import javax.inject.Provider; 57 58 59 /** 60 * Controller for {@link QSPanel}. 61 */ 62 @QSScope 63 public class QSPanelController extends QSPanelControllerBase<QSPanel> { 64 65 private final TunerService mTunerService; 66 private final QSCustomizerController mQsCustomizerController; 67 private final QSTileRevealController.Factory mQsTileRevealControllerFactory; 68 private final FalsingManager mFalsingManager; 69 private BrightnessController mBrightnessController; 70 private BrightnessSliderController mBrightnessSliderController; 71 private BrightnessMirrorHandler mBrightnessMirrorHandler; 72 private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; 73 private boolean mListening; 74 75 private final boolean mSceneContainerEnabled; 76 77 private int mLastDensity; 78 private final BrightnessSliderController.Factory mBrightnessSliderControllerFactory; 79 private final BrightnessController.Factory mBrightnessControllerFactory; 80 81 protected final MediaCarouselInteractor mMediaCarouselInteractor; 82 83 private View.OnTouchListener mTileLayoutTouchListener = new View.OnTouchListener() { 84 @Override 85 public boolean onTouch(View v, MotionEvent event) { 86 if (event.getActionMasked() == MotionEvent.ACTION_UP) { 87 mFalsingManager.isFalseTouch(QS_SWIPE_SIDE); 88 } 89 return false; 90 } 91 }; 92 93 @Inject QSPanelController(QSPanel view, TunerService tunerService, QSHost qsHost, 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, StatusBarKeyguardViewManager statusBarKeyguardViewManager, SplitShadeStateController splitShadeStateController, Provider<QSLongPressEffect> longPRessEffectProvider, MediaCarouselInteractor mediaCarouselInteractor, @ShadeDisplayAware ConfigurationController configurationController)94 QSPanelController(QSPanel view, TunerService tunerService, 95 QSHost qsHost, QSCustomizerController qsCustomizerController, 96 @Named(QS_USING_MEDIA_PLAYER) boolean usingMediaPlayer, 97 @Named(QS_PANEL) MediaHost mediaHost, 98 QSTileRevealController.Factory qsTileRevealControllerFactory, 99 DumpManager dumpManager, MetricsLogger metricsLogger, UiEventLogger uiEventLogger, 100 QSLogger qsLogger, BrightnessController.Factory brightnessControllerFactory, 101 BrightnessSliderController.Factory brightnessSliderFactory, 102 FalsingManager falsingManager, 103 StatusBarKeyguardViewManager statusBarKeyguardViewManager, 104 SplitShadeStateController splitShadeStateController, 105 Provider<QSLongPressEffect> longPRessEffectProvider, 106 MediaCarouselInteractor mediaCarouselInteractor, 107 @ShadeDisplayAware ConfigurationController configurationController) { 108 super(view, qsHost, qsCustomizerController, usingMediaPlayer, mediaHost, 109 metricsLogger, uiEventLogger, qsLogger, dumpManager, splitShadeStateController, 110 longPRessEffectProvider, configurationController); 111 mTunerService = tunerService; 112 mQsCustomizerController = qsCustomizerController; 113 mQsTileRevealControllerFactory = qsTileRevealControllerFactory; 114 mFalsingManager = falsingManager; 115 mBrightnessSliderControllerFactory = brightnessSliderFactory; 116 mBrightnessControllerFactory = brightnessControllerFactory; 117 118 mBrightnessSliderController = brightnessSliderFactory.create(getContext(), mView); 119 mView.setBrightnessView(mBrightnessSliderController.getRootView()); 120 121 mBrightnessController = brightnessControllerFactory.create(mBrightnessSliderController); 122 mBrightnessMirrorHandler = new BrightnessMirrorHandler(mBrightnessController); 123 mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; 124 mLastDensity = view.getResources().getConfiguration().densityDpi; 125 mSceneContainerEnabled = SceneContainerFlag.isEnabled(); 126 mMediaCarouselInteractor = mediaCarouselInteractor; 127 } 128 129 @Override onInit()130 public void onInit() { 131 super.onInit(); 132 mMediaHost.setExpansion(MediaHostState.EXPANDED); 133 mMediaHost.setShowsOnlyActiveMedia(false); 134 mMediaHost.init(MediaHierarchyManager.LOCATION_QS); 135 mQsCustomizerController.init(); 136 mBrightnessSliderController.init(); 137 } 138 139 @Override getMediaVisibleFlow()140 StateFlow<Boolean> getMediaVisibleFlow() { 141 return mMediaCarouselInteractor.getHasAnyMediaOrRecommendation(); 142 } 143 144 @Override onViewAttached()145 protected void onViewAttached() { 146 super.onViewAttached(); 147 148 updateMediaDisappearParameters(); 149 150 mTunerService.addTunable(mView, QS_SHOW_BRIGHTNESS); 151 mView.updateResources(); 152 mView.setSceneContainerEnabled(mSceneContainerEnabled); 153 if (mView.isListening()) { 154 refreshAllTiles(); 155 } 156 switchTileLayout(true); 157 mBrightnessMirrorHandler.onQsPanelAttached(); 158 PagedTileLayout pagedTileLayout= ((PagedTileLayout) mView.getOrCreateTileLayout()); 159 pagedTileLayout.setOnTouchListener(mTileLayoutTouchListener); 160 maybeReinflateBrightnessSlider(); 161 } 162 163 @Override createTileRevealController()164 protected QSTileRevealController createTileRevealController() { 165 return mQsTileRevealControllerFactory.create( 166 this, (PagedTileLayout) mView.getOrCreateTileLayout()); 167 } 168 169 @Override onViewDetached()170 protected void onViewDetached() { 171 mTunerService.removeTunable(mView); 172 mBrightnessMirrorHandler.onQsPanelDettached(); 173 super.onViewDetached(); 174 } 175 176 @Override onConfigurationChanged()177 protected void onConfigurationChanged() { 178 mView.updateResources(); 179 maybeReinflateBrightnessSlider(); 180 if (mView.isListening()) { 181 refreshAllTiles(); 182 } 183 } 184 maybeReinflateBrightnessSlider()185 private void maybeReinflateBrightnessSlider() { 186 int newDensity = mView.getResources().getConfiguration().densityDpi; 187 if (newDensity != mLastDensity) { 188 mLastDensity = newDensity; 189 reinflateBrightnessSlider(); 190 } 191 } 192 reinflateBrightnessSlider()193 private void reinflateBrightnessSlider() { 194 mBrightnessController.unregisterCallbacks(); 195 mBrightnessSliderController = 196 mBrightnessSliderControllerFactory.create(getContext(), mView); 197 mView.setBrightnessView(mBrightnessSliderController.getRootView()); 198 mBrightnessController = mBrightnessControllerFactory.create(mBrightnessSliderController); 199 mBrightnessMirrorHandler.setBrightnessController(mBrightnessController); 200 mBrightnessSliderController.init(); 201 if (mListening) { 202 mBrightnessController.registerCallbacks(); 203 } 204 } 205 206 207 @Override onSplitShadeChanged(boolean shouldUseSplitNotificationShade)208 protected void onSplitShadeChanged(boolean shouldUseSplitNotificationShade) { 209 ((PagedTileLayout) mView.getOrCreateTileLayout()) 210 .forceTilesRedistribution("Split shade state changed"); 211 mView.setCanCollapse(!shouldUseSplitNotificationShade); 212 } 213 214 /** */ setVisibility(int visibility)215 public void setVisibility(int visibility) { 216 mView.setVisibility(visibility); 217 } 218 219 /** */ setListening(boolean listening, boolean expanded)220 public void setListening(boolean listening, boolean expanded) { 221 setListening(listening && expanded); 222 223 if (listening != mListening) { 224 mListening = listening; 225 // Set the listening as soon as the QS fragment starts listening regardless of the 226 //expansion, so it will update the current brightness before the slider is visible. 227 if (listening) { 228 mBrightnessController.registerCallbacks(); 229 } else { 230 mBrightnessController.unregisterCallbacks(); 231 } 232 } 233 } 234 setBrightnessMirror(@ullable MirrorController brightnessMirrorController)235 public void setBrightnessMirror(@Nullable MirrorController brightnessMirrorController) { 236 mBrightnessMirrorHandler.setController(brightnessMirrorController); 237 } 238 239 /** Update appearance of QSPanel. */ updateResources()240 public void updateResources() { 241 mView.updateResources(); 242 } 243 244 /** Update state of all tiles. */ refreshAllTiles()245 public void refreshAllTiles() { 246 mBrightnessController.checkRestrictionAndSetEnabled(); 247 super.refreshAllTiles(); 248 } 249 250 /** Start customizing the Quick Settings. */ showEdit(View view)251 public void showEdit(View view) { 252 view.post(() -> { 253 if (!mQsCustomizerController.isCustomizing()) { 254 int[] loc = view.getLocationOnScreen(); 255 int x = loc[0] + view.getWidth() / 2; 256 int y = loc[1] + view.getHeight() / 2; 257 mQsCustomizerController.show(x, y, false); 258 } 259 }); 260 } 261 isLayoutRtl()262 public boolean isLayoutRtl() { 263 return mView.isLayoutRtl(); 264 } 265 266 /** */ setPageListener(PagedTileLayout.PageListener listener)267 public void setPageListener(PagedTileLayout.PageListener listener) { 268 mView.setPageListener(listener); 269 } 270 isShown()271 public boolean isShown() { 272 return mView.isShown(); 273 } 274 275 /** */ setContentMargins(int startMargin, int endMargin)276 public void setContentMargins(int startMargin, int endMargin) { 277 mView.setContentMargins(startMargin, endMargin, mMediaHost.getHostView()); 278 } 279 280 /** */ setFooterPageIndicator(PageIndicator pageIndicator)281 public void setFooterPageIndicator(PageIndicator pageIndicator) { 282 mView.setFooterPageIndicator(pageIndicator); 283 } 284 285 /** */ isExpanded()286 public boolean isExpanded() { 287 return mView.isExpanded(); 288 } 289 setPageMargin(int pageMarginStart, int pageMarginEnd)290 void setPageMargin(int pageMarginStart, int pageMarginEnd) { 291 mView.setPageMargin(pageMarginStart, pageMarginEnd); 292 } 293 294 /** 295 * Determines if bouncer expansion is between 0 and 1 non-inclusive. 296 * 297 * @return if bouncer is in transit 298 */ isBouncerInTransit()299 public boolean isBouncerInTransit() { 300 return mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit(); 301 } 302 getPaddingBottom()303 public int getPaddingBottom() { 304 return mView.getPaddingBottom(); 305 } 306 getViewBottom()307 int getViewBottom() { 308 return mView.getBottom(); 309 } 310 } 311 312