• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * 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
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * 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.
13  */
14 
15 package com.android.systemui.statusbar.phone;
16 
17 import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_ICON;
18 import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_MOBILE;
19 import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_WIFI;
20 
21 import android.annotation.Nullable;
22 import android.content.Context;
23 import android.os.Bundle;
24 import android.text.TextUtils;
25 import android.util.ArraySet;
26 import android.view.Gravity;
27 import android.view.View;
28 import android.view.ViewGroup;
29 import android.widget.ImageView;
30 import android.widget.LinearLayout;
31 import android.widget.LinearLayout.LayoutParams;
32 
33 import androidx.annotation.VisibleForTesting;
34 
35 import com.android.internal.statusbar.StatusBarIcon;
36 import com.android.systemui.Dependency;
37 import com.android.systemui.R;
38 import com.android.systemui.demomode.DemoModeCommandReceiver;
39 import com.android.systemui.plugins.DarkIconDispatcher;
40 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
41 import com.android.systemui.statusbar.FeatureFlags;
42 import com.android.systemui.statusbar.StatusBarIconView;
43 import com.android.systemui.statusbar.StatusBarMobileView;
44 import com.android.systemui.statusbar.StatusBarWifiView;
45 import com.android.systemui.statusbar.StatusIconDisplayable;
46 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState;
47 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
48 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
49 
50 import java.util.ArrayList;
51 import java.util.List;
52 
53 public interface StatusBarIconController {
54 
55     /**
56      * When an icon is added with TAG_PRIMARY, it will be treated as the primary icon
57      * in that slot and not added as a sub slot.
58      */
59     int TAG_PRIMARY = 0;
60 
61     /** */
addIconGroup(IconManager iconManager)62     void addIconGroup(IconManager iconManager);
63     /** */
removeIconGroup(IconManager iconManager)64     void removeIconGroup(IconManager iconManager);
65     /** */
setExternalIcon(String slot)66     void setExternalIcon(String slot);
67     /** */
setIcon(String slot, int resourceId, CharSequence contentDescription)68     void setIcon(String slot, int resourceId, CharSequence contentDescription);
69     /** */
setIcon(String slot, StatusBarIcon icon)70     void setIcon(String slot, StatusBarIcon icon);
71     /** */
setSignalIcon(String slot, WifiIconState state)72     void setSignalIcon(String slot, WifiIconState state);
73     /** */
setMobileIcons(String slot, List<MobileIconState> states)74     void setMobileIcons(String slot, List<MobileIconState> states);
75     /**
76      * Display the no calling & SMS icons.
77      */
setCallStrengthIcons(String slot, List<CallIndicatorIconState> states)78     void setCallStrengthIcons(String slot, List<CallIndicatorIconState> states);
79     /**
80      * Display the no calling & SMS icons.
81      */
setNoCallingIcons(String slot, List<CallIndicatorIconState> states)82     void setNoCallingIcons(String slot, List<CallIndicatorIconState> states);
setIconVisibility(String slot, boolean b)83     public void setIconVisibility(String slot, boolean b);
84 
85     /**
86      * Sets the live region mode for the icon
87      * @see android.view.View#setAccessibilityLiveRegion(int)
88      * @param slot Icon slot to set region for
89      * @param accessibilityLiveRegion live region mode for the icon
90      */
setIconAccessibilityLiveRegion(String slot, int accessibilityLiveRegion)91     void setIconAccessibilityLiveRegion(String slot, int accessibilityLiveRegion);
92 
93     /**
94      * If you don't know what to pass for `tag`, either remove all icons for slot, or use
95      * TAG_PRIMARY to refer to the first icon at a given slot.
96      */
removeIcon(String slot, int tag)97     void removeIcon(String slot, int tag);
98     /** */
removeAllIconsForSlot(String slot)99     void removeAllIconsForSlot(String slot);
100 
101     // TODO: See if we can rename this tunable name.
102     String ICON_HIDE_LIST = "icon_blacklist";
103 
104     /** Reads the default hide list from config value unless hideListStr is provided. */
getIconHideList(Context context, String hideListStr)105     static ArraySet<String> getIconHideList(Context context, String hideListStr) {
106         ArraySet<String> ret = new ArraySet<>();
107         String[] hideList = hideListStr == null
108             ? context.getResources().getStringArray(R.array.config_statusBarIconsToExclude)
109             : hideListStr.split(",");
110         for (String slot : hideList) {
111             if (!TextUtils.isEmpty(slot)) {
112                 ret.add(slot);
113             }
114         }
115         return ret;
116     }
117 
118     /**
119      * Version of ViewGroup that observes state from the DarkIconDispatcher.
120      */
121     class DarkIconManager extends IconManager {
122         private final DarkIconDispatcher mDarkIconDispatcher;
123         private int mIconHPadding;
124 
DarkIconManager(LinearLayout linearLayout, FeatureFlags featureFlags)125         public DarkIconManager(LinearLayout linearLayout, FeatureFlags featureFlags) {
126             super(linearLayout, featureFlags);
127             mIconHPadding = mContext.getResources().getDimensionPixelSize(
128                     R.dimen.status_bar_icon_padding);
129             mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
130         }
131 
132         @Override
onIconAdded(int index, String slot, boolean blocked, StatusBarIconHolder holder)133         protected void onIconAdded(int index, String slot, boolean blocked,
134                 StatusBarIconHolder holder) {
135             StatusIconDisplayable view = addHolder(index, slot, blocked, holder);
136             mDarkIconDispatcher.addDarkReceiver((DarkReceiver) view);
137         }
138 
139         @Override
onCreateLayoutParams()140         protected LayoutParams onCreateLayoutParams() {
141             LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
142                     ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
143             lp.setMargins(mIconHPadding, 0, mIconHPadding, 0);
144             return lp;
145         }
146 
147         @Override
destroy()148         protected void destroy() {
149             for (int i = 0; i < mGroup.getChildCount(); i++) {
150                 mDarkIconDispatcher.removeDarkReceiver((DarkReceiver) mGroup.getChildAt(i));
151             }
152             mGroup.removeAllViews();
153         }
154 
155         @Override
onRemoveIcon(int viewIndex)156         protected void onRemoveIcon(int viewIndex) {
157             mDarkIconDispatcher.removeDarkReceiver((DarkReceiver) mGroup.getChildAt(viewIndex));
158             super.onRemoveIcon(viewIndex);
159         }
160 
161         @Override
onSetIcon(int viewIndex, StatusBarIcon icon)162         public void onSetIcon(int viewIndex, StatusBarIcon icon) {
163             super.onSetIcon(viewIndex, icon);
164             mDarkIconDispatcher.applyDark((DarkReceiver) mGroup.getChildAt(viewIndex));
165         }
166 
167         @Override
createDemoStatusIcons()168         protected DemoStatusIcons createDemoStatusIcons() {
169             DemoStatusIcons icons = super.createDemoStatusIcons();
170             mDarkIconDispatcher.addDarkReceiver(icons);
171 
172             return icons;
173         }
174 
175         @Override
exitDemoMode()176         protected void exitDemoMode() {
177             mDarkIconDispatcher.removeDarkReceiver(mDemoStatusIcons);
178             super.exitDemoMode();
179         }
180     }
181 
182     /** */
183     class TintedIconManager extends IconManager {
184         private int mColor;
185 
TintedIconManager(ViewGroup group, FeatureFlags featureFlags)186         public TintedIconManager(ViewGroup group, FeatureFlags featureFlags) {
187             super(group, featureFlags);
188         }
189 
190         @Override
onIconAdded(int index, String slot, boolean blocked, StatusBarIconHolder holder)191         protected void onIconAdded(int index, String slot, boolean blocked,
192                 StatusBarIconHolder holder) {
193             StatusIconDisplayable view = addHolder(index, slot, blocked, holder);
194             view.setStaticDrawableColor(mColor);
195             view.setDecorColor(mColor);
196         }
197 
setTint(int color)198         public void setTint(int color) {
199             mColor = color;
200             for (int i = 0; i < mGroup.getChildCount(); i++) {
201                 View child = mGroup.getChildAt(i);
202                 if (child instanceof StatusIconDisplayable) {
203                     StatusIconDisplayable icon = (StatusIconDisplayable) child;
204                     icon.setStaticDrawableColor(mColor);
205                     icon.setDecorColor(mColor);
206                 }
207             }
208         }
209 
210         @Override
createDemoStatusIcons()211         protected DemoStatusIcons createDemoStatusIcons() {
212             DemoStatusIcons icons = super.createDemoStatusIcons();
213             icons.setColor(mColor);
214             return icons;
215         }
216     }
217 
218     /**
219      * Turns info from StatusBarIconController into ImageViews in a ViewGroup.
220      */
221     class IconManager implements DemoModeCommandReceiver {
222         private final FeatureFlags mFeatureFlags;
223         protected final ViewGroup mGroup;
224         protected final Context mContext;
225         protected final int mIconSize;
226         // Whether or not these icons show up in dumpsys
227         protected boolean mShouldLog = false;
228 
229         // Enables SystemUI demo mode to take effect in this group
230         protected boolean mDemoable = true;
231         private boolean mIsInDemoMode;
232         protected DemoStatusIcons mDemoStatusIcons;
233 
234         protected ArrayList<String> mBlockList = new ArrayList<>();
235 
IconManager(ViewGroup group, FeatureFlags featureFlags)236         public IconManager(ViewGroup group, FeatureFlags featureFlags) {
237             mFeatureFlags = featureFlags;
238             mGroup = group;
239             mContext = group.getContext();
240             mIconSize = mContext.getResources().getDimensionPixelSize(
241                     com.android.internal.R.dimen.status_bar_icon_size);
242         }
243 
isDemoable()244         public boolean isDemoable() {
245             return mDemoable;
246         }
247 
setIsDemoable(boolean demoable)248         public void setIsDemoable(boolean demoable) {
249             mDemoable = demoable;
250         }
251 
setBlockList(@ullable List<String> blockList)252         public void setBlockList(@Nullable List<String> blockList) {
253             mBlockList.clear();
254             if (blockList == null || blockList.isEmpty()) {
255                 return;
256             }
257 
258             mBlockList.addAll(blockList);
259         }
260 
setShouldLog(boolean should)261         public void setShouldLog(boolean should) {
262             mShouldLog = should;
263         }
264 
shouldLog()265         public boolean shouldLog() {
266             return mShouldLog;
267         }
268 
onIconAdded(int index, String slot, boolean blocked, StatusBarIconHolder holder)269         protected void onIconAdded(int index, String slot, boolean blocked,
270                 StatusBarIconHolder holder) {
271             addHolder(index, slot, blocked, holder);
272         }
273 
addHolder(int index, String slot, boolean blocked, StatusBarIconHolder holder)274         protected StatusIconDisplayable addHolder(int index, String slot, boolean blocked,
275                 StatusBarIconHolder holder) {
276             // This is a little hacky, and probably regrettable, but just set `blocked` on any icon
277             // that is in our blocked list, then we'll never see it
278             if (mBlockList.contains(slot)) {
279                 blocked = true;
280             }
281             switch (holder.getType()) {
282                 case TYPE_ICON:
283                     return addIcon(index, slot, blocked, holder.getIcon());
284 
285                 case TYPE_WIFI:
286                     return addSignalIcon(index, slot, holder.getWifiState());
287 
288                 case TYPE_MOBILE:
289                     return addMobileIcon(index, slot, holder.getMobileState());
290             }
291 
292             return null;
293         }
294 
295         @VisibleForTesting
addIcon(int index, String slot, boolean blocked, StatusBarIcon icon)296         protected StatusBarIconView addIcon(int index, String slot, boolean blocked,
297                 StatusBarIcon icon) {
298             StatusBarIconView view = onCreateStatusBarIconView(slot, blocked);
299             view.set(icon);
300             mGroup.addView(view, index, onCreateLayoutParams());
301             return view;
302         }
303 
304         @VisibleForTesting
addSignalIcon(int index, String slot, WifiIconState state)305         protected StatusBarWifiView addSignalIcon(int index, String slot, WifiIconState state) {
306             StatusBarWifiView view = onCreateStatusBarWifiView(slot);
307             view.applyWifiState(state);
308             mGroup.addView(view, index, onCreateLayoutParams());
309 
310             if (mIsInDemoMode) {
311                 mDemoStatusIcons.addDemoWifiView(state);
312             }
313             return view;
314         }
315 
316         @VisibleForTesting
addMobileIcon(int index, String slot, MobileIconState state)317         protected StatusBarMobileView addMobileIcon(int index, String slot, MobileIconState state) {
318             StatusBarMobileView view = onCreateStatusBarMobileView(slot);
319             view.applyMobileState(state);
320             mGroup.addView(view, index, onCreateLayoutParams());
321 
322             if (mIsInDemoMode) {
323                 mDemoStatusIcons.addMobileView(state);
324             }
325             return view;
326         }
327 
onCreateStatusBarIconView(String slot, boolean blocked)328         private StatusBarIconView onCreateStatusBarIconView(String slot, boolean blocked) {
329             return new StatusBarIconView(mContext, slot, null, blocked);
330         }
331 
onCreateStatusBarWifiView(String slot)332         private StatusBarWifiView onCreateStatusBarWifiView(String slot) {
333             StatusBarWifiView view = StatusBarWifiView.fromContext(mContext, slot);
334             return view;
335         }
336 
onCreateStatusBarMobileView(String slot)337         private StatusBarMobileView onCreateStatusBarMobileView(String slot) {
338             StatusBarMobileView view = StatusBarMobileView.fromContext(
339                             mContext, slot, mFeatureFlags.isCombinedStatusBarSignalIconsEnabled());
340             return view;
341         }
342 
onCreateLayoutParams()343         protected LinearLayout.LayoutParams onCreateLayoutParams() {
344             return new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
345         }
346 
destroy()347         protected void destroy() {
348             mGroup.removeAllViews();
349         }
350 
onIconExternal(int viewIndex, int height)351         protected void onIconExternal(int viewIndex, int height) {
352             ImageView imageView = (ImageView) mGroup.getChildAt(viewIndex);
353             imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
354             imageView.setAdjustViewBounds(true);
355             setHeightAndCenter(imageView, height);
356         }
357 
onDensityOrFontScaleChanged()358         protected void onDensityOrFontScaleChanged() {
359             for (int i = 0; i < mGroup.getChildCount(); i++) {
360                 View child = mGroup.getChildAt(i);
361                 LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
362                         ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
363                 child.setLayoutParams(lp);
364             }
365         }
366 
setHeightAndCenter(ImageView imageView, int height)367         private void setHeightAndCenter(ImageView imageView, int height) {
368             ViewGroup.LayoutParams params = imageView.getLayoutParams();
369             params.height = height;
370             if (params instanceof LinearLayout.LayoutParams) {
371                 ((LinearLayout.LayoutParams) params).gravity = Gravity.CENTER_VERTICAL;
372             }
373             imageView.setLayoutParams(params);
374         }
375 
onRemoveIcon(int viewIndex)376         protected void onRemoveIcon(int viewIndex) {
377             if (mIsInDemoMode) {
378                 mDemoStatusIcons.onRemoveIcon((StatusIconDisplayable) mGroup.getChildAt(viewIndex));
379             }
380             mGroup.removeViewAt(viewIndex);
381         }
382 
onSetIcon(int viewIndex, StatusBarIcon icon)383         public void onSetIcon(int viewIndex, StatusBarIcon icon) {
384             StatusBarIconView view = (StatusBarIconView) mGroup.getChildAt(viewIndex);
385             view.set(icon);
386         }
387 
onSetIconHolder(int viewIndex, StatusBarIconHolder holder)388         public void onSetIconHolder(int viewIndex, StatusBarIconHolder holder) {
389             switch (holder.getType()) {
390                 case TYPE_ICON:
391                     onSetIcon(viewIndex, holder.getIcon());
392                     return;
393                 case TYPE_WIFI:
394                     onSetSignalIcon(viewIndex, holder.getWifiState());
395                     return;
396 
397                 case TYPE_MOBILE:
398                     onSetMobileIcon(viewIndex, holder.getMobileState());
399                 default:
400                     break;
401             }
402         }
403 
onSetSignalIcon(int viewIndex, WifiIconState state)404         public void onSetSignalIcon(int viewIndex, WifiIconState state) {
405             StatusBarWifiView wifiView = (StatusBarWifiView) mGroup.getChildAt(viewIndex);
406             if (wifiView != null) {
407                 wifiView.applyWifiState(state);
408             }
409 
410             if (mIsInDemoMode) {
411                 mDemoStatusIcons.updateWifiState(state);
412             }
413         }
414 
onSetMobileIcon(int viewIndex, MobileIconState state)415         public void onSetMobileIcon(int viewIndex, MobileIconState state) {
416             StatusBarMobileView view = (StatusBarMobileView) mGroup.getChildAt(viewIndex);
417             if (view != null) {
418                 view.applyMobileState(state);
419             }
420 
421             if (mIsInDemoMode) {
422                 mDemoStatusIcons.updateMobileState(state);
423             }
424         }
425 
426         @Override
dispatchDemoCommand(String command, Bundle args)427         public void dispatchDemoCommand(String command, Bundle args) {
428             if (!mDemoable) {
429                 return;
430             }
431 
432             mDemoStatusIcons.dispatchDemoCommand(command, args);
433         }
434 
435         @Override
onDemoModeStarted()436         public void onDemoModeStarted() {
437             mIsInDemoMode = true;
438             if (mDemoStatusIcons == null) {
439                 mDemoStatusIcons = createDemoStatusIcons();
440             }
441             mDemoStatusIcons.onDemoModeStarted();
442         }
443 
444         @Override
onDemoModeFinished()445         public void onDemoModeFinished() {
446             if (mDemoStatusIcons != null) {
447                 mDemoStatusIcons.onDemoModeFinished();
448                 exitDemoMode();
449                 mIsInDemoMode = false;
450             }
451         }
452 
exitDemoMode()453         protected void exitDemoMode() {
454             mDemoStatusIcons.remove();
455             mDemoStatusIcons = null;
456         }
457 
createDemoStatusIcons()458         protected DemoStatusIcons createDemoStatusIcons() {
459             return new DemoStatusIcons((LinearLayout) mGroup, mIconSize, mFeatureFlags);
460         }
461     }
462 }
463