1 /* 2 * Copyright (C) 2017 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 17 package com.android.systemui.statusbar.phone; 18 19 import android.content.Context; 20 import android.graphics.drawable.Icon; 21 import android.os.Bundle; 22 import android.os.UserHandle; 23 import android.util.ArraySet; 24 import android.view.ViewGroup; 25 import android.widget.LinearLayout; 26 27 import com.android.internal.statusbar.StatusBarIcon; 28 import com.android.systemui.Dependency; 29 import com.android.systemui.Dumpable; 30 import com.android.systemui.R; 31 import com.android.systemui.SysUiServiceProvider; 32 import com.android.systemui.statusbar.CommandQueue; 33 import com.android.systemui.statusbar.StatusBarIconView; 34 import com.android.systemui.statusbar.policy.ConfigurationController; 35 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; 36 import com.android.systemui.statusbar.policy.DarkIconDispatcher; 37 import com.android.systemui.statusbar.policy.IconLogger; 38 import com.android.systemui.tuner.TunerService; 39 import com.android.systemui.tuner.TunerService.Tunable; 40 41 import java.io.FileDescriptor; 42 import java.io.PrintWriter; 43 import java.util.ArrayList; 44 45 /** 46 * Receives the callbacks from CommandQueue related to icons and tracks the state of 47 * all the icons. Dispatches this state to any IconManagers that are currently 48 * registered with it. 49 */ 50 public class StatusBarIconControllerImpl extends StatusBarIconList implements Tunable, 51 ConfigurationListener, Dumpable, CommandQueue.Callbacks, StatusBarIconController { 52 53 private final DarkIconDispatcher mDarkIconDispatcher; 54 55 private Context mContext; 56 private DemoStatusIcons mDemoStatusIcons; 57 58 private final ArrayList<IconManager> mIconGroups = new ArrayList<>(); 59 60 private final ArraySet<String> mIconBlacklist = new ArraySet<>(); 61 private final IconLogger mIconLogger = Dependency.get(IconLogger.class); 62 63 public StatusBarIconControllerImpl(Context context) { 64 super(context.getResources().getStringArray( 65 com.android.internal.R.array.config_statusBarIcons)); 66 Dependency.get(ConfigurationController.class).addCallback(this); 67 mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class); 68 mContext = context; 69 70 loadDimens(); 71 72 SysUiServiceProvider.getComponent(context, CommandQueue.class) 73 .addCallbacks(this); 74 Dependency.get(TunerService.class).addTunable(this, ICON_BLACKLIST); 75 } 76 77 @Override 78 public void addIconGroup(IconManager group) { 79 mIconGroups.add(group); 80 for (int i = 0; i < mIcons.size(); i++) { 81 StatusBarIcon icon = mIcons.get(i); 82 if (icon != null) { 83 String slot = mSlots.get(i); 84 boolean blocked = mIconBlacklist.contains(slot); 85 group.onIconAdded(getViewIndex(getSlotIndex(slot)), slot, blocked, icon); 86 } 87 } 88 } 89 90 @Override 91 public void removeIconGroup(IconManager group) { 92 group.destroy(); 93 mIconGroups.remove(group); 94 } 95 96 @Override 97 public void onTuningChanged(String key, String newValue) { 98 if (!ICON_BLACKLIST.equals(key)) { 99 return; 100 } 101 mIconBlacklist.clear(); 102 mIconBlacklist.addAll(StatusBarIconController.getIconBlacklist(newValue)); 103 ArrayList<StatusBarIcon> current = new ArrayList<>(mIcons); 104 ArrayList<String> currentSlots = new ArrayList<>(mSlots); 105 // Remove all the icons. 106 for (int i = current.size() - 1; i >= 0; i--) { 107 removeIcon(currentSlots.get(i)); 108 } 109 // Add them all back 110 for (int i = 0; i < current.size(); i++) { 111 setIcon(currentSlots.get(i), current.get(i)); 112 } 113 } 114 115 private void loadDimens() { 116 } 117 118 private void addSystemIcon(int index, StatusBarIcon icon) { 119 String slot = getSlot(index); 120 int viewIndex = getViewIndex(index); 121 boolean blocked = mIconBlacklist.contains(slot); 122 123 mIconLogger.onIconVisibility(getSlot(index), icon.visible); 124 mIconGroups.forEach(l -> l.onIconAdded(viewIndex, slot, blocked, icon)); 125 } 126 127 @Override 128 public void setIcon(String slot, int resourceId, CharSequence contentDescription) { 129 int index = getSlotIndex(slot); 130 StatusBarIcon icon = getIcon(index); 131 if (icon == null) { 132 icon = new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(), 133 Icon.createWithResource(mContext, resourceId), 0, 0, contentDescription); 134 setIcon(slot, icon); 135 } else { 136 icon.icon = Icon.createWithResource(mContext, resourceId); 137 icon.contentDescription = contentDescription; 138 handleSet(index, icon); 139 } 140 } 141 142 @Override 143 public void setExternalIcon(String slot) { 144 int viewIndex = getViewIndex(getSlotIndex(slot)); 145 int height = mContext.getResources().getDimensionPixelSize( 146 R.dimen.status_bar_icon_drawing_size); 147 mIconGroups.forEach(l -> l.onIconExternal(viewIndex, height)); 148 } 149 150 @Override 151 public void setIcon(String slot, StatusBarIcon icon) { 152 setIcon(getSlotIndex(slot), icon); 153 } 154 155 @Override 156 public void removeIcon(String slot) { 157 int index = getSlotIndex(slot); 158 removeIcon(index); 159 } 160 161 public void setIconVisibility(String slot, boolean visibility) { 162 int index = getSlotIndex(slot); 163 StatusBarIcon icon = getIcon(index); 164 if (icon == null || icon.visible == visibility) { 165 return; 166 } 167 icon.visible = visibility; 168 handleSet(index, icon); 169 } 170 171 @Override 172 public void removeIcon(int index) { 173 if (getIcon(index) == null) { 174 return; 175 } 176 mIconLogger.onIconHidden(getSlot(index)); 177 super.removeIcon(index); 178 int viewIndex = getViewIndex(index); 179 mIconGroups.forEach(l -> l.onRemoveIcon(viewIndex)); 180 } 181 182 @Override 183 public void setIcon(int index, StatusBarIcon icon) { 184 if (icon == null) { 185 removeIcon(index); 186 return; 187 } 188 boolean isNew = getIcon(index) == null; 189 super.setIcon(index, icon); 190 if (isNew) { 191 addSystemIcon(index, icon); 192 } else { 193 handleSet(index, icon); 194 } 195 } 196 197 private void handleSet(int index, StatusBarIcon icon) { 198 int viewIndex = getViewIndex(index); 199 mIconLogger.onIconVisibility(getSlot(index), icon.visible); 200 mIconGroups.forEach(l -> l.onSetIcon(viewIndex, icon)); 201 } 202 203 @Override 204 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 205 // TODO: Dump info about all icon groups? 206 ViewGroup statusIcons = mIconGroups.get(0).mGroup; 207 int N = statusIcons.getChildCount(); 208 pw.println(" icon views: " + N); 209 for (int i = 0; i < N; i++) { 210 StatusBarIconView ic = (StatusBarIconView) statusIcons.getChildAt(i); 211 pw.println(" [" + i + "] icon=" + ic); 212 } 213 super.dump(pw); 214 } 215 216 public void dispatchDemoCommand(String command, Bundle args) { 217 if (mDemoStatusIcons == null) { 218 // TODO: Rework how we handle demo mode. 219 int iconSize = mContext.getResources().getDimensionPixelSize( 220 com.android.internal.R.dimen.status_bar_icon_size); 221 mDemoStatusIcons = new DemoStatusIcons((LinearLayout) mIconGroups.get(0).mGroup, 222 iconSize); 223 } 224 mDemoStatusIcons.dispatchDemoCommand(command, args); 225 } 226 227 @Override 228 public void onDensityOrFontScaleChanged() { 229 loadDimens(); 230 } 231 } 232