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