blob: fcaf98165016b3e4320e318d18257497263b9809 [file] [log] [blame]
John Spurlockaf8d6c42014-05-07 17:49:08 -04001/*
2 * Copyright (C) 2014 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
17package com.android.systemui.qs;
18
Jason Monke5b770e2017-03-03 21:49:29 -050019import static com.android.systemui.qs.tileimpl.QSTileImpl.getColorForState;
20
Rohan Shahdb2cfa32018-02-20 11:27:22 -080021import android.annotation.Nullable;
Jason Monk7e53f202016-01-28 10:40:20 -050022import android.content.ComponentName;
John Spurlockaf8d6c42014-05-07 17:49:08 -040023import android.content.Context;
Jorim Jaggie17c4b42014-08-26 17:27:31 +020024import android.content.res.Configuration;
John Spurlock4bf31982014-05-21 13:04:22 -040025import android.content.res.Resources;
Jason Monkcb4b31d2017-05-03 10:37:34 -040026import android.metrics.LogMaker;
Fabian Kozynski407ddb22018-10-03 15:04:56 -040027import android.os.Bundle;
John Spurlockaf8d6c42014-05-07 17:49:08 -040028import android.os.Handler;
29import android.os.Message;
Jason Monke5b770e2017-03-03 21:49:29 -050030import android.service.quicksettings.Tile;
John Spurlockaf8d6c42014-05-07 17:49:08 -040031import android.util.AttributeSet;
John Spurlock7f8f22a2014-07-02 18:54:17 -040032import android.view.LayoutInflater;
John Spurlockaf8d6c42014-05-07 17:49:08 -040033import android.view.View;
Jason Monk520ea062015-08-18 14:53:06 -040034import android.widget.LinearLayout;
Jason Monkcb4b31d2017-05-03 10:37:34 -040035
Chris Wren457a21c2015-05-06 17:50:34 -040036import com.android.internal.logging.MetricsLogger;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010037import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Jason Monk824ffff2017-04-11 15:49:06 -040038import com.android.settingslib.Utils;
Jason Monkde850bb2017-02-01 19:26:30 -050039import com.android.systemui.Dependency;
John Spurlockaf8d6c42014-05-07 17:49:08 -040040import com.android.systemui.R;
Jason Monke5b770e2017-03-03 21:49:29 -050041import com.android.systemui.plugins.qs.DetailAdapter;
Jason Monk702e2eb2017-03-03 16:53:44 -050042import com.android.systemui.plugins.qs.QSTile;
43import com.android.systemui.plugins.qs.QSTileView;
44import com.android.systemui.qs.QSHost.Callback;
Jason Monkbd6dbb02015-09-03 15:46:25 -040045import com.android.systemui.qs.customize.QSCustomizer;
Jason Monk7e53f202016-01-28 10:40:20 -050046import com.android.systemui.qs.external.CustomTile;
Jorim Jaggi3f48f462014-07-08 16:53:29 +020047import com.android.systemui.settings.BrightnessController;
Muyuan Li3b0f8922016-04-18 19:27:29 -070048import com.android.systemui.settings.ToggleSliderView;
Adrian Roos5fd872e2014-08-12 17:28:58 +020049import com.android.systemui.statusbar.policy.BrightnessMirrorController;
Adrian Roosb01793f2017-08-09 14:34:55 +020050import com.android.systemui.statusbar.policy.BrightnessMirrorController.BrightnessMirrorListener;
Jason Monkcaf37622015-08-18 12:33:50 -040051import com.android.systemui.tuner.TunerService;
52import com.android.systemui.tuner.TunerService.Tunable;
John Spurlockaf8d6c42014-05-07 17:49:08 -040053
54import java.util.ArrayList;
John Spurlockbceed062014-08-10 18:04:16 -040055import java.util.Collection;
John Spurlockaf8d6c42014-05-07 17:49:08 -040056
Rohan Shahd3cf7562018-02-23 11:12:28 -080057/** View that represents the quick settings tile panel (when expanded/pulled down). **/
Adrian Roosb01793f2017-08-09 14:34:55 +020058public class QSPanel extends LinearLayout implements Tunable, Callback, BrightnessMirrorListener {
Jason Monkcaf37622015-08-18 12:33:50 -040059
60 public static final String QS_SHOW_BRIGHTNESS = "qs_show_brightness";
Rohan Shahd3cf7562018-02-23 11:12:28 -080061 public static final String QS_SHOW_HEADER = "qs_show_header";
John Spurlockaf8d6c42014-05-07 17:49:08 -040062
Fabian Kozynski0db39af2018-08-31 15:56:45 -040063 private static final String TAG = "QSPanel";
64
Jason Monkbd6dbb02015-09-03 15:46:25 -040065 protected final Context mContext;
Amin Shaikha07a17b2018-02-23 16:02:52 -050066 protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
Jason Monk11a77442015-05-12 19:29:02 -040067 protected final View mBrightnessView;
John Spurlockaf8d6c42014-05-07 17:49:08 -040068 private final H mHandler = new H();
Jason Monk8c09ac72017-03-16 11:53:40 -040069 private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
Amin Shaikha07a17b2018-02-23 16:02:52 -050070 private final QSTileRevealController mQsTileRevealController;
John Spurlockaf8d6c42014-05-07 17:49:08 -040071
Muyuan Li0e9f5382016-04-27 15:51:15 -070072 protected boolean mExpanded;
Jason Monk1bec6af2016-05-31 15:40:58 -040073 protected boolean mListening;
John Spurlockaf8d6c42014-05-07 17:49:08 -040074
Jason Monke5b770e2017-03-03 21:49:29 -050075 private QSDetail.Callback mCallback;
Jorim Jaggi3f48f462014-07-08 16:53:29 +020076 private BrightnessController mBrightnessController;
Jason Monkbbadff82015-11-06 15:47:26 -050077 protected QSTileHost mHost;
John Spurlockaf8d6c42014-05-07 17:49:08 -040078
Jason Monke5b770e2017-03-03 21:49:29 -050079 protected QSSecurityFooter mFooter;
Rohan Shah3090e792018-04-12 00:01:00 -040080 private PageIndicator mFooterPageIndicator;
Selim Cineke32010a2014-08-20 23:50:41 +020081 private boolean mGridContentVisible = true;
Jason Monk3d5f5512014-07-25 11:17:28 -040082
Jason Monkbd6dbb02015-09-03 15:46:25 -040083 protected QSTileLayout mTileLayout;
84
85 private QSCustomizer mCustomizePanel;
Jason Monk377e7ad2016-02-16 14:03:21 -050086 private Record mDetailRecord;
Jason Monk520ea062015-08-18 14:53:06 -040087
Adrian Roos429c9622016-06-15 13:02:17 -070088 private BrightnessMirrorController mBrightnessMirrorController;
Jason Monke5b770e2017-03-03 21:49:29 -050089 private View mDivider;
Adrian Roos429c9622016-06-15 13:02:17 -070090
John Spurlockaf8d6c42014-05-07 17:49:08 -040091 public QSPanel(Context context) {
92 this(context, null);
93 }
94
95 public QSPanel(Context context, AttributeSet attrs) {
96 super(context, attrs);
97 mContext = context;
98
Jason Monk162011e2016-02-19 08:11:55 -050099 setOrientation(VERTICAL);
Jason Monk520ea062015-08-18 14:53:06 -0400100
Jason Monk231b0522018-01-04 10:49:55 -0500101 mBrightnessView = LayoutInflater.from(mContext).inflate(
102 R.layout.quick_settings_brightness_dialog, this, false);
Amin Shaikh15781d62018-02-16 16:00:13 -0500103 addView(mBrightnessView);
104
105 mTileLayout = (QSTileLayout) LayoutInflater.from(mContext).inflate(
106 R.layout.qs_paged_tile_layout, this, false);
Jason Monk231b0522018-01-04 10:49:55 -0500107 mTileLayout.setListening(mListening);
Amin Shaikh15781d62018-02-16 16:00:13 -0500108 addView((View) mTileLayout);
109
Amin Shaikha07a17b2018-02-23 16:02:52 -0500110 mQsTileRevealController = new QSTileRevealController(mContext, this,
Rohan Shah3090e792018-04-12 00:01:00 -0400111 (PagedTileLayout) mTileLayout);
Jason Monk32508852017-01-18 09:17:13 -0500112
Jason Monke5b770e2017-03-03 21:49:29 -0500113 addDivider();
114
phweiss4f70f102017-04-12 19:32:55 +0200115 mFooter = new QSSecurityFooter(this, context);
116 addView(mFooter.getView());
117
John Spurlockaf8d6c42014-05-07 17:49:08 -0400118 updateResources();
Jorim Jaggi3f48f462014-07-08 16:53:29 +0200119
120 mBrightnessController = new BrightnessController(getContext(),
Jason Monke5b770e2017-03-03 21:49:29 -0500121 findViewById(R.id.brightness_slider));
122 }
123
124 protected void addDivider() {
125 mDivider = LayoutInflater.from(mContext).inflate(R.layout.qs_divider, this, false);
Jason Monk824ffff2017-04-11 15:49:06 -0400126 mDivider.setBackgroundColor(Utils.applyAlpha(mDivider.getAlpha(),
127 getColorForState(mContext, Tile.STATE_ACTIVE)));
Jason Monke5b770e2017-03-03 21:49:29 -0500128 addView(mDivider);
129 }
130
Fabian Kozynski72cd84a92019-04-15 14:09:43 -0400131 @Override
132 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
133 // We want all the logic of LinearLayout#onMeasure, and for it to assign the excess space
134 // not used by the other children to PagedTileLayout. However, in this case, LinearLayout
135 // assumes that PagedTileLayout would use all the excess space. This is not the case as
136 // PagedTileLayout height is quantized (because it shows a certain number of rows).
137 // Therefore, after everything is measured, we need to make sure that we add up the correct
138 // total height
139 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
140 int height = getPaddingBottom() + getPaddingTop();
141 int numChildren = getChildCount();
142 for (int i = 0; i < numChildren; i++) {
143 View child = getChildAt(i);
144 if (child.getVisibility() != View.GONE) height += child.getMeasuredHeight();
145 }
146 setMeasuredDimension(getMeasuredWidth(), height);
147 }
148
Jason Monke5b770e2017-03-03 21:49:29 -0500149 public View getDivider() {
150 return mDivider;
Jason Monk32508852017-01-18 09:17:13 -0500151 }
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200152
Amin Shaikha07a17b2018-02-23 16:02:52 -0500153 public QSTileRevealController getQsTileRevealController() {
154 return mQsTileRevealController;
155 }
156
Jason Monk377e7ad2016-02-16 14:03:21 -0500157 public boolean isShowingCustomize() {
158 return mCustomizePanel != null && mCustomizePanel.isCustomizing();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400159 }
160
Jason Monkcaf37622015-08-18 12:33:50 -0400161 @Override
162 protected void onAttachedToWindow() {
163 super.onAttachedToWindow();
Rohan Shahdb2cfa32018-02-20 11:27:22 -0800164 final TunerService tunerService = Dependency.get(TunerService.class);
165 tunerService.addTunable(this, QS_SHOW_BRIGHTNESS);
Rohan Shahdb2cfa32018-02-20 11:27:22 -0800166
Jason Monkf160edca2016-03-30 13:48:56 -0400167 if (mHost != null) {
168 setTiles(mHost.getTiles());
169 }
Adrian Roosb01793f2017-08-09 14:34:55 +0200170 if (mBrightnessMirrorController != null) {
171 mBrightnessMirrorController.addCallback(this);
172 }
Jason Monkcaf37622015-08-18 12:33:50 -0400173 }
174
175 @Override
176 protected void onDetachedFromWindow() {
Jason Monkde850bb2017-02-01 19:26:30 -0500177 Dependency.get(TunerService.class).removeTunable(this);
178 if (mHost != null) {
179 mHost.removeCallback(this);
180 }
Jason Monkf160edca2016-03-30 13:48:56 -0400181 for (TileRecord record : mRecords) {
182 record.tile.removeCallbacks();
183 }
Adrian Roosb01793f2017-08-09 14:34:55 +0200184 if (mBrightnessMirrorController != null) {
185 mBrightnessMirrorController.removeCallback(this);
186 }
Jason Monkcaf37622015-08-18 12:33:50 -0400187 super.onDetachedFromWindow();
188 }
189
190 @Override
Jason Monk46dbfb42016-02-25 14:59:20 -0500191 public void onTilesChanged() {
192 setTiles(mHost.getTiles());
193 }
194
195 @Override
Jason Monkcaf37622015-08-18 12:33:50 -0400196 public void onTuningChanged(String key, String newValue) {
197 if (QS_SHOW_BRIGHTNESS.equals(key)) {
Rohan Shahdb2cfa32018-02-20 11:27:22 -0800198 updateViewVisibilityForTuningValue(mBrightnessView, newValue);
Jason Monkcaf37622015-08-18 12:33:50 -0400199 }
200 }
201
Rohan Shahdb2cfa32018-02-20 11:27:22 -0800202 private void updateViewVisibilityForTuningValue(View view, @Nullable String newValue) {
Henrik Baarda2c86e82019-03-14 12:23:04 +0100203 view.setVisibility(TunerService.parseIntegerSwitch(newValue, true) ? VISIBLE : GONE);
Rohan Shahdb2cfa32018-02-20 11:27:22 -0800204 }
205
Jason Monka9927322015-12-13 16:22:37 -0500206 public void openDetails(String subPanel) {
Jason Monk702e2eb2017-03-03 16:53:44 -0500207 QSTile tile = getTile(subPanel);
Fabian Kozynskie3137e32018-09-28 11:20:04 -0400208 // If there's no tile with that name (as defined in QSFactoryImpl or other QSFactory),
209 // QSFactory will not be able to create a tile and getTile will return null
210 if (tile != null) {
211 showDetailAdapter(true, tile.getDetailAdapter(), new int[]{getWidth() / 2, 0});
212 }
Jason Monka9927322015-12-13 16:22:37 -0500213 }
214
Jason Monk702e2eb2017-03-03 16:53:44 -0500215 private QSTile getTile(String subPanel) {
Jason Monka9927322015-12-13 16:22:37 -0500216 for (int i = 0; i < mRecords.size(); i++) {
217 if (subPanel.equals(mRecords.get(i).tile.getTileSpec())) {
218 return mRecords.get(i).tile;
219 }
220 }
221 return mHost.createTile(subPanel);
222 }
223
Adrian Roos5fd872e2014-08-12 17:28:58 +0200224 public void setBrightnessMirror(BrightnessMirrorController c) {
Adrian Roosb01793f2017-08-09 14:34:55 +0200225 if (mBrightnessMirrorController != null) {
226 mBrightnessMirrorController.removeCallback(this);
227 }
Adrian Roos429c9622016-06-15 13:02:17 -0700228 mBrightnessMirrorController = c;
Adrian Roosb01793f2017-08-09 14:34:55 +0200229 if (mBrightnessMirrorController != null) {
230 mBrightnessMirrorController.addCallback(this);
231 }
232 updateBrightnessMirror();
233 }
234
235 @Override
236 public void onBrightnessMirrorReinflated(View brightnessMirror) {
237 updateBrightnessMirror();
Adrian Roos5fd872e2014-08-12 17:28:58 +0200238 }
239
Jason Monkb46059a2016-06-30 14:22:42 -0400240 View getBrightnessView() {
241 return mBrightnessView;
242 }
243
Jason Monke5b770e2017-03-03 21:49:29 -0500244 public void setCallback(QSDetail.Callback callback) {
John Spurlock5729d092014-05-29 17:42:51 -0400245 mCallback = callback;
246 }
247
Jason Monk8b9d67f2016-03-02 08:59:08 -0500248 public void setHost(QSTileHost host, QSCustomizer customizer) {
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200249 mHost = host;
Jason Monk46dbfb42016-02-25 14:59:20 -0500250 mHost.addCallback(this);
251 setTiles(mHost.getTiles());
Jason Monk9c7844c2017-01-18 15:21:53 -0500252 mFooter.setHostEnvironment(host);
Jason Monk8b9d67f2016-03-02 08:59:08 -0500253 mCustomizePanel = customizer;
254 if (mCustomizePanel != null) {
255 mCustomizePanel.setHost(mHost);
256 }
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200257 }
258
Rohan Shah3090e792018-04-12 00:01:00 -0400259 /**
260 * Links the footer's page indicator, which is used in landscape orientation to save space.
261 *
262 * @param pageIndicator indicator to use for page scrolling
263 */
264 public void setFooterPageIndicator(PageIndicator pageIndicator) {
265 if (mTileLayout instanceof PagedTileLayout) {
266 mFooterPageIndicator = pageIndicator;
267 updatePageIndicator();
268 }
269 }
270
271 private void updatePageIndicator() {
272 if (mTileLayout instanceof PagedTileLayout) {
Rohan Shah3090e792018-04-12 00:01:00 -0400273 if (mFooterPageIndicator != null) {
274 mFooterPageIndicator.setVisibility(View.GONE);
Rohan Shah3090e792018-04-12 00:01:00 -0400275
Fabian Kozynski4e76d1f2019-02-25 16:30:04 -0500276 ((PagedTileLayout) mTileLayout).setPageIndicator(mFooterPageIndicator);
277 }
Rohan Shah3090e792018-04-12 00:01:00 -0400278 }
279 }
280
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200281 public QSTileHost getHost() {
282 return mHost;
283 }
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200284
John Spurlockaf8d6c42014-05-07 17:49:08 -0400285 public void updateResources() {
John Spurlock4bf31982014-05-21 13:04:22 -0400286 final Resources res = mContext.getResources();
Rohan Shahd3cf7562018-02-23 11:12:28 -0800287 setPadding(0, res.getDimensionPixelSize(R.dimen.qs_panel_padding_top), 0, res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom));
Rohan Shah3090e792018-04-12 00:01:00 -0400288
289 updatePageIndicator();
290
John Spurlock1a462c12014-07-14 10:52:01 -0400291 if (mListening) {
292 refreshAllTiles();
293 }
Jason Monkcaf37622015-08-18 12:33:50 -0400294 if (mTileLayout != null) {
295 mTileLayout.updateResources();
296 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400297 }
298
Jorim Jaggie17c4b42014-08-26 17:27:31 +0200299 @Override
300 protected void onConfigurationChanged(Configuration newConfig) {
301 super.onConfigurationChanged(newConfig);
Jorim Jaggie17c4b42014-08-26 17:27:31 +0200302 mFooter.onConfigurationChanged();
Fabian Kozynskib1aee812019-04-04 14:17:48 -0400303 updateResources();
Adrian Roos429c9622016-06-15 13:02:17 -0700304
Adrian Roosb01793f2017-08-09 14:34:55 +0200305 updateBrightnessMirror();
306 }
307
308 public void updateBrightnessMirror() {
Adrian Roos429c9622016-06-15 13:02:17 -0700309 if (mBrightnessMirrorController != null) {
Adrian Roosb01793f2017-08-09 14:34:55 +0200310 ToggleSliderView brightnessSlider = findViewById(R.id.brightness_slider);
311 ToggleSliderView mirrorSlider = mBrightnessMirrorController.getMirror()
312 .findViewById(R.id.brightness_slider);
313 brightnessSlider.setMirror(mirrorSlider);
314 brightnessSlider.setMirrorController(mBrightnessMirrorController);
Adrian Roos429c9622016-06-15 13:02:17 -0700315 }
Jorim Jaggie17c4b42014-08-26 17:27:31 +0200316 }
317
Jason Monkbd6dbb02015-09-03 15:46:25 -0400318 public void onCollapse() {
Yoshinori Hirano1dd7d072016-09-05 16:11:59 +0900319 if (mCustomizePanel != null && mCustomizePanel.isShown()) {
Fabian Kozynski0db39af2018-08-31 15:56:45 -0400320 mCustomizePanel.hide();
Jason Monkbd6dbb02015-09-03 15:46:25 -0400321 }
322 }
323
John Spurlockaf8d6c42014-05-07 17:49:08 -0400324 public void setExpanded(boolean expanded) {
John Spurlock5729d092014-05-29 17:42:51 -0400325 if (mExpanded == expanded) return;
326 mExpanded = expanded;
Amin Shaikh15781d62018-02-16 16:00:13 -0500327 if (!mExpanded && mTileLayout instanceof PagedTileLayout) {
328 ((PagedTileLayout) mTileLayout).setCurrentItem(0, false);
Jason Monk162011e2016-02-19 08:11:55 -0500329 }
Jason Monk8c09ac72017-03-16 11:53:40 -0400330 mMetricsLogger.visibility(MetricsEvent.QS_PANEL, mExpanded);
John Spurlock5729d092014-05-29 17:42:51 -0400331 if (!mExpanded) {
John Spurlockf7ae4422014-08-01 12:45:18 -0400332 closeDetail();
Chris Wren457a21c2015-05-06 17:50:34 -0400333 } else {
334 logTiles();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400335 }
Jorim Jaggie65e3102014-07-01 22:00:50 +0200336 }
337
Amin Shaikh5da602f2018-02-02 15:00:25 -0500338 public void setPageListener(final PagedTileLayout.PageListener pageListener) {
339 if (mTileLayout instanceof PagedTileLayout) {
340 ((PagedTileLayout) mTileLayout).setPageListener(pageListener);
Amin Shaikh5da602f2018-02-02 15:00:25 -0500341 }
342 }
343
Muyuan Li0e9f5382016-04-27 15:51:15 -0700344 public boolean isExpanded() {
345 return mExpanded;
346 }
347
Jorim Jaggie65e3102014-07-01 22:00:50 +0200348 public void setListening(boolean listening) {
349 if (mListening == listening) return;
350 mListening = listening;
Jason Monk1bec6af2016-05-31 15:40:58 -0400351 if (mTileLayout != null) {
352 mTileLayout.setListening(listening);
John Spurlock1a462c12014-07-14 10:52:01 -0400353 }
354 if (mListening) {
355 refreshAllTiles();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400356 }
Fabian Kozynskib9dc0c72018-09-20 13:00:17 -0400357 }
358
359 public void setListening(boolean listening, boolean expanded) {
360 setListening(listening && expanded);
361 getFooter().setListening(listening);
362 // Set the listening as soon as the QS fragment starts listening regardless of the expansion,
363 // so it will update the current brightness before the slider is visible.
364 setBrightnessListening(listening);
365 }
366
367 public void setBrightnessListening(boolean listening) {
368 if (listening) {
369 mBrightnessController.registerCallbacks();
370 } else {
371 mBrightnessController.unregisterCallbacks();
Jorim Jaggi3f48f462014-07-08 16:53:29 +0200372 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400373 }
374
Jorim Jaggi1ecd7cd2014-11-03 16:18:03 +0100375 public void refreshAllTiles() {
yuemingweb2bf7d182018-01-23 16:05:08 +0000376 mBrightnessController.checkRestrictionAndSetEnabled();
John Spurlock1a462c12014-07-14 10:52:01 -0400377 for (TileRecord r : mRecords) {
378 r.tile.refreshState();
379 }
Jason Monk3d5f5512014-07-25 11:17:28 -0400380 mFooter.refreshState();
John Spurlock1a462c12014-07-14 10:52:01 -0400381 }
382
Adrian Roos970be532014-11-21 15:50:16 +0100383 public void showDetailAdapter(boolean show, DetailAdapter adapter, int[] locationInWindow) {
384 int xInWindow = locationInWindow[0];
385 int yInWindow = locationInWindow[1];
Jason Monk377e7ad2016-02-16 14:03:21 -0500386 ((View) getParent()).getLocationInWindow(locationInWindow);
Adrian Roos970be532014-11-21 15:50:16 +0100387
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200388 Record r = new Record();
389 r.detailAdapter = adapter;
Adrian Roos970be532014-11-21 15:50:16 +0100390 r.x = xInWindow - locationInWindow[0];
391 r.y = yInWindow - locationInWindow[1];
392
393 locationInWindow[0] = xInWindow;
394 locationInWindow[1] = yInWindow;
395
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200396 showDetail(show, r);
397 }
398
Jason Monkdc35dcb2015-12-04 16:36:15 -0500399 protected void showDetail(boolean show, Record r) {
John Spurlockaf8d6c42014-05-07 17:49:08 -0400400 mHandler.obtainMessage(H.SHOW_DETAIL, show ? 1 : 0, 0, r).sendToTarget();
401 }
402
Jason Monk702e2eb2017-03-03 16:53:44 -0500403 public void setTiles(Collection<QSTile> tiles) {
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400404 setTiles(tiles, false);
405 }
406
Jason Monk702e2eb2017-03-03 16:53:44 -0500407 public void setTiles(Collection<QSTile> tiles, boolean collapsedView) {
Amin Shaikha07a17b2018-02-23 16:02:52 -0500408 if (!collapsedView) {
409 mQsTileRevealController.updateRevealedTiles(tiles);
410 }
John Spurlockbceed062014-08-10 18:04:16 -0400411 for (TileRecord record : mRecords) {
Jason Monkcaf37622015-08-18 12:33:50 -0400412 mTileLayout.removeTile(record);
Xiaohui Chen08e266c2016-04-18 12:53:28 -0700413 record.tile.removeCallback(record.callback);
John Spurlockbceed062014-08-10 18:04:16 -0400414 }
415 mRecords.clear();
Jason Monk702e2eb2017-03-03 16:53:44 -0500416 for (QSTile tile : tiles) {
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400417 addTile(tile, collapsedView);
John Spurlockbceed062014-08-10 18:04:16 -0400418 }
John Spurlockbceed062014-08-10 18:04:16 -0400419 }
420
Jason Monkec87a872016-03-01 15:00:16 -0500421 protected void drawTile(TileRecord r, QSTile.State state) {
John Spurlock20c89052015-05-11 13:11:24 -0400422 r.tileView.onStateChanged(state);
423 }
424
Jason Monk702e2eb2017-03-03 16:53:44 -0500425 protected QSTileView createTileView(QSTile tile, boolean collapsedView) {
426 return mHost.createTileView(tile, collapsedView);
Jason Monkdc35dcb2015-12-04 16:36:15 -0500427 }
428
Xiaohui Chen66448932016-04-18 12:53:28 -0700429 protected boolean shouldShowDetail() {
430 return mExpanded;
431 }
432
Jason Monk702e2eb2017-03-03 16:53:44 -0500433 protected TileRecord addTile(final QSTile tile, boolean collapsedView) {
John Spurlockaf8d6c42014-05-07 17:49:08 -0400434 final TileRecord r = new TileRecord();
435 r.tile = tile;
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400436 r.tileView = createTileView(tile, collapsedView);
John Spurlockbceed062014-08-10 18:04:16 -0400437 final QSTile.Callback callback = new QSTile.Callback() {
John Spurlockaf8d6c42014-05-07 17:49:08 -0400438 @Override
439 public void onStateChanged(QSTile.State state) {
Jason Monk377e7ad2016-02-16 14:03:21 -0500440 drawTile(r, state);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400441 }
Jason Monkca894a02016-01-12 15:30:22 -0500442
John Spurlockaf8d6c42014-05-07 17:49:08 -0400443 @Override
444 public void onShowDetail(boolean show) {
Xiaohui Chen66448932016-04-18 12:53:28 -0700445 // Both the collapsed and full QS panels get this callback, this check determines
446 // which one should handle showing the detail.
447 if (shouldShowDetail()) {
448 QSPanel.this.showDetail(show, r);
449 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400450 }
Jason Monkca894a02016-01-12 15:30:22 -0500451
John Spurlock7f8f22a2014-07-02 18:54:17 -0400452 @Override
453 public void onToggleStateChanged(boolean state) {
454 if (mDetailRecord == r) {
455 fireToggleStateChanged(state);
456 }
457 }
Jason Monkca894a02016-01-12 15:30:22 -0500458
John Spurlock486b78e2014-07-07 08:37:56 -0400459 @Override
460 public void onScanStateChanged(boolean state) {
John Spurlock465cefa2014-08-16 10:39:33 -0400461 r.scanState = state;
John Spurlock486b78e2014-07-07 08:37:56 -0400462 if (mDetailRecord == r) {
John Spurlock465cefa2014-08-16 10:39:33 -0400463 fireScanStateChanged(r.scanState);
John Spurlock486b78e2014-07-07 08:37:56 -0400464 }
465 }
Selim Cinek4fda7b22014-08-18 22:07:25 +0200466
467 @Override
468 public void onAnnouncementRequested(CharSequence announcement) {
dooyoung.hwang1b006622016-12-22 20:04:20 +0900469 if (announcement != null) {
470 mHandler.obtainMessage(H.ANNOUNCE_FOR_ACCESSIBILITY, announcement)
471 .sendToTarget();
472 }
Selim Cinek4fda7b22014-08-18 22:07:25 +0200473 }
John Spurlockbceed062014-08-10 18:04:16 -0400474 };
Jason Monkca894a02016-01-12 15:30:22 -0500475 r.tile.addCallback(callback);
Xiaohui Chen08e266c2016-04-18 12:53:28 -0700476 r.callback = callback;
Jason Monk702e2eb2017-03-03 16:53:44 -0500477 r.tileView.init(r.tile);
John Spurlockccb6b9a2014-05-17 15:54:40 -0400478 r.tile.refreshState();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400479 mRecords.add(r);
480
Jason Monkcaf37622015-08-18 12:33:50 -0400481 if (mTileLayout != null) {
482 mTileLayout.addTile(r);
483 }
Muyuan Lib40004b2016-05-11 14:47:29 -0700484
485 return r;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400486 }
487
Jason Monk21428432016-02-10 16:42:38 -0500488
Jason Monk4bb7b1a2016-05-27 15:19:15 -0400489 public void showEdit(final View v) {
Jason Monk21428432016-02-10 16:42:38 -0500490 v.post(new Runnable() {
491 @Override
492 public void run() {
493 if (mCustomizePanel != null) {
494 if (!mCustomizePanel.isCustomizing()) {
Fabian Kozynski0db39af2018-08-31 15:56:45 -0400495 int[] loc = v.getLocationOnScreen();
Jason Monk4bb7b1a2016-05-27 15:19:15 -0400496 int x = loc[0] + v.getWidth() / 2;
497 int y = loc[1] + v.getHeight() / 2;
Jason Monk21428432016-02-10 16:42:38 -0500498 mCustomizePanel.show(x, y);
499 }
500 }
501
502 }
503 });
504 }
505
John Spurlockf7ae4422014-08-01 12:45:18 -0400506 public void closeDetail() {
Yoshinori Hirano1dd7d072016-09-05 16:11:59 +0900507 if (mCustomizePanel != null && mCustomizePanel.isShown()) {
Jason Monkbd6dbb02015-09-03 15:46:25 -0400508 // Treat this as a detail panel for now, to make things easy.
Fabian Kozynski0db39af2018-08-31 15:56:45 -0400509 mCustomizePanel.hide();
Jason Monkbd6dbb02015-09-03 15:46:25 -0400510 return;
511 }
John Spurlockf7ae4422014-08-01 12:45:18 -0400512 showDetail(false, mDetailRecord);
513 }
514
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100515 public int getGridHeight() {
Jason Monk162011e2016-02-19 08:11:55 -0500516 return getMeasuredHeight();
Jorim Jaggi8bc983e2014-12-10 17:45:50 +0100517 }
518
Jason Monkdc35dcb2015-12-04 16:36:15 -0500519 protected void handleShowDetail(Record r, boolean show) {
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200520 if (r instanceof TileRecord) {
521 handleShowDetailTile((TileRecord) r, show);
522 } else {
Adrian Roos970be532014-11-21 15:50:16 +0100523 int x = 0;
524 int y = 0;
525 if (r != null) {
526 x = r.x;
527 y = r.y;
528 }
529 handleShowDetailImpl(r, show, x, y);
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200530 }
531 }
532
533 private void handleShowDetailTile(TileRecord r, boolean show) {
Jason Monkefe3d3f2015-06-10 16:48:03 -0400534 if ((mDetailRecord != null) == show && mDetailRecord == r) return;
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200535
John Spurlockaf8d6c42014-05-07 17:49:08 -0400536 if (show) {
John Spurlock7f8f22a2014-07-02 18:54:17 -0400537 r.detailAdapter = r.tile.getDetailAdapter();
538 if (r.detailAdapter == null) return;
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200539 }
Jason Monk0d6a1c42015-04-20 16:38:51 -0400540 r.tile.setDetailListening(show);
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200541 int x = r.tileView.getLeft() + r.tileView.getWidth() / 2;
Jason Monk702e2eb2017-03-03 16:53:44 -0500542 int y = r.tileView.getDetailY() + mTileLayout.getOffsetTop(r) + getTop();
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200543 handleShowDetailImpl(r, show, x, y);
544 }
545
546 private void handleShowDetailImpl(Record r, boolean show, int x, int y) {
Jason Monk377e7ad2016-02-16 14:03:21 -0500547 setDetailRecord(show ? r : null);
548 fireShowingDetail(show ? r.detailAdapter : null, x, y);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400549 }
550
Muyuan Li4074b462016-05-06 13:40:42 -0700551 protected void setDetailRecord(Record r) {
Jason Monk377e7ad2016-02-16 14:03:21 -0500552 if (r == mDetailRecord) return;
553 mDetailRecord = r;
554 final boolean scanState = mDetailRecord instanceof TileRecord
555 && ((TileRecord) mDetailRecord).scanState;
556 fireScanStateChanged(scanState);
557 }
558
559 void setGridContentVisibility(boolean visible) {
Selim Cineke32010a2014-08-20 23:50:41 +0200560 int newVis = visible ? VISIBLE : INVISIBLE;
Jason Monk162011e2016-02-19 08:11:55 -0500561 setVisibility(newVis);
Chris Wren457a21c2015-05-06 17:50:34 -0400562 if (mGridContentVisible != visible) {
Jason Monk8c09ac72017-03-16 11:53:40 -0400563 mMetricsLogger.visibility(MetricsEvent.QS_PANEL, newVis);
Chris Wren457a21c2015-05-06 17:50:34 -0400564 }
Selim Cineke32010a2014-08-20 23:50:41 +0200565 mGridContentVisible = visible;
566 }
567
Chris Wren457a21c2015-05-06 17:50:34 -0400568 private void logTiles() {
569 for (int i = 0; i < mRecords.size(); i++) {
Jason Monkcb4b31d2017-05-03 10:37:34 -0400570 QSTile tile = mRecords.get(i).tile;
571 mMetricsLogger.write(tile.populate(new LogMaker(tile.getMetricsCategory())
572 .setType(MetricsEvent.TYPE_OPEN)));
Chris Wren457a21c2015-05-06 17:50:34 -0400573 }
574 }
575
Jason Monk377e7ad2016-02-16 14:03:21 -0500576 private void fireShowingDetail(DetailAdapter detail, int x, int y) {
John Spurlock5729d092014-05-29 17:42:51 -0400577 if (mCallback != null) {
Jason Monk377e7ad2016-02-16 14:03:21 -0500578 mCallback.onShowingDetail(detail, x, y);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400579 }
580 }
581
582 private void fireToggleStateChanged(boolean state) {
583 if (mCallback != null) {
584 mCallback.onToggleStateChanged(state);
John Spurlock5729d092014-05-29 17:42:51 -0400585 }
586 }
587
John Spurlock486b78e2014-07-07 08:37:56 -0400588 private void fireScanStateChanged(boolean state) {
589 if (mCallback != null) {
590 mCallback.onScanStateChanged(state);
591 }
592 }
593
Jason Monk7e53f202016-01-28 10:40:20 -0500594 public void clickTile(ComponentName tile) {
595 final String spec = CustomTile.toSpec(tile);
596 final int N = mRecords.size();
597 for (int i = 0; i < N; i++) {
598 if (mRecords.get(i).tile.getTileSpec().equals(spec)) {
599 mRecords.get(i).tile.click();
600 break;
601 }
602 }
603 }
604
Jason Monk162011e2016-02-19 08:11:55 -0500605 QSTileLayout getTileLayout() {
606 return mTileLayout;
607 }
608
Jason Monk702e2eb2017-03-03 16:53:44 -0500609 QSTileView getTileView(QSTile tile) {
Jason Monk162011e2016-02-19 08:11:55 -0500610 for (TileRecord r : mRecords) {
611 if (r.tile == tile) {
612 return r.tileView;
613 }
614 }
615 return null;
616 }
617
Jason Monke5b770e2017-03-03 21:49:29 -0500618 public QSSecurityFooter getFooter() {
Jason Monkdf36aed2016-07-25 11:21:56 -0400619 return mFooter;
620 }
621
phweissa0cb2512016-12-14 21:37:48 +0100622 public void showDeviceMonitoringDialog() {
623 mFooter.showDeviceMonitoringDialog();
624 }
625
Amin Shaikhbc1a4e82018-04-16 12:14:35 -0400626 public void setMargins(int sideMargins) {
627 for (int i = 0; i < getChildCount(); i++) {
628 View view = getChildAt(i);
629 if (view != mTileLayout) {
630 LayoutParams lp = (LayoutParams) view.getLayoutParams();
631 lp.leftMargin = sideMargins;
632 lp.rightMargin = sideMargins;
633 }
634 }
635 }
636
John Spurlockaf8d6c42014-05-07 17:49:08 -0400637 private class H extends Handler {
638 private static final int SHOW_DETAIL = 1;
639 private static final int SET_TILE_VISIBILITY = 2;
dooyoung.hwang1b006622016-12-22 20:04:20 +0900640 private static final int ANNOUNCE_FOR_ACCESSIBILITY = 3;
Jason Monkcb4b31d2017-05-03 10:37:34 -0400641
John Spurlockaf8d6c42014-05-07 17:49:08 -0400642 @Override
643 public void handleMessage(Message msg) {
644 if (msg.what == SHOW_DETAIL) {
Jason Monkcb4b31d2017-05-03 10:37:34 -0400645 handleShowDetail((Record) msg.obj, msg.arg1 != 0);
dooyoung.hwang1b006622016-12-22 20:04:20 +0900646 } else if (msg.what == ANNOUNCE_FOR_ACCESSIBILITY) {
Jason Monkcb4b31d2017-05-03 10:37:34 -0400647 announceForAccessibility((CharSequence) msg.obj);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400648 }
649 }
650 }
651
Jason Monkdc35dcb2015-12-04 16:36:15 -0500652 protected static class Record {
John Spurlock7f8f22a2014-07-02 18:54:17 -0400653 DetailAdapter detailAdapter;
Adrian Roos970be532014-11-21 15:50:16 +0100654 int x;
655 int y;
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200656 }
657
Jason Monkbd6dbb02015-09-03 15:46:25 -0400658 public static final class TileRecord extends Record {
Jason Monk702e2eb2017-03-03 16:53:44 -0500659 public QSTile tile;
660 public com.android.systemui.plugins.qs.QSTileView tileView;
Jason Monk11a77442015-05-12 19:29:02 -0400661 public boolean scanState;
Xiaohui Chen08e266c2016-04-18 12:53:28 -0700662 public QSTile.Callback callback;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400663 }
664
Jason Monkcaf37622015-08-18 12:33:50 -0400665 public interface QSTileLayout {
Fabian Kozynski407ddb22018-10-03 15:04:56 -0400666
667 default void saveInstanceState(Bundle outState) {}
668
669 default void restoreInstanceState(Bundle savedInstanceState) {}
670
Jason Monkcaf37622015-08-18 12:33:50 -0400671 void addTile(TileRecord tile);
Jason Monkcb4b31d2017-05-03 10:37:34 -0400672
Jason Monkcaf37622015-08-18 12:33:50 -0400673 void removeTile(TileRecord tile);
Jason Monkcb4b31d2017-05-03 10:37:34 -0400674
Jason Monkcaf37622015-08-18 12:33:50 -0400675 int getOffsetTop(TileRecord tile);
Jason Monkcb4b31d2017-05-03 10:37:34 -0400676
Jason Monk9d02a432016-01-20 16:33:46 -0500677 boolean updateResources();
Jason Monk1bec6af2016-05-31 15:40:58 -0400678
679 void setListening(boolean listening);
Amin Shaikh0f8ea5432018-03-27 11:09:27 -0400680
681 default void setExpansion(float expansion) {}
Fabian Kozynski802279f2018-09-07 13:44:54 -0400682
683 int getNumVisibleTiles();
Jason Monkcaf37622015-08-18 12:33:50 -0400684 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400685}