blob: 8777a9140a51e9814e8dedb8bd65bad3dbdf4eb9 [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
Sudheer Shankab6fc9312016-01-27 19:59:03 +000019import android.app.ActivityManager;
Adrian Roos62692b22015-09-11 17:46:23 -070020import android.app.PendingIntent;
John Spurlockaf8d6c42014-05-07 17:49:08 -040021import android.content.Context;
22import android.content.Intent;
John Spurlock444eb2e2014-05-14 13:32:14 -040023import android.graphics.drawable.Drawable;
John Spurlockaf8d6c42014-05-07 17:49:08 -040024import android.os.Handler;
25import android.os.Looper;
26import android.os.Message;
Sudheer Shanka1c15e012016-03-29 21:12:08 -070027import android.os.UserHandle;
28import android.os.UserManager;
John Spurlockaf8d6c42014-05-07 17:49:08 -040029import android.util.Log;
John Spurlock2d695812014-10-30 13:25:21 -040030import android.util.SparseArray;
John Spurlockaf8d6c42014-05-07 17:49:08 -040031import android.view.View;
32import android.view.ViewGroup;
Sudheer Shanka1c7cda82015-12-31 14:46:02 +000033
Jason Monk96defbe2016-03-29 16:51:03 -040034import com.android.internal.logging.MetricsLogger;
35import com.android.internal.logging.MetricsProto.MetricsEvent;
Sudheer Shanka1c7cda82015-12-31 14:46:02 +000036import com.android.settingslib.RestrictedLockUtils;
John Spurlockaf8d6c42014-05-07 17:49:08 -040037import com.android.systemui.qs.QSTile.State;
Jason Monk66c89c12016-01-06 08:51:26 -050038import com.android.systemui.qs.external.TileServices;
Jason Monkc3f42c12016-02-05 12:33:13 -050039import com.android.systemui.statusbar.phone.ManagedProfileController;
Jason Monk66239fb2015-12-21 14:27:00 -050040import com.android.systemui.statusbar.policy.BatteryController;
41import com.android.systemui.statusbar.policy.BluetoothController;
42import com.android.systemui.statusbar.policy.CastController;
Jason Monk5dbd4aa2016-02-07 13:13:39 -050043import com.android.systemui.statusbar.policy.NightModeController;
Jason Monk66239fb2015-12-21 14:27:00 -050044import com.android.systemui.statusbar.policy.FlashlightController;
45import com.android.systemui.statusbar.policy.HotspotController;
46import com.android.systemui.statusbar.policy.KeyguardMonitor;
47import com.android.systemui.statusbar.policy.Listenable;
48import com.android.systemui.statusbar.policy.LocationController;
49import com.android.systemui.statusbar.policy.NetworkController;
50import com.android.systemui.statusbar.policy.RotationLockController;
51import com.android.systemui.statusbar.policy.UserInfoController;
52import com.android.systemui.statusbar.policy.UserSwitcherController;
53import com.android.systemui.statusbar.policy.ZenModeController;
John Spurlockaf8d6c42014-05-07 17:49:08 -040054
Jason Monkca894a02016-01-12 15:30:22 -050055import java.util.ArrayList;
John Spurlockbceed062014-08-10 18:04:16 -040056import java.util.Collection;
John Spurlockaf8d6c42014-05-07 17:49:08 -040057import java.util.Objects;
58
Sudheer Shanka1c7cda82015-12-31 14:46:02 +000059import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
60
John Spurlockaf8d6c42014-05-07 17:49:08 -040061/**
62 * Base quick-settings tile, extend this to create a new tile.
63 *
64 * State management done on a looper provided by the host. Tiles should update state in
65 * handleUpdateState. Callbacks affecting state should use refreshState to trigger another
66 * state update pass on tile looper.
67 */
John Spurlockccb6b9a2014-05-17 15:54:40 -040068public abstract class QSTile<TState extends State> implements Listenable {
Jason Monkbbadff82015-11-06 15:47:26 -050069 protected final String TAG = "Tile." + getClass().getSimpleName();
70 protected static final boolean DEBUG = Log.isLoggable("Tile", Log.DEBUG);
John Spurlockaf8d6c42014-05-07 17:49:08 -040071
72 protected final Host mHost;
73 protected final Context mContext;
74 protected final H mHandler;
John Spurlock76c43b92014-05-13 21:10:51 -040075 protected final Handler mUiHandler = new Handler(Looper.getMainLooper());
John Spurlockaf8d6c42014-05-07 17:49:08 -040076
Jason Monkca894a02016-01-12 15:30:22 -050077 private final ArrayList<Callback> mCallbacks = new ArrayList<>();
Jason Monka758ba62015-07-14 12:29:28 -040078 protected TState mState = newTileState();
79 private TState mTmpState = newTileState();
Selim Cinek4fda7b22014-08-18 22:07:25 +020080 private boolean mAnnounceNextStateChange;
John Spurlockaf8d6c42014-05-07 17:49:08 -040081
Jason Monkbd6dbb02015-09-03 15:46:25 -040082 private String mTileSpec;
83
Jason Monk62b63a02016-02-02 15:15:31 -050084 public abstract TState newTileState();
Chris Wren9e7283f2015-05-08 17:23:47 -040085 abstract protected void handleClick();
John Spurlockaf8d6c42014-05-07 17:49:08 -040086 abstract protected void handleUpdateState(TState state, Object arg);
87
Sudheer Shanka1c15e012016-03-29 21:12:08 -070088 private UserManager mUserManager;
89
Chris Wren457a21c2015-05-06 17:50:34 -040090 /**
91 * Declare the category of this tile.
92 *
Chris Wrenf6e9228b2016-01-26 18:04:35 -050093 * Categories are defined in {@link com.android.internal.logging.MetricsProto.MetricsEvent}
94 * by editing frameworks/base/proto/src/metrics_constants.proto.
Chris Wren457a21c2015-05-06 17:50:34 -040095 */
96 abstract public int getMetricsCategory();
97
John Spurlockaf8d6c42014-05-07 17:49:08 -040098 protected QSTile(Host host) {
99 mHost = host;
100 mContext = host.getContext();
101 mHandler = new H(host.getLooper());
Sudheer Shanka1c15e012016-03-29 21:12:08 -0700102 mUserManager = UserManager.get(mContext);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400103 }
Jason Monkbd6dbb02015-09-03 15:46:25 -0400104
105 public String getTileSpec() {
106 return mTileSpec;
107 }
108
109 public void setTileSpec(String tileSpec) {
110 mTileSpec = tileSpec;
111 }
112
John Spurlockaf8d6c42014-05-07 17:49:08 -0400113 public Host getHost() {
114 return mHost;
115 }
116
Jason Monkdc35dcb2015-12-04 16:36:15 -0500117 public QSIconView createTileView(Context context) {
118 return new QSIconView(context);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400119 }
120
John Spurlock7f8f22a2014-07-02 18:54:17 -0400121 public DetailAdapter getDetailAdapter() {
John Spurlockaf8d6c42014-05-07 17:49:08 -0400122 return null; // optional
123 }
124
Jason Monkc3f42c12016-02-05 12:33:13 -0500125 /**
126 * Is a startup check whether this device currently supports this tile.
127 * Should not be used to conditionally hide tiles. Only checked on tile
128 * creation or whether should be shown in edit screen.
129 */
130 public boolean isAvailable() {
131 return true;
132 }
133
John Spurlock7f8f22a2014-07-02 18:54:17 -0400134 public interface DetailAdapter {
Jason Monkc06fbb12016-01-08 14:12:18 -0500135 CharSequence getTitle();
John Spurlock7f8f22a2014-07-02 18:54:17 -0400136 Boolean getToggleState();
137 View createDetailView(Context context, View convertView, ViewGroup parent);
138 Intent getSettingsIntent();
139 void setToggleState(boolean state);
Chris Wren457a21c2015-05-06 17:50:34 -0400140 int getMetricsCategory();
John Spurlock7f8f22a2014-07-02 18:54:17 -0400141 }
142
John Spurlockaf8d6c42014-05-07 17:49:08 -0400143 // safe to call from any thread
144
Jason Monkca894a02016-01-12 15:30:22 -0500145 public void addCallback(Callback callback) {
146 mHandler.obtainMessage(H.ADD_CALLBACK, callback).sendToTarget();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400147 }
148
Jason Monk9d02a432016-01-20 16:33:46 -0500149 public void removeCallbacks() {
150 mHandler.sendEmptyMessage(H.REMOVE_CALLBACKS);
151 }
152
John Spurlockaf8d6c42014-05-07 17:49:08 -0400153 public void click() {
154 mHandler.sendEmptyMessage(H.CLICK);
155 }
156
157 public void secondaryClick() {
158 mHandler.sendEmptyMessage(H.SECONDARY_CLICK);
159 }
160
John Spurlockc247b8f2014-11-06 23:06:25 -0500161 public void longClick() {
162 mHandler.sendEmptyMessage(H.LONG_CLICK);
163 }
164
John Spurlockaf8d6c42014-05-07 17:49:08 -0400165 public void showDetail(boolean show) {
166 mHandler.obtainMessage(H.SHOW_DETAIL, show ? 1 : 0, 0).sendToTarget();
167 }
168
Jason Monk5db8a412015-10-21 15:16:23 -0700169 public final void refreshState() {
John Spurlockaf8d6c42014-05-07 17:49:08 -0400170 refreshState(null);
171 }
172
173 protected final void refreshState(Object arg) {
174 mHandler.obtainMessage(H.REFRESH_STATE, arg).sendToTarget();
175 }
176
Jason Monka758ba62015-07-14 12:29:28 -0400177 public final void clearState() {
178 mHandler.sendEmptyMessage(H.CLEAR_STATE);
179 }
180
John Spurlockaf8d6c42014-05-07 17:49:08 -0400181 public void userSwitch(int newUserId) {
Adrian Roos32d88e82014-09-24 17:08:22 +0200182 mHandler.obtainMessage(H.USER_SWITCH, newUserId, 0).sendToTarget();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400183 }
184
John Spurlock7f8f22a2014-07-02 18:54:17 -0400185 public void fireToggleStateChanged(boolean state) {
186 mHandler.obtainMessage(H.TOGGLE_STATE_CHANGED, state ? 1 : 0, 0).sendToTarget();
187 }
188
John Spurlock486b78e2014-07-07 08:37:56 -0400189 public void fireScanStateChanged(boolean state) {
190 mHandler.obtainMessage(H.SCAN_STATE_CHANGED, state ? 1 : 0, 0).sendToTarget();
191 }
192
John Spurlockbceed062014-08-10 18:04:16 -0400193 public void destroy() {
194 mHandler.sendEmptyMessage(H.DESTROY);
195 }
196
197 public TState getState() {
198 return mState;
199 }
200
Jason Monk0d6a1c42015-04-20 16:38:51 -0400201 public void setDetailListening(boolean listening) {
202 // optional
203 }
204
John Spurlockaf8d6c42014-05-07 17:49:08 -0400205 // call only on tile worker looper
206
Jason Monkca894a02016-01-12 15:30:22 -0500207 private void handleAddCallback(Callback callback) {
208 mCallbacks.add(callback);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400209 handleRefreshState(null);
210 }
211
Jason Monk9d02a432016-01-20 16:33:46 -0500212 private void handleRemoveCallbacks() {
213 mCallbacks.clear();
214 }
215
John Spurlockaf8d6c42014-05-07 17:49:08 -0400216 protected void handleSecondaryClick() {
Jason Monkdc35dcb2015-12-04 16:36:15 -0500217 // Default to normal click.
218 handleClick();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400219 }
220
John Spurlockc247b8f2014-11-06 23:06:25 -0500221 protected void handleLongClick() {
Jason Monk96defbe2016-03-29 16:51:03 -0400222 MetricsLogger.action(mContext, MetricsEvent.ACTION_QS_LONG_PRESS, getTileSpec());
Jason Monk76c67aa2016-02-19 14:49:42 -0500223 mHost.startActivityDismissingKeyguard(getLongClickIntent());
John Spurlockc247b8f2014-11-06 23:06:25 -0500224 }
225
Jason Monk76c67aa2016-02-19 14:49:42 -0500226 public abstract Intent getLongClickIntent();
227
Jason Monka758ba62015-07-14 12:29:28 -0400228 protected void handleClearState() {
229 mTmpState = newTileState();
230 mState = newTileState();
231 }
232
John Spurlockaf8d6c42014-05-07 17:49:08 -0400233 protected void handleRefreshState(Object arg) {
234 handleUpdateState(mTmpState, arg);
235 final boolean changed = mTmpState.copyTo(mState);
236 if (changed) {
237 handleStateChanged();
238 }
239 }
240
241 private void handleStateChanged() {
Selim Cinek4fda7b22014-08-18 22:07:25 +0200242 boolean delayAnnouncement = shouldAnnouncementBeDelayed();
Jason Monkca894a02016-01-12 15:30:22 -0500243 if (mCallbacks.size() != 0) {
244 for (int i = 0; i < mCallbacks.size(); i++) {
245 mCallbacks.get(i).onStateChanged(mState);
246 }
Selim Cinek4fda7b22014-08-18 22:07:25 +0200247 if (mAnnounceNextStateChange && !delayAnnouncement) {
248 String announcement = composeChangeAnnouncement();
249 if (announcement != null) {
Jason Monkca894a02016-01-12 15:30:22 -0500250 mCallbacks.get(0).onAnnouncementRequested(announcement);
Selim Cinek4fda7b22014-08-18 22:07:25 +0200251 }
252 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400253 }
Selim Cinek4fda7b22014-08-18 22:07:25 +0200254 mAnnounceNextStateChange = mAnnounceNextStateChange && delayAnnouncement;
255 }
256
257 protected boolean shouldAnnouncementBeDelayed() {
258 return false;
259 }
260
261 protected String composeChangeAnnouncement() {
262 return null;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400263 }
264
265 private void handleShowDetail(boolean show) {
Jason Monkca894a02016-01-12 15:30:22 -0500266 for (int i = 0; i < mCallbacks.size(); i++) {
267 mCallbacks.get(i).onShowDetail(show);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400268 }
269 }
270
John Spurlock7f8f22a2014-07-02 18:54:17 -0400271 private void handleToggleStateChanged(boolean state) {
Jason Monkca894a02016-01-12 15:30:22 -0500272 for (int i = 0; i < mCallbacks.size(); i++) {
273 mCallbacks.get(i).onToggleStateChanged(state);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400274 }
275 }
276
John Spurlock486b78e2014-07-07 08:37:56 -0400277 private void handleScanStateChanged(boolean state) {
Jason Monkca894a02016-01-12 15:30:22 -0500278 for (int i = 0; i < mCallbacks.size(); i++) {
279 mCallbacks.get(i).onScanStateChanged(state);
John Spurlock486b78e2014-07-07 08:37:56 -0400280 }
281 }
282
John Spurlockaf8d6c42014-05-07 17:49:08 -0400283 protected void handleUserSwitch(int newUserId) {
284 handleRefreshState(null);
285 }
286
John Spurlockbceed062014-08-10 18:04:16 -0400287 protected void handleDestroy() {
288 setListening(false);
Jason Monkca894a02016-01-12 15:30:22 -0500289 mCallbacks.clear();
John Spurlockbceed062014-08-10 18:04:16 -0400290 }
291
Sudheer Shankaa8fbbb32016-02-11 17:17:57 +0000292 protected void checkIfRestrictionEnforcedByAdminOnly(State state, String userRestriction) {
Sudheer Shanka1c15e012016-03-29 21:12:08 -0700293 UserHandle user = UserHandle.of(ActivityManager.getCurrentUser());
294 if (mUserManager.hasUserRestriction(userRestriction, user)
295 && !mUserManager.hasBaseUserRestriction(userRestriction, user)) {
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000296 state.disabledByPolicy = true;
Sudheer Shanka1c15e012016-03-29 21:12:08 -0700297 state.enforcedAdmin = EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000298 } else {
299 state.disabledByPolicy = false;
300 state.enforcedAdmin = null;
301 }
302 }
303
Jason Monk39c98e62016-03-16 09:18:35 -0400304 public abstract CharSequence getTileLabel();
305
John Spurlockaf8d6c42014-05-07 17:49:08 -0400306 protected final class H extends Handler {
Jason Monkca894a02016-01-12 15:30:22 -0500307 private static final int ADD_CALLBACK = 1;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400308 private static final int CLICK = 2;
309 private static final int SECONDARY_CLICK = 3;
John Spurlockc247b8f2014-11-06 23:06:25 -0500310 private static final int LONG_CLICK = 4;
311 private static final int REFRESH_STATE = 5;
312 private static final int SHOW_DETAIL = 6;
313 private static final int USER_SWITCH = 7;
314 private static final int TOGGLE_STATE_CHANGED = 8;
315 private static final int SCAN_STATE_CHANGED = 9;
316 private static final int DESTROY = 10;
Jason Monka758ba62015-07-14 12:29:28 -0400317 private static final int CLEAR_STATE = 11;
Jason Monk9d02a432016-01-20 16:33:46 -0500318 private static final int REMOVE_CALLBACKS = 12;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400319
320 private H(Looper looper) {
321 super(looper);
322 }
323
324 @Override
325 public void handleMessage(Message msg) {
326 String name = null;
327 try {
Jason Monkca894a02016-01-12 15:30:22 -0500328 if (msg.what == ADD_CALLBACK) {
329 name = "handleAddCallback";
Jason Monk9d02a432016-01-20 16:33:46 -0500330 handleAddCallback((QSTile.Callback) msg.obj);
331 } else if (msg.what == REMOVE_CALLBACKS) {
332 name = "handleRemoveCallbacks";
333 handleRemoveCallbacks();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400334 } else if (msg.what == CLICK) {
335 name = "handleClick";
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000336 if (mState.disabledByPolicy) {
337 Intent intent = RestrictedLockUtils.getShowAdminSupportDetailsIntent(
338 mContext, mState.enforcedAdmin);
339 mHost.startActivityDismissingKeyguard(intent);
340 } else {
341 mAnnounceNextStateChange = true;
342 handleClick();
343 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400344 } else if (msg.what == SECONDARY_CLICK) {
345 name = "handleSecondaryClick";
346 handleSecondaryClick();
John Spurlockc247b8f2014-11-06 23:06:25 -0500347 } else if (msg.what == LONG_CLICK) {
348 name = "handleLongClick";
349 handleLongClick();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400350 } else if (msg.what == REFRESH_STATE) {
351 name = "handleRefreshState";
352 handleRefreshState(msg.obj);
353 } else if (msg.what == SHOW_DETAIL) {
354 name = "handleShowDetail";
355 handleShowDetail(msg.arg1 != 0);
356 } else if (msg.what == USER_SWITCH) {
357 name = "handleUserSwitch";
358 handleUserSwitch(msg.arg1);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400359 } else if (msg.what == TOGGLE_STATE_CHANGED) {
360 name = "handleToggleStateChanged";
361 handleToggleStateChanged(msg.arg1 != 0);
John Spurlock486b78e2014-07-07 08:37:56 -0400362 } else if (msg.what == SCAN_STATE_CHANGED) {
363 name = "handleScanStateChanged";
364 handleScanStateChanged(msg.arg1 != 0);
John Spurlockbceed062014-08-10 18:04:16 -0400365 } else if (msg.what == DESTROY) {
366 name = "handleDestroy";
367 handleDestroy();
Jason Monka758ba62015-07-14 12:29:28 -0400368 } else if (msg.what == CLEAR_STATE) {
369 name = "handleClearState";
370 handleClearState();
John Spurlockbceed062014-08-10 18:04:16 -0400371 } else {
372 throw new IllegalArgumentException("Unknown msg: " + msg.what);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400373 }
374 } catch (Throwable t) {
375 final String error = "Error in " + name;
376 Log.w(TAG, error, t);
377 mHost.warn(error, t);
378 }
379 }
380 }
381
382 public interface Callback {
383 void onStateChanged(State state);
384 void onShowDetail(boolean show);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400385 void onToggleStateChanged(boolean state);
John Spurlock486b78e2014-07-07 08:37:56 -0400386 void onScanStateChanged(boolean state);
Selim Cinek4fda7b22014-08-18 22:07:25 +0200387 void onAnnouncementRequested(CharSequence announcement);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400388 }
389
390 public interface Host {
Jason Monkee43cdf2015-06-19 14:20:46 -0400391 void startActivityDismissingKeyguard(Intent intent);
Adrian Roos62692b22015-09-11 17:46:23 -0700392 void startActivityDismissingKeyguard(PendingIntent intent);
Jason Monkba2318e2015-12-08 09:04:23 -0500393 void startRunnableDismissingKeyguard(Runnable runnable);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400394 void warn(String message, Throwable t);
395 void collapsePanels();
Jason Monkca894a02016-01-12 15:30:22 -0500396 void animateExpandQS();
Jason Monkba2318e2015-12-08 09:04:23 -0500397 void openPanels();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400398 Looper getLooper();
399 Context getContext();
John Spurlockbceed062014-08-10 18:04:16 -0400400 Collection<QSTile<?>> getTiles();
Jason Monkbbadff82015-11-06 15:47:26 -0500401 void addCallback(Callback callback);
Jason Monk46dbfb42016-02-25 14:59:20 -0500402 void removeCallback(Callback callback);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400403 BluetoothController getBluetoothController();
404 LocationController getLocationController();
405 RotationLockController getRotationLockController();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400406 NetworkController getNetworkController();
407 ZenModeController getZenModeController();
Jason Monk51e4dc02014-07-22 12:00:47 -0400408 HotspotController getHotspotController();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400409 CastController getCastController();
Adrian Roosb83777b2014-06-30 15:11:53 +0200410 FlashlightController getFlashlightController();
John Spurlock657c62c2014-07-22 12:18:09 -0400411 KeyguardMonitor getKeyguardMonitor();
Jason Monkabe19742015-09-29 09:47:06 -0400412 UserSwitcherController getUserSwitcherController();
413 UserInfoController getUserInfoController();
414 BatteryController getBatteryController();
Jason Monk66c89c12016-01-06 08:51:26 -0500415 TileServices getTileServices();
Jason Monk5dbd4aa2016-02-07 13:13:39 -0500416 NightModeController getNightModeController();
Jason Monkba2318e2015-12-08 09:04:23 -0500417 void removeTile(String tileSpec);
Jason Monkc3f42c12016-02-05 12:33:13 -0500418 ManagedProfileController getManagedProfileController();
John Spurlockbceed062014-08-10 18:04:16 -0400419
Jason Monk66c89c12016-01-06 08:51:26 -0500420
John Spurlockbceed062014-08-10 18:04:16 -0400421 public interface Callback {
422 void onTilesChanged();
423 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400424 }
425
John Spurlock2d695812014-10-30 13:25:21 -0400426 public static abstract class Icon {
427 abstract public Drawable getDrawable(Context context);
428
Jason Monk1aec93f2016-03-01 09:39:30 -0500429 public Drawable getInvisibleDrawable(Context context) {
430 return getDrawable(context);
431 }
432
John Spurlock2d695812014-10-30 13:25:21 -0400433 @Override
434 public int hashCode() {
435 return Icon.class.hashCode();
436 }
Jason Monkb53b6c52016-02-24 17:25:49 -0500437
438 public int getPadding() {
439 return 0;
440 }
John Spurlock2d695812014-10-30 13:25:21 -0400441 }
442
Jason Monk5db8a412015-10-21 15:16:23 -0700443 public static class DrawableIcon extends Icon {
444 protected final Drawable mDrawable;
445
446 public DrawableIcon(Drawable drawable) {
447 mDrawable = drawable;
448 }
449
450 @Override
451 public Drawable getDrawable(Context context) {
452 return mDrawable;
453 }
Jason Monk1aec93f2016-03-01 09:39:30 -0500454
455 @Override
456 public Drawable getInvisibleDrawable(Context context) {
457 return mDrawable;
458 }
Jason Monk5db8a412015-10-21 15:16:23 -0700459 }
460
John Spurlock2d695812014-10-30 13:25:21 -0400461 public static class ResourceIcon extends Icon {
462 private static final SparseArray<Icon> ICONS = new SparseArray<Icon>();
463
Andrew Flynna478d702015-04-14 23:33:45 -0400464 protected final int mResId;
John Spurlock2d695812014-10-30 13:25:21 -0400465
466 private ResourceIcon(int resId) {
467 mResId = resId;
468 }
469
470 public static Icon get(int resId) {
471 Icon icon = ICONS.get(resId);
472 if (icon == null) {
473 icon = new ResourceIcon(resId);
474 ICONS.put(resId, icon);
475 }
476 return icon;
477 }
478
479 @Override
480 public Drawable getDrawable(Context context) {
Jason Monk66239fb2015-12-21 14:27:00 -0500481 return context.getDrawable(mResId);
John Spurlock2d695812014-10-30 13:25:21 -0400482 }
483
484 @Override
Jason Monk1aec93f2016-03-01 09:39:30 -0500485 public Drawable getInvisibleDrawable(Context context) {
486 return context.getDrawable(mResId);
487 }
488
489 @Override
John Spurlock2d695812014-10-30 13:25:21 -0400490 public boolean equals(Object o) {
491 return o instanceof ResourceIcon && ((ResourceIcon) o).mResId == mResId;
492 }
493
494 @Override
495 public String toString() {
496 return String.format("ResourceIcon[resId=0x%08x]", mResId);
497 }
498 }
499
500 protected class AnimationIcon extends ResourceIcon {
Jason Monk1aec93f2016-03-01 09:39:30 -0500501 private final int mAnimatedResId;
502
503 public AnimationIcon(int resId, int staticResId) {
504 super(staticResId);
505 mAnimatedResId = resId;
John Spurlock2d695812014-10-30 13:25:21 -0400506 }
507
John Spurlock2d695812014-10-30 13:25:21 -0400508 @Override
509 public Drawable getDrawable(Context context) {
510 // workaround: get a clean state for every new AVD
Jason Monk1aec93f2016-03-01 09:39:30 -0500511 return context.getDrawable(mAnimatedResId).getConstantState().newDrawable();
John Spurlock2d695812014-10-30 13:25:21 -0400512 }
513 }
514
John Spurlockaf8d6c42014-05-07 17:49:08 -0400515 public static class State {
John Spurlock2d695812014-10-30 13:25:21 -0400516 public Icon icon;
Jason Monkbbadff82015-11-06 15:47:26 -0500517 public CharSequence label;
518 public CharSequence contentDescription;
519 public CharSequence dualLabelContentDescription;
Selim Cinek06d3bca2014-08-26 17:29:20 +0200520 public boolean autoMirrorDrawable = true;
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000521 public boolean disabledByPolicy;
522 public EnforcedAdmin enforcedAdmin;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400523
524 public boolean copyTo(State other) {
525 if (other == null) throw new IllegalArgumentException();
526 if (!other.getClass().equals(getClass())) throw new IllegalArgumentException();
Jason Monkba2318e2015-12-08 09:04:23 -0500527 final boolean changed = !Objects.equals(other.icon, icon)
John Spurlockaf8d6c42014-05-07 17:49:08 -0400528 || !Objects.equals(other.label, label)
Selim Cineke5557a92014-08-15 19:59:23 +0200529 || !Objects.equals(other.contentDescription, contentDescription)
Selim Cinek06d3bca2014-08-26 17:29:20 +0200530 || !Objects.equals(other.autoMirrorDrawable, autoMirrorDrawable)
Selim Cineke5557a92014-08-15 19:59:23 +0200531 || !Objects.equals(other.dualLabelContentDescription,
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000532 dualLabelContentDescription)
533 || !Objects.equals(other.disabledByPolicy, disabledByPolicy)
534 || !Objects.equals(other.enforcedAdmin, enforcedAdmin);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400535 other.icon = icon;
536 other.label = label;
537 other.contentDescription = contentDescription;
Selim Cineke5557a92014-08-15 19:59:23 +0200538 other.dualLabelContentDescription = dualLabelContentDescription;
Selim Cinek06d3bca2014-08-26 17:29:20 +0200539 other.autoMirrorDrawable = autoMirrorDrawable;
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000540 other.disabledByPolicy = disabledByPolicy;
Sudheer Shanka1c09db22016-01-18 11:18:35 +0000541 if (enforcedAdmin == null) {
542 other.enforcedAdmin = null;
543 } else if (other.enforcedAdmin == null) {
544 other.enforcedAdmin = new EnforcedAdmin(enforcedAdmin);
545 } else {
546 enforcedAdmin.copyTo(other.enforcedAdmin);
547 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400548 return changed;
549 }
550
551 @Override
552 public String toString() {
553 return toStringBuilder().toString();
554 }
555
556 protected StringBuilder toStringBuilder() {
John Spurlock2d695812014-10-30 13:25:21 -0400557 final StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('[');
John Spurlockaf8d6c42014-05-07 17:49:08 -0400558 sb.append(",icon=").append(icon);
559 sb.append(",label=").append(label);
560 sb.append(",contentDescription=").append(contentDescription);
Selim Cineke5557a92014-08-15 19:59:23 +0200561 sb.append(",dualLabelContentDescription=").append(dualLabelContentDescription);
Selim Cinek06d3bca2014-08-26 17:29:20 +0200562 sb.append(",autoMirrorDrawable=").append(autoMirrorDrawable);
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000563 sb.append(",disabledByPolicy=").append(disabledByPolicy);
564 sb.append(",enforcedAdmin=").append(enforcedAdmin);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400565 return sb.append(']');
566 }
567 }
568
569 public static class BooleanState extends State {
570 public boolean value;
571
572 @Override
573 public boolean copyTo(State other) {
574 final BooleanState o = (BooleanState) other;
575 final boolean changed = super.copyTo(other) || o.value != value;
576 o.value = value;
577 return changed;
578 }
579
580 @Override
581 protected StringBuilder toStringBuilder() {
582 final StringBuilder rt = super.toStringBuilder();
583 rt.insert(rt.length() - 1, ",value=" + value);
584 return rt;
585 }
586 }
587
588 public static final class SignalState extends State {
589 public boolean enabled;
590 public boolean connected;
591 public boolean activityIn;
592 public boolean activityOut;
593 public int overlayIconId;
John Spurlock899f4392014-06-11 10:59:11 -0400594 public boolean filter;
Jorim Jaggic737b9b2014-09-08 23:57:20 +0200595 public boolean isOverlayIconWide;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400596
597 @Override
598 public boolean copyTo(State other) {
599 final SignalState o = (SignalState) other;
600 final boolean changed = o.enabled != enabled
601 || o.connected != connected || o.activityIn != activityIn
602 || o.activityOut != activityOut
Jorim Jaggic737b9b2014-09-08 23:57:20 +0200603 || o.overlayIconId != overlayIconId
604 || o.isOverlayIconWide != isOverlayIconWide;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400605 o.enabled = enabled;
606 o.connected = connected;
607 o.activityIn = activityIn;
608 o.activityOut = activityOut;
609 o.overlayIconId = overlayIconId;
John Spurlock899f4392014-06-11 10:59:11 -0400610 o.filter = filter;
Jorim Jaggic737b9b2014-09-08 23:57:20 +0200611 o.isOverlayIconWide = isOverlayIconWide;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400612 return super.copyTo(other) || changed;
613 }
614
615 @Override
616 protected StringBuilder toStringBuilder() {
617 final StringBuilder rt = super.toStringBuilder();
618 rt.insert(rt.length() - 1, ",enabled=" + enabled);
619 rt.insert(rt.length() - 1, ",connected=" + connected);
620 rt.insert(rt.length() - 1, ",activityIn=" + activityIn);
621 rt.insert(rt.length() - 1, ",activityOut=" + activityOut);
622 rt.insert(rt.length() - 1, ",overlayIconId=" + overlayIconId);
John Spurlock899f4392014-06-11 10:59:11 -0400623 rt.insert(rt.length() - 1, ",filter=" + filter);
Jorim Jaggic737b9b2014-09-08 23:57:20 +0200624 rt.insert(rt.length() - 1, ",wideOverlayIcon=" + isOverlayIconWide);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400625 return rt;
626 }
627 }
628}