blob: 73f6fc5ea2f48ae63834c07487b370248e7cf387 [file] [log] [blame]
Jason Monkc34befb2015-10-07 16:40:02 -04001/*
2 * Copyright (C) 2015 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
Fabian Kozynski00d494d2019-04-04 09:53:50 -040019import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
20
Jason Monkc34befb2015-10-07 16:40:02 -040021import android.content.Context;
Rohan Shah14394642018-03-13 20:10:12 -070022import android.content.res.Configuration;
Fabian Kozynski802279f2018-09-07 13:44:54 -040023import android.graphics.Rect;
Jason Monkc34befb2015-10-07 16:40:02 -040024import android.util.AttributeSet;
Jason Monkc133d262015-10-27 12:32:45 -040025import android.view.Gravity;
Jason Monkc34befb2015-10-07 16:40:02 -040026import android.view.View;
Jason Monkc34befb2015-10-07 16:40:02 -040027import android.widget.LinearLayout;
Julia Reynolds20aef8a2016-05-04 16:44:08 -040028
Jason Monkde850bb2017-02-01 19:26:30 -050029import com.android.systemui.Dependency;
Fabian Kozynski00d494d2019-04-04 09:53:50 -040030import com.android.systemui.DumpController;
Jason Monkc34befb2015-10-07 16:40:02 -040031import com.android.systemui.R;
Charles Hece2a7c02017-10-11 20:25:20 +010032import com.android.systemui.plugins.qs.QSTile;
Jason Monk702e2eb2017-03-03 16:53:44 -050033import com.android.systemui.plugins.qs.QSTile.SignalState;
34import com.android.systemui.plugins.qs.QSTile.State;
Jason Monka9df9992016-03-15 12:41:13 -040035import com.android.systemui.qs.customize.QSCustomizer;
Jason Monk8fb77872016-03-03 16:39:42 -050036import com.android.systemui.tuner.TunerService;
37import com.android.systemui.tuner.TunerService.Tunable;
Jason Monkc34befb2015-10-07 16:40:02 -040038
39import java.util.ArrayList;
40import java.util.Collection;
41
Fabian Kozynski00d494d2019-04-04 09:53:50 -040042import javax.inject.Inject;
43import javax.inject.Named;
44
Jason Monkc34befb2015-10-07 16:40:02 -040045/**
Jason Monkdc35dcb2015-12-04 16:36:15 -050046 * Version of QSPanel that only shows N Quick Tiles in the QS Header.
Jason Monkc34befb2015-10-07 16:40:02 -040047 */
48public class QuickQSPanel extends QSPanel {
49
Jason Monk8fb77872016-03-03 16:39:42 -050050 public static final String NUM_QUICK_TILES = "sysui_qqs_count";
Fabian Kozynski802279f2018-09-07 13:44:54 -040051 private static final String TAG = "QuickQSPanel";
Jason Monk8fb77872016-03-03 16:39:42 -050052
Charles Hece2a7c02017-10-11 20:25:20 +010053 private boolean mDisabledByPolicy;
Bill Linad15fe332018-06-13 19:26:15 +080054 private static int mDefaultMaxTiles;
Jason Monkdc35dcb2015-12-04 16:36:15 -050055 private int mMaxTiles;
Muyuan Li0e9f5382016-04-27 15:51:15 -070056 protected QSPanel mFullPanel;
Jason Monkdc35dcb2015-12-04 16:36:15 -050057
Fabian Kozynski00d494d2019-04-04 09:53:50 -040058 @Inject
59 public QuickQSPanel(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
60 DumpController dumpController) {
61 super(context, attrs, dumpController);
phweisse3983312017-02-17 15:14:19 +010062 if (mFooter != null) {
Jason Monk231b0522018-01-04 10:49:55 -050063 removeView(mFooter.getView());
phweisse3983312017-02-17 15:14:19 +010064 }
Jason Monkc34befb2015-10-07 16:40:02 -040065 if (mTileLayout != null) {
66 for (int i = 0; i < mRecords.size(); i++) {
67 mTileLayout.removeTile(mRecords.get(i));
68 }
Amin Shaikh15781d62018-02-16 16:00:13 -050069 removeView((View) mTileLayout);
Jason Monkc34befb2015-10-07 16:40:02 -040070 }
Bill Linad15fe332018-06-13 19:26:15 +080071 mDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
Jason Monkc34befb2015-10-07 16:40:02 -040072 mTileLayout = new HeaderTileLayout(context);
Jason Monk1bec6af2016-05-31 15:40:58 -040073 mTileLayout.setListening(mListening);
Jason Monk32508852017-01-18 09:17:13 -050074 addView((View) mTileLayout, 0 /* Between brightness and footer */);
Jason Monk7b3d4e42017-05-30 12:47:10 -040075 super.setPadding(0, 0, 0, 0);
76 }
77
78 @Override
79 public void setPadding(int left, int top, int right, int bottom) {
80 // Always have no padding.
Jason Monkc34befb2015-10-07 16:40:02 -040081 }
82
Jason Monk51c444b2016-01-06 16:32:29 -050083 @Override
Jason Monke5b770e2017-03-03 21:49:29 -050084 protected void addDivider() {
85 }
86
87 @Override
Jason Monk8fb77872016-03-03 16:39:42 -050088 protected void onAttachedToWindow() {
89 super.onAttachedToWindow();
Jason Monkde850bb2017-02-01 19:26:30 -050090 Dependency.get(TunerService.class).addTunable(mNumTiles, NUM_QUICK_TILES);
Jason Monk8fb77872016-03-03 16:39:42 -050091 }
92
93 @Override
94 protected void onDetachedFromWindow() {
95 super.onDetachedFromWindow();
Jason Monkde850bb2017-02-01 19:26:30 -050096 Dependency.get(TunerService.class).removeTunable(mNumTiles);
Jason Monk8fb77872016-03-03 16:39:42 -050097 }
98
Jason Monkdc35dcb2015-12-04 16:36:15 -050099 public void setQSPanelAndHeader(QSPanel fullPanel, View header) {
100 mFullPanel = fullPanel;
Jason Monkdc35dcb2015-12-04 16:36:15 -0500101 }
102
103 @Override
Xiaohui Chen66448932016-04-18 12:53:28 -0700104 protected boolean shouldShowDetail() {
105 return !mExpanded;
106 }
107
108 @Override
Jason Monkec87a872016-03-01 15:00:16 -0500109 protected void drawTile(TileRecord r, State state) {
110 if (state instanceof SignalState) {
Jason Monk702e2eb2017-03-03 16:53:44 -0500111 SignalState copy = new SignalState();
Jason Monkec87a872016-03-01 15:00:16 -0500112 state.copyTo(copy);
113 // No activity shown in the quick panel.
Jason Monk702e2eb2017-03-03 16:53:44 -0500114 copy.activityIn = false;
115 copy.activityOut = false;
Jason Monkec87a872016-03-01 15:00:16 -0500116 state = copy;
117 }
118 super.drawTile(r, state);
119 }
120
121 @Override
Jason Monka9df9992016-03-15 12:41:13 -0400122 public void setHost(QSTileHost host, QSCustomizer customizer) {
123 super.setHost(host, customizer);
124 setTiles(mHost.getTiles());
125 }
126
Jason Monkdc35dcb2015-12-04 16:36:15 -0500127 public void setMaxTiles(int maxTiles) {
128 mMaxTiles = maxTiles;
Jason Monka9df9992016-03-15 12:41:13 -0400129 if (mHost != null) {
130 setTiles(mHost.getTiles());
131 }
Jason Monkdc35dcb2015-12-04 16:36:15 -0500132 }
133
134 @Override
Jason Monkc34befb2015-10-07 16:40:02 -0400135 public void onTuningChanged(String key, String newValue) {
Rohan Shahd3cf7562018-02-23 11:12:28 -0800136 if (QS_SHOW_BRIGHTNESS.equals(key)) {
Rohan Shahdb2cfa32018-02-20 11:27:22 -0800137 // No Brightness or Tooltip for you!
Jason Monkc34befb2015-10-07 16:40:02 -0400138 super.onTuningChanged(key, "0");
139 }
140 }
141
142 @Override
Jason Monk702e2eb2017-03-03 16:53:44 -0500143 public void setTiles(Collection<QSTile> tiles) {
144 ArrayList<QSTile> quickTiles = new ArrayList<>();
145 for (QSTile tile : tiles) {
Jason Monkdc35dcb2015-12-04 16:36:15 -0500146 quickTiles.add(tile);
147 if (quickTiles.size() == mMaxTiles) {
Jason Monkc34befb2015-10-07 16:40:02 -0400148 break;
149 }
150 }
Jason Monkc59249f2016-06-17 10:19:43 -0400151 super.setTiles(quickTiles, true);
Jason Monkc34befb2015-10-07 16:40:02 -0400152 }
153
Jason Monk8fb77872016-03-03 16:39:42 -0500154 private final Tunable mNumTiles = new Tunable() {
155 @Override
156 public void onTuningChanged(String key, String newValue) {
157 setMaxTiles(getNumQuickTiles(mContext));
158 }
159 };
160
Jason Monke5b770e2017-03-03 21:49:29 -0500161 public static int getNumQuickTiles(Context context) {
Bill Linad15fe332018-06-13 19:26:15 +0800162 return Dependency.get(TunerService.class).getValue(NUM_QUICK_TILES, mDefaultMaxTiles);
Jason Monk8fb77872016-03-03 16:39:42 -0500163 }
164
Charles Hece2a7c02017-10-11 20:25:20 +0100165 void setDisabledByPolicy(boolean disabled) {
166 if (disabled != mDisabledByPolicy) {
167 mDisabledByPolicy = disabled;
168 setVisibility(disabled ? View.GONE : View.VISIBLE);
169 }
170 }
171
172 /**
173 * Sets the visibility of this {@link QuickQSPanel}. This method has no effect when this panel
174 * is disabled by policy through {@link #setDisabledByPolicy(boolean)}, and in this case the
175 * visibility will always be {@link View#GONE}. This method is called externally by
176 * {@link QSAnimator} only.
177 */
178 @Override
179 public void setVisibility(int visibility) {
180 if (mDisabledByPolicy) {
181 if (getVisibility() == View.GONE) {
182 return;
183 }
184 visibility = View.GONE;
185 }
186 super.setVisibility(visibility);
187 }
188
Fabian Kozynski802279f2018-09-07 13:44:54 -0400189 private static class HeaderTileLayout extends TileLayout {
Jason Monkc34befb2015-10-07 16:40:02 -0400190
Jason Monk1bec6af2016-05-31 15:40:58 -0400191 private boolean mListening;
Fabian Kozynskidc23ef62019-04-22 14:30:59 -0400192 private Rect mClippingBounds = new Rect();
Jason Monkfece2ab2016-02-04 11:41:18 -0500193
Jason Monkc34befb2015-10-07 16:40:02 -0400194 public HeaderTileLayout(Context context) {
195 super(context);
Jason Monkdc35dcb2015-12-04 16:36:15 -0500196 setClipChildren(false);
197 setClipToPadding(false);
Fabian Kozynski7a4e3312019-04-24 11:10:21 -0400198 LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
199 LayoutParams.MATCH_PARENT);
200 lp.gravity = Gravity.CENTER_HORIZONTAL;
201 setLayoutParams(lp);
Jason Monkfece2ab2016-02-04 11:41:18 -0500202 }
203
204 @Override
Rohan Shah14394642018-03-13 20:10:12 -0700205 protected void onConfigurationChanged(Configuration newConfig) {
206 super.onConfigurationChanged(newConfig);
Fabian Kozynski802279f2018-09-07 13:44:54 -0400207 updateResources();
208 }
209
210 @Override
211 public void onFinishInflate(){
212 updateResources();
Amin Shaikh6a298d62018-06-18 16:44:14 -0400213 }
Rohan Shah14394642018-03-13 20:10:12 -0700214
Fabian Kozynski52728302018-09-07 12:45:59 +0000215 private LayoutParams generateTileLayoutParams() {
Fabian Kozynski802279f2018-09-07 13:44:54 -0400216 LayoutParams lp = new LayoutParams(mCellWidth, mCellHeight);
Fabian Kozynski52728302018-09-07 12:45:59 +0000217 return lp;
218 }
219
220 @Override
Fabian Kozynski802279f2018-09-07 13:44:54 -0400221 protected void addTileView(TileRecord tile) {
222 addView(tile.tileView, getChildCount(), generateTileLayoutParams());
Fabian Kozynski52728302018-09-07 12:45:59 +0000223 }
224
225 @Override
Fabian Kozynski802279f2018-09-07 13:44:54 -0400226 protected void onLayout(boolean changed, int l, int t, int r, int b) {
227 // We only care about clipping on the right side
Fabian Kozynskidc23ef62019-04-22 14:30:59 -0400228 mClippingBounds.set(0, 0, r - l, 10000);
229 setClipBounds(mClippingBounds);
Fabian Kozynski802279f2018-09-07 13:44:54 -0400230
231 calculateColumns();
232
233 for (int i = 0; i < mRecords.size(); i++) {
234 mRecords.get(i).tileView.setVisibility( i < mColumns ? View.VISIBLE : View.GONE);
235 }
236
237 setAccessibilityOrder();
238 layoutTileRecords(mColumns);
Jason Monkc34befb2015-10-07 16:40:02 -0400239 }
240
241 @Override
Jason Monk9d02a432016-01-20 16:33:46 -0500242 public boolean updateResources() {
Fabian Kozynski802279f2018-09-07 13:44:54 -0400243 mCellWidth = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
244 mCellHeight = mCellWidth;
245
Jason Monk9d02a432016-01-20 16:33:46 -0500246 return false;
Jason Monkc34befb2015-10-07 16:40:02 -0400247 }
Jason Monkc5bdafb2016-02-25 16:24:21 -0500248
Fabian Kozynski802279f2018-09-07 13:44:54 -0400249 private boolean calculateColumns() {
250 int prevNumColumns = mColumns;
251 int maxTiles = mRecords.size();
Fabian Kozynski40c9f0d2018-08-29 16:21:42 -0400252
Fabian Kozynski802279f2018-09-07 13:44:54 -0400253 if (maxTiles == 0){ // Early return during setup
254 mColumns = 0;
255 return true;
Fabian Kozynski52728302018-09-07 12:45:59 +0000256 }
257
Fabian Kozynski802279f2018-09-07 13:44:54 -0400258 final int availableWidth = getMeasuredWidth() - getPaddingStart() - getPaddingEnd();
Fabian Kozynskidc23ef62019-04-22 14:30:59 -0400259 final int leftoverWhitespace = availableWidth - maxTiles * mCellWidth;
Fabian Kozynski1967f7d2018-10-02 09:18:52 -0400260 final int smallestHorizontalMarginNeeded;
Fabian Kozynskidc23ef62019-04-22 14:30:59 -0400261 smallestHorizontalMarginNeeded = leftoverWhitespace / Math.max(1, maxTiles - 1);
Fabian Kozynski802279f2018-09-07 13:44:54 -0400262
263 if (smallestHorizontalMarginNeeded > 0){
264 mCellMarginHorizontal = smallestHorizontalMarginNeeded;
265 mColumns = maxTiles;
266 } else{
267 mColumns = mCellWidth == 0 ? 1 :
268 Math.min(maxTiles, availableWidth / mCellWidth );
269 mCellMarginHorizontal = (availableWidth - mColumns * mCellWidth) / (mColumns - 1);
270 }
271 return mColumns != prevNumColumns;
272 }
273
274 private void setAccessibilityOrder() {
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400275 if (mRecords != null && mRecords.size() > 0) {
276 View previousView = this;
277 for (TileRecord record : mRecords) {
278 if (record.tileView.getVisibility() == GONE) continue;
279 previousView = record.tileView.updateAccessibilityOrder(previousView);
280 }
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400281 mRecords.get(mRecords.size() - 1).tileView.setAccessibilityTraversalBefore(
282 R.id.expand_indicator);
283 }
284 }
Amin Shaikh6a298d62018-06-18 16:44:14 -0400285
Fabian Kozynski802279f2018-09-07 13:44:54 -0400286 @Override
287 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
288 // Measure each QS tile.
289 for (TileRecord record : mRecords) {
290 if (record.tileView.getVisibility() == GONE) continue;
291 record.tileView.measure(exactly(mCellWidth), exactly(mCellHeight));
Amin Shaikh6a298d62018-06-18 16:44:14 -0400292 }
Fabian Kozynski802279f2018-09-07 13:44:54 -0400293
294 int height = mCellHeight;
295 if (height < 0) height = 0;
296
297 setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height);
298 }
299
300 @Override
301 public int getNumVisibleTiles() {
302 return mColumns;
303 }
304
305 @Override
306 protected int getColumnStart(int column) {
307 return getPaddingStart() + column * (mCellWidth + mCellMarginHorizontal);
Amin Shaikh6a298d62018-06-18 16:44:14 -0400308 }
Jason Monkc34befb2015-10-07 16:40:02 -0400309 }
310}