blob: 94e004bd1b47d3ad40281154f275c6189d5571ad [file] [log] [blame]
Jorim Jaggi66ac1332015-01-21 19:22:26 +01001/*
Jason Monkaa573e92017-01-27 17:00:29 -05002 * Copyright (C) 2017 The Android Open Source Project
Jorim Jaggi66ac1332015-01-21 19:22:26 +01003 *
Jason Monkaa573e92017-01-27 17:00:29 -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
Jorim Jaggi66ac1332015-01-21 19:22:26 +01006 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
Jason Monkaa573e92017-01-27 17:00:29 -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.
Jorim Jaggi66ac1332015-01-21 19:22:26 +010013 */
14
15package com.android.systemui.statusbar.phone;
16
Charles He6a79b0d2017-09-18 09:50:58 +010017import static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS;
18import static android.app.StatusBarManager.DISABLE_NONE;
Evan Lairde1d13c92018-03-20 16:58:01 -040019import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_ICON;
20import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_MOBILE;
21import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_WIFI;
Charles He6a79b0d2017-09-18 09:50:58 +010022
Jorim Jaggi66ac1332015-01-21 19:22:26 +010023import android.content.Context;
Evan Laird937d9fa2018-02-08 10:12:16 -080024import android.os.Bundle;
Jason Monk6eb906e2017-03-29 15:04:25 -040025import android.support.annotation.VisibleForTesting;
Jason Monk3b230072015-05-29 11:11:29 -040026import android.text.TextUtils;
27import android.util.ArraySet;
Evan Lairde1d13c92018-03-20 16:58:01 -040028import android.util.Log;
Jason Monk6d6672f2016-02-05 14:18:21 -050029import android.view.Gravity;
Jorim Jaggi66ac1332015-01-21 19:22:26 +010030import android.view.View;
31import android.view.ViewGroup;
Jorim Jaggidd0107a2015-01-21 22:23:48 +010032import android.widget.ImageView;
Jorim Jaggi66ac1332015-01-21 19:22:26 +010033import android.widget.LinearLayout;
Jason Monk6eb906e2017-03-29 15:04:25 -040034import android.widget.LinearLayout.LayoutParams;
Jason Monkaa573e92017-01-27 17:00:29 -050035
Jorim Jaggi66ac1332015-01-21 19:22:26 +010036import com.android.internal.statusbar.StatusBarIcon;
Evan Laird937d9fa2018-02-08 10:12:16 -080037import com.android.systemui.DemoMode;
Jason Monkde850bb2017-02-01 19:26:30 -050038import com.android.systemui.Dependency;
Jorim Jaggi66ac1332015-01-21 19:22:26 +010039import com.android.systemui.R;
Evan Lairde1d13c92018-03-20 16:58:01 -040040import com.android.systemui.statusbar.StatusIconDisplayable;
Jorim Jaggi66ac1332015-01-21 19:22:26 +010041import com.android.systemui.statusbar.StatusBarIconView;
Evan Lairde1d13c92018-03-20 16:58:01 -040042import com.android.systemui.statusbar.StatusBarMobileView;
43import com.android.systemui.statusbar.StatusBarWifiView;
44import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
45import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
Jason Monkaa573e92017-01-27 17:00:29 -050046import com.android.systemui.statusbar.policy.DarkIconDispatcher;
Evan Lairde1d13c92018-03-20 16:58:01 -040047import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
Charles He6a79b0d2017-09-18 09:50:58 +010048import com.android.systemui.util.Utils.DisableStateTracker;
Evan Lairde1d13c92018-03-20 16:58:01 -040049import java.util.List;
Jorim Jaggi66ac1332015-01-21 19:22:26 +010050
Jason Monkaa573e92017-01-27 17:00:29 -050051public interface StatusBarIconController {
Jorim Jaggi66ac1332015-01-21 19:22:26 +010052
Evan Lairde1d13c92018-03-20 16:58:01 -040053 /**
54 * When an icon is added with TAG_PRIMARY, it will be treated as the primary icon
55 * in that slot and not added as a sub slot.
56 */
57 public static final int TAG_PRIMARY = 0;
58
Jason Monkaa573e92017-01-27 17:00:29 -050059 public void addIconGroup(IconManager iconManager);
60 public void removeIconGroup(IconManager iconManager);
61 public void setExternalIcon(String slot);
62 public void setIcon(String slot, int resourceId, CharSequence contentDescription);
63 public void setIcon(String slot, StatusBarIcon icon);
Evan Lairde1d13c92018-03-20 16:58:01 -040064 public void setSignalIcon(String slot, WifiIconState state);
65 public void setMobileIcons(String slot, List<MobileIconState> states);
66 public void setIconVisibility(String slot, boolean b);
67 /**
68 * If you don't know what to pass for `tag`, either remove all icons for slot, or use
69 * TAG_PRIMARY to refer to the first icon at a given slot.
70 */
71 public void removeIcon(String slot, int tag);
72 public void removeAllIconsForSlot(String slot);
Jorim Jaggi66ac1332015-01-21 19:22:26 +010073
Jason Monk3b230072015-05-29 11:11:29 -040074 public static final String ICON_BLACKLIST = "icon_blacklist";
Jorim Jaggidd0107a2015-01-21 22:23:48 +010075
Jason Monk5e745172015-06-02 19:14:44 -040076 public static ArraySet<String> getIconBlacklist(String blackListStr) {
Jason Monkaa573e92017-01-27 17:00:29 -050077 ArraySet<String> ret = new ArraySet<>();
Jason Monk3e189872016-01-12 09:10:34 -050078 if (blackListStr == null) {
79 blackListStr = "rotate,headset";
80 }
81 String[] blacklist = blackListStr.split(",");
82 for (String slot : blacklist) {
83 if (!TextUtils.isEmpty(slot)) {
84 ret.add(slot);
Jason Monk3b230072015-05-29 11:11:29 -040085 }
86 }
87 return ret;
88 }
Selim Cinek3e7592d2016-04-11 09:35:54 +080089
Jason Monkaa573e92017-01-27 17:00:29 -050090 /**
Evan Laird058c8ae2018-01-12 14:26:10 -050091 * Version of ViewGroup that observes state from the DarkIconDispatcher.
Jason Monkaa573e92017-01-27 17:00:29 -050092 */
93 public static class DarkIconManager extends IconManager {
94 private final DarkIconDispatcher mDarkIconDispatcher;
95 private int mIconHPadding;
96
97 public DarkIconManager(LinearLayout linearLayout) {
98 super(linearLayout);
99 mIconHPadding = mContext.getResources().getDimensionPixelSize(
100 R.dimen.status_bar_icon_padding);
101 mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
102 }
103
104 @Override
Jason Monk6eb906e2017-03-29 15:04:25 -0400105 protected void onIconAdded(int index, String slot, boolean blocked,
Evan Lairde1d13c92018-03-20 16:58:01 -0400106 StatusBarIconHolder holder) {
107 StatusIconDisplayable view = addHolder(index, slot, blocked, holder);
108 mDarkIconDispatcher.addDarkReceiver((DarkReceiver) view);
Jason Monk6eb906e2017-03-29 15:04:25 -0400109 }
110
111 @Override
112 protected LayoutParams onCreateLayoutParams() {
Selim Cinek3e7592d2016-04-11 09:35:54 +0800113 LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
114 ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
115 lp.setMargins(mIconHPadding, 0, mIconHPadding, 0);
Jason Monk6eb906e2017-03-29 15:04:25 -0400116 return lp;
Selim Cinek3e7592d2016-04-11 09:35:54 +0800117 }
Jason Monkaa573e92017-01-27 17:00:29 -0500118
119 @Override
120 protected void destroy() {
121 for (int i = 0; i < mGroup.getChildCount(); i++) {
Evan Lairde1d13c92018-03-20 16:58:01 -0400122 mDarkIconDispatcher.removeDarkReceiver((DarkReceiver) mGroup.getChildAt(i));
Jason Monkaa573e92017-01-27 17:00:29 -0500123 }
124 mGroup.removeAllViews();
Selim Cinek3e7592d2016-04-11 09:35:54 +0800125 }
Jason Monkaa573e92017-01-27 17:00:29 -0500126
127 @Override
128 protected void onRemoveIcon(int viewIndex) {
Evan Lairde1d13c92018-03-20 16:58:01 -0400129 mDarkIconDispatcher.removeDarkReceiver((DarkReceiver) mGroup.getChildAt(viewIndex));
Jason Monkaa573e92017-01-27 17:00:29 -0500130 super.onRemoveIcon(viewIndex);
131 }
132
133 @Override
134 public void onSetIcon(int viewIndex, StatusBarIcon icon) {
135 super.onSetIcon(viewIndex, icon);
Evan Lairde1d13c92018-03-20 16:58:01 -0400136 mDarkIconDispatcher.applyDark((DarkReceiver) mGroup.getChildAt(viewIndex));
Jason Monkaa573e92017-01-27 17:00:29 -0500137 }
Evan Laird937d9fa2018-02-08 10:12:16 -0800138
139 @Override
140 protected DemoStatusIcons createDemoStatusIcons() {
141 DemoStatusIcons icons = super.createDemoStatusIcons();
142 mDarkIconDispatcher.addDarkReceiver(icons);
143
144 return icons;
145 }
146
147 @Override
148 protected void exitDemoMode() {
149 mDarkIconDispatcher.removeDarkReceiver(mDemoStatusIcons);
150 super.exitDemoMode();
151 }
Selim Cinek3e7592d2016-04-11 09:35:54 +0800152 }
153
Jason Monk9cac5ff2017-06-02 11:35:50 -0400154 public static class TintedIconManager extends IconManager {
155 private int mColor;
156
157 public TintedIconManager(ViewGroup group) {
158 super(group);
159 }
160
161 @Override
Evan Lairde1d13c92018-03-20 16:58:01 -0400162 protected void onIconAdded(int index, String slot, boolean blocked,
163 StatusBarIconHolder holder) {
164 StatusIconDisplayable view = addHolder(index, slot, blocked, holder);
165 view.setStaticDrawableColor(mColor);
Jason Monk9cac5ff2017-06-02 11:35:50 -0400166 }
167
168 public void setTint(int color) {
169 mColor = color;
170 for (int i = 0; i < mGroup.getChildCount(); i++) {
171 View child = mGroup.getChildAt(i);
Evan Lairde1d13c92018-03-20 16:58:01 -0400172 if (child instanceof StatusIconDisplayable) {
173 StatusIconDisplayable icon = (StatusIconDisplayable) child;
Jason Monk9cac5ff2017-06-02 11:35:50 -0400174 icon.setStaticDrawableColor(mColor);
175 }
176 }
177 }
Evan Laird937d9fa2018-02-08 10:12:16 -0800178
179 @Override
180 protected DemoStatusIcons createDemoStatusIcons() {
181 DemoStatusIcons icons = super.createDemoStatusIcons();
182 icons.setColor(mColor);
183 return icons;
184 }
Jason Monk9cac5ff2017-06-02 11:35:50 -0400185 }
186
Jason Monkaa573e92017-01-27 17:00:29 -0500187 /**
188 * Turns info from StatusBarIconController into ImageViews in a ViewGroup.
189 */
Evan Laird937d9fa2018-02-08 10:12:16 -0800190 public static class IconManager implements DemoMode {
Jason Monkaa573e92017-01-27 17:00:29 -0500191 protected final ViewGroup mGroup;
192 protected final Context mContext;
193 protected final int mIconSize;
Evan Laird937d9fa2018-02-08 10:12:16 -0800194 // Whether or not these icons show up in dumpsys
195 protected boolean mShouldLog = false;
196
197 // Enables SystemUI demo mode to take effect in this group
198 protected boolean mDemoable = true;
Evan Lairde1d13c92018-03-20 16:58:01 -0400199 private boolean mIsInDemoMode;
Evan Laird937d9fa2018-02-08 10:12:16 -0800200 protected DemoStatusIcons mDemoStatusIcons;
Jason Monkaa573e92017-01-27 17:00:29 -0500201
202 public IconManager(ViewGroup group) {
203 mGroup = group;
204 mContext = group.getContext();
205 mIconSize = mContext.getResources().getDimensionPixelSize(
206 com.android.internal.R.dimen.status_bar_icon_size);
Charles He6a79b0d2017-09-18 09:50:58 +0100207
208 DisableStateTracker tracker =
209 new DisableStateTracker(DISABLE_NONE, DISABLE2_SYSTEM_ICONS);
210 mGroup.addOnAttachStateChangeListener(tracker);
211 if (mGroup.isAttachedToWindow()) {
212 // In case we miss the first onAttachedToWindow event
213 tracker.onViewAttachedToWindow(mGroup);
214 }
Jason Monkaa573e92017-01-27 17:00:29 -0500215 }
216
Evan Laird937d9fa2018-02-08 10:12:16 -0800217 public boolean isDemoable() {
218 return mDemoable;
219 }
220
221 public void setIsDemoable(boolean demoable) {
222 mDemoable = demoable;
223 }
224
225 public void setShouldLog(boolean should) {
226 mShouldLog = should;
227 }
228
229 public boolean shouldLog() {
230 return mShouldLog;
231 }
232
Jason Monk6eb906e2017-03-29 15:04:25 -0400233 protected void onIconAdded(int index, String slot, boolean blocked,
Evan Lairde1d13c92018-03-20 16:58:01 -0400234 StatusBarIconHolder holder) {
235 addHolder(index, slot, blocked, holder);
Jason Monk6eb906e2017-03-29 15:04:25 -0400236 }
237
Evan Lairde1d13c92018-03-20 16:58:01 -0400238 protected StatusIconDisplayable addHolder(int index, String slot, boolean blocked,
239 StatusBarIconHolder holder) {
240 switch (holder.getType()) {
241 case TYPE_ICON:
242 return addIcon(index, slot, blocked, holder.getIcon());
243
244 case TYPE_WIFI:
245 return addSignalIcon(index, slot, holder.getWifiState());
246
247 case TYPE_MOBILE:
248 return addMobileIcon(index, slot, holder.getMobileState());
249 }
250
251 return null;
252 }
253
254 @VisibleForTesting
Jason Monk6eb906e2017-03-29 15:04:25 -0400255 protected StatusBarIconView addIcon(int index, String slot, boolean blocked,
256 StatusBarIcon icon) {
257 StatusBarIconView view = onCreateStatusBarIconView(slot, blocked);
Jason Monkaa573e92017-01-27 17:00:29 -0500258 view.set(icon);
Jason Monk6eb906e2017-03-29 15:04:25 -0400259 mGroup.addView(view, index, onCreateLayoutParams());
260 return view;
261 }
262
263 @VisibleForTesting
Evan Lairde1d13c92018-03-20 16:58:01 -0400264 protected StatusBarWifiView addSignalIcon(int index, String slot, WifiIconState state) {
265 StatusBarWifiView view = onCreateStatusBarWifiView(slot);
266 view.applyWifiState(state);
267 mGroup.addView(view, index, onCreateLayoutParams());
268
269 if (mIsInDemoMode) {
270 mDemoStatusIcons.addDemoWifiView(state);
271 }
272 return view;
273 }
274
275 @VisibleForTesting
276 protected StatusBarMobileView addMobileIcon(int index, String slot, MobileIconState state) {
277 StatusBarMobileView view = onCreateStatusBarMobileView(slot);
278 view.applyMobileState(state);
279 mGroup.addView(view, index, onCreateLayoutParams());
280
281 if (mIsInDemoMode) {
282 mDemoStatusIcons.addMobileView(state);
283 }
284 return view;
285 }
286
287 private StatusBarIconView onCreateStatusBarIconView(String slot, boolean blocked) {
Jason Monk6eb906e2017-03-29 15:04:25 -0400288 return new StatusBarIconView(mContext, slot, null, blocked);
289 }
290
Evan Lairde1d13c92018-03-20 16:58:01 -0400291 private StatusBarWifiView onCreateStatusBarWifiView(String slot) {
292 StatusBarWifiView view = StatusBarWifiView.fromContext(mContext);
293 view.setSlot(slot);
294 return view;
295 }
296
297 private StatusBarMobileView onCreateStatusBarMobileView(String slot) {
298 StatusBarMobileView view = StatusBarMobileView.fromContext(mContext);
299 view.setSlot(slot);
300 return view;
301 }
302
Jason Monk6eb906e2017-03-29 15:04:25 -0400303 protected LinearLayout.LayoutParams onCreateLayoutParams() {
304 return new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
Jason Monkaa573e92017-01-27 17:00:29 -0500305 }
306
307 protected void destroy() {
308 mGroup.removeAllViews();
309 }
310
311 protected void onIconExternal(int viewIndex, int height) {
312 ImageView imageView = (ImageView) mGroup.getChildAt(viewIndex);
313 imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
314 imageView.setAdjustViewBounds(true);
315 setHeightAndCenter(imageView, height);
316 }
317
318 protected void onDensityOrFontScaleChanged() {
319 for (int i = 0; i < mGroup.getChildCount(); i++) {
320 View child = mGroup.getChildAt(i);
321 LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
322 ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
323 child.setLayoutParams(lp);
324 }
325 }
326
327 private void setHeightAndCenter(ImageView imageView, int height) {
328 ViewGroup.LayoutParams params = imageView.getLayoutParams();
329 params.height = height;
330 if (params instanceof LinearLayout.LayoutParams) {
331 ((LinearLayout.LayoutParams) params).gravity = Gravity.CENTER_VERTICAL;
332 }
333 imageView.setLayoutParams(params);
334 }
335
336 protected void onRemoveIcon(int viewIndex) {
Evan Lairde1d13c92018-03-20 16:58:01 -0400337 if (mIsInDemoMode) {
338 mDemoStatusIcons.onRemoveIcon((StatusIconDisplayable) mGroup.getChildAt(viewIndex));
339 }
Jason Monkaa573e92017-01-27 17:00:29 -0500340 mGroup.removeViewAt(viewIndex);
341 }
342
343 public void onSetIcon(int viewIndex, StatusBarIcon icon) {
344 StatusBarIconView view = (StatusBarIconView) mGroup.getChildAt(viewIndex);
345 view.set(icon);
346 }
Evan Laird937d9fa2018-02-08 10:12:16 -0800347
Evan Lairde1d13c92018-03-20 16:58:01 -0400348 public void onSetIconHolder(int viewIndex, StatusBarIconHolder holder) {
349 switch (holder.getType()) {
350 case TYPE_ICON:
351 onSetIcon(viewIndex, holder.getIcon());
352 return;
353 case TYPE_WIFI:
354 onSetSignalIcon(viewIndex, holder.getWifiState());
355 return;
356
357 case TYPE_MOBILE:
358 onSetMobileIcon(viewIndex, holder.getMobileState());
359 default:
360 break;
361 }
362 }
363
364 public void onSetSignalIcon(int viewIndex, WifiIconState state) {
365 StatusBarWifiView wifiView = (StatusBarWifiView) mGroup.getChildAt(viewIndex);
366 if (wifiView != null) {
367 wifiView.applyWifiState(state);
368 }
369
370 if (mIsInDemoMode) {
371 mDemoStatusIcons.updateWifiState(state);
372 }
373 }
374
375 public void onSetMobileIcon(int viewIndex, MobileIconState state) {
376 StatusBarMobileView view = (StatusBarMobileView) mGroup.getChildAt(viewIndex);
377 if (view != null) {
378 view.applyMobileState(state);
379 }
380
381 if (mIsInDemoMode) {
382 mDemoStatusIcons.updateMobileState(state);
383 }
384 }
385
Evan Laird937d9fa2018-02-08 10:12:16 -0800386 @Override
387 public void dispatchDemoCommand(String command, Bundle args) {
388 if (!mDemoable) {
389 return;
390 }
391
Evan Lairde1d13c92018-03-20 16:58:01 -0400392 if (command.equals(COMMAND_EXIT)) {
393 if (mDemoStatusIcons != null) {
394 mDemoStatusIcons.dispatchDemoCommand(command, args);
395 exitDemoMode();
396 }
397 mIsInDemoMode = false;
Evan Laird937d9fa2018-02-08 10:12:16 -0800398 } else {
399 if (mDemoStatusIcons == null) {
Evan Lairde1d13c92018-03-20 16:58:01 -0400400 mIsInDemoMode = true;
Evan Laird937d9fa2018-02-08 10:12:16 -0800401 mDemoStatusIcons = createDemoStatusIcons();
402 }
403 mDemoStatusIcons.dispatchDemoCommand(command, args);
404 }
405 }
406
407 protected void exitDemoMode() {
408 mDemoStatusIcons.remove();
409 mDemoStatusIcons = null;
410 }
411
412 protected DemoStatusIcons createDemoStatusIcons() {
413 return new DemoStatusIcons((LinearLayout) mGroup, mIconSize);
414 }
Selim Cinek3e7592d2016-04-11 09:35:54 +0800415 }
Jorim Jaggi66ac1332015-01-21 19:22:26 +0100416}