blob: 672f2c2df06e4c5b9d3fd59921c8e3d216f787a7 [file] [log] [blame]
John Spurlockaf8d6c42014-05-07 17:49:08 -04001/*
Jason Monk702e2eb2017-03-03 16:53:44 -05002 * Copyright (C) 2017 The Android Open Source Project
John Spurlockaf8d6c42014-05-07 17:49:08 -04003 *
Jason Monk702e2eb2017-03-03 16:53:44 -05004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5 * except in compliance with the License. You may obtain a copy of the License at
John Spurlockaf8d6c42014-05-07 17:49:08 -04006 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
Jason Monk702e2eb2017-03-03 16:53:44 -05009 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11 * KIND, either express or implied. See the License for the specific language governing
12 * permissions and limitations under the License.
John Spurlockaf8d6c42014-05-07 17:49:08 -040013 */
14
Jason Monk702e2eb2017-03-03 16:53:44 -050015package com.android.systemui.qs.tileimpl;
16
Jason Monk8c09ac72017-03-16 11:53:40 -040017import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_CLICK;
18import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_LONG_PRESS;
19import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_SECONDARY_CLICK;
20import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_QS_POSITION;
21import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_QS_VALUE;
22import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_ACTION;
Jason Monk702e2eb2017-03-03 16:53:44 -050023import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
John Spurlockaf8d6c42014-05-07 17:49:08 -040024
Jason Monk824ffff2017-04-11 15:49:06 -040025import android.R.attr;
Sudheer Shankab6fc9312016-01-27 19:59:03 +000026import android.app.ActivityManager;
John Spurlockaf8d6c42014-05-07 17:49:08 -040027import android.content.Context;
28import android.content.Intent;
John Spurlock444eb2e2014-05-14 13:32:14 -040029import android.graphics.drawable.Drawable;
Jason Monk8c09ac72017-03-16 11:53:40 -040030import android.metrics.LogMaker;
John Spurlockaf8d6c42014-05-07 17:49:08 -040031import android.os.Handler;
32import android.os.Looper;
33import android.os.Message;
Jason Monk32508852017-01-18 09:17:13 -050034import android.service.quicksettings.Tile;
Jason Monk1bec6af2016-05-31 15:40:58 -040035import android.util.ArraySet;
John Spurlockaf8d6c42014-05-07 17:49:08 -040036import android.util.Log;
John Spurlock2d695812014-10-30 13:25:21 -040037import android.util.SparseArray;
Sudheer Shanka1c7cda82015-12-31 14:46:02 +000038
Jason Monk96defbe2016-03-29 16:51:03 -040039import com.android.internal.logging.MetricsLogger;
Sudheer Shanka1c7cda82015-12-31 14:46:02 +000040import com.android.settingslib.RestrictedLockUtils;
Jason Monk702e2eb2017-03-03 16:53:44 -050041import com.android.settingslib.Utils;
Jason Monk9c7844c2017-01-18 15:21:53 -050042import com.android.systemui.Dependency;
Jason Monkec34da82017-02-24 15:57:05 -050043import com.android.systemui.plugins.ActivityStarter;
Jason Monke5b770e2017-03-03 21:49:29 -050044import com.android.systemui.plugins.qs.DetailAdapter;
Jason Monk702e2eb2017-03-03 16:53:44 -050045import com.android.systemui.plugins.qs.QSIconView;
46import com.android.systemui.plugins.qs.QSTile;
47import com.android.systemui.plugins.qs.QSTile.State;
48import com.android.systemui.qs.QSHost;
John Spurlockaf8d6c42014-05-07 17:49:08 -040049
Jason Monkca894a02016-01-12 15:30:22 -050050import java.util.ArrayList;
Sudheer Shanka1c7cda82015-12-31 14:46:02 +000051
John Spurlockaf8d6c42014-05-07 17:49:08 -040052/**
53 * Base quick-settings tile, extend this to create a new tile.
54 *
55 * State management done on a looper provided by the host. Tiles should update state in
56 * handleUpdateState. Callbacks affecting state should use refreshState to trigger another
57 * state update pass on tile looper.
58 */
Jason Monk702e2eb2017-03-03 16:53:44 -050059public abstract class QSTileImpl<TState extends State> implements QSTile {
Jason Monkbbadff82015-11-06 15:47:26 -050060 protected final String TAG = "Tile." + getClass().getSimpleName();
61 protected static final boolean DEBUG = Log.isLoggable("Tile", Log.DEBUG);
John Spurlockaf8d6c42014-05-07 17:49:08 -040062
Jason Monk702e2eb2017-03-03 16:53:44 -050063 protected final QSHost mHost;
John Spurlockaf8d6c42014-05-07 17:49:08 -040064 protected final Context mContext;
Evan Laird6b284732017-02-28 17:27:04 -050065 protected final H mHandler = new H(Dependency.get(Dependency.BG_LOOPER));
John Spurlock76c43b92014-05-13 21:10:51 -040066 protected final Handler mUiHandler = new Handler(Looper.getMainLooper());
Jason Monk1bec6af2016-05-31 15:40:58 -040067 private final ArraySet<Object> mListeners = new ArraySet<>();
Jason Monk8c09ac72017-03-16 11:53:40 -040068 private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
John Spurlockaf8d6c42014-05-07 17:49:08 -040069
Jason Monkca894a02016-01-12 15:30:22 -050070 private final ArrayList<Callback> mCallbacks = new ArrayList<>();
Jason Monka758ba62015-07-14 12:29:28 -040071 protected TState mState = newTileState();
72 private TState mTmpState = newTileState();
Selim Cinek4fda7b22014-08-18 22:07:25 +020073 private boolean mAnnounceNextStateChange;
John Spurlockaf8d6c42014-05-07 17:49:08 -040074
Jason Monkbd6dbb02015-09-03 15:46:25 -040075 private String mTileSpec;
Jason Monk702e2eb2017-03-03 16:53:44 -050076 private EnforcedAdmin mEnforcedAdmin;
Jason Monkbe3235a2017-04-05 09:29:53 -040077 private boolean mShowingDetail;
Jason Monkbd6dbb02015-09-03 15:46:25 -040078
Jason Monk62b63a02016-02-02 15:15:31 -050079 public abstract TState newTileState();
Jason Monk32508852017-01-18 09:17:13 -050080
Chris Wren9e7283f2015-05-08 17:23:47 -040081 abstract protected void handleClick();
Jason Monk32508852017-01-18 09:17:13 -050082
John Spurlockaf8d6c42014-05-07 17:49:08 -040083 abstract protected void handleUpdateState(TState state, Object arg);
84
Chris Wren457a21c2015-05-06 17:50:34 -040085 /**
86 * Declare the category of this tile.
87 *
Jason Monk8c09ac72017-03-16 11:53:40 -040088 * Categories are defined in {@link com.android.internal.logging.nano.MetricsProto.MetricsEvent}
Chris Wrenf6e9228b2016-01-26 18:04:35 -050089 * by editing frameworks/base/proto/src/metrics_constants.proto.
Chris Wren457a21c2015-05-06 17:50:34 -040090 */
91 abstract public int getMetricsCategory();
92
Jason Monk702e2eb2017-03-03 16:53:44 -050093 protected QSTileImpl(QSHost host) {
John Spurlockaf8d6c42014-05-07 17:49:08 -040094 mHost = host;
95 mContext = host.getContext();
John Spurlockaf8d6c42014-05-07 17:49:08 -040096 }
Jason Monkbd6dbb02015-09-03 15:46:25 -040097
Jason Monk1bec6af2016-05-31 15:40:58 -040098 /**
99 * Adds or removes a listening client for the tile. If the tile has one or more
100 * listening client it will go into the listening state.
101 */
102 public void setListening(Object listener, boolean listening) {
103 if (listening) {
104 if (mListeners.add(listener) && mListeners.size() == 1) {
105 if (DEBUG) Log.d(TAG, "setListening " + true);
106 mHandler.obtainMessage(H.SET_LISTENING, 1, 0).sendToTarget();
107 }
108 } else {
109 if (mListeners.remove(listener) && mListeners.size() == 0) {
110 if (DEBUG) Log.d(TAG, "setListening " + false);
111 mHandler.obtainMessage(H.SET_LISTENING, 0, 0).sendToTarget();
112 }
113 }
114 }
115
Jason Monkbd6dbb02015-09-03 15:46:25 -0400116 public String getTileSpec() {
117 return mTileSpec;
118 }
119
120 public void setTileSpec(String tileSpec) {
121 mTileSpec = tileSpec;
122 }
123
Jason Monk702e2eb2017-03-03 16:53:44 -0500124 public QSHost getHost() {
John Spurlockaf8d6c42014-05-07 17:49:08 -0400125 return mHost;
126 }
127
Jason Monkdc35dcb2015-12-04 16:36:15 -0500128 public QSIconView createTileView(Context context) {
Jason Monk702e2eb2017-03-03 16:53:44 -0500129 return new QSIconViewImpl(context);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400130 }
131
John Spurlock7f8f22a2014-07-02 18:54:17 -0400132 public DetailAdapter getDetailAdapter() {
John Spurlockaf8d6c42014-05-07 17:49:08 -0400133 return null; // optional
134 }
135
Jason Monk32508852017-01-18 09:17:13 -0500136 protected DetailAdapter createDetailAdapter() {
137 throw new UnsupportedOperationException();
138 }
Muyuan Li0e9f5382016-04-27 15:51:15 -0700139
Jason Monkc3f42c12016-02-05 12:33:13 -0500140 /**
141 * Is a startup check whether this device currently supports this tile.
142 * Should not be used to conditionally hide tiles. Only checked on tile
143 * creation or whether should be shown in edit screen.
144 */
145 public boolean isAvailable() {
146 return true;
147 }
148
John Spurlockaf8d6c42014-05-07 17:49:08 -0400149 // safe to call from any thread
150
Jason Monkca894a02016-01-12 15:30:22 -0500151 public void addCallback(Callback callback) {
152 mHandler.obtainMessage(H.ADD_CALLBACK, callback).sendToTarget();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400153 }
154
Xiaohui Chen08e266c2016-04-18 12:53:28 -0700155 public void removeCallback(Callback callback) {
156 mHandler.obtainMessage(H.REMOVE_CALLBACK, callback).sendToTarget();
157 }
158
Jason Monk9d02a432016-01-20 16:33:46 -0500159 public void removeCallbacks() {
160 mHandler.sendEmptyMessage(H.REMOVE_CALLBACKS);
161 }
162
John Spurlockaf8d6c42014-05-07 17:49:08 -0400163 public void click() {
Jason Monk8c09ac72017-03-16 11:53:40 -0400164 mMetricsLogger.write(populate(new LogMaker(ACTION_QS_CLICK).setType(TYPE_ACTION)));
John Spurlockaf8d6c42014-05-07 17:49:08 -0400165 mHandler.sendEmptyMessage(H.CLICK);
166 }
167
168 public void secondaryClick() {
Jason Monk8c09ac72017-03-16 11:53:40 -0400169 mMetricsLogger.write(populate(new LogMaker(ACTION_QS_SECONDARY_CLICK).setType(TYPE_ACTION)));
John Spurlockaf8d6c42014-05-07 17:49:08 -0400170 mHandler.sendEmptyMessage(H.SECONDARY_CLICK);
171 }
172
John Spurlockc247b8f2014-11-06 23:06:25 -0500173 public void longClick() {
Jason Monk8c09ac72017-03-16 11:53:40 -0400174 mMetricsLogger.write(populate(new LogMaker(ACTION_QS_LONG_PRESS).setType(TYPE_ACTION)));
John Spurlockc247b8f2014-11-06 23:06:25 -0500175 mHandler.sendEmptyMessage(H.LONG_CLICK);
176 }
177
Jason Monkcb4b31d2017-05-03 10:37:34 -0400178 public LogMaker populate(LogMaker logMaker) {
Jason Monk8c09ac72017-03-16 11:53:40 -0400179 if (mState instanceof BooleanState) {
180 logMaker.addTaggedData(FIELD_QS_VALUE, ((BooleanState) mState).value ? 1 : 0);
181 }
182 return logMaker.setSubtype(getMetricsCategory())
183 .addTaggedData(FIELD_QS_POSITION, mHost.indexOf(mTileSpec));
184 }
185
John Spurlockaf8d6c42014-05-07 17:49:08 -0400186 public void showDetail(boolean show) {
187 mHandler.obtainMessage(H.SHOW_DETAIL, show ? 1 : 0, 0).sendToTarget();
188 }
189
Evan Laird6b284732017-02-28 17:27:04 -0500190 public void refreshState() {
John Spurlockaf8d6c42014-05-07 17:49:08 -0400191 refreshState(null);
192 }
193
194 protected final void refreshState(Object arg) {
195 mHandler.obtainMessage(H.REFRESH_STATE, arg).sendToTarget();
196 }
197
Evan Laird6b284732017-02-28 17:27:04 -0500198 public void clearState() {
Jason Monka758ba62015-07-14 12:29:28 -0400199 mHandler.sendEmptyMessage(H.CLEAR_STATE);
200 }
201
John Spurlockaf8d6c42014-05-07 17:49:08 -0400202 public void userSwitch(int newUserId) {
Adrian Roos32d88e82014-09-24 17:08:22 +0200203 mHandler.obtainMessage(H.USER_SWITCH, newUserId, 0).sendToTarget();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400204 }
205
John Spurlock7f8f22a2014-07-02 18:54:17 -0400206 public void fireToggleStateChanged(boolean state) {
207 mHandler.obtainMessage(H.TOGGLE_STATE_CHANGED, state ? 1 : 0, 0).sendToTarget();
208 }
209
John Spurlock486b78e2014-07-07 08:37:56 -0400210 public void fireScanStateChanged(boolean state) {
211 mHandler.obtainMessage(H.SCAN_STATE_CHANGED, state ? 1 : 0, 0).sendToTarget();
212 }
213
John Spurlockbceed062014-08-10 18:04:16 -0400214 public void destroy() {
215 mHandler.sendEmptyMessage(H.DESTROY);
216 }
217
218 public TState getState() {
219 return mState;
220 }
221
Jason Monk0d6a1c42015-04-20 16:38:51 -0400222 public void setDetailListening(boolean listening) {
223 // optional
224 }
225
John Spurlockaf8d6c42014-05-07 17:49:08 -0400226 // call only on tile worker looper
227
Jason Monkca894a02016-01-12 15:30:22 -0500228 private void handleAddCallback(Callback callback) {
229 mCallbacks.add(callback);
Jason Monk968d2692016-06-17 13:48:44 -0400230 callback.onStateChanged(mState);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400231 }
232
Xiaohui Chen08e266c2016-04-18 12:53:28 -0700233 private void handleRemoveCallback(Callback callback) {
234 mCallbacks.remove(callback);
235 }
236
Jason Monk9d02a432016-01-20 16:33:46 -0500237 private void handleRemoveCallbacks() {
238 mCallbacks.clear();
239 }
240
John Spurlockaf8d6c42014-05-07 17:49:08 -0400241 protected void handleSecondaryClick() {
Jason Monkdc35dcb2015-12-04 16:36:15 -0500242 // Default to normal click.
243 handleClick();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400244 }
245
John Spurlockc247b8f2014-11-06 23:06:25 -0500246 protected void handleLongClick() {
Jason Monk9c7844c2017-01-18 15:21:53 -0500247 Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(
248 getLongClickIntent(), 0);
John Spurlockc247b8f2014-11-06 23:06:25 -0500249 }
250
Jason Monk76c67aa2016-02-19 14:49:42 -0500251 public abstract Intent getLongClickIntent();
252
Jason Monka758ba62015-07-14 12:29:28 -0400253 protected void handleClearState() {
254 mTmpState = newTileState();
255 mState = newTileState();
256 }
257
John Spurlockaf8d6c42014-05-07 17:49:08 -0400258 protected void handleRefreshState(Object arg) {
259 handleUpdateState(mTmpState, arg);
260 final boolean changed = mTmpState.copyTo(mState);
261 if (changed) {
262 handleStateChanged();
263 }
264 }
265
266 private void handleStateChanged() {
Selim Cinek4fda7b22014-08-18 22:07:25 +0200267 boolean delayAnnouncement = shouldAnnouncementBeDelayed();
Jason Monkca894a02016-01-12 15:30:22 -0500268 if (mCallbacks.size() != 0) {
269 for (int i = 0; i < mCallbacks.size(); i++) {
270 mCallbacks.get(i).onStateChanged(mState);
271 }
Selim Cinek4fda7b22014-08-18 22:07:25 +0200272 if (mAnnounceNextStateChange && !delayAnnouncement) {
273 String announcement = composeChangeAnnouncement();
274 if (announcement != null) {
Jason Monkca894a02016-01-12 15:30:22 -0500275 mCallbacks.get(0).onAnnouncementRequested(announcement);
Selim Cinek4fda7b22014-08-18 22:07:25 +0200276 }
277 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400278 }
Selim Cinek4fda7b22014-08-18 22:07:25 +0200279 mAnnounceNextStateChange = mAnnounceNextStateChange && delayAnnouncement;
280 }
281
282 protected boolean shouldAnnouncementBeDelayed() {
283 return false;
284 }
285
286 protected String composeChangeAnnouncement() {
287 return null;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400288 }
289
290 private void handleShowDetail(boolean show) {
Jason Monkbe3235a2017-04-05 09:29:53 -0400291 mShowingDetail = show;
Jason Monkca894a02016-01-12 15:30:22 -0500292 for (int i = 0; i < mCallbacks.size(); i++) {
293 mCallbacks.get(i).onShowDetail(show);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400294 }
295 }
296
Jason Monkbe3235a2017-04-05 09:29:53 -0400297 protected boolean isShowingDetail() {
298 return mShowingDetail;
299 }
300
John Spurlock7f8f22a2014-07-02 18:54:17 -0400301 private void handleToggleStateChanged(boolean state) {
Jason Monkca894a02016-01-12 15:30:22 -0500302 for (int i = 0; i < mCallbacks.size(); i++) {
303 mCallbacks.get(i).onToggleStateChanged(state);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400304 }
305 }
306
John Spurlock486b78e2014-07-07 08:37:56 -0400307 private void handleScanStateChanged(boolean state) {
Jason Monkca894a02016-01-12 15:30:22 -0500308 for (int i = 0; i < mCallbacks.size(); i++) {
309 mCallbacks.get(i).onScanStateChanged(state);
John Spurlock486b78e2014-07-07 08:37:56 -0400310 }
311 }
312
John Spurlockaf8d6c42014-05-07 17:49:08 -0400313 protected void handleUserSwitch(int newUserId) {
314 handleRefreshState(null);
315 }
316
Jason Monk1bec6af2016-05-31 15:40:58 -0400317 protected abstract void setListening(boolean listening);
318
John Spurlockbceed062014-08-10 18:04:16 -0400319 protected void handleDestroy() {
Jason Monk794bcd22017-06-06 16:38:00 -0400320 if (mListeners.size() != 0) {
321 setListening(false);
322 }
Jason Monkca894a02016-01-12 15:30:22 -0500323 mCallbacks.clear();
John Spurlockbceed062014-08-10 18:04:16 -0400324 }
325
Sudheer Shankaa8fbbb32016-02-11 17:17:57 +0000326 protected void checkIfRestrictionEnforcedByAdminOnly(State state, String userRestriction) {
Sudheer Shankaad143c02016-03-31 00:24:05 +0000327 EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
328 userRestriction, ActivityManager.getCurrentUser());
329 if (admin != null && !RestrictedLockUtils.hasBaseUserRestriction(mContext,
330 userRestriction, ActivityManager.getCurrentUser())) {
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000331 state.disabledByPolicy = true;
Jason Monk702e2eb2017-03-03 16:53:44 -0500332 mEnforcedAdmin = admin;
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000333 } else {
334 state.disabledByPolicy = false;
Jason Monk702e2eb2017-03-03 16:53:44 -0500335 mEnforcedAdmin = null;
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000336 }
337 }
338
Jason Monk39c98e62016-03-16 09:18:35 -0400339 public abstract CharSequence getTileLabel();
340
Jason Monk32508852017-01-18 09:17:13 -0500341 public static int getColorForState(Context context, int state) {
342 switch (state) {
343 case Tile.STATE_UNAVAILABLE:
344 return Utils.getDisabled(context,
Jason Monk3536b232017-04-19 13:11:11 -0400345 Utils.getColorAttr(context, android.R.attr.colorForeground));
Jason Monkb4cc7b12017-05-09 13:50:47 -0400346 case Tile.STATE_INACTIVE:
347 return Utils.getColorAttr(context, android.R.attr.textColorHint);
Jason Monk32508852017-01-18 09:17:13 -0500348 case Tile.STATE_ACTIVE:
Jason Monk3536b232017-04-19 13:11:11 -0400349 return Utils.getColorAttr(context, android.R.attr.textColorPrimary);
Jason Monk32508852017-01-18 09:17:13 -0500350 default:
351 Log.e("QSTile", "Invalid state " + state);
352 return 0;
353 }
354 }
355
John Spurlockaf8d6c42014-05-07 17:49:08 -0400356 protected final class H extends Handler {
Jason Monkca894a02016-01-12 15:30:22 -0500357 private static final int ADD_CALLBACK = 1;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400358 private static final int CLICK = 2;
359 private static final int SECONDARY_CLICK = 3;
John Spurlockc247b8f2014-11-06 23:06:25 -0500360 private static final int LONG_CLICK = 4;
361 private static final int REFRESH_STATE = 5;
362 private static final int SHOW_DETAIL = 6;
363 private static final int USER_SWITCH = 7;
364 private static final int TOGGLE_STATE_CHANGED = 8;
365 private static final int SCAN_STATE_CHANGED = 9;
366 private static final int DESTROY = 10;
Jason Monka758ba62015-07-14 12:29:28 -0400367 private static final int CLEAR_STATE = 11;
Jason Monk9d02a432016-01-20 16:33:46 -0500368 private static final int REMOVE_CALLBACKS = 12;
Xiaohui Chen08e266c2016-04-18 12:53:28 -0700369 private static final int REMOVE_CALLBACK = 13;
Jason Monk1bec6af2016-05-31 15:40:58 -0400370 private static final int SET_LISTENING = 14;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400371
372 private H(Looper looper) {
373 super(looper);
374 }
375
376 @Override
377 public void handleMessage(Message msg) {
378 String name = null;
379 try {
Jason Monkca894a02016-01-12 15:30:22 -0500380 if (msg.what == ADD_CALLBACK) {
381 name = "handleAddCallback";
Jason Monk9d02a432016-01-20 16:33:46 -0500382 handleAddCallback((QSTile.Callback) msg.obj);
383 } else if (msg.what == REMOVE_CALLBACKS) {
384 name = "handleRemoveCallbacks";
385 handleRemoveCallbacks();
Xiaohui Chen08e266c2016-04-18 12:53:28 -0700386 } else if (msg.what == REMOVE_CALLBACK) {
387 name = "handleRemoveCallback";
388 handleRemoveCallback((QSTile.Callback) msg.obj);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400389 } else if (msg.what == CLICK) {
390 name = "handleClick";
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000391 if (mState.disabledByPolicy) {
392 Intent intent = RestrictedLockUtils.getShowAdminSupportDetailsIntent(
Jason Monk702e2eb2017-03-03 16:53:44 -0500393 mContext, mEnforcedAdmin);
Jason Monk9c7844c2017-01-18 15:21:53 -0500394 Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(
395 intent, 0);
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000396 } else {
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000397 handleClick();
398 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400399 } else if (msg.what == SECONDARY_CLICK) {
400 name = "handleSecondaryClick";
401 handleSecondaryClick();
John Spurlockc247b8f2014-11-06 23:06:25 -0500402 } else if (msg.what == LONG_CLICK) {
403 name = "handleLongClick";
404 handleLongClick();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400405 } else if (msg.what == REFRESH_STATE) {
406 name = "handleRefreshState";
407 handleRefreshState(msg.obj);
408 } else if (msg.what == SHOW_DETAIL) {
409 name = "handleShowDetail";
410 handleShowDetail(msg.arg1 != 0);
411 } else if (msg.what == USER_SWITCH) {
412 name = "handleUserSwitch";
413 handleUserSwitch(msg.arg1);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400414 } else if (msg.what == TOGGLE_STATE_CHANGED) {
415 name = "handleToggleStateChanged";
416 handleToggleStateChanged(msg.arg1 != 0);
John Spurlock486b78e2014-07-07 08:37:56 -0400417 } else if (msg.what == SCAN_STATE_CHANGED) {
418 name = "handleScanStateChanged";
419 handleScanStateChanged(msg.arg1 != 0);
John Spurlockbceed062014-08-10 18:04:16 -0400420 } else if (msg.what == DESTROY) {
421 name = "handleDestroy";
422 handleDestroy();
Jason Monka758ba62015-07-14 12:29:28 -0400423 } else if (msg.what == CLEAR_STATE) {
424 name = "handleClearState";
425 handleClearState();
Jason Monk1bec6af2016-05-31 15:40:58 -0400426 } else if (msg.what == SET_LISTENING) {
427 name = "setListening";
428 setListening(msg.arg1 != 0);
John Spurlockbceed062014-08-10 18:04:16 -0400429 } else {
430 throw new IllegalArgumentException("Unknown msg: " + msg.what);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400431 }
432 } catch (Throwable t) {
433 final String error = "Error in " + name;
434 Log.w(TAG, error, t);
435 mHost.warn(error, t);
436 }
437 }
438 }
439
Jason Monk5db8a412015-10-21 15:16:23 -0700440 public static class DrawableIcon extends Icon {
441 protected final Drawable mDrawable;
442
443 public DrawableIcon(Drawable drawable) {
444 mDrawable = drawable;
445 }
446
447 @Override
448 public Drawable getDrawable(Context context) {
449 return mDrawable;
450 }
Jason Monkd2274f82016-12-12 12:02:16 -0500451 }
452
453 public static class DrawableIconWithRes extends DrawableIcon {
454 private final int mId;
455
456 public DrawableIconWithRes(Drawable drawable, int id) {
457 super(drawable);
458 mId = id;
459 }
Jason Monk1aec93f2016-03-01 09:39:30 -0500460
461 @Override
Jason Monkd2274f82016-12-12 12:02:16 -0500462 public boolean equals(Object o) {
463 return o instanceof DrawableIconWithRes && ((DrawableIconWithRes) o).mId == mId;
Jason Monk1aec93f2016-03-01 09:39:30 -0500464 }
Jason Monk5db8a412015-10-21 15:16:23 -0700465 }
466
John Spurlock2d695812014-10-30 13:25:21 -0400467 public static class ResourceIcon extends Icon {
468 private static final SparseArray<Icon> ICONS = new SparseArray<Icon>();
469
Andrew Flynna478d702015-04-14 23:33:45 -0400470 protected final int mResId;
John Spurlock2d695812014-10-30 13:25:21 -0400471
472 private ResourceIcon(int resId) {
473 mResId = resId;
474 }
475
476 public static Icon get(int resId) {
477 Icon icon = ICONS.get(resId);
478 if (icon == null) {
479 icon = new ResourceIcon(resId);
480 ICONS.put(resId, icon);
481 }
482 return icon;
483 }
484
485 @Override
486 public Drawable getDrawable(Context context) {
Jason Monk66239fb2015-12-21 14:27:00 -0500487 return context.getDrawable(mResId);
John Spurlock2d695812014-10-30 13:25:21 -0400488 }
489
490 @Override
Jason Monk1aec93f2016-03-01 09:39:30 -0500491 public Drawable getInvisibleDrawable(Context context) {
492 return context.getDrawable(mResId);
493 }
494
495 @Override
John Spurlock2d695812014-10-30 13:25:21 -0400496 public boolean equals(Object o) {
497 return o instanceof ResourceIcon && ((ResourceIcon) o).mResId == mResId;
498 }
499
500 @Override
501 public String toString() {
502 return String.format("ResourceIcon[resId=0x%08x]", mResId);
503 }
504 }
505
506 protected class AnimationIcon extends ResourceIcon {
Jason Monk1aec93f2016-03-01 09:39:30 -0500507 private final int mAnimatedResId;
508
509 public AnimationIcon(int resId, int staticResId) {
510 super(staticResId);
511 mAnimatedResId = resId;
John Spurlock2d695812014-10-30 13:25:21 -0400512 }
513
John Spurlock2d695812014-10-30 13:25:21 -0400514 @Override
515 public Drawable getDrawable(Context context) {
516 // workaround: get a clean state for every new AVD
Jason Monk1aec93f2016-03-01 09:39:30 -0500517 return context.getDrawable(mAnimatedResId).getConstantState().newDrawable();
John Spurlock2d695812014-10-30 13:25:21 -0400518 }
519 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400520}