blob: 6654b7ab0749740c7b41ce0b8459a308938cd726 [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
Fabian Kozynskicc4c6c32020-03-09 15:11:33 -040021import android.annotation.Nullable;
Jason Monkc34befb2015-10-07 16:40:02 -040022import android.content.Context;
Rohan Shah14394642018-03-13 20:10:12 -070023import android.content.res.Configuration;
Fabian Kozynski802279f2018-09-07 13:44:54 -040024import android.graphics.Rect;
Jason Monkc34befb2015-10-07 16:40:02 -040025import android.util.AttributeSet;
Jason Monkc133d262015-10-27 12:32:45 -040026import android.view.Gravity;
Jason Monkc34befb2015-10-07 16:40:02 -040027import android.view.View;
Jason Monkc34befb2015-10-07 16:40:02 -040028import android.widget.LinearLayout;
Julia Reynolds20aef8a2016-05-04 16:44:08 -040029
Fabian Kozynskicc4c6c32020-03-09 15:11:33 -040030import com.android.settingslib.bluetooth.LocalBluetoothManager;
Jason Monkde850bb2017-02-01 19:26:30 -050031import com.android.systemui.Dependency;
Jason Monkc34befb2015-10-07 16:40:02 -040032import com.android.systemui.R;
Fabian Kozynskica30f572019-10-24 10:01:04 -040033import com.android.systemui.broadcast.BroadcastDispatcher;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050034import com.android.systemui.dagger.qualifiers.Background;
Ned Burnsaaeb44b2020-02-12 23:48:26 -050035import com.android.systemui.dump.DumpManager;
Charles Hece2a7c02017-10-11 20:25:20 +010036import com.android.systemui.plugins.qs.QSTile;
Jason Monk702e2eb2017-03-03 16:53:44 -050037import com.android.systemui.plugins.qs.QSTile.SignalState;
38import com.android.systemui.plugins.qs.QSTile.State;
Jason Monka9df9992016-03-15 12:41:13 -040039import com.android.systemui.qs.customize.QSCustomizer;
Fabian Kozynskica30f572019-10-24 10:01:04 -040040import com.android.systemui.qs.logging.QSLogger;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050041import com.android.systemui.statusbar.NotificationMediaManager;
Jason Monk8fb77872016-03-03 16:39:42 -050042import com.android.systemui.tuner.TunerService;
43import com.android.systemui.tuner.TunerService.Tunable;
Matt Pietal5a19cb62019-10-30 12:31:07 -040044import com.android.systemui.util.Utils;
Jason Monkc34befb2015-10-07 16:40:02 -040045
46import java.util.ArrayList;
47import java.util.Collection;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050048import java.util.concurrent.Executor;
Jason Monkc34befb2015-10-07 16:40:02 -040049
Fabian Kozynski00d494d2019-04-04 09:53:50 -040050import javax.inject.Inject;
51import javax.inject.Named;
52
Jason Monkc34befb2015-10-07 16:40:02 -040053/**
Jason Monkdc35dcb2015-12-04 16:36:15 -050054 * Version of QSPanel that only shows N Quick Tiles in the QS Header.
Jason Monkc34befb2015-10-07 16:40:02 -040055 */
56public class QuickQSPanel extends QSPanel {
57
Jason Monk8fb77872016-03-03 16:39:42 -050058 public static final String NUM_QUICK_TILES = "sysui_qqs_count";
Fabian Kozynski802279f2018-09-07 13:44:54 -040059 private static final String TAG = "QuickQSPanel";
Fabian Kozynskic8d8f052019-09-09 09:15:04 -040060 // Start it at 6 so a non-zero value can be obtained statically.
61 private static int sDefaultMaxTiles = 6;
Jason Monk8fb77872016-03-03 16:39:42 -050062
Charles Hece2a7c02017-10-11 20:25:20 +010063 private boolean mDisabledByPolicy;
Jason Monkdc35dcb2015-12-04 16:36:15 -050064 private int mMaxTiles;
Muyuan Li0e9f5382016-04-27 15:51:15 -070065 protected QSPanel mFullPanel;
Beth Thibodeau07d20c32019-10-16 13:45:56 -040066 private QuickQSMediaPlayer mMediaPlayer;
Fabian Kozynskiaba2a542019-12-04 12:25:59 -050067 private boolean mUsingMediaPlayer;
68 private LinearLayout mHorizontalLinearLayout;
69
70 // Only used with media
71 private QSTileLayout mMediaTileLayout;
72 private QSTileLayout mRegularTileLayout;
Jason Monkdc35dcb2015-12-04 16:36:15 -050073
Fabian Kozynski00d494d2019-04-04 09:53:50 -040074 @Inject
Fabian Kozynskica30f572019-10-24 10:01:04 -040075 public QuickQSPanel(
76 @Named(VIEW_CONTEXT) Context context,
77 AttributeSet attrs,
Ned Burnsaaeb44b2020-02-12 23:48:26 -050078 DumpManager dumpManager,
Fabian Kozynskica30f572019-10-24 10:01:04 -040079 BroadcastDispatcher broadcastDispatcher,
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050080 QSLogger qsLogger,
81 NotificationMediaManager notificationMediaManager,
Fabian Kozynskicc4c6c32020-03-09 15:11:33 -040082 @Background Executor backgroundExecutor,
83 @Nullable LocalBluetoothManager localBluetoothManager
Fabian Kozynskica30f572019-10-24 10:01:04 -040084 ) {
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050085 super(context, attrs, dumpManager, broadcastDispatcher, qsLogger, notificationMediaManager,
Fabian Kozynskicc4c6c32020-03-09 15:11:33 -040086 backgroundExecutor, localBluetoothManager);
phweisse3983312017-02-17 15:14:19 +010087 if (mFooter != null) {
Jason Monk231b0522018-01-04 10:49:55 -050088 removeView(mFooter.getView());
phweisse3983312017-02-17 15:14:19 +010089 }
Jason Monkc34befb2015-10-07 16:40:02 -040090 if (mTileLayout != null) {
91 for (int i = 0; i < mRecords.size(); i++) {
92 mTileLayout.removeTile(mRecords.get(i));
93 }
Amin Shaikh15781d62018-02-16 16:00:13 -050094 removeView((View) mTileLayout);
Jason Monkc34befb2015-10-07 16:40:02 -040095 }
Beth Thibodeau07d20c32019-10-16 13:45:56 -040096
Fabian Kozynskiaba2a542019-12-04 12:25:59 -050097 mUsingMediaPlayer = Utils.useQsMediaPlayer(context);
98 if (mUsingMediaPlayer) {
99 mHorizontalLinearLayout = new LinearLayout(mContext);
Beth Thibodeau07d20c32019-10-16 13:45:56 -0400100 mHorizontalLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
101 mHorizontalLinearLayout.setClipChildren(false);
102 mHorizontalLinearLayout.setClipToPadding(false);
103
Beth Thibodeau8cb6d422020-01-31 14:57:09 -0500104 int marginSize = (int) mContext.getResources().getDimension(R.dimen.qqs_media_spacing);
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500105 mMediaPlayer = new QuickQSMediaPlayer(mContext, mHorizontalLinearLayout,
106 notificationMediaManager, backgroundExecutor);
Beth Thibodeau8cb6d422020-01-31 14:57:09 -0500107 LayoutParams lp2 = new LayoutParams(0, LayoutParams.MATCH_PARENT, 1);
108 lp2.setMarginEnd(marginSize);
109 lp2.setMarginStart(0);
110 mHorizontalLinearLayout.addView(mMediaPlayer.getView(), lp2);
111
Beth Thibodeau07d20c32019-10-16 13:45:56 -0400112 mTileLayout = new DoubleLineTileLayout(context);
Fabian Kozynskiaba2a542019-12-04 12:25:59 -0500113 mMediaTileLayout = mTileLayout;
114 mRegularTileLayout = new HeaderTileLayout(context);
Beth Thibodeau899b5952020-01-07 17:50:07 -0500115 LayoutParams lp = new LayoutParams(0, LayoutParams.MATCH_PARENT, 1);
Beth Thibodeau8cb6d422020-01-31 14:57:09 -0500116 lp.setMarginEnd(0);
117 lp.setMarginStart(marginSize);
Beth Thibodeau07d20c32019-10-16 13:45:56 -0400118 mHorizontalLinearLayout.addView((View) mTileLayout, lp);
119
Beth Thibodeau07d20c32019-10-16 13:45:56 -0400120 sDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
121
122 mTileLayout.setListening(mListening);
123 addView(mHorizontalLinearLayout, 0 /* Between brightness and footer */);
Fabian Kozynskiaba2a542019-12-04 12:25:59 -0500124 ((View) mRegularTileLayout).setVisibility(View.GONE);
125 addView((View) mRegularTileLayout, 0);
Beth Thibodeau07d20c32019-10-16 13:45:56 -0400126 super.setPadding(0, 0, 0, 0);
127 } else {
128 sDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
129 mTileLayout = new HeaderTileLayout(context);
130 mTileLayout.setListening(mListening);
131 addView((View) mTileLayout, 0 /* Between brightness and footer */);
132 super.setPadding(0, 0, 0, 0);
133 }
134 }
135
136 public QuickQSMediaPlayer getMediaPlayer() {
137 return mMediaPlayer;
Jason Monk7b3d4e42017-05-30 12:47:10 -0400138 }
139
140 @Override
141 public void setPadding(int left, int top, int right, int bottom) {
142 // Always have no padding.
Jason Monkc34befb2015-10-07 16:40:02 -0400143 }
144
Jason Monk51c444b2016-01-06 16:32:29 -0500145 @Override
Jason Monke5b770e2017-03-03 21:49:29 -0500146 protected void addDivider() {
147 }
148
149 @Override
Jason Monk8fb77872016-03-03 16:39:42 -0500150 protected void onAttachedToWindow() {
151 super.onAttachedToWindow();
Jason Monkde850bb2017-02-01 19:26:30 -0500152 Dependency.get(TunerService.class).addTunable(mNumTiles, NUM_QUICK_TILES);
Jason Monk8fb77872016-03-03 16:39:42 -0500153 }
154
155 @Override
156 protected void onDetachedFromWindow() {
157 super.onDetachedFromWindow();
Jason Monkde850bb2017-02-01 19:26:30 -0500158 Dependency.get(TunerService.class).removeTunable(mNumTiles);
Jason Monk8fb77872016-03-03 16:39:42 -0500159 }
160
Ned Burns66b6e372019-07-26 13:45:42 -0400161 @Override
162 protected String getDumpableTag() {
163 return TAG;
164 }
165
Jason Monkdc35dcb2015-12-04 16:36:15 -0500166 public void setQSPanelAndHeader(QSPanel fullPanel, View header) {
167 mFullPanel = fullPanel;
Jason Monkdc35dcb2015-12-04 16:36:15 -0500168 }
169
170 @Override
Jason Monkec87a872016-03-01 15:00:16 -0500171 protected void drawTile(TileRecord r, State state) {
172 if (state instanceof SignalState) {
Jason Monk702e2eb2017-03-03 16:53:44 -0500173 SignalState copy = new SignalState();
Jason Monkec87a872016-03-01 15:00:16 -0500174 state.copyTo(copy);
175 // No activity shown in the quick panel.
Jason Monk702e2eb2017-03-03 16:53:44 -0500176 copy.activityIn = false;
177 copy.activityOut = false;
Jason Monkec87a872016-03-01 15:00:16 -0500178 state = copy;
179 }
180 super.drawTile(r, state);
181 }
182
Fabian Kozynskiaba2a542019-12-04 12:25:59 -0500183 boolean switchTileLayout() {
184 if (!mUsingMediaPlayer) return false;
185 if (mMediaPlayer.hasMediaSession()
186 && mHorizontalLinearLayout.getVisibility() == View.GONE) {
187 mHorizontalLinearLayout.setVisibility(View.VISIBLE);
188 ((View) mRegularTileLayout).setVisibility(View.GONE);
189 mTileLayout.setListening(false);
190 for (TileRecord record : mRecords) {
191 mTileLayout.removeTile(record);
192 record.tile.removeCallback(record.callback);
193 }
194 mTileLayout = mMediaTileLayout;
Fabian Kozynskif13ce792019-12-12 16:05:10 -0500195 if (mHost != null) setTiles(mHost.getTiles());
Fabian Kozynskiaba2a542019-12-04 12:25:59 -0500196 mTileLayout.setListening(mListening);
197 return true;
198 } else if (!mMediaPlayer.hasMediaSession()
199 && mHorizontalLinearLayout.getVisibility() == View.VISIBLE) {
200 mHorizontalLinearLayout.setVisibility(View.GONE);
201 ((View) mRegularTileLayout).setVisibility(View.VISIBLE);
202 mTileLayout.setListening(false);
203 for (TileRecord record : mRecords) {
204 mTileLayout.removeTile(record);
205 record.tile.removeCallback(record.callback);
206 }
207 mTileLayout = mRegularTileLayout;
Fabian Kozynskif13ce792019-12-12 16:05:10 -0500208 if (mHost != null) setTiles(mHost.getTiles());
Fabian Kozynskiaba2a542019-12-04 12:25:59 -0500209 mTileLayout.setListening(mListening);
210 return true;
211 }
212 return false;
213 }
214
215 public boolean hasMediaPlayerSession() {
216 return mMediaPlayer.hasMediaSession();
217 }
218
Jason Monkec87a872016-03-01 15:00:16 -0500219 @Override
Jason Monka9df9992016-03-15 12:41:13 -0400220 public void setHost(QSTileHost host, QSCustomizer customizer) {
221 super.setHost(host, customizer);
222 setTiles(mHost.getTiles());
223 }
224
Jason Monkdc35dcb2015-12-04 16:36:15 -0500225 public void setMaxTiles(int maxTiles) {
226 mMaxTiles = maxTiles;
Jason Monka9df9992016-03-15 12:41:13 -0400227 if (mHost != null) {
228 setTiles(mHost.getTiles());
229 }
Jason Monkdc35dcb2015-12-04 16:36:15 -0500230 }
231
232 @Override
Jason Monkc34befb2015-10-07 16:40:02 -0400233 public void onTuningChanged(String key, String newValue) {
Rohan Shahd3cf7562018-02-23 11:12:28 -0800234 if (QS_SHOW_BRIGHTNESS.equals(key)) {
Rohan Shahdb2cfa32018-02-20 11:27:22 -0800235 // No Brightness or Tooltip for you!
Jason Monkc34befb2015-10-07 16:40:02 -0400236 super.onTuningChanged(key, "0");
237 }
238 }
239
240 @Override
Jason Monk702e2eb2017-03-03 16:53:44 -0500241 public void setTiles(Collection<QSTile> tiles) {
242 ArrayList<QSTile> quickTiles = new ArrayList<>();
243 for (QSTile tile : tiles) {
Jason Monkdc35dcb2015-12-04 16:36:15 -0500244 quickTiles.add(tile);
245 if (quickTiles.size() == mMaxTiles) {
Jason Monkc34befb2015-10-07 16:40:02 -0400246 break;
247 }
248 }
Jason Monkc59249f2016-06-17 10:19:43 -0400249 super.setTiles(quickTiles, true);
Jason Monkc34befb2015-10-07 16:40:02 -0400250 }
251
Jason Monk8fb77872016-03-03 16:39:42 -0500252 private final Tunable mNumTiles = new Tunable() {
253 @Override
254 public void onTuningChanged(String key, String newValue) {
Fabian Kozynskic8d8f052019-09-09 09:15:04 -0400255 setMaxTiles(parseNumTiles(newValue));
Jason Monk8fb77872016-03-03 16:39:42 -0500256 }
257 };
258
Fabian Kozynskic8d8f052019-09-09 09:15:04 -0400259 public int getNumQuickTiles() {
260 return mMaxTiles;
261 }
262
263 /**
264 * Parses the String setting into the number of tiles. Defaults to {@code mDefaultMaxTiles}
265 *
266 * @param numTilesValue value of the setting to parse
267 * @return parsed value of numTilesValue OR {@code mDefaultMaxTiles} on error
268 */
269 public static int parseNumTiles(String numTilesValue) {
270 try {
271 return Integer.parseInt(numTilesValue);
272 } catch (NumberFormatException e) {
273 // Couldn't read an int from the new setting value. Use default.
274 return sDefaultMaxTiles;
275 }
276 }
277
278 public static int getDefaultMaxTiles() {
279 return sDefaultMaxTiles;
Jason Monk8fb77872016-03-03 16:39:42 -0500280 }
281
Charles Hece2a7c02017-10-11 20:25:20 +0100282 void setDisabledByPolicy(boolean disabled) {
283 if (disabled != mDisabledByPolicy) {
284 mDisabledByPolicy = disabled;
285 setVisibility(disabled ? View.GONE : View.VISIBLE);
286 }
287 }
288
289 /**
290 * Sets the visibility of this {@link QuickQSPanel}. This method has no effect when this panel
291 * is disabled by policy through {@link #setDisabledByPolicy(boolean)}, and in this case the
292 * visibility will always be {@link View#GONE}. This method is called externally by
293 * {@link QSAnimator} only.
294 */
295 @Override
296 public void setVisibility(int visibility) {
297 if (mDisabledByPolicy) {
298 if (getVisibility() == View.GONE) {
299 return;
300 }
301 visibility = View.GONE;
302 }
303 super.setVisibility(visibility);
304 }
305
Fabian Kozynski802279f2018-09-07 13:44:54 -0400306 private static class HeaderTileLayout extends TileLayout {
Jason Monkc34befb2015-10-07 16:40:02 -0400307
Jason Monk1bec6af2016-05-31 15:40:58 -0400308 private boolean mListening;
Fabian Kozynskidc23ef62019-04-22 14:30:59 -0400309 private Rect mClippingBounds = new Rect();
Jason Monkfece2ab2016-02-04 11:41:18 -0500310
Jason Monkc34befb2015-10-07 16:40:02 -0400311 public HeaderTileLayout(Context context) {
312 super(context);
Jason Monkdc35dcb2015-12-04 16:36:15 -0500313 setClipChildren(false);
314 setClipToPadding(false);
Fabian Kozynski7a4e3312019-04-24 11:10:21 -0400315 LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
316 LayoutParams.MATCH_PARENT);
317 lp.gravity = Gravity.CENTER_HORIZONTAL;
318 setLayoutParams(lp);
Jason Monkfece2ab2016-02-04 11:41:18 -0500319 }
320
321 @Override
Rohan Shah14394642018-03-13 20:10:12 -0700322 protected void onConfigurationChanged(Configuration newConfig) {
323 super.onConfigurationChanged(newConfig);
Fabian Kozynski802279f2018-09-07 13:44:54 -0400324 updateResources();
325 }
326
327 @Override
328 public void onFinishInflate(){
329 updateResources();
Amin Shaikh6a298d62018-06-18 16:44:14 -0400330 }
Rohan Shah14394642018-03-13 20:10:12 -0700331
Fabian Kozynski52728302018-09-07 12:45:59 +0000332 private LayoutParams generateTileLayoutParams() {
Fabian Kozynski802279f2018-09-07 13:44:54 -0400333 LayoutParams lp = new LayoutParams(mCellWidth, mCellHeight);
Fabian Kozynski52728302018-09-07 12:45:59 +0000334 return lp;
335 }
336
337 @Override
Fabian Kozynski802279f2018-09-07 13:44:54 -0400338 protected void addTileView(TileRecord tile) {
339 addView(tile.tileView, getChildCount(), generateTileLayoutParams());
Fabian Kozynski52728302018-09-07 12:45:59 +0000340 }
341
342 @Override
Fabian Kozynski802279f2018-09-07 13:44:54 -0400343 protected void onLayout(boolean changed, int l, int t, int r, int b) {
344 // We only care about clipping on the right side
Fabian Kozynskidc23ef62019-04-22 14:30:59 -0400345 mClippingBounds.set(0, 0, r - l, 10000);
346 setClipBounds(mClippingBounds);
Fabian Kozynski802279f2018-09-07 13:44:54 -0400347
348 calculateColumns();
349
350 for (int i = 0; i < mRecords.size(); i++) {
351 mRecords.get(i).tileView.setVisibility( i < mColumns ? View.VISIBLE : View.GONE);
352 }
353
354 setAccessibilityOrder();
355 layoutTileRecords(mColumns);
Jason Monkc34befb2015-10-07 16:40:02 -0400356 }
357
358 @Override
Jason Monk9d02a432016-01-20 16:33:46 -0500359 public boolean updateResources() {
Fabian Kozynski802279f2018-09-07 13:44:54 -0400360 mCellWidth = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
361 mCellHeight = mCellWidth;
362
Jason Monk9d02a432016-01-20 16:33:46 -0500363 return false;
Jason Monkc34befb2015-10-07 16:40:02 -0400364 }
Jason Monkc5bdafb2016-02-25 16:24:21 -0500365
Fabian Kozynski802279f2018-09-07 13:44:54 -0400366 private boolean calculateColumns() {
367 int prevNumColumns = mColumns;
368 int maxTiles = mRecords.size();
Fabian Kozynski40c9f0d2018-08-29 16:21:42 -0400369
Fabian Kozynski802279f2018-09-07 13:44:54 -0400370 if (maxTiles == 0){ // Early return during setup
371 mColumns = 0;
372 return true;
Fabian Kozynski52728302018-09-07 12:45:59 +0000373 }
374
Fabian Kozynski802279f2018-09-07 13:44:54 -0400375 final int availableWidth = getMeasuredWidth() - getPaddingStart() - getPaddingEnd();
Fabian Kozynskidc23ef62019-04-22 14:30:59 -0400376 final int leftoverWhitespace = availableWidth - maxTiles * mCellWidth;
Fabian Kozynski1967f7d2018-10-02 09:18:52 -0400377 final int smallestHorizontalMarginNeeded;
Fabian Kozynskidc23ef62019-04-22 14:30:59 -0400378 smallestHorizontalMarginNeeded = leftoverWhitespace / Math.max(1, maxTiles - 1);
Fabian Kozynski802279f2018-09-07 13:44:54 -0400379
380 if (smallestHorizontalMarginNeeded > 0){
381 mCellMarginHorizontal = smallestHorizontalMarginNeeded;
382 mColumns = maxTiles;
383 } else{
384 mColumns = mCellWidth == 0 ? 1 :
385 Math.min(maxTiles, availableWidth / mCellWidth );
Fabian Kozynski4372f7c2019-11-11 12:16:27 -0500386 // If we can only fit one column, use mCellMarginHorizontal to center it.
387 if (mColumns == 1) {
388 mCellMarginHorizontal = (availableWidth - mCellWidth) / 2;
389 } else {
390 mCellMarginHorizontal =
391 (availableWidth - mColumns * mCellWidth) / (mColumns - 1);
392 }
393
Fabian Kozynski802279f2018-09-07 13:44:54 -0400394 }
395 return mColumns != prevNumColumns;
396 }
397
398 private void setAccessibilityOrder() {
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400399 if (mRecords != null && mRecords.size() > 0) {
400 View previousView = this;
401 for (TileRecord record : mRecords) {
402 if (record.tileView.getVisibility() == GONE) continue;
403 previousView = record.tileView.updateAccessibilityOrder(previousView);
404 }
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400405 mRecords.get(mRecords.size() - 1).tileView.setAccessibilityTraversalBefore(
406 R.id.expand_indicator);
407 }
408 }
Amin Shaikh6a298d62018-06-18 16:44:14 -0400409
Fabian Kozynski802279f2018-09-07 13:44:54 -0400410 @Override
411 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
412 // Measure each QS tile.
413 for (TileRecord record : mRecords) {
414 if (record.tileView.getVisibility() == GONE) continue;
415 record.tileView.measure(exactly(mCellWidth), exactly(mCellHeight));
Amin Shaikh6a298d62018-06-18 16:44:14 -0400416 }
Fabian Kozynski802279f2018-09-07 13:44:54 -0400417
418 int height = mCellHeight;
419 if (height < 0) height = 0;
420
421 setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height);
422 }
423
424 @Override
425 public int getNumVisibleTiles() {
426 return mColumns;
427 }
428
429 @Override
430 protected int getColumnStart(int column) {
Fabian Kozynski4372f7c2019-11-11 12:16:27 -0500431 if (mColumns == 1) {
432 // Only one column/tile. Use the margin to center the tile.
433 return getPaddingStart() + mCellMarginHorizontal;
434 }
Fabian Kozynski802279f2018-09-07 13:44:54 -0400435 return getPaddingStart() + column * (mCellWidth + mCellMarginHorizontal);
Amin Shaikh6a298d62018-06-18 16:44:14 -0400436 }
Jason Monkc34befb2015-10-07 16:40:02 -0400437 }
438}