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