Home | History | Annotate | Download | only in phone
      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 android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS;
     18 import static android.app.StatusBarManager.DISABLE_NONE;
     19 import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_ICON;
     20 import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_MOBILE;
     21 import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_WIFI;
     22 
     23 import android.content.Context;
     24 import android.os.Bundle;
     25 import android.support.annotation.VisibleForTesting;
     26 import android.text.TextUtils;
     27 import android.util.ArraySet;
     28 import android.util.Log;
     29 import android.view.Gravity;
     30 import android.view.View;
     31 import android.view.ViewGroup;
     32 import android.widget.ImageView;
     33 import android.widget.LinearLayout;
     34 import android.widget.LinearLayout.LayoutParams;
     35 
     36 import com.android.internal.statusbar.StatusBarIcon;
     37 import com.android.systemui.DemoMode;
     38 import com.android.systemui.Dependency;
     39 import com.android.systemui.R;
     40 import com.android.systemui.statusbar.StatusIconDisplayable;
     41 import com.android.systemui.statusbar.StatusBarIconView;
     42 import com.android.systemui.statusbar.StatusBarMobileView;
     43 import com.android.systemui.statusbar.StatusBarWifiView;
     44 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
     45 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
     46 import com.android.systemui.statusbar.policy.DarkIconDispatcher;
     47 import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
     48 import com.android.systemui.util.Utils.DisableStateTracker;
     49 import java.util.List;
     50 
     51 public interface StatusBarIconController {
     52 
     53     /**
     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 
     59     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);
     64     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);
     73 
     74     public static final String ICON_BLACKLIST = "icon_blacklist";
     75 
     76     public static ArraySet<String> getIconBlacklist(String blackListStr) {
     77         ArraySet<String> ret = new ArraySet<>();
     78         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);
     85             }
     86         }
     87         return ret;
     88     }
     89 
     90     /**
     91      * Version of ViewGroup that observes state from the DarkIconDispatcher.
     92      */
     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
    105         protected void onIconAdded(int index, String slot, boolean blocked,
    106                 StatusBarIconHolder holder) {
    107             StatusIconDisplayable view = addHolder(index, slot, blocked, holder);
    108             mDarkIconDispatcher.addDarkReceiver((DarkReceiver) view);
    109         }
    110 
    111         @Override
    112         protected LayoutParams onCreateLayoutParams() {
    113             LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
    114                     ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
    115             lp.setMargins(mIconHPadding, 0, mIconHPadding, 0);
    116             return lp;
    117         }
    118 
    119         @Override
    120         protected void destroy() {
    121             for (int i = 0; i < mGroup.getChildCount(); i++) {
    122                 mDarkIconDispatcher.removeDarkReceiver((DarkReceiver) mGroup.getChildAt(i));
    123             }
    124             mGroup.removeAllViews();
    125         }
    126 
    127         @Override
    128         protected void onRemoveIcon(int viewIndex) {
    129             mDarkIconDispatcher.removeDarkReceiver((DarkReceiver) mGroup.getChildAt(viewIndex));
    130             super.onRemoveIcon(viewIndex);
    131         }
    132 
    133         @Override
    134         public void onSetIcon(int viewIndex, StatusBarIcon icon) {
    135             super.onSetIcon(viewIndex, icon);
    136             mDarkIconDispatcher.applyDark((DarkReceiver) mGroup.getChildAt(viewIndex));
    137         }
    138 
    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         }
    152     }
    153 
    154     public static class TintedIconManager extends IconManager {
    155         private int mColor;
    156 
    157         public TintedIconManager(ViewGroup group) {
    158             super(group);
    159         }
    160 
    161         @Override
    162         protected void onIconAdded(int index, String slot, boolean blocked,
    163                 StatusBarIconHolder holder) {
    164             StatusIconDisplayable view = addHolder(index, slot, blocked, holder);
    165             view.setStaticDrawableColor(mColor);
    166             view.setDecorColor(mColor);
    167         }
    168 
    169         public void setTint(int color) {
    170             mColor = color;
    171             for (int i = 0; i < mGroup.getChildCount(); i++) {
    172                 View child = mGroup.getChildAt(i);
    173                 if (child instanceof StatusIconDisplayable) {
    174                     StatusIconDisplayable icon = (StatusIconDisplayable) child;
    175                     icon.setStaticDrawableColor(mColor);
    176                     icon.setDecorColor(mColor);
    177                 }
    178             }
    179         }
    180 
    181         @Override
    182         protected DemoStatusIcons createDemoStatusIcons() {
    183             DemoStatusIcons icons = super.createDemoStatusIcons();
    184             icons.setColor(mColor);
    185             return icons;
    186         }
    187     }
    188 
    189     /**
    190      * Turns info from StatusBarIconController into ImageViews in a ViewGroup.
    191      */
    192     public static class IconManager implements DemoMode {
    193         protected final ViewGroup mGroup;
    194         protected final Context mContext;
    195         protected final int mIconSize;
    196         // Whether or not these icons show up in dumpsys
    197         protected boolean mShouldLog = false;
    198 
    199         // Enables SystemUI demo mode to take effect in this group
    200         protected boolean mDemoable = true;
    201         private boolean mIsInDemoMode;
    202         protected DemoStatusIcons mDemoStatusIcons;
    203 
    204         public IconManager(ViewGroup group) {
    205             mGroup = group;
    206             mContext = group.getContext();
    207             mIconSize = mContext.getResources().getDimensionPixelSize(
    208                     com.android.internal.R.dimen.status_bar_icon_size);
    209 
    210             DisableStateTracker tracker =
    211                     new DisableStateTracker(DISABLE_NONE, DISABLE2_SYSTEM_ICONS);
    212             mGroup.addOnAttachStateChangeListener(tracker);
    213             if (mGroup.isAttachedToWindow()) {
    214                 // In case we miss the first onAttachedToWindow event
    215                 tracker.onViewAttachedToWindow(mGroup);
    216             }
    217         }
    218 
    219         public boolean isDemoable() {
    220             return mDemoable;
    221         }
    222 
    223         public void setIsDemoable(boolean demoable) {
    224             mDemoable = demoable;
    225         }
    226 
    227         public void setShouldLog(boolean should) {
    228             mShouldLog = should;
    229         }
    230 
    231         public boolean shouldLog() {
    232             return mShouldLog;
    233         }
    234 
    235         protected void onIconAdded(int index, String slot, boolean blocked,
    236                 StatusBarIconHolder holder) {
    237             addHolder(index, slot, blocked, holder);
    238         }
    239 
    240         protected StatusIconDisplayable addHolder(int index, String slot, boolean blocked,
    241                 StatusBarIconHolder holder) {
    242             switch (holder.getType()) {
    243                 case TYPE_ICON:
    244                     return addIcon(index, slot, blocked, holder.getIcon());
    245 
    246                 case TYPE_WIFI:
    247                     return addSignalIcon(index, slot, holder.getWifiState());
    248 
    249                 case TYPE_MOBILE:
    250                     return addMobileIcon(index, slot, holder.getMobileState());
    251             }
    252 
    253             return null;
    254         }
    255 
    256         @VisibleForTesting
    257         protected StatusBarIconView addIcon(int index, String slot, boolean blocked,
    258                 StatusBarIcon icon) {
    259             StatusBarIconView view = onCreateStatusBarIconView(slot, blocked);
    260             view.set(icon);
    261             mGroup.addView(view, index, onCreateLayoutParams());
    262             return view;
    263         }
    264 
    265         @VisibleForTesting
    266         protected StatusBarWifiView addSignalIcon(int index, String slot, WifiIconState state) {
    267             StatusBarWifiView view = onCreateStatusBarWifiView(slot);
    268             view.applyWifiState(state);
    269             mGroup.addView(view, index, onCreateLayoutParams());
    270 
    271             if (mIsInDemoMode) {
    272                 mDemoStatusIcons.addDemoWifiView(state);
    273             }
    274             return view;
    275         }
    276 
    277         @VisibleForTesting
    278         protected StatusBarMobileView addMobileIcon(int index, String slot, MobileIconState state) {
    279             StatusBarMobileView view = onCreateStatusBarMobileView(slot);
    280             view.applyMobileState(state);
    281             mGroup.addView(view, index, onCreateLayoutParams());
    282 
    283             if (mIsInDemoMode) {
    284                 mDemoStatusIcons.addMobileView(state);
    285             }
    286             return view;
    287         }
    288 
    289         private StatusBarIconView onCreateStatusBarIconView(String slot, boolean blocked) {
    290             return new StatusBarIconView(mContext, slot, null, blocked);
    291         }
    292 
    293         private StatusBarWifiView onCreateStatusBarWifiView(String slot) {
    294             StatusBarWifiView view = StatusBarWifiView.fromContext(mContext, slot);
    295             return view;
    296         }
    297 
    298         private StatusBarMobileView onCreateStatusBarMobileView(String slot) {
    299             StatusBarMobileView view = StatusBarMobileView.fromContext(mContext, slot);
    300             return view;
    301         }
    302 
    303         protected LinearLayout.LayoutParams onCreateLayoutParams() {
    304             return new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
    305         }
    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) {
    337             if (mIsInDemoMode) {
    338                 mDemoStatusIcons.onRemoveIcon((StatusIconDisplayable) mGroup.getChildAt(viewIndex));
    339             }
    340             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         }
    347 
    348         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 
    386         @Override
    387         public void dispatchDemoCommand(String command, Bundle args) {
    388             if (!mDemoable) {
    389                 return;
    390             }
    391 
    392             if (command.equals(COMMAND_EXIT)) {
    393                 if (mDemoStatusIcons != null) {
    394                     mDemoStatusIcons.dispatchDemoCommand(command, args);
    395                     exitDemoMode();
    396                 }
    397                 mIsInDemoMode = false;
    398             } else {
    399                 if (mDemoStatusIcons == null) {
    400                     mIsInDemoMode = true;
    401                     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         }
    415     }
    416 }
    417