blob: 1fa97bd887f82ea7244ba4dd7756dd9bca5ac25f [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
19import android.animation.Animator;
20import android.animation.Animator.AnimatorListener;
21import android.animation.AnimatorListenerAdapter;
22import android.content.Context;
John Spurlock7f8f22a2014-07-02 18:54:17 -040023import android.content.Intent;
John Spurlock4bf31982014-05-21 13:04:22 -040024import android.content.res.Resources;
John Spurlockaf8d6c42014-05-07 17:49:08 -040025import android.os.Handler;
26import android.os.Message;
27import android.util.AttributeSet;
John Spurlock7f8f22a2014-07-02 18:54:17 -040028import android.view.LayoutInflater;
John Spurlockaf8d6c42014-05-07 17:49:08 -040029import android.view.View;
30import android.view.ViewGroup;
Jorim Jaggi3f48f462014-07-08 16:53:29 +020031import android.widget.ImageView;
John Spurlockaf8d6c42014-05-07 17:49:08 -040032
33import com.android.systemui.R;
John Spurlock7f8f22a2014-07-02 18:54:17 -040034import com.android.systemui.qs.QSTile.DetailAdapter;
Jorim Jaggi3f48f462014-07-08 16:53:29 +020035import com.android.systemui.settings.BrightnessController;
36import com.android.systemui.settings.ToggleSlider;
Adrian Roos1ef80fe2014-07-14 22:53:54 +020037import com.android.systemui.statusbar.phone.QSTileHost;
Adrian Roos5fd872e2014-08-12 17:28:58 +020038import com.android.systemui.statusbar.policy.BrightnessMirrorController;
John Spurlockaf8d6c42014-05-07 17:49:08 -040039
40import java.util.ArrayList;
John Spurlockbceed062014-08-10 18:04:16 -040041import java.util.Collection;
John Spurlockaf8d6c42014-05-07 17:49:08 -040042
43/** View that represents the quick settings tile panel. **/
44public class QSPanel extends ViewGroup {
John Spurlock4bf31982014-05-21 13:04:22 -040045 private static final float TILE_ASPECT = 1.2f;
John Spurlockaf8d6c42014-05-07 17:49:08 -040046
47 private final Context mContext;
48 private final ArrayList<TileRecord> mRecords = new ArrayList<TileRecord>();
John Spurlock7f8f22a2014-07-02 18:54:17 -040049 private final View mDetail;
50 private final ViewGroup mDetailContent;
51 private final View mDetailSettingsButton;
52 private final View mDetailDoneButton;
Jorim Jaggi3f48f462014-07-08 16:53:29 +020053 private final View mBrightnessView;
John Spurlock8af525d2014-08-02 10:56:05 -040054 private final QSDetailClipper mClipper;
John Spurlockaf8d6c42014-05-07 17:49:08 -040055 private final H mHandler = new H();
56
57 private int mColumns;
58 private int mCellWidth;
59 private int mCellHeight;
60 private int mLargeCellWidth;
61 private int mLargeCellHeight;
John Spurlock92d9b192014-06-29 12:54:24 -040062 private int mPanelPaddingBottom;
John Spurlock39076ed2014-06-30 20:47:20 -040063 private int mDualTileUnderlap;
Adrian Rooscd542b82014-08-12 22:25:35 +020064 private int mBrightnessPaddingTop;
John Spurlock5729d092014-05-29 17:42:51 -040065 private boolean mExpanded;
Jorim Jaggie65e3102014-07-01 22:00:50 +020066 private boolean mListening;
John Spurlockaf8d6c42014-05-07 17:49:08 -040067
Adrian Roos1ef80fe2014-07-14 22:53:54 +020068 private Record mDetailRecord;
John Spurlock5729d092014-05-29 17:42:51 -040069 private Callback mCallback;
Jorim Jaggi3f48f462014-07-08 16:53:29 +020070 private BrightnessController mBrightnessController;
Adrian Roos1ef80fe2014-07-14 22:53:54 +020071 private QSTileHost mHost;
John Spurlockaf8d6c42014-05-07 17:49:08 -040072
Jason Monk3d5f5512014-07-25 11:17:28 -040073 private QSFooter mFooter;
74
John Spurlockaf8d6c42014-05-07 17:49:08 -040075 public QSPanel(Context context) {
76 this(context, null);
77 }
78
79 public QSPanel(Context context, AttributeSet attrs) {
80 super(context, attrs);
81 mContext = context;
82
John Spurlock7f8f22a2014-07-02 18:54:17 -040083 mDetail = LayoutInflater.from(context).inflate(R.layout.qs_detail, this, false);
84 mDetailContent = (ViewGroup) mDetail.findViewById(android.R.id.content);
85 mDetailSettingsButton = mDetail.findViewById(android.R.id.button2);
86 mDetailDoneButton = mDetail.findViewById(android.R.id.button1);
John Spurlockaf8d6c42014-05-07 17:49:08 -040087 mDetail.setVisibility(GONE);
88 mDetail.setClickable(true);
Jorim Jaggi3f48f462014-07-08 16:53:29 +020089 mBrightnessView = LayoutInflater.from(context).inflate(
90 R.layout.quick_settings_brightness_dialog, this, false);
Jason Monk3d5f5512014-07-25 11:17:28 -040091 mFooter = new QSFooter(this, context);
John Spurlockaf8d6c42014-05-07 17:49:08 -040092 addView(mDetail);
Jorim Jaggi3f48f462014-07-08 16:53:29 +020093 addView(mBrightnessView);
Jason Monk3d5f5512014-07-25 11:17:28 -040094 addView(mFooter.getView());
John Spurlock8af525d2014-08-02 10:56:05 -040095 mClipper = new QSDetailClipper(mDetail);
John Spurlockaf8d6c42014-05-07 17:49:08 -040096 updateResources();
Jorim Jaggi3f48f462014-07-08 16:53:29 +020097
98 mBrightnessController = new BrightnessController(getContext(),
99 (ImageView) findViewById(R.id.brightness_icon),
100 (ToggleSlider) findViewById(R.id.brightness_slider));
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200101
102 mDetailDoneButton.setOnClickListener(new OnClickListener() {
103 @Override
104 public void onClick(View v) {
John Spurlockf7ae4422014-08-01 12:45:18 -0400105 closeDetail();
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200106 }
107 });
John Spurlockaf8d6c42014-05-07 17:49:08 -0400108 }
109
Adrian Roos5fd872e2014-08-12 17:28:58 +0200110 public void setBrightnessMirror(BrightnessMirrorController c) {
111 super.onFinishInflate();
112 ToggleSlider brightnessSlider = (ToggleSlider) findViewById(R.id.brightness_slider);
113 ToggleSlider mirror = (ToggleSlider) c.getMirror().findViewById(R.id.brightness_slider);
114 brightnessSlider.setMirror(mirror);
115 brightnessSlider.setMirrorController(c);
116 }
117
John Spurlock5729d092014-05-29 17:42:51 -0400118 public void setCallback(Callback callback) {
119 mCallback = callback;
120 }
121
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200122 public void setHost(QSTileHost host) {
123 mHost = host;
Jason Monk3d5f5512014-07-25 11:17:28 -0400124 mFooter.setHost(host);
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200125 }
126
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200127 public QSTileHost getHost() {
128 return mHost;
129 }
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200130
John Spurlockaf8d6c42014-05-07 17:49:08 -0400131 public void updateResources() {
John Spurlock4bf31982014-05-21 13:04:22 -0400132 final Resources res = mContext.getResources();
133 final int columns = Math.max(1, res.getInteger(R.integer.quick_settings_num_columns));
134 mCellHeight = res.getDimensionPixelSize(R.dimen.qs_tile_height);
135 mCellWidth = (int)(mCellHeight * TILE_ASPECT);
136 mLargeCellHeight = res.getDimensionPixelSize(R.dimen.qs_dual_tile_height);
137 mLargeCellWidth = (int)(mLargeCellHeight * TILE_ASPECT);
John Spurlock92d9b192014-06-29 12:54:24 -0400138 mPanelPaddingBottom = res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom);
John Spurlock39076ed2014-06-30 20:47:20 -0400139 mDualTileUnderlap = res.getDimensionPixelSize(R.dimen.qs_dual_tile_padding_vertical);
Adrian Rooscd542b82014-08-12 22:25:35 +0200140 mBrightnessPaddingTop = res.getDimensionPixelSize(R.dimen.qs_brightness_padding_top);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400141 if (mColumns != columns) {
142 mColumns = columns;
143 postInvalidate();
144 }
John Spurlock1a462c12014-07-14 10:52:01 -0400145 if (mListening) {
146 refreshAllTiles();
147 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400148 }
149
150 public void setExpanded(boolean expanded) {
John Spurlock5729d092014-05-29 17:42:51 -0400151 if (mExpanded == expanded) return;
152 mExpanded = expanded;
153 if (!mExpanded) {
John Spurlockf7ae4422014-08-01 12:45:18 -0400154 closeDetail();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400155 }
Jorim Jaggie65e3102014-07-01 22:00:50 +0200156 }
157
158 public void setListening(boolean listening) {
159 if (mListening == listening) return;
160 mListening = listening;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400161 for (TileRecord r : mRecords) {
Jorim Jaggie65e3102014-07-01 22:00:50 +0200162 r.tile.setListening(mListening);
John Spurlock1a462c12014-07-14 10:52:01 -0400163 }
Jason Monk3d5f5512014-07-25 11:17:28 -0400164 mFooter.setListening(mListening);
John Spurlock1a462c12014-07-14 10:52:01 -0400165 if (mListening) {
166 refreshAllTiles();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400167 }
Jorim Jaggi3f48f462014-07-08 16:53:29 +0200168 if (listening) {
169 mBrightnessController.registerCallbacks();
170 } else {
171 mBrightnessController.unregisterCallbacks();
172 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400173 }
174
John Spurlock1a462c12014-07-14 10:52:01 -0400175 private void refreshAllTiles() {
176 for (TileRecord r : mRecords) {
177 r.tile.refreshState();
178 }
Jason Monk3d5f5512014-07-25 11:17:28 -0400179 mFooter.refreshState();
John Spurlock1a462c12014-07-14 10:52:01 -0400180 }
181
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200182 public void showDetailAdapter(boolean show, DetailAdapter adapter) {
183 Record r = new Record();
184 r.detailAdapter = adapter;
185 showDetail(show, r);
186 }
187
188 private void showDetail(boolean show, Record r) {
John Spurlockaf8d6c42014-05-07 17:49:08 -0400189 mHandler.obtainMessage(H.SHOW_DETAIL, show ? 1 : 0, 0, r).sendToTarget();
190 }
191
192 private void setTileVisibility(View v, boolean visible) {
193 mHandler.obtainMessage(H.SET_TILE_VISIBILITY, visible ? 1 : 0, 0, v).sendToTarget();
194 }
195
196 private void handleSetTileVisibility(View v, boolean visible) {
John Spurlock360e15b2014-07-08 18:45:21 -0400197 if (visible == (v.getVisibility() == VISIBLE)) return;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400198 v.setVisibility(visible ? VISIBLE : GONE);
199 }
200
John Spurlockbceed062014-08-10 18:04:16 -0400201 public void setTiles(Collection<QSTile<?>> tiles) {
202 for (TileRecord record : mRecords) {
203 removeView(record.tileView);
204 }
205 mRecords.clear();
206 for (QSTile<?> tile : tiles) {
207 addTile(tile);
208 }
209 if (isShowingDetail()) {
210 mDetail.bringToFront();
211 }
212 }
213
214 private void addTile(final QSTile<?> tile) {
John Spurlockaf8d6c42014-05-07 17:49:08 -0400215 final TileRecord r = new TileRecord();
216 r.tile = tile;
217 r.tileView = tile.createTileView(mContext);
218 r.tileView.setVisibility(View.GONE);
John Spurlockbceed062014-08-10 18:04:16 -0400219 final QSTile.Callback callback = new QSTile.Callback() {
John Spurlockaf8d6c42014-05-07 17:49:08 -0400220 @Override
221 public void onStateChanged(QSTile.State state) {
222 setTileVisibility(r.tileView, state.visible);
223 r.tileView.onStateChanged(state);
224 }
225 @Override
226 public void onShowDetail(boolean show) {
227 QSPanel.this.showDetail(show, r);
228 }
John Spurlock7f8f22a2014-07-02 18:54:17 -0400229 @Override
230 public void onToggleStateChanged(boolean state) {
231 if (mDetailRecord == r) {
232 fireToggleStateChanged(state);
233 }
234 }
John Spurlock486b78e2014-07-07 08:37:56 -0400235 @Override
236 public void onScanStateChanged(boolean state) {
John Spurlock465cefa2014-08-16 10:39:33 -0400237 r.scanState = state;
John Spurlock486b78e2014-07-07 08:37:56 -0400238 if (mDetailRecord == r) {
John Spurlock465cefa2014-08-16 10:39:33 -0400239 fireScanStateChanged(r.scanState);
John Spurlock486b78e2014-07-07 08:37:56 -0400240 }
241 }
John Spurlockbceed062014-08-10 18:04:16 -0400242 };
243 r.tile.setCallback(callback);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400244 final View.OnClickListener click = new View.OnClickListener() {
245 @Override
246 public void onClick(View v) {
247 r.tile.click();
248 }
249 };
250 final View.OnClickListener clickSecondary = new View.OnClickListener() {
251 @Override
252 public void onClick(View v) {
253 r.tile.secondaryClick();
254 }
255 };
256 r.tileView.init(click, clickSecondary);
John Spurlockbceed062014-08-10 18:04:16 -0400257 r.tile.setListening(mListening);
258 callback.onStateChanged(r.tile.getState());
John Spurlockccb6b9a2014-05-17 15:54:40 -0400259 r.tile.refreshState();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400260 mRecords.add(r);
261
262 addView(r.tileView);
263 }
264
John Spurlockf7ae4422014-08-01 12:45:18 -0400265 public boolean isShowingDetail() {
266 return mDetailRecord != null;
267 }
268
269 public void closeDetail() {
270 showDetail(false, mDetailRecord);
271 }
272
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200273 private void handleShowDetail(Record r, boolean show) {
274 if (r instanceof TileRecord) {
275 handleShowDetailTile((TileRecord) r, show);
276 } else {
277 handleShowDetailImpl(r, show, getWidth() /* x */, 0/* y */);
278 }
279 }
280
281 private void handleShowDetailTile(TileRecord r, boolean show) {
282 if ((mDetailRecord != null) == show) return;
283
John Spurlockaf8d6c42014-05-07 17:49:08 -0400284 if (show) {
John Spurlock7f8f22a2014-07-02 18:54:17 -0400285 r.detailAdapter = r.tile.getDetailAdapter();
286 if (r.detailAdapter == null) return;
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200287 }
288 int x = r.tileView.getLeft() + r.tileView.getWidth() / 2;
289 int y = r.tileView.getTop() + r.tileView.getHeight() / 2;
290 handleShowDetailImpl(r, show, x, y);
291 }
292
293 private void handleShowDetailImpl(Record r, boolean show, int x, int y) {
294 if ((mDetailRecord != null) == show) return; // already in right state
295 DetailAdapter detailAdapter = null;
296 AnimatorListener listener = null;
297 if (show) {
298 detailAdapter = r.detailAdapter;
299 r.detailView = detailAdapter.createDetailView(mContext, r.detailView, mDetailContent);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400300 if (r.detailView == null) throw new IllegalStateException("Must return detail view");
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200301
302 final Intent settingsIntent = detailAdapter.getSettingsIntent();
John Spurlock7f8f22a2014-07-02 18:54:17 -0400303 mDetailSettingsButton.setVisibility(settingsIntent != null ? VISIBLE : GONE);
304 mDetailSettingsButton.setOnClickListener(new OnClickListener() {
305 @Override
306 public void onClick(View v) {
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200307 mHost.startSettingsActivity(settingsIntent);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400308 }
309 });
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200310
John Spurlock7f8f22a2014-07-02 18:54:17 -0400311 mDetailContent.removeAllViews();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400312 mDetail.bringToFront();
John Spurlock7f8f22a2014-07-02 18:54:17 -0400313 mDetailContent.addView(r.detailView);
John Spurlock465cefa2014-08-16 10:39:33 -0400314 setDetailRecord(r);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400315 } else {
John Spurlockaf8d6c42014-05-07 17:49:08 -0400316 listener = mTeardownDetailWhenDone;
John Spurlock465cefa2014-08-16 10:39:33 -0400317 fireScanStateChanged(false);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400318 }
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200319 fireShowingDetail(show ? detailAdapter : null);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400320 mClipper.animateCircularClip(x, y, show, listener);
321 }
322
323 @Override
324 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
325 final int width = MeasureSpec.getSize(widthMeasureSpec);
Jorim Jaggi3f48f462014-07-08 16:53:29 +0200326 mBrightnessView.measure(exactly(width), MeasureSpec.UNSPECIFIED);
Adrian Rooscd542b82014-08-12 22:25:35 +0200327 final int brightnessHeight = mBrightnessView.getMeasuredHeight() + mBrightnessPaddingTop;
Jason Monk3d5f5512014-07-25 11:17:28 -0400328 mFooter.getView().measure(exactly(width), MeasureSpec.UNSPECIFIED);
John Spurlockccb6b9a2014-05-17 15:54:40 -0400329 int r = -1;
330 int c = -1;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400331 int rows = 0;
John Spurlockccb6b9a2014-05-17 15:54:40 -0400332 boolean rowIsDual = false;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400333 for (TileRecord record : mRecords) {
334 if (record.tileView.getVisibility() == GONE) continue;
John Spurlockccb6b9a2014-05-17 15:54:40 -0400335 // wrap to next column if we've reached the max # of columns
336 // also don't allow dual + single tiles on the same row
337 if (r == -1 || c == (mColumns - 1) || rowIsDual != record.tile.supportsDualTargets()) {
338 r++;
339 c = 0;
340 rowIsDual = record.tile.supportsDualTargets();
341 } else {
342 c++;
343 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400344 record.row = r;
345 record.col = c;
346 rows = r + 1;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400347 }
348
349 for (TileRecord record : mRecords) {
350 if (record.tileView.getVisibility() == GONE) continue;
John Spurlockccb6b9a2014-05-17 15:54:40 -0400351 record.tileView.setDual(record.tile.supportsDualTargets());
John Spurlockaf8d6c42014-05-07 17:49:08 -0400352 final int cw = record.row == 0 ? mLargeCellWidth : mCellWidth;
353 final int ch = record.row == 0 ? mLargeCellHeight : mCellHeight;
354 record.tileView.measure(exactly(cw), exactly(ch));
355 }
Adrian Rooscd542b82014-08-12 22:25:35 +0200356 int h = rows == 0 ? brightnessHeight : (getRowTop(rows) + mPanelPaddingBottom);
Jason Monk3d5f5512014-07-25 11:17:28 -0400357 if (mFooter.hasFooter()) {
Adrian Rooscd542b82014-08-12 22:25:35 +0200358 h += mFooter.getView().getMeasuredHeight();
Jason Monk3d5f5512014-07-25 11:17:28 -0400359 }
Adrian Roos19408922014-08-07 20:54:12 +0200360 mDetail.measure(exactly(width), MeasureSpec.UNSPECIFIED);
361 if (mDetail.getMeasuredHeight() < h) {
362 mDetail.measure(exactly(width), exactly(h));
363 }
364 setMeasuredDimension(width, Math.max(h, mDetail.getMeasuredHeight()));
John Spurlockaf8d6c42014-05-07 17:49:08 -0400365 }
366
367 private static int exactly(int size) {
368 return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
369 }
370
371 @Override
372 protected void onLayout(boolean changed, int l, int t, int r, int b) {
John Spurlock4bf31982014-05-21 13:04:22 -0400373 final int w = getWidth();
Adrian Rooscd542b82014-08-12 22:25:35 +0200374 mBrightnessView.layout(0, mBrightnessPaddingTop,
375 mBrightnessView.getMeasuredWidth(),
376 mBrightnessPaddingTop + mBrightnessView.getMeasuredHeight());
John Spurlockaf8d6c42014-05-07 17:49:08 -0400377 for (TileRecord record : mRecords) {
378 if (record.tileView.getVisibility() == GONE) continue;
379 final int cols = getColumnCount(record.row);
380 final int cw = record.row == 0 ? mLargeCellWidth : mCellWidth;
381 final int extra = (w - cw * cols) / (cols + 1);
382 final int left = record.col * cw + (record.col + 1) * extra;
383 final int top = getRowTop(record.row);
384 record.tileView.layout(left, top,
385 left + record.tileView.getMeasuredWidth(),
386 top + record.tileView.getMeasuredHeight());
387 }
John Spurlock3e04cc82014-05-30 12:34:03 -0400388 final int dh = Math.max(mDetail.getMeasuredHeight(), getMeasuredHeight());
389 mDetail.layout(0, 0, mDetail.getMeasuredWidth(), dh);
Jason Monk3d5f5512014-07-25 11:17:28 -0400390 if (mFooter.hasFooter()) {
391 View footer = mFooter.getView();
392 footer.layout(0, getMeasuredHeight() - footer.getMeasuredHeight(),
393 footer.getMeasuredWidth(), getMeasuredHeight());
394 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400395 }
396
397 private int getRowTop(int row) {
Adrian Rooscd542b82014-08-12 22:25:35 +0200398 if (row <= 0) return mBrightnessView.getMeasuredHeight() + mBrightnessPaddingTop;
399 return mBrightnessView.getMeasuredHeight() + mBrightnessPaddingTop
Jorim Jaggi3f48f462014-07-08 16:53:29 +0200400 + mLargeCellHeight - mDualTileUnderlap + (row - 1) * mCellHeight;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400401 }
402
403 private int getColumnCount(int row) {
404 int cols = 0;
405 for (TileRecord record : mRecords) {
406 if (record.tileView.getVisibility() == GONE) continue;
407 if (record.row == row) cols++;
408 }
409 return cols;
410 }
411
John Spurlock7f8f22a2014-07-02 18:54:17 -0400412 private void fireShowingDetail(QSTile.DetailAdapter detail) {
John Spurlock5729d092014-05-29 17:42:51 -0400413 if (mCallback != null) {
John Spurlock7f8f22a2014-07-02 18:54:17 -0400414 mCallback.onShowingDetail(detail);
415 }
416 }
417
418 private void fireToggleStateChanged(boolean state) {
419 if (mCallback != null) {
420 mCallback.onToggleStateChanged(state);
John Spurlock5729d092014-05-29 17:42:51 -0400421 }
422 }
423
John Spurlock486b78e2014-07-07 08:37:56 -0400424 private void fireScanStateChanged(boolean state) {
425 if (mCallback != null) {
426 mCallback.onScanStateChanged(state);
427 }
428 }
429
John Spurlock465cefa2014-08-16 10:39:33 -0400430 private void setDetailRecord(Record r) {
431 if (r == mDetailRecord) return;
432 mDetailRecord = r;
433 final boolean scanState = mDetailRecord instanceof TileRecord
434 && ((TileRecord) mDetailRecord).scanState;
435 fireScanStateChanged(scanState);
436 }
437
John Spurlockaf8d6c42014-05-07 17:49:08 -0400438 private class H extends Handler {
439 private static final int SHOW_DETAIL = 1;
440 private static final int SET_TILE_VISIBILITY = 2;
441 @Override
442 public void handleMessage(Message msg) {
443 if (msg.what == SHOW_DETAIL) {
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200444 handleShowDetail((Record)msg.obj, msg.arg1 != 0);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400445 } else if (msg.what == SET_TILE_VISIBILITY) {
446 handleSetTileVisibility((View)msg.obj, msg.arg1 != 0);
447 }
448 }
449 }
450
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200451 private static class Record {
John Spurlock856edeb2014-06-01 20:36:47 -0400452 View detailView;
John Spurlock7f8f22a2014-07-02 18:54:17 -0400453 DetailAdapter detailAdapter;
Adrian Roos1ef80fe2014-07-14 22:53:54 +0200454 }
455
456 private static final class TileRecord extends Record {
457 QSTile<?> tile;
458 QSTileView tileView;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400459 int row;
460 int col;
John Spurlock465cefa2014-08-16 10:39:33 -0400461 boolean scanState;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400462 }
463
464 private final AnimatorListenerAdapter mTeardownDetailWhenDone = new AnimatorListenerAdapter() {
465 public void onAnimationEnd(Animator animation) {
John Spurlock7f8f22a2014-07-02 18:54:17 -0400466 mDetailContent.removeAllViews();
John Spurlock465cefa2014-08-16 10:39:33 -0400467 setDetailRecord(null);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400468 };
469 };
John Spurlock5729d092014-05-29 17:42:51 -0400470
471 public interface Callback {
John Spurlock7f8f22a2014-07-02 18:54:17 -0400472 void onShowingDetail(QSTile.DetailAdapter detail);
473 void onToggleStateChanged(boolean state);
John Spurlock486b78e2014-07-07 08:37:56 -0400474 void onScanStateChanged(boolean state);
John Spurlock5729d092014-05-29 17:42:51 -0400475 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400476}