blob: 93b55e848936609f4f4c011447f7344e4e63df73 [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;
Jason Monkfece2ab2016-02-04 11:41:18 -0500192
Jason Monkc34befb2015-10-07 16:40:02 -0400193 public HeaderTileLayout(Context context) {
194 super(context);
Jason Monkdc35dcb2015-12-04 16:36:15 -0500195 setClipChildren(false);
196 setClipToPadding(false);
Jason Monkfece2ab2016-02-04 11:41:18 -0500197 }
198
199 @Override
Rohan Shah14394642018-03-13 20:10:12 -0700200 protected void onConfigurationChanged(Configuration newConfig) {
201 super.onConfigurationChanged(newConfig);
Fabian Kozynski802279f2018-09-07 13:44:54 -0400202 updateResources();
203 }
204
205 @Override
206 public void onFinishInflate(){
207 updateResources();
Amin Shaikh6a298d62018-06-18 16:44:14 -0400208 }
Rohan Shah14394642018-03-13 20:10:12 -0700209
Amin Shaikh6a298d62018-06-18 16:44:14 -0400210 private void updateLayoutParams() {
Amin Shaikh6a298d62018-06-18 16:44:14 -0400211 int width = getResources().getDimensionPixelSize(R.dimen.qs_quick_layout_width);
Fabian Kozynski802279f2018-09-07 13:44:54 -0400212 LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(width, LayoutParams.MATCH_PARENT);
Amin Shaikh6a298d62018-06-18 16:44:14 -0400213 lp.gravity = Gravity.CENTER_HORIZONTAL;
214 setLayoutParams(lp);
Rohan Shah14394642018-03-13 20:10:12 -0700215 }
216
Fabian Kozynski52728302018-09-07 12:45:59 +0000217 private LayoutParams generateTileLayoutParams() {
Fabian Kozynski802279f2018-09-07 13:44:54 -0400218 LayoutParams lp = new LayoutParams(mCellWidth, mCellHeight);
Fabian Kozynski52728302018-09-07 12:45:59 +0000219 return lp;
220 }
221
222 @Override
Fabian Kozynski802279f2018-09-07 13:44:54 -0400223 protected void addTileView(TileRecord tile) {
224 addView(tile.tileView, getChildCount(), generateTileLayoutParams());
Fabian Kozynski52728302018-09-07 12:45:59 +0000225 }
226
227 @Override
Fabian Kozynski802279f2018-09-07 13:44:54 -0400228 protected void onLayout(boolean changed, int l, int t, int r, int b) {
229 // We only care about clipping on the right side
230 Rect bounds = new Rect(0, 0, r - l, 10000);
231 setClipBounds(bounds);
232
233 calculateColumns();
234
235 for (int i = 0; i < mRecords.size(); i++) {
236 mRecords.get(i).tileView.setVisibility( i < mColumns ? View.VISIBLE : View.GONE);
237 }
238
239 setAccessibilityOrder();
240 layoutTileRecords(mColumns);
Jason Monkc34befb2015-10-07 16:40:02 -0400241 }
242
243 @Override
Jason Monk9d02a432016-01-20 16:33:46 -0500244 public boolean updateResources() {
Fabian Kozynski802279f2018-09-07 13:44:54 -0400245 mCellWidth = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
246 mCellHeight = mCellWidth;
247
248 updateLayoutParams();
249
Jason Monk9d02a432016-01-20 16:33:46 -0500250 return false;
Jason Monkc34befb2015-10-07 16:40:02 -0400251 }
Jason Monkc5bdafb2016-02-25 16:24:21 -0500252
Fabian Kozynski802279f2018-09-07 13:44:54 -0400253 private boolean calculateColumns() {
254 int prevNumColumns = mColumns;
255 int maxTiles = mRecords.size();
Fabian Kozynski40c9f0d2018-08-29 16:21:42 -0400256
Fabian Kozynski802279f2018-09-07 13:44:54 -0400257 if (maxTiles == 0){ // Early return during setup
258 mColumns = 0;
259 return true;
Fabian Kozynski52728302018-09-07 12:45:59 +0000260 }
261
Fabian Kozynski802279f2018-09-07 13:44:54 -0400262 final int availableWidth = getMeasuredWidth() - getPaddingStart() - getPaddingEnd();
263 final int leftoverWithespace = availableWidth - maxTiles * mCellWidth;
Fabian Kozynski1967f7d2018-10-02 09:18:52 -0400264 final int smallestHorizontalMarginNeeded;
265 smallestHorizontalMarginNeeded = leftoverWithespace / Math.max(1, maxTiles - 1);
Fabian Kozynski802279f2018-09-07 13:44:54 -0400266
267 if (smallestHorizontalMarginNeeded > 0){
268 mCellMarginHorizontal = smallestHorizontalMarginNeeded;
269 mColumns = maxTiles;
270 } else{
271 mColumns = mCellWidth == 0 ? 1 :
272 Math.min(maxTiles, availableWidth / mCellWidth );
273 mCellMarginHorizontal = (availableWidth - mColumns * mCellWidth) / (mColumns - 1);
274 }
275 return mColumns != prevNumColumns;
276 }
277
278 private void setAccessibilityOrder() {
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400279 if (mRecords != null && mRecords.size() > 0) {
280 View previousView = this;
281 for (TileRecord record : mRecords) {
282 if (record.tileView.getVisibility() == GONE) continue;
283 previousView = record.tileView.updateAccessibilityOrder(previousView);
284 }
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400285 mRecords.get(mRecords.size() - 1).tileView.setAccessibilityTraversalBefore(
286 R.id.expand_indicator);
287 }
288 }
Amin Shaikh6a298d62018-06-18 16:44:14 -0400289
Fabian Kozynski802279f2018-09-07 13:44:54 -0400290 @Override
291 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
292 // Measure each QS tile.
293 for (TileRecord record : mRecords) {
294 if (record.tileView.getVisibility() == GONE) continue;
295 record.tileView.measure(exactly(mCellWidth), exactly(mCellHeight));
Amin Shaikh6a298d62018-06-18 16:44:14 -0400296 }
Fabian Kozynski802279f2018-09-07 13:44:54 -0400297
298 int height = mCellHeight;
299 if (height < 0) height = 0;
300
301 setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height);
302 }
303
304 @Override
305 public int getNumVisibleTiles() {
306 return mColumns;
307 }
308
309 @Override
310 protected int getColumnStart(int column) {
311 return getPaddingStart() + column * (mCellWidth + mCellMarginHorizontal);
Amin Shaikh6a298d62018-06-18 16:44:14 -0400312 }
Jason Monkc34befb2015-10-07 16:40:02 -0400313 }
314}