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 17package com.android.systemui.statusbar; 18 19import android.content.ComponentName; 20import android.graphics.Rect; 21import android.os.Bundle; 22import android.os.Handler; 23import android.os.IBinder; 24import android.os.Message; 25import android.util.Pair; 26 27import com.android.internal.os.SomeArgs; 28import com.android.internal.statusbar.IStatusBar; 29import com.android.internal.statusbar.StatusBarIcon; 30 31/** 32 * This class takes the functions from IStatusBar that come in on 33 * binder pool threads and posts messages to get them onto the main 34 * thread, and calls onto Callbacks. It also takes care of 35 * coalescing these calls so they don't stack up. For the calls 36 * are coalesced, note that they are all idempotent. 37 */ 38public class CommandQueue extends IStatusBar.Stub { 39 private static final int INDEX_MASK = 0xffff; 40 private static final int MSG_SHIFT = 16; 41 private static final int MSG_MASK = 0xffff << MSG_SHIFT; 42 43 private static final int OP_SET_ICON = 1; 44 private static final int OP_REMOVE_ICON = 2; 45 46 private static final int MSG_ICON = 1 << MSG_SHIFT; 47 private static final int MSG_DISABLE = 2 << MSG_SHIFT; 48 private static final int MSG_EXPAND_NOTIFICATIONS = 3 << MSG_SHIFT; 49 private static final int MSG_COLLAPSE_PANELS = 4 << MSG_SHIFT; 50 private static final int MSG_EXPAND_SETTINGS = 5 << MSG_SHIFT; 51 private static final int MSG_SET_SYSTEMUI_VISIBILITY = 6 << MSG_SHIFT; 52 private static final int MSG_TOP_APP_WINDOW_CHANGED = 7 << MSG_SHIFT; 53 private static final int MSG_SHOW_IME_BUTTON = 8 << MSG_SHIFT; 54 private static final int MSG_TOGGLE_RECENT_APPS = 9 << MSG_SHIFT; 55 private static final int MSG_PRELOAD_RECENT_APPS = 10 << MSG_SHIFT; 56 private static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 11 << MSG_SHIFT; 57 private static final int MSG_SET_WINDOW_STATE = 12 << MSG_SHIFT; 58 private static final int MSG_SHOW_RECENT_APPS = 13 << MSG_SHIFT; 59 private static final int MSG_HIDE_RECENT_APPS = 14 << MSG_SHIFT; 60 private static final int MSG_BUZZ_BEEP_BLINKED = 15 << MSG_SHIFT; 61 private static final int MSG_NOTIFICATION_LIGHT_OFF = 16 << MSG_SHIFT; 62 private static final int MSG_NOTIFICATION_LIGHT_PULSE = 17 << MSG_SHIFT; 63 private static final int MSG_SHOW_SCREEN_PIN_REQUEST = 18 << MSG_SHIFT; 64 private static final int MSG_APP_TRANSITION_PENDING = 19 << MSG_SHIFT; 65 private static final int MSG_APP_TRANSITION_CANCELLED = 20 << MSG_SHIFT; 66 private static final int MSG_APP_TRANSITION_STARTING = 21 << MSG_SHIFT; 67 private static final int MSG_ASSIST_DISCLOSURE = 22 << MSG_SHIFT; 68 private static final int MSG_START_ASSIST = 23 << MSG_SHIFT; 69 private static final int MSG_CAMERA_LAUNCH_GESTURE = 24 << MSG_SHIFT; 70 private static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS = 25 << MSG_SHIFT; 71 private static final int MSG_SHOW_TV_PICTURE_IN_PICTURE_MENU = 26 << MSG_SHIFT; 72 private static final int MSG_ADD_QS_TILE = 27 << MSG_SHIFT; 73 private static final int MSG_REMOVE_QS_TILE = 28 << MSG_SHIFT; 74 private static final int MSG_CLICK_QS_TILE = 29 << MSG_SHIFT; 75 private static final int MSG_TOGGLE_APP_SPLIT_SCREEN = 30 << MSG_SHIFT; 76 private static final int MSG_APP_TRANSITION_FINISHED = 31 << MSG_SHIFT; 77 private static final int MSG_DISMISS_KEYBOARD_SHORTCUTS = 32 << MSG_SHIFT; 78 79 public static final int FLAG_EXCLUDE_NONE = 0; 80 public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0; 81 public static final int FLAG_EXCLUDE_RECENTS_PANEL = 1 << 1; 82 public static final int FLAG_EXCLUDE_NOTIFICATION_PANEL = 1 << 2; 83 public static final int FLAG_EXCLUDE_INPUT_METHODS_PANEL = 1 << 3; 84 public static final int FLAG_EXCLUDE_COMPAT_MODE_PANEL = 1 << 4; 85 86 private static final String SHOW_IME_SWITCHER_KEY = "showImeSwitcherKey"; 87 88 private final Object mLock = new Object(); 89 private Callbacks mCallbacks; 90 private Handler mHandler = new H(); 91 92 /** 93 * These methods are called back on the main thread. 94 */ 95 public interface Callbacks { 96 void setIcon(String slot, StatusBarIcon icon); 97 void removeIcon(String slot); 98 void disable(int state1, int state2, boolean animate); 99 void animateExpandNotificationsPanel(); 100 void animateCollapsePanels(int flags); 101 void animateExpandSettingsPanel(String obj); 102 void setSystemUiVisibility(int vis, int fullscreenStackVis, 103 int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds); 104 void topAppWindowChanged(boolean visible); 105 void setImeWindowStatus(IBinder token, int vis, int backDisposition, 106 boolean showImeSwitcher); 107 void showRecentApps(boolean triggeredFromAltTab, boolean fromHome); 108 void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey); 109 void toggleRecentApps(); 110 void toggleSplitScreen(); 111 void preloadRecentApps(); 112 void dismissKeyboardShortcutsMenu(); 113 void toggleKeyboardShortcutsMenu(int deviceId); 114 void cancelPreloadRecentApps(); 115 void setWindowState(int window, int state); 116 void buzzBeepBlinked(); 117 void notificationLightOff(); 118 void notificationLightPulse(int argb, int onMillis, int offMillis); 119 void showScreenPinningRequest(int taskId); 120 void appTransitionPending(); 121 void appTransitionCancelled(); 122 void appTransitionStarting(long startTime, long duration); 123 void appTransitionFinished(); 124 void showAssistDisclosure(); 125 void startAssist(Bundle args); 126 void onCameraLaunchGestureDetected(int source); 127 void showTvPictureInPictureMenu(); 128 129 void addQsTile(ComponentName tile); 130 void remQsTile(ComponentName tile); 131 void clickTile(ComponentName tile); 132 } 133 134 public CommandQueue(Callbacks callbacks) { 135 mCallbacks = callbacks; 136 } 137 138 public void setIcon(String slot, StatusBarIcon icon) { 139 synchronized (mLock) { 140 // don't coalesce these 141 mHandler.obtainMessage(MSG_ICON, OP_SET_ICON, 0, 142 new Pair<String, StatusBarIcon>(slot, icon)).sendToTarget(); 143 } 144 } 145 146 public void removeIcon(String slot) { 147 synchronized (mLock) { 148 // don't coalesce these 149 mHandler.obtainMessage(MSG_ICON, OP_REMOVE_ICON, 0, slot).sendToTarget(); 150 } 151 } 152 153 public void disable(int state1, int state2) { 154 synchronized (mLock) { 155 mHandler.removeMessages(MSG_DISABLE); 156 mHandler.obtainMessage(MSG_DISABLE, state1, state2, null).sendToTarget(); 157 } 158 } 159 160 public void animateExpandNotificationsPanel() { 161 synchronized (mLock) { 162 mHandler.removeMessages(MSG_EXPAND_NOTIFICATIONS); 163 mHandler.sendEmptyMessage(MSG_EXPAND_NOTIFICATIONS); 164 } 165 } 166 167 public void animateCollapsePanels() { 168 synchronized (mLock) { 169 mHandler.removeMessages(MSG_COLLAPSE_PANELS); 170 mHandler.sendEmptyMessage(MSG_COLLAPSE_PANELS); 171 } 172 } 173 174 public void animateExpandSettingsPanel(String subPanel) { 175 synchronized (mLock) { 176 mHandler.removeMessages(MSG_EXPAND_SETTINGS); 177 mHandler.obtainMessage(MSG_EXPAND_SETTINGS, subPanel).sendToTarget(); 178 } 179 } 180 181 public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, 182 int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) { 183 synchronized (mLock) { 184 // Don't coalesce these, since it might have one time flags set such as 185 // STATUS_BAR_UNHIDE which might get lost. 186 SomeArgs args = SomeArgs.obtain(); 187 args.argi1 = vis; 188 args.argi2 = fullscreenStackVis; 189 args.argi3 = dockedStackVis; 190 args.argi4 = mask; 191 args.arg1 = fullscreenStackBounds; 192 args.arg2 = dockedStackBounds; 193 mHandler.obtainMessage(MSG_SET_SYSTEMUI_VISIBILITY, args).sendToTarget(); 194 } 195 } 196 197 public void topAppWindowChanged(boolean menuVisible) { 198 synchronized (mLock) { 199 mHandler.removeMessages(MSG_TOP_APP_WINDOW_CHANGED); 200 mHandler.obtainMessage(MSG_TOP_APP_WINDOW_CHANGED, menuVisible ? 1 : 0, 0, 201 null).sendToTarget(); 202 } 203 } 204 205 public void setImeWindowStatus(IBinder token, int vis, int backDisposition, 206 boolean showImeSwitcher) { 207 synchronized (mLock) { 208 mHandler.removeMessages(MSG_SHOW_IME_BUTTON); 209 Message m = mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, vis, backDisposition, token); 210 m.getData().putBoolean(SHOW_IME_SWITCHER_KEY, showImeSwitcher); 211 m.sendToTarget(); 212 } 213 } 214 215 public void showRecentApps(boolean triggeredFromAltTab, boolean fromHome) { 216 synchronized (mLock) { 217 mHandler.removeMessages(MSG_SHOW_RECENT_APPS); 218 mHandler.obtainMessage(MSG_SHOW_RECENT_APPS, 219 triggeredFromAltTab ? 1 : 0, fromHome ? 1 : 0, null).sendToTarget(); 220 } 221 } 222 223 public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { 224 synchronized (mLock) { 225 mHandler.removeMessages(MSG_HIDE_RECENT_APPS); 226 mHandler.obtainMessage(MSG_HIDE_RECENT_APPS, 227 triggeredFromAltTab ? 1 : 0, triggeredFromHomeKey ? 1 : 0, 228 null).sendToTarget(); 229 } 230 } 231 232 public void toggleSplitScreen() { 233 synchronized (mLock) { 234 mHandler.removeMessages(MSG_TOGGLE_APP_SPLIT_SCREEN); 235 mHandler.obtainMessage(MSG_TOGGLE_APP_SPLIT_SCREEN, 0, 0, null).sendToTarget(); 236 } 237 } 238 239 public void toggleRecentApps() { 240 synchronized (mLock) { 241 mHandler.removeMessages(MSG_TOGGLE_RECENT_APPS); 242 mHandler.obtainMessage(MSG_TOGGLE_RECENT_APPS, 0, 0, null).sendToTarget(); 243 } 244 } 245 246 public void preloadRecentApps() { 247 synchronized (mLock) { 248 mHandler.removeMessages(MSG_PRELOAD_RECENT_APPS); 249 mHandler.obtainMessage(MSG_PRELOAD_RECENT_APPS, 0, 0, null).sendToTarget(); 250 } 251 } 252 253 public void cancelPreloadRecentApps() { 254 synchronized (mLock) { 255 mHandler.removeMessages(MSG_CANCEL_PRELOAD_RECENT_APPS); 256 mHandler.obtainMessage(MSG_CANCEL_PRELOAD_RECENT_APPS, 0, 0, null).sendToTarget(); 257 } 258 } 259 260 @Override 261 public void dismissKeyboardShortcutsMenu() { 262 synchronized (mLock) { 263 mHandler.removeMessages(MSG_DISMISS_KEYBOARD_SHORTCUTS); 264 mHandler.obtainMessage(MSG_DISMISS_KEYBOARD_SHORTCUTS).sendToTarget(); 265 } 266 } 267 268 @Override 269 public void toggleKeyboardShortcutsMenu(int deviceId) { 270 synchronized (mLock) { 271 mHandler.removeMessages(MSG_TOGGLE_KEYBOARD_SHORTCUTS); 272 mHandler.obtainMessage(MSG_TOGGLE_KEYBOARD_SHORTCUTS, deviceId, 0).sendToTarget(); 273 } 274 } 275 276 @Override 277 public void showTvPictureInPictureMenu() { 278 synchronized (mLock) { 279 mHandler.removeMessages(MSG_SHOW_TV_PICTURE_IN_PICTURE_MENU); 280 mHandler.obtainMessage(MSG_SHOW_TV_PICTURE_IN_PICTURE_MENU).sendToTarget(); 281 } 282 } 283 284 public void setWindowState(int window, int state) { 285 synchronized (mLock) { 286 // don't coalesce these 287 mHandler.obtainMessage(MSG_SET_WINDOW_STATE, window, state, null).sendToTarget(); 288 } 289 } 290 291 public void buzzBeepBlinked() { 292 synchronized (mLock) { 293 mHandler.removeMessages(MSG_BUZZ_BEEP_BLINKED); 294 mHandler.sendEmptyMessage(MSG_BUZZ_BEEP_BLINKED); 295 } 296 } 297 298 public void notificationLightOff() { 299 synchronized (mLock) { 300 mHandler.sendEmptyMessage(MSG_NOTIFICATION_LIGHT_OFF); 301 } 302 } 303 304 public void notificationLightPulse(int argb, int onMillis, int offMillis) { 305 synchronized (mLock) { 306 mHandler.obtainMessage(MSG_NOTIFICATION_LIGHT_PULSE, onMillis, offMillis, argb) 307 .sendToTarget(); 308 } 309 } 310 311 public void showScreenPinningRequest(int taskId) { 312 synchronized (mLock) { 313 mHandler.obtainMessage(MSG_SHOW_SCREEN_PIN_REQUEST, taskId, 0, null) 314 .sendToTarget(); 315 } 316 } 317 318 public void appTransitionPending() { 319 synchronized (mLock) { 320 mHandler.removeMessages(MSG_APP_TRANSITION_PENDING); 321 mHandler.sendEmptyMessage(MSG_APP_TRANSITION_PENDING); 322 } 323 } 324 325 public void appTransitionCancelled() { 326 synchronized (mLock) { 327 mHandler.removeMessages(MSG_APP_TRANSITION_PENDING); 328 mHandler.sendEmptyMessage(MSG_APP_TRANSITION_PENDING); 329 } 330 } 331 332 public void appTransitionStarting(long startTime, long duration) { 333 synchronized (mLock) { 334 mHandler.removeMessages(MSG_APP_TRANSITION_STARTING); 335 mHandler.obtainMessage(MSG_APP_TRANSITION_STARTING, Pair.create(startTime, duration)) 336 .sendToTarget(); 337 } 338 } 339 340 @Override 341 public void appTransitionFinished() { 342 synchronized (mLock) { 343 mHandler.removeMessages(MSG_APP_TRANSITION_FINISHED); 344 mHandler.sendEmptyMessage(MSG_APP_TRANSITION_FINISHED); 345 } 346 } 347 348 public void showAssistDisclosure() { 349 synchronized (mLock) { 350 mHandler.removeMessages(MSG_ASSIST_DISCLOSURE); 351 mHandler.obtainMessage(MSG_ASSIST_DISCLOSURE).sendToTarget(); 352 } 353 } 354 355 public void startAssist(Bundle args) { 356 synchronized (mLock) { 357 mHandler.removeMessages(MSG_START_ASSIST); 358 mHandler.obtainMessage(MSG_START_ASSIST, args).sendToTarget(); 359 } 360 } 361 362 @Override 363 public void onCameraLaunchGestureDetected(int source) { 364 synchronized (mLock) { 365 mHandler.removeMessages(MSG_CAMERA_LAUNCH_GESTURE); 366 mHandler.obtainMessage(MSG_CAMERA_LAUNCH_GESTURE, source, 0).sendToTarget(); 367 } 368 } 369 370 @Override 371 public void addQsTile(ComponentName tile) { 372 synchronized (mLock) { 373 mHandler.obtainMessage(MSG_ADD_QS_TILE, tile).sendToTarget(); 374 } 375 } 376 377 @Override 378 public void remQsTile(ComponentName tile) { 379 synchronized (mLock) { 380 mHandler.obtainMessage(MSG_REMOVE_QS_TILE, tile).sendToTarget(); 381 } 382 } 383 384 @Override 385 public void clickQsTile(ComponentName tile) { 386 synchronized (mLock) { 387 mHandler.obtainMessage(MSG_CLICK_QS_TILE, tile).sendToTarget(); 388 } 389 } 390 391 private final class H extends Handler { 392 public void handleMessage(Message msg) { 393 final int what = msg.what & MSG_MASK; 394 switch (what) { 395 case MSG_ICON: { 396 switch (msg.arg1) { 397 case OP_SET_ICON: { 398 Pair<String, StatusBarIcon> p = (Pair<String, StatusBarIcon>) msg.obj; 399 mCallbacks.setIcon(p.first, p.second); 400 break; 401 } 402 case OP_REMOVE_ICON: 403 mCallbacks.removeIcon((String) msg.obj); 404 break; 405 } 406 break; 407 } 408 case MSG_DISABLE: 409 mCallbacks.disable(msg.arg1, msg.arg2, true /* animate */); 410 break; 411 case MSG_EXPAND_NOTIFICATIONS: 412 mCallbacks.animateExpandNotificationsPanel(); 413 break; 414 case MSG_COLLAPSE_PANELS: 415 mCallbacks.animateCollapsePanels(0); 416 break; 417 case MSG_EXPAND_SETTINGS: 418 mCallbacks.animateExpandSettingsPanel((String) msg.obj); 419 break; 420 case MSG_SET_SYSTEMUI_VISIBILITY: 421 SomeArgs args = (SomeArgs) msg.obj; 422 mCallbacks.setSystemUiVisibility(args.argi1, args.argi2, args.argi3, 423 args.argi4, (Rect) args.arg1, (Rect) args.arg2); 424 args.recycle(); 425 break; 426 case MSG_TOP_APP_WINDOW_CHANGED: 427 mCallbacks.topAppWindowChanged(msg.arg1 != 0); 428 break; 429 case MSG_SHOW_IME_BUTTON: 430 mCallbacks.setImeWindowStatus((IBinder) msg.obj, msg.arg1, msg.arg2, 431 msg.getData().getBoolean(SHOW_IME_SWITCHER_KEY, false)); 432 break; 433 case MSG_SHOW_RECENT_APPS: 434 mCallbacks.showRecentApps(msg.arg1 != 0, msg.arg2 != 0); 435 break; 436 case MSG_HIDE_RECENT_APPS: 437 mCallbacks.hideRecentApps(msg.arg1 != 0, msg.arg2 != 0); 438 break; 439 case MSG_TOGGLE_RECENT_APPS: 440 mCallbacks.toggleRecentApps(); 441 break; 442 case MSG_PRELOAD_RECENT_APPS: 443 mCallbacks.preloadRecentApps(); 444 break; 445 case MSG_CANCEL_PRELOAD_RECENT_APPS: 446 mCallbacks.cancelPreloadRecentApps(); 447 break; 448 case MSG_DISMISS_KEYBOARD_SHORTCUTS: 449 mCallbacks.dismissKeyboardShortcutsMenu(); 450 break; 451 case MSG_TOGGLE_KEYBOARD_SHORTCUTS: 452 mCallbacks.toggleKeyboardShortcutsMenu(msg.arg1); 453 break; 454 case MSG_SET_WINDOW_STATE: 455 mCallbacks.setWindowState(msg.arg1, msg.arg2); 456 break; 457 case MSG_BUZZ_BEEP_BLINKED: 458 mCallbacks.buzzBeepBlinked(); 459 break; 460 case MSG_NOTIFICATION_LIGHT_OFF: 461 mCallbacks.notificationLightOff(); 462 break; 463 case MSG_NOTIFICATION_LIGHT_PULSE: 464 mCallbacks.notificationLightPulse((Integer) msg.obj, msg.arg1, msg.arg2); 465 break; 466 case MSG_SHOW_SCREEN_PIN_REQUEST: 467 mCallbacks.showScreenPinningRequest(msg.arg1); 468 break; 469 case MSG_APP_TRANSITION_PENDING: 470 mCallbacks.appTransitionPending(); 471 break; 472 case MSG_APP_TRANSITION_CANCELLED: 473 mCallbacks.appTransitionCancelled(); 474 break; 475 case MSG_APP_TRANSITION_STARTING: 476 Pair<Long, Long> data = (Pair<Long, Long>) msg.obj; 477 mCallbacks.appTransitionStarting(data.first, data.second); 478 break; 479 case MSG_APP_TRANSITION_FINISHED: 480 mCallbacks.appTransitionFinished(); 481 break; 482 case MSG_ASSIST_DISCLOSURE: 483 mCallbacks.showAssistDisclosure(); 484 break; 485 case MSG_START_ASSIST: 486 mCallbacks.startAssist((Bundle) msg.obj); 487 break; 488 case MSG_CAMERA_LAUNCH_GESTURE: 489 mCallbacks.onCameraLaunchGestureDetected(msg.arg1); 490 break; 491 case MSG_SHOW_TV_PICTURE_IN_PICTURE_MENU: 492 mCallbacks.showTvPictureInPictureMenu(); 493 break; 494 case MSG_ADD_QS_TILE: 495 mCallbacks.addQsTile((ComponentName) msg.obj); 496 break; 497 case MSG_REMOVE_QS_TILE: 498 mCallbacks.remQsTile((ComponentName) msg.obj); 499 break; 500 case MSG_CLICK_QS_TILE: 501 mCallbacks.clickTile((ComponentName) msg.obj); 502 break; 503 case MSG_TOGGLE_APP_SPLIT_SCREEN: 504 mCallbacks.toggleSplitScreen(); 505 break; 506 } 507 } 508 } 509} 510 511