1 /* 2 * Copyright (C) 2010 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; 18 19 import android.os.Handler; 20 import android.os.IBinder; 21 import android.os.Message; 22 23 import com.android.internal.statusbar.IStatusBar; 24 import com.android.internal.statusbar.StatusBarIcon; 25 import com.android.internal.statusbar.StatusBarIconList; 26 27 /** 28 * This class takes the functions from IStatusBar that come in on 29 * binder pool threads and posts messages to get them onto the main 30 * thread, and calls onto Callbacks. It also takes care of 31 * coalescing these calls so they don't stack up. For the calls 32 * are coalesced, note that they are all idempotent. 33 */ 34 public class CommandQueue extends IStatusBar.Stub { 35 private static final int INDEX_MASK = 0xffff; 36 private static final int MSG_SHIFT = 16; 37 private static final int MSG_MASK = 0xffff << MSG_SHIFT; 38 39 private static final int OP_SET_ICON = 1; 40 private static final int OP_REMOVE_ICON = 2; 41 42 private static final int MSG_ICON = 1 << MSG_SHIFT; 43 private static final int MSG_DISABLE = 2 << MSG_SHIFT; 44 private static final int MSG_EXPAND_NOTIFICATIONS = 3 << MSG_SHIFT; 45 private static final int MSG_COLLAPSE_PANELS = 4 << MSG_SHIFT; 46 private static final int MSG_EXPAND_SETTINGS = 5 << MSG_SHIFT; 47 private static final int MSG_SET_SYSTEMUI_VISIBILITY = 6 << MSG_SHIFT; 48 private static final int MSG_TOP_APP_WINDOW_CHANGED = 7 << MSG_SHIFT; 49 private static final int MSG_SHOW_IME_BUTTON = 8 << MSG_SHIFT; 50 private static final int MSG_TOGGLE_RECENT_APPS = 9 << MSG_SHIFT; 51 private static final int MSG_PRELOAD_RECENT_APPS = 10 << MSG_SHIFT; 52 private static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 11 << MSG_SHIFT; 53 private static final int MSG_SET_WINDOW_STATE = 12 << MSG_SHIFT; 54 private static final int MSG_SHOW_RECENT_APPS = 13 << MSG_SHIFT; 55 private static final int MSG_HIDE_RECENT_APPS = 14 << MSG_SHIFT; 56 private static final int MSG_BUZZ_BEEP_BLINKED = 15 << MSG_SHIFT; 57 private static final int MSG_NOTIFICATION_LIGHT_OFF = 16 << MSG_SHIFT; 58 private static final int MSG_NOTIFICATION_LIGHT_PULSE = 17 << MSG_SHIFT; 59 private static final int MSG_SHOW_SCREEN_PIN_REQUEST = 18 << MSG_SHIFT; 60 61 public static final int FLAG_EXCLUDE_NONE = 0; 62 public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0; 63 public static final int FLAG_EXCLUDE_RECENTS_PANEL = 1 << 1; 64 public static final int FLAG_EXCLUDE_NOTIFICATION_PANEL = 1 << 2; 65 public static final int FLAG_EXCLUDE_INPUT_METHODS_PANEL = 1 << 3; 66 public static final int FLAG_EXCLUDE_COMPAT_MODE_PANEL = 1 << 4; 67 68 private static final String SHOW_IME_SWITCHER_KEY = "showImeSwitcherKey"; 69 70 private StatusBarIconList mList; 71 private Callbacks mCallbacks; 72 private Handler mHandler = new H(); 73 74 /** 75 * These methods are called back on the main thread. 76 */ 77 public interface Callbacks { 78 public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon); 79 public void updateIcon(String slot, int index, int viewIndex, 80 StatusBarIcon old, StatusBarIcon icon); 81 public void removeIcon(String slot, int index, int viewIndex); 82 public void disable(int state, boolean animate); 83 public void animateExpandNotificationsPanel(); 84 public void animateCollapsePanels(int flags); 85 public void animateExpandSettingsPanel(); 86 public void setSystemUiVisibility(int vis, int mask); 87 public void topAppWindowChanged(boolean visible); 88 public void setImeWindowStatus(IBinder token, int vis, int backDisposition, 89 boolean showImeSwitcher); 90 public void showRecentApps(boolean triggeredFromAltTab); 91 public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey); 92 public void toggleRecentApps(); 93 public void preloadRecentApps(); 94 public void cancelPreloadRecentApps(); 95 public void showSearchPanel(); 96 public void hideSearchPanel(); 97 public void setWindowState(int window, int state); 98 public void buzzBeepBlinked(); 99 public void notificationLightOff(); 100 public void notificationLightPulse(int argb, int onMillis, int offMillis); 101 public void showScreenPinningRequest(); 102 } 103 104 public CommandQueue(Callbacks callbacks, StatusBarIconList list) { 105 mCallbacks = callbacks; 106 mList = list; 107 } 108 109 public void setIcon(int index, StatusBarIcon icon) { 110 synchronized (mList) { 111 int what = MSG_ICON | index; 112 mHandler.removeMessages(what); 113 mHandler.obtainMessage(what, OP_SET_ICON, 0, icon.clone()).sendToTarget(); 114 } 115 } 116 117 public void removeIcon(int index) { 118 synchronized (mList) { 119 int what = MSG_ICON | index; 120 mHandler.removeMessages(what); 121 mHandler.obtainMessage(what, OP_REMOVE_ICON, 0, null).sendToTarget(); 122 } 123 } 124 125 public void disable(int state) { 126 synchronized (mList) { 127 mHandler.removeMessages(MSG_DISABLE); 128 mHandler.obtainMessage(MSG_DISABLE, state, 0, null).sendToTarget(); 129 } 130 } 131 132 public void animateExpandNotificationsPanel() { 133 synchronized (mList) { 134 mHandler.removeMessages(MSG_EXPAND_NOTIFICATIONS); 135 mHandler.sendEmptyMessage(MSG_EXPAND_NOTIFICATIONS); 136 } 137 } 138 139 public void animateCollapsePanels() { 140 synchronized (mList) { 141 mHandler.removeMessages(MSG_COLLAPSE_PANELS); 142 mHandler.sendEmptyMessage(MSG_COLLAPSE_PANELS); 143 } 144 } 145 146 public void animateExpandSettingsPanel() { 147 synchronized (mList) { 148 mHandler.removeMessages(MSG_EXPAND_SETTINGS); 149 mHandler.sendEmptyMessage(MSG_EXPAND_SETTINGS); 150 } 151 } 152 153 public void setSystemUiVisibility(int vis, int mask) { 154 synchronized (mList) { 155 mHandler.removeMessages(MSG_SET_SYSTEMUI_VISIBILITY); 156 mHandler.obtainMessage(MSG_SET_SYSTEMUI_VISIBILITY, vis, mask, null).sendToTarget(); 157 } 158 } 159 160 public void topAppWindowChanged(boolean menuVisible) { 161 synchronized (mList) { 162 mHandler.removeMessages(MSG_TOP_APP_WINDOW_CHANGED); 163 mHandler.obtainMessage(MSG_TOP_APP_WINDOW_CHANGED, menuVisible ? 1 : 0, 0, 164 null).sendToTarget(); 165 } 166 } 167 168 public void setImeWindowStatus(IBinder token, int vis, int backDisposition, 169 boolean showImeSwitcher) { 170 synchronized (mList) { 171 mHandler.removeMessages(MSG_SHOW_IME_BUTTON); 172 Message m = mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, vis, backDisposition, token); 173 m.getData().putBoolean(SHOW_IME_SWITCHER_KEY, showImeSwitcher); 174 m.sendToTarget(); 175 } 176 } 177 178 public void showRecentApps(boolean triggeredFromAltTab) { 179 synchronized (mList) { 180 mHandler.removeMessages(MSG_SHOW_RECENT_APPS); 181 mHandler.obtainMessage(MSG_SHOW_RECENT_APPS, 182 triggeredFromAltTab ? 1 : 0, 0, null).sendToTarget(); 183 } 184 } 185 186 public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { 187 synchronized (mList) { 188 mHandler.removeMessages(MSG_HIDE_RECENT_APPS); 189 mHandler.obtainMessage(MSG_HIDE_RECENT_APPS, 190 triggeredFromAltTab ? 1 : 0, triggeredFromHomeKey ? 1 : 0, 191 null).sendToTarget(); 192 } 193 } 194 195 public void toggleRecentApps() { 196 synchronized (mList) { 197 mHandler.removeMessages(MSG_TOGGLE_RECENT_APPS); 198 mHandler.obtainMessage(MSG_TOGGLE_RECENT_APPS, 0, 0, null).sendToTarget(); 199 } 200 } 201 202 public void preloadRecentApps() { 203 synchronized (mList) { 204 mHandler.removeMessages(MSG_PRELOAD_RECENT_APPS); 205 mHandler.obtainMessage(MSG_PRELOAD_RECENT_APPS, 0, 0, null).sendToTarget(); 206 } 207 } 208 209 public void cancelPreloadRecentApps() { 210 synchronized (mList) { 211 mHandler.removeMessages(MSG_CANCEL_PRELOAD_RECENT_APPS); 212 mHandler.obtainMessage(MSG_CANCEL_PRELOAD_RECENT_APPS, 0, 0, null).sendToTarget(); 213 } 214 } 215 216 public void setWindowState(int window, int state) { 217 synchronized (mList) { 218 // don't coalesce these 219 mHandler.obtainMessage(MSG_SET_WINDOW_STATE, window, state, null).sendToTarget(); 220 } 221 } 222 223 public void buzzBeepBlinked() { 224 synchronized (mList) { 225 mHandler.removeMessages(MSG_BUZZ_BEEP_BLINKED); 226 mHandler.sendEmptyMessage(MSG_BUZZ_BEEP_BLINKED); 227 } 228 } 229 230 public void notificationLightOff() { 231 synchronized (mList) { 232 mHandler.sendEmptyMessage(MSG_NOTIFICATION_LIGHT_OFF); 233 } 234 } 235 236 public void notificationLightPulse(int argb, int onMillis, int offMillis) { 237 synchronized (mList) { 238 mHandler.obtainMessage(MSG_NOTIFICATION_LIGHT_PULSE, onMillis, offMillis, argb) 239 .sendToTarget(); 240 } 241 } 242 243 public void showScreenPinningRequest() { 244 synchronized (mList) { 245 mHandler.sendEmptyMessage(MSG_SHOW_SCREEN_PIN_REQUEST); 246 } 247 } 248 249 private final class H extends Handler { 250 public void handleMessage(Message msg) { 251 final int what = msg.what & MSG_MASK; 252 switch (what) { 253 case MSG_ICON: { 254 final int index = msg.what & INDEX_MASK; 255 final int viewIndex = mList.getViewIndex(index); 256 switch (msg.arg1) { 257 case OP_SET_ICON: { 258 StatusBarIcon icon = (StatusBarIcon)msg.obj; 259 StatusBarIcon old = mList.getIcon(index); 260 if (old == null) { 261 mList.setIcon(index, icon); 262 mCallbacks.addIcon(mList.getSlot(index), index, viewIndex, icon); 263 } else { 264 mList.setIcon(index, icon); 265 mCallbacks.updateIcon(mList.getSlot(index), index, viewIndex, 266 old, icon); 267 } 268 break; 269 } 270 case OP_REMOVE_ICON: 271 if (mList.getIcon(index) != null) { 272 mList.removeIcon(index); 273 mCallbacks.removeIcon(mList.getSlot(index), index, viewIndex); 274 } 275 break; 276 } 277 break; 278 } 279 case MSG_DISABLE: 280 mCallbacks.disable(msg.arg1, true /* animate */); 281 break; 282 case MSG_EXPAND_NOTIFICATIONS: 283 mCallbacks.animateExpandNotificationsPanel(); 284 break; 285 case MSG_COLLAPSE_PANELS: 286 mCallbacks.animateCollapsePanels(0); 287 break; 288 case MSG_EXPAND_SETTINGS: 289 mCallbacks.animateExpandSettingsPanel(); 290 break; 291 case MSG_SET_SYSTEMUI_VISIBILITY: 292 mCallbacks.setSystemUiVisibility(msg.arg1, msg.arg2); 293 break; 294 case MSG_TOP_APP_WINDOW_CHANGED: 295 mCallbacks.topAppWindowChanged(msg.arg1 != 0); 296 break; 297 case MSG_SHOW_IME_BUTTON: 298 mCallbacks.setImeWindowStatus((IBinder) msg.obj, msg.arg1, msg.arg2, 299 msg.getData().getBoolean(SHOW_IME_SWITCHER_KEY, false)); 300 break; 301 case MSG_SHOW_RECENT_APPS: 302 mCallbacks.showRecentApps(msg.arg1 != 0); 303 break; 304 case MSG_HIDE_RECENT_APPS: 305 mCallbacks.hideRecentApps(msg.arg1 != 0, msg.arg2 != 0); 306 break; 307 case MSG_TOGGLE_RECENT_APPS: 308 mCallbacks.toggleRecentApps(); 309 break; 310 case MSG_PRELOAD_RECENT_APPS: 311 mCallbacks.preloadRecentApps(); 312 break; 313 case MSG_CANCEL_PRELOAD_RECENT_APPS: 314 mCallbacks.cancelPreloadRecentApps(); 315 break; 316 case MSG_SET_WINDOW_STATE: 317 mCallbacks.setWindowState(msg.arg1, msg.arg2); 318 break; 319 case MSG_BUZZ_BEEP_BLINKED: 320 mCallbacks.buzzBeepBlinked(); 321 break; 322 case MSG_NOTIFICATION_LIGHT_OFF: 323 mCallbacks.notificationLightOff(); 324 break; 325 case MSG_NOTIFICATION_LIGHT_PULSE: 326 mCallbacks.notificationLightPulse((Integer) msg.obj, msg.arg1, msg.arg2); 327 break; 328 case MSG_SHOW_SCREEN_PIN_REQUEST: 329 mCallbacks.showScreenPinningRequest(); 330 break; 331 } 332 } 333 } 334 } 335 336