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 static android.app.StatusBarManager.DISABLE2_NONE; 20 import static android.app.StatusBarManager.DISABLE_NONE; 21 import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT; 22 import static android.inputmethodservice.InputMethodService.IME_INVISIBLE; 23 import static android.view.Display.DEFAULT_DISPLAY; 24 import static android.view.Display.INVALID_DISPLAY; 25 26 import static com.android.systemui.statusbar.phone.StatusBar.ONLY_CORE_APPS; 27 28 import android.app.StatusBarManager; 29 import android.app.StatusBarManager.Disable2Flags; 30 import android.app.StatusBarManager.DisableFlags; 31 import android.app.StatusBarManager.WindowType; 32 import android.app.StatusBarManager.WindowVisibleState; 33 import android.content.ComponentName; 34 import android.content.Context; 35 import android.graphics.Rect; 36 import android.hardware.biometrics.IBiometricServiceReceiverInternal; 37 import android.hardware.display.DisplayManager; 38 import android.inputmethodservice.InputMethodService.BackDispositionMode; 39 import android.os.Bundle; 40 import android.os.Handler; 41 import android.os.IBinder; 42 import android.os.Looper; 43 import android.os.Message; 44 import android.util.Pair; 45 import android.util.SparseArray; 46 import android.view.inputmethod.InputMethodSystemProperty; 47 48 import androidx.annotation.VisibleForTesting; 49 50 import com.android.internal.os.SomeArgs; 51 import com.android.internal.statusbar.IStatusBar; 52 import com.android.internal.statusbar.StatusBarIcon; 53 import com.android.systemui.SystemUI; 54 import com.android.systemui.statusbar.CommandQueue.Callbacks; 55 import com.android.systemui.statusbar.policy.CallbackController; 56 57 import java.util.ArrayList; 58 59 /** 60 * This class takes the functions from IStatusBar that come in on 61 * binder pool threads and posts messages to get them onto the main 62 * thread, and calls onto Callbacks. It also takes care of 63 * coalescing these calls so they don't stack up. For the calls 64 * are coalesced, note that they are all idempotent. 65 */ 66 public class CommandQueue extends IStatusBar.Stub implements CallbackController<Callbacks>, 67 DisplayManager.DisplayListener { 68 private static final int INDEX_MASK = 0xffff; 69 private static final int MSG_SHIFT = 16; 70 private static final int MSG_MASK = 0xffff << MSG_SHIFT; 71 72 private static final int OP_SET_ICON = 1; 73 private static final int OP_REMOVE_ICON = 2; 74 75 private static final int MSG_ICON = 1 << MSG_SHIFT; 76 private static final int MSG_DISABLE = 2 << MSG_SHIFT; 77 private static final int MSG_EXPAND_NOTIFICATIONS = 3 << MSG_SHIFT; 78 private static final int MSG_COLLAPSE_PANELS = 4 << MSG_SHIFT; 79 private static final int MSG_EXPAND_SETTINGS = 5 << MSG_SHIFT; 80 private static final int MSG_SET_SYSTEMUI_VISIBILITY = 6 << MSG_SHIFT; 81 private static final int MSG_DISPLAY_READY = 7 << MSG_SHIFT; 82 private static final int MSG_SHOW_IME_BUTTON = 8 << MSG_SHIFT; 83 private static final int MSG_TOGGLE_RECENT_APPS = 9 << MSG_SHIFT; 84 private static final int MSG_PRELOAD_RECENT_APPS = 10 << MSG_SHIFT; 85 private static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 11 << MSG_SHIFT; 86 private static final int MSG_SET_WINDOW_STATE = 12 << MSG_SHIFT; 87 private static final int MSG_SHOW_RECENT_APPS = 13 << MSG_SHIFT; 88 private static final int MSG_HIDE_RECENT_APPS = 14 << MSG_SHIFT; 89 private static final int MSG_SHOW_SCREEN_PIN_REQUEST = 18 << MSG_SHIFT; 90 private static final int MSG_APP_TRANSITION_PENDING = 19 << MSG_SHIFT; 91 private static final int MSG_APP_TRANSITION_CANCELLED = 20 << MSG_SHIFT; 92 private static final int MSG_APP_TRANSITION_STARTING = 21 << MSG_SHIFT; 93 private static final int MSG_ASSIST_DISCLOSURE = 22 << MSG_SHIFT; 94 private static final int MSG_START_ASSIST = 23 << MSG_SHIFT; 95 private static final int MSG_CAMERA_LAUNCH_GESTURE = 24 << MSG_SHIFT; 96 private static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS = 25 << MSG_SHIFT; 97 private static final int MSG_SHOW_PICTURE_IN_PICTURE_MENU = 26 << MSG_SHIFT; 98 private static final int MSG_ADD_QS_TILE = 27 << MSG_SHIFT; 99 private static final int MSG_REMOVE_QS_TILE = 28 << MSG_SHIFT; 100 private static final int MSG_CLICK_QS_TILE = 29 << MSG_SHIFT; 101 private static final int MSG_TOGGLE_APP_SPLIT_SCREEN = 30 << MSG_SHIFT; 102 private static final int MSG_APP_TRANSITION_FINISHED = 31 << MSG_SHIFT; 103 private static final int MSG_DISMISS_KEYBOARD_SHORTCUTS = 32 << MSG_SHIFT; 104 private static final int MSG_HANDLE_SYSTEM_KEY = 33 << MSG_SHIFT; 105 private static final int MSG_SHOW_GLOBAL_ACTIONS = 34 << MSG_SHIFT; 106 private static final int MSG_TOGGLE_PANEL = 35 << MSG_SHIFT; 107 private static final int MSG_SHOW_SHUTDOWN_UI = 36 << MSG_SHIFT; 108 private static final int MSG_SET_TOP_APP_HIDES_STATUS_BAR = 37 << MSG_SHIFT; 109 private static final int MSG_ROTATION_PROPOSAL = 38 << MSG_SHIFT; 110 private static final int MSG_BIOMETRIC_SHOW = 39 << MSG_SHIFT; 111 private static final int MSG_BIOMETRIC_AUTHENTICATED = 40 << MSG_SHIFT; 112 private static final int MSG_BIOMETRIC_HELP = 41 << MSG_SHIFT; 113 private static final int MSG_BIOMETRIC_ERROR = 42 << MSG_SHIFT; 114 private static final int MSG_BIOMETRIC_HIDE = 43 << MSG_SHIFT; 115 private static final int MSG_SHOW_CHARGING_ANIMATION = 44 << MSG_SHIFT; 116 private static final int MSG_SHOW_PINNING_TOAST_ENTER_EXIT = 45 << MSG_SHIFT; 117 private static final int MSG_SHOW_PINNING_TOAST_ESCAPE = 46 << MSG_SHIFT; 118 private static final int MSG_RECENTS_ANIMATION_STATE_CHANGED = 47 << MSG_SHIFT; 119 120 public static final int FLAG_EXCLUDE_NONE = 0; 121 public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0; 122 public static final int FLAG_EXCLUDE_RECENTS_PANEL = 1 << 1; 123 public static final int FLAG_EXCLUDE_NOTIFICATION_PANEL = 1 << 2; 124 public static final int FLAG_EXCLUDE_INPUT_METHODS_PANEL = 1 << 3; 125 public static final int FLAG_EXCLUDE_COMPAT_MODE_PANEL = 1 << 4; 126 127 private static final String SHOW_IME_SWITCHER_KEY = "showImeSwitcherKey"; 128 129 private final Object mLock = new Object(); 130 private ArrayList<Callbacks> mCallbacks = new ArrayList<>(); 131 private Handler mHandler = new H(Looper.getMainLooper()); 132 /** A map of display id - disable flag pair */ 133 private SparseArray<Pair<Integer, Integer>> mDisplayDisabled = new SparseArray<>(); 134 /** 135 * The last ID of the display where IME window for which we received setImeWindowStatus 136 * event. 137 */ 138 private int mLastUpdatedImeDisplayId = INVALID_DISPLAY; 139 140 /** 141 * These methods are called back on the main thread. 142 */ 143 public interface Callbacks { 144 default void setIcon(String slot, StatusBarIcon icon) { } 145 default void removeIcon(String slot) { } 146 147 /** 148 * Called to notify that disable flags are updated. 149 * @see IStatusBar#disable(int, int, int). 150 * 151 * @param displayId The id of the display to notify. 152 * @param state1 The combination of following DISABLE_* flags: 153 * @param state2 The combination of following DISABLE2_* flags: 154 * @param animate {@code true} to show animations. 155 */ 156 default void disable(int displayId, @DisableFlags int state1, @Disable2Flags int state2, 157 boolean animate) { } 158 default void animateExpandNotificationsPanel() { } 159 default void animateCollapsePanels(int flags, boolean force) { } 160 default void togglePanel() { } 161 default void animateExpandSettingsPanel(String obj) { } 162 163 /** 164 * Called to notify visibility flag changes. 165 * @see IStatusBar#setSystemUiVisibility(int, int, int, int, int, Rect, Rect). 166 * 167 * @param displayId The id of the display to notify. 168 * @param vis The visibility flags except SYSTEM_UI_FLAG_LIGHT_STATUS_BAR which will 169 * be reported separately in fullscreenStackVis and dockedStackVis. 170 * @param fullscreenStackVis The flags which only apply in the region of the fullscreen 171 * stack, which is currently only SYSTEM_UI_FLAG_LIGHT_STATUS_BAR. 172 * @param dockedStackVis The flags that only apply in the region of the docked stack, which 173 * is currently only SYSTEM_UI_FLAG_LIGHT_STATUS_BAR. 174 * @param mask Which flags to change. 175 * @param fullscreenStackBounds The current bounds of the fullscreen stack, in screen 176 * coordinates. 177 * @param dockedStackBounds The current bounds of the docked stack, in screen coordinates. 178 * @param navbarColorManagedByIme {@code true} if navigation bar color is managed by IME. 179 */ 180 default void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, 181 int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, 182 boolean navbarColorManagedByIme) { 183 } 184 185 /** 186 * Called to notify IME window status changes. 187 * 188 * @param displayId The id of the display to notify. 189 * @param token IME token. 190 * @param vis IME visibility. 191 * @param backDisposition Disposition mode of back button. It should be one of below flags: 192 * @param showImeSwitcher {@code true} to show IME switch button. 193 */ 194 default void setImeWindowStatus(int displayId, IBinder token, int vis, 195 @BackDispositionMode int backDisposition, boolean showImeSwitcher) { } 196 default void showRecentApps(boolean triggeredFromAltTab) { } 197 default void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { } 198 default void toggleRecentApps() { } 199 default void toggleSplitScreen() { } 200 default void preloadRecentApps() { } 201 default void dismissKeyboardShortcutsMenu() { } 202 default void toggleKeyboardShortcutsMenu(int deviceId) { } 203 default void cancelPreloadRecentApps() { } 204 205 /** 206 * Called to notify window state changes. 207 * @see IStatusBar#setWindowState(int, int, int) 208 * 209 * @param displayId The id of the display to notify. 210 * @param window Window type. It should be one of {@link StatusBarManager#WINDOW_STATUS_BAR} 211 * or {@link StatusBarManager#WINDOW_NAVIGATION_BAR} 212 * @param state Window visible state. 213 */ 214 default void setWindowState(int displayId, @WindowType int window, 215 @WindowVisibleState int state) { } 216 default void showScreenPinningRequest(int taskId) { } 217 218 /** 219 * Called to notify System UI that an application transition is pending. 220 * @see IStatusBar#appTransitionPending(int). 221 * 222 * @param displayId The id of the display to notify. 223 * @param forced {@code true} to force transition pending. 224 */ 225 default void appTransitionPending(int displayId, boolean forced) { } 226 227 /** 228 * Called to notify System UI that an application transition is canceled. 229 * @see IStatusBar#appTransitionCancelled(int). 230 * 231 * @param displayId The id of the display to notify. 232 */ 233 default void appTransitionCancelled(int displayId) { } 234 235 /** 236 * Called to notify System UI that an application transition is starting. 237 * @see IStatusBar#appTransitionStarting(int, long, long). 238 * 239 * @param displayId The id of the display to notify. 240 * @param startTime Transition start time. 241 * @param duration Transition duration. 242 * @param forced {@code true} to force transition pending. 243 */ 244 default void appTransitionStarting( 245 int displayId, long startTime, long duration, boolean forced) { } 246 247 /** 248 * Called to notify System UI that an application transition is finished. 249 * @see IStatusBar#appTransitionFinished(int) 250 * 251 * @param displayId The id of the display to notify. 252 */ 253 default void appTransitionFinished(int displayId) { } 254 default void showAssistDisclosure() { } 255 default void startAssist(Bundle args) { } 256 default void onCameraLaunchGestureDetected(int source) { } 257 default void showPictureInPictureMenu() { } 258 default void setTopAppHidesStatusBar(boolean topAppHidesStatusBar) { } 259 260 default void addQsTile(ComponentName tile) { } 261 default void remQsTile(ComponentName tile) { } 262 default void clickTile(ComponentName tile) { } 263 264 default void handleSystemKey(int arg1) { } 265 default void showPinningEnterExitToast(boolean entering) { } 266 default void showPinningEscapeToast() { } 267 default void handleShowGlobalActionsMenu() { } 268 default void handleShowShutdownUi(boolean isReboot, String reason) { } 269 270 default void showWirelessChargingAnimation(int batteryLevel) { } 271 272 default void onRotationProposal(int rotation, boolean isValid) { } 273 274 default void showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver, 275 int type, boolean requireConfirmation, int userId) { } 276 default void onBiometricAuthenticated(boolean authenticated, String failureReason) { } 277 default void onBiometricHelp(String message) { } 278 default void onBiometricError(String error) { } 279 default void hideBiometricDialog() { } 280 281 /** 282 * @see IStatusBar#onDisplayReady(int) 283 */ 284 default void onDisplayReady(int displayId) { } 285 286 /** 287 * @see DisplayManager.DisplayListener#onDisplayRemoved(int) 288 */ 289 default void onDisplayRemoved(int displayId) { } 290 291 /** 292 * @see IStatusBar#onRecentsAnimationStateChanged(boolean) 293 */ 294 default void onRecentsAnimationStateChanged(boolean running) { } 295 } 296 297 @VisibleForTesting 298 public CommandQueue(Context context) { 299 context.getSystemService(DisplayManager.class).registerDisplayListener(this, mHandler); 300 // We always have default display. 301 setDisabled(DEFAULT_DISPLAY, DISABLE_NONE, DISABLE2_NONE); 302 } 303 304 @Override 305 public void onDisplayAdded(int displayId) { } 306 307 @Override 308 public void onDisplayRemoved(int displayId) { 309 synchronized (mLock) { 310 mDisplayDisabled.remove(displayId); 311 } 312 // This callback is registered with {@link #mHandler} that already posts to run on main 313 // thread, so it is safe to dispatch directly. 314 for (int i = mCallbacks.size() - 1; i >= 0; i--) { 315 mCallbacks.get(i).onDisplayRemoved(displayId); 316 } 317 } 318 319 @Override 320 public void onDisplayChanged(int displayId) { } 321 322 // TODO(b/118592525): add multi-display support if needed. 323 public boolean panelsEnabled() { 324 final int disabled1 = getDisabled1(DEFAULT_DISPLAY); 325 final int disabled2 = getDisabled2(DEFAULT_DISPLAY); 326 return (disabled1 & StatusBarManager.DISABLE_EXPAND) == 0 327 && (disabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0 328 && !ONLY_CORE_APPS; 329 } 330 331 public void addCallback(Callbacks callbacks) { 332 mCallbacks.add(callbacks); 333 // TODO(b/117478341): find a better way to pass disable flags by display. 334 for (int i = 0; i < mDisplayDisabled.size(); i++) { 335 int displayId = mDisplayDisabled.keyAt(i); 336 int disabled1 = getDisabled1(displayId); 337 int disabled2 = getDisabled2(displayId); 338 callbacks.disable(displayId, disabled1, disabled2, false /* animate */); 339 } 340 } 341 342 public void removeCallback(Callbacks callbacks) { 343 mCallbacks.remove(callbacks); 344 } 345 346 public void setIcon(String slot, StatusBarIcon icon) { 347 synchronized (mLock) { 348 // don't coalesce these 349 mHandler.obtainMessage(MSG_ICON, OP_SET_ICON, 0, 350 new Pair<String, StatusBarIcon>(slot, icon)).sendToTarget(); 351 } 352 } 353 354 public void removeIcon(String slot) { 355 synchronized (mLock) { 356 // don't coalesce these 357 mHandler.obtainMessage(MSG_ICON, OP_REMOVE_ICON, 0, slot).sendToTarget(); 358 } 359 } 360 361 /** 362 * Called to notify that disable flags are updated. 363 * @see Callbacks#disable(int, int, int, boolean). 364 */ 365 public void disable(int displayId, @DisableFlags int state1, @Disable2Flags int state2, 366 boolean animate) { 367 synchronized (mLock) { 368 setDisabled(displayId, state1, state2); 369 mHandler.removeMessages(MSG_DISABLE); 370 final SomeArgs args = SomeArgs.obtain(); 371 args.argi1 = displayId; 372 args.argi2 = state1; 373 args.argi3 = state2; 374 args.argi4 = animate ? 1 : 0; 375 Message msg = mHandler.obtainMessage(MSG_DISABLE, args); 376 if (Looper.myLooper() == mHandler.getLooper()) { 377 // If its the right looper execute immediately so hides can be handled quickly. 378 mHandler.handleMessage(msg); 379 msg.recycle(); 380 } else { 381 msg.sendToTarget(); 382 } 383 } 384 } 385 386 @Override 387 public void disable(int displayId, @DisableFlags int state1, @Disable2Flags int state2) { 388 disable(displayId, state1, state2, true); 389 } 390 391 /** 392 * Apply current disable flags by {@link CommandQueue#disable(int, int, int, boolean)}. 393 * 394 * @param displayId The id of the display to notify. 395 * @param animate {@code true} to show animations. 396 */ 397 public void recomputeDisableFlags(int displayId, boolean animate) { 398 int disabled1 = getDisabled1(displayId); 399 int disabled2 = getDisabled2(displayId); 400 disable(displayId, disabled1, disabled2, animate); 401 } 402 403 private void setDisabled(int displayId, int disabled1, int disabled2) { 404 mDisplayDisabled.put(displayId, new Pair<>(disabled1, disabled2)); 405 } 406 407 private int getDisabled1(int displayId) { 408 return getDisabled(displayId).first; 409 } 410 411 private int getDisabled2(int displayId) { 412 return getDisabled(displayId).second; 413 } 414 415 private Pair<Integer, Integer> getDisabled(int displayId) { 416 Pair<Integer, Integer> disablePair = mDisplayDisabled.get(displayId); 417 if (disablePair == null) { 418 disablePair = new Pair<>(DISABLE_NONE, DISABLE2_NONE); 419 mDisplayDisabled.put(displayId, disablePair); 420 } 421 return disablePair; 422 } 423 424 public void animateExpandNotificationsPanel() { 425 synchronized (mLock) { 426 mHandler.removeMessages(MSG_EXPAND_NOTIFICATIONS); 427 mHandler.sendEmptyMessage(MSG_EXPAND_NOTIFICATIONS); 428 } 429 } 430 431 public void animateCollapsePanels() { 432 synchronized (mLock) { 433 mHandler.removeMessages(MSG_COLLAPSE_PANELS); 434 mHandler.obtainMessage(MSG_COLLAPSE_PANELS, 0, 0).sendToTarget(); 435 } 436 } 437 438 public void animateCollapsePanels(int flags, boolean force) { 439 synchronized (mLock) { 440 mHandler.removeMessages(MSG_COLLAPSE_PANELS); 441 mHandler.obtainMessage(MSG_COLLAPSE_PANELS, flags, force ? 1 : 0).sendToTarget(); 442 } 443 } 444 445 public void togglePanel() { 446 synchronized (mLock) { 447 mHandler.removeMessages(MSG_TOGGLE_PANEL); 448 mHandler.obtainMessage(MSG_TOGGLE_PANEL, 0, 0).sendToTarget(); 449 } 450 } 451 452 public void animateExpandSettingsPanel(String subPanel) { 453 synchronized (mLock) { 454 mHandler.removeMessages(MSG_EXPAND_SETTINGS); 455 mHandler.obtainMessage(MSG_EXPAND_SETTINGS, subPanel).sendToTarget(); 456 } 457 } 458 459 @Override 460 public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, 461 int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, 462 boolean navbarColorManagedByIme) { 463 synchronized (mLock) { 464 // Don't coalesce these, since it might have one time flags set such as 465 // STATUS_BAR_UNHIDE which might get lost. 466 SomeArgs args = SomeArgs.obtain(); 467 args.argi1 = displayId; 468 args.argi2 = vis; 469 args.argi3 = fullscreenStackVis; 470 args.argi4 = dockedStackVis; 471 args.argi5 = mask; 472 args.argi6 = navbarColorManagedByIme ? 1 : 0; 473 args.arg1 = fullscreenStackBounds; 474 args.arg2 = dockedStackBounds; 475 mHandler.obtainMessage(MSG_SET_SYSTEMUI_VISIBILITY, args).sendToTarget(); 476 } 477 } 478 479 @Override 480 public void topAppWindowChanged(int displayId, boolean menuVisible) { } 481 482 @Override 483 public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition, 484 boolean showImeSwitcher) { 485 synchronized (mLock) { 486 mHandler.removeMessages(MSG_SHOW_IME_BUTTON); 487 SomeArgs args = SomeArgs.obtain(); 488 args.argi1 = displayId; 489 args.argi2 = vis; 490 args.argi3 = backDisposition; 491 args.argi4 = showImeSwitcher ? 1 : 0; 492 args.arg1 = token; 493 Message m = mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, args); 494 m.sendToTarget(); 495 } 496 } 497 498 public void showRecentApps(boolean triggeredFromAltTab) { 499 synchronized (mLock) { 500 mHandler.removeMessages(MSG_SHOW_RECENT_APPS); 501 mHandler.obtainMessage(MSG_SHOW_RECENT_APPS, triggeredFromAltTab ? 1 : 0, 0, 502 null).sendToTarget(); 503 } 504 } 505 506 public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { 507 synchronized (mLock) { 508 mHandler.removeMessages(MSG_HIDE_RECENT_APPS); 509 mHandler.obtainMessage(MSG_HIDE_RECENT_APPS, 510 triggeredFromAltTab ? 1 : 0, triggeredFromHomeKey ? 1 : 0, 511 null).sendToTarget(); 512 } 513 } 514 515 public void toggleSplitScreen() { 516 synchronized (mLock) { 517 mHandler.removeMessages(MSG_TOGGLE_APP_SPLIT_SCREEN); 518 mHandler.obtainMessage(MSG_TOGGLE_APP_SPLIT_SCREEN, 0, 0, null).sendToTarget(); 519 } 520 } 521 522 public void toggleRecentApps() { 523 synchronized (mLock) { 524 mHandler.removeMessages(MSG_TOGGLE_RECENT_APPS); 525 Message msg = mHandler.obtainMessage(MSG_TOGGLE_RECENT_APPS, 0, 0, null); 526 msg.setAsynchronous(true); 527 msg.sendToTarget(); 528 } 529 } 530 531 public void preloadRecentApps() { 532 synchronized (mLock) { 533 mHandler.removeMessages(MSG_PRELOAD_RECENT_APPS); 534 mHandler.obtainMessage(MSG_PRELOAD_RECENT_APPS, 0, 0, null).sendToTarget(); 535 } 536 } 537 538 public void cancelPreloadRecentApps() { 539 synchronized (mLock) { 540 mHandler.removeMessages(MSG_CANCEL_PRELOAD_RECENT_APPS); 541 mHandler.obtainMessage(MSG_CANCEL_PRELOAD_RECENT_APPS, 0, 0, null).sendToTarget(); 542 } 543 } 544 545 @Override 546 public void dismissKeyboardShortcutsMenu() { 547 synchronized (mLock) { 548 mHandler.removeMessages(MSG_DISMISS_KEYBOARD_SHORTCUTS); 549 mHandler.obtainMessage(MSG_DISMISS_KEYBOARD_SHORTCUTS).sendToTarget(); 550 } 551 } 552 553 @Override 554 public void toggleKeyboardShortcutsMenu(int deviceId) { 555 synchronized (mLock) { 556 mHandler.removeMessages(MSG_TOGGLE_KEYBOARD_SHORTCUTS); 557 mHandler.obtainMessage(MSG_TOGGLE_KEYBOARD_SHORTCUTS, deviceId, 0).sendToTarget(); 558 } 559 } 560 561 @Override 562 public void showPictureInPictureMenu() { 563 synchronized (mLock) { 564 mHandler.removeMessages(MSG_SHOW_PICTURE_IN_PICTURE_MENU); 565 mHandler.obtainMessage(MSG_SHOW_PICTURE_IN_PICTURE_MENU).sendToTarget(); 566 } 567 } 568 569 @Override 570 public void setWindowState(int displayId, int window, int state) { 571 synchronized (mLock) { 572 // don't coalesce these 573 mHandler.obtainMessage(MSG_SET_WINDOW_STATE, displayId, window, state).sendToTarget(); 574 } 575 } 576 577 public void showScreenPinningRequest(int taskId) { 578 synchronized (mLock) { 579 mHandler.obtainMessage(MSG_SHOW_SCREEN_PIN_REQUEST, taskId, 0, null) 580 .sendToTarget(); 581 } 582 } 583 584 @Override 585 public void appTransitionPending(int displayId) { 586 appTransitionPending(displayId, false /* forced */); 587 } 588 589 /** 590 * Called to notify System UI that an application transition is pending. 591 * @see Callbacks#appTransitionPending(int, boolean) 592 */ 593 public void appTransitionPending(int displayId, boolean forced) { 594 synchronized (mLock) { 595 mHandler.obtainMessage(MSG_APP_TRANSITION_PENDING, displayId, forced ? 1 : 0) 596 .sendToTarget(); 597 } 598 } 599 600 @Override 601 public void appTransitionCancelled(int displayId) { 602 synchronized (mLock) { 603 mHandler.obtainMessage(MSG_APP_TRANSITION_CANCELLED, displayId, 0 /* unused */) 604 .sendToTarget(); 605 } 606 } 607 608 @Override 609 public void appTransitionStarting(int displayId, long startTime, long duration) { 610 appTransitionStarting(displayId, startTime, duration, false /* forced */); 611 } 612 613 /** 614 * Called to notify System UI that an application transition is starting. 615 * @see Callbacks#appTransitionStarting(int, long, long, boolean). 616 */ 617 public void appTransitionStarting(int displayId, long startTime, long duration, 618 boolean forced) { 619 synchronized (mLock) { 620 final SomeArgs args = SomeArgs.obtain(); 621 args.argi1 = displayId; 622 args.argi2 = forced ? 1 : 0; 623 args.arg1 = startTime; 624 args.arg2 = duration; 625 mHandler.obtainMessage(MSG_APP_TRANSITION_STARTING, args).sendToTarget(); 626 } 627 } 628 629 @Override 630 public void appTransitionFinished(int displayId) { 631 synchronized (mLock) { 632 mHandler.obtainMessage(MSG_APP_TRANSITION_FINISHED, displayId, 0 /* unused */) 633 .sendToTarget(); 634 } 635 } 636 637 public void showAssistDisclosure() { 638 synchronized (mLock) { 639 mHandler.removeMessages(MSG_ASSIST_DISCLOSURE); 640 mHandler.obtainMessage(MSG_ASSIST_DISCLOSURE).sendToTarget(); 641 } 642 } 643 644 public void startAssist(Bundle args) { 645 synchronized (mLock) { 646 mHandler.removeMessages(MSG_START_ASSIST); 647 mHandler.obtainMessage(MSG_START_ASSIST, args).sendToTarget(); 648 } 649 } 650 651 @Override 652 public void onCameraLaunchGestureDetected(int source) { 653 synchronized (mLock) { 654 mHandler.removeMessages(MSG_CAMERA_LAUNCH_GESTURE); 655 mHandler.obtainMessage(MSG_CAMERA_LAUNCH_GESTURE, source, 0).sendToTarget(); 656 } 657 } 658 659 @Override 660 public void addQsTile(ComponentName tile) { 661 synchronized (mLock) { 662 mHandler.obtainMessage(MSG_ADD_QS_TILE, tile).sendToTarget(); 663 } 664 } 665 666 @Override 667 public void remQsTile(ComponentName tile) { 668 synchronized (mLock) { 669 mHandler.obtainMessage(MSG_REMOVE_QS_TILE, tile).sendToTarget(); 670 } 671 } 672 673 @Override 674 public void clickQsTile(ComponentName tile) { 675 synchronized (mLock) { 676 mHandler.obtainMessage(MSG_CLICK_QS_TILE, tile).sendToTarget(); 677 } 678 } 679 680 @Override 681 public void handleSystemKey(int key) { 682 synchronized (mLock) { 683 mHandler.obtainMessage(MSG_HANDLE_SYSTEM_KEY, key, 0).sendToTarget(); 684 } 685 } 686 687 @Override 688 public void showPinningEnterExitToast(boolean entering) { 689 synchronized (mLock) { 690 mHandler.obtainMessage(MSG_SHOW_PINNING_TOAST_ENTER_EXIT, entering).sendToTarget(); 691 } 692 } 693 694 @Override 695 public void showPinningEscapeToast() { 696 synchronized (mLock) { 697 mHandler.obtainMessage(MSG_SHOW_PINNING_TOAST_ESCAPE).sendToTarget(); 698 } 699 } 700 701 702 @Override 703 public void showGlobalActionsMenu() { 704 synchronized (mLock) { 705 mHandler.removeMessages(MSG_SHOW_GLOBAL_ACTIONS); 706 mHandler.obtainMessage(MSG_SHOW_GLOBAL_ACTIONS).sendToTarget(); 707 } 708 } 709 710 @Override 711 public void setTopAppHidesStatusBar(boolean hidesStatusBar) { 712 mHandler.removeMessages(MSG_SET_TOP_APP_HIDES_STATUS_BAR); 713 mHandler.obtainMessage(MSG_SET_TOP_APP_HIDES_STATUS_BAR, hidesStatusBar ? 1 : 0, 0) 714 .sendToTarget(); 715 } 716 717 @Override 718 public void showShutdownUi(boolean isReboot, String reason) { 719 synchronized (mLock) { 720 mHandler.removeMessages(MSG_SHOW_SHUTDOWN_UI); 721 mHandler.obtainMessage(MSG_SHOW_SHUTDOWN_UI, isReboot ? 1 : 0, 0, reason) 722 .sendToTarget(); 723 } 724 } 725 726 @Override 727 public void showWirelessChargingAnimation(int batteryLevel) { 728 mHandler.removeMessages(MSG_SHOW_CHARGING_ANIMATION); 729 mHandler.obtainMessage(MSG_SHOW_CHARGING_ANIMATION, batteryLevel, 0) 730 .sendToTarget(); 731 } 732 733 @Override 734 public void onProposedRotationChanged(int rotation, boolean isValid) { 735 synchronized (mLock) { 736 mHandler.removeMessages(MSG_ROTATION_PROPOSAL); 737 mHandler.obtainMessage(MSG_ROTATION_PROPOSAL, rotation, isValid ? 1 : 0, 738 null).sendToTarget(); 739 } 740 } 741 742 @Override 743 public void showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver, 744 int type, boolean requireConfirmation, int userId) { 745 synchronized (mLock) { 746 SomeArgs args = SomeArgs.obtain(); 747 args.arg1 = bundle; 748 args.arg2 = receiver; 749 args.argi1 = type; 750 args.arg3 = requireConfirmation; 751 args.argi2 = userId; 752 mHandler.obtainMessage(MSG_BIOMETRIC_SHOW, args) 753 .sendToTarget(); 754 } 755 } 756 757 @Override 758 public void onBiometricAuthenticated(boolean authenticated, String failureReason) { 759 synchronized (mLock) { 760 SomeArgs args = SomeArgs.obtain(); 761 args.arg1 = authenticated; 762 args.arg2 = failureReason; 763 mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED, args).sendToTarget(); 764 } 765 } 766 767 @Override 768 public void onBiometricHelp(String message) { 769 synchronized (mLock) { 770 mHandler.obtainMessage(MSG_BIOMETRIC_HELP, message).sendToTarget(); 771 } 772 } 773 774 @Override 775 public void onBiometricError(String error) { 776 synchronized (mLock) { 777 mHandler.obtainMessage(MSG_BIOMETRIC_ERROR, error).sendToTarget(); 778 } 779 } 780 781 @Override 782 public void hideBiometricDialog() { 783 synchronized (mLock) { 784 mHandler.obtainMessage(MSG_BIOMETRIC_HIDE).sendToTarget(); 785 } 786 } 787 788 @Override 789 public void onDisplayReady(int displayId) { 790 synchronized (mLock) { 791 mHandler.obtainMessage(MSG_DISPLAY_READY, displayId, 0).sendToTarget(); 792 } 793 } 794 795 @Override 796 public void onRecentsAnimationStateChanged(boolean running) { 797 synchronized (mLock) { 798 mHandler.obtainMessage(MSG_RECENTS_ANIMATION_STATE_CHANGED, running ? 1 : 0, 0) 799 .sendToTarget(); 800 } 801 } 802 803 private void handleShowImeButton(int displayId, IBinder token, int vis, int backDisposition, 804 boolean showImeSwitcher) { 805 if (displayId == INVALID_DISPLAY) return; 806 807 if (!InputMethodSystemProperty.MULTI_CLIENT_IME_ENABLED 808 && mLastUpdatedImeDisplayId != displayId 809 && mLastUpdatedImeDisplayId != INVALID_DISPLAY) { 810 // Set previous NavBar's IME window status as invisible when IME 811 // window switched to another display for single-session IME case. 812 sendImeInvisibleStatusForPrevNavBar(); 813 } 814 for (int i = 0; i < mCallbacks.size(); i++) { 815 mCallbacks.get(i).setImeWindowStatus(displayId, token, vis, backDisposition, 816 showImeSwitcher); 817 } 818 mLastUpdatedImeDisplayId = displayId; 819 } 820 821 private void sendImeInvisibleStatusForPrevNavBar() { 822 for (int i = 0; i < mCallbacks.size(); i++) { 823 mCallbacks.get(i).setImeWindowStatus(mLastUpdatedImeDisplayId, 824 null /* token */, IME_INVISIBLE, BACK_DISPOSITION_DEFAULT, 825 false /* showImeSwitcher */); 826 } 827 } 828 829 private final class H extends Handler { 830 private H(Looper l) { 831 super(l); 832 } 833 834 public void handleMessage(Message msg) { 835 final int what = msg.what & MSG_MASK; 836 switch (what) { 837 case MSG_ICON: { 838 switch (msg.arg1) { 839 case OP_SET_ICON: { 840 Pair<String, StatusBarIcon> p = (Pair<String, StatusBarIcon>) msg.obj; 841 for (int i = 0; i < mCallbacks.size(); i++) { 842 mCallbacks.get(i).setIcon(p.first, p.second); 843 } 844 break; 845 } 846 case OP_REMOVE_ICON: 847 for (int i = 0; i < mCallbacks.size(); i++) { 848 mCallbacks.get(i).removeIcon((String) msg.obj); 849 } 850 break; 851 } 852 break; 853 } 854 case MSG_DISABLE: 855 SomeArgs args = (SomeArgs) msg.obj; 856 for (int i = 0; i < mCallbacks.size(); i++) { 857 mCallbacks.get(i).disable(args.argi1, args.argi2, args.argi3, 858 args.argi4 != 0 /* animate */); 859 } 860 break; 861 case MSG_EXPAND_NOTIFICATIONS: 862 for (int i = 0; i < mCallbacks.size(); i++) { 863 mCallbacks.get(i).animateExpandNotificationsPanel(); 864 } 865 break; 866 case MSG_COLLAPSE_PANELS: 867 for (int i = 0; i < mCallbacks.size(); i++) { 868 mCallbacks.get(i).animateCollapsePanels(msg.arg1, msg.arg2 != 0); 869 } 870 break; 871 case MSG_TOGGLE_PANEL: 872 for (int i = 0; i < mCallbacks.size(); i++) { 873 mCallbacks.get(i).togglePanel(); 874 } 875 break; 876 case MSG_EXPAND_SETTINGS: 877 for (int i = 0; i < mCallbacks.size(); i++) { 878 mCallbacks.get(i).animateExpandSettingsPanel((String) msg.obj); 879 } 880 break; 881 case MSG_SET_SYSTEMUI_VISIBILITY: 882 args = (SomeArgs) msg.obj; 883 for (int i = 0; i < mCallbacks.size(); i++) { 884 mCallbacks.get(i).setSystemUiVisibility(args.argi1, args.argi2, args.argi3, 885 args.argi4, args.argi5, (Rect) args.arg1, (Rect) args.arg2, 886 args.argi6 == 1); 887 } 888 args.recycle(); 889 break; 890 case MSG_SHOW_IME_BUTTON: 891 args = (SomeArgs) msg.obj; 892 handleShowImeButton(args.argi1 /* displayId */, (IBinder) args.arg1 /* token */, 893 args.argi2 /* vis */, args.argi3 /* backDisposition */, 894 args.argi4 != 0 /* showImeSwitcher */); 895 break; 896 case MSG_SHOW_RECENT_APPS: 897 for (int i = 0; i < mCallbacks.size(); i++) { 898 mCallbacks.get(i).showRecentApps(msg.arg1 != 0); 899 } 900 break; 901 case MSG_HIDE_RECENT_APPS: 902 for (int i = 0; i < mCallbacks.size(); i++) { 903 mCallbacks.get(i).hideRecentApps(msg.arg1 != 0, msg.arg2 != 0); 904 } 905 break; 906 case MSG_TOGGLE_RECENT_APPS: 907 for (int i = 0; i < mCallbacks.size(); i++) { 908 mCallbacks.get(i).toggleRecentApps(); 909 } 910 break; 911 case MSG_PRELOAD_RECENT_APPS: 912 for (int i = 0; i < mCallbacks.size(); i++) { 913 mCallbacks.get(i).preloadRecentApps(); 914 } 915 break; 916 case MSG_CANCEL_PRELOAD_RECENT_APPS: 917 for (int i = 0; i < mCallbacks.size(); i++) { 918 mCallbacks.get(i).cancelPreloadRecentApps(); 919 } 920 break; 921 case MSG_DISMISS_KEYBOARD_SHORTCUTS: 922 for (int i = 0; i < mCallbacks.size(); i++) { 923 mCallbacks.get(i).dismissKeyboardShortcutsMenu(); 924 } 925 break; 926 case MSG_TOGGLE_KEYBOARD_SHORTCUTS: 927 for (int i = 0; i < mCallbacks.size(); i++) { 928 mCallbacks.get(i).toggleKeyboardShortcutsMenu(msg.arg1); 929 } 930 break; 931 case MSG_SET_WINDOW_STATE: 932 for (int i = 0; i < mCallbacks.size(); i++) { 933 mCallbacks.get(i).setWindowState(msg.arg1, msg.arg2, (int) msg.obj); 934 } 935 break; 936 case MSG_SHOW_SCREEN_PIN_REQUEST: 937 for (int i = 0; i < mCallbacks.size(); i++) { 938 mCallbacks.get(i).showScreenPinningRequest(msg.arg1); 939 } 940 break; 941 case MSG_APP_TRANSITION_PENDING: 942 for (int i = 0; i < mCallbacks.size(); i++) { 943 mCallbacks.get(i).appTransitionPending(msg.arg1, msg.arg2 != 0); 944 } 945 break; 946 case MSG_APP_TRANSITION_CANCELLED: 947 for (int i = 0; i < mCallbacks.size(); i++) { 948 mCallbacks.get(i).appTransitionCancelled(msg.arg1); 949 } 950 break; 951 case MSG_APP_TRANSITION_STARTING: 952 args = (SomeArgs) msg.obj; 953 for (int i = 0; i < mCallbacks.size(); i++) { 954 mCallbacks.get(i).appTransitionStarting(args.argi1, (long) args.arg1, 955 (long) args.arg2, args.argi2 != 0 /* forced */); 956 } 957 break; 958 case MSG_APP_TRANSITION_FINISHED: 959 for (int i = 0; i < mCallbacks.size(); i++) { 960 mCallbacks.get(i).appTransitionFinished(msg.arg1); 961 } 962 break; 963 case MSG_ASSIST_DISCLOSURE: 964 for (int i = 0; i < mCallbacks.size(); i++) { 965 mCallbacks.get(i).showAssistDisclosure(); 966 } 967 break; 968 case MSG_START_ASSIST: 969 for (int i = 0; i < mCallbacks.size(); i++) { 970 mCallbacks.get(i).startAssist((Bundle) msg.obj); 971 } 972 break; 973 case MSG_CAMERA_LAUNCH_GESTURE: 974 for (int i = 0; i < mCallbacks.size(); i++) { 975 mCallbacks.get(i).onCameraLaunchGestureDetected(msg.arg1); 976 } 977 break; 978 case MSG_SHOW_PICTURE_IN_PICTURE_MENU: 979 for (int i = 0; i < mCallbacks.size(); i++) { 980 mCallbacks.get(i).showPictureInPictureMenu(); 981 } 982 break; 983 case MSG_ADD_QS_TILE: 984 for (int i = 0; i < mCallbacks.size(); i++) { 985 mCallbacks.get(i).addQsTile((ComponentName) msg.obj); 986 } 987 break; 988 case MSG_REMOVE_QS_TILE: 989 for (int i = 0; i < mCallbacks.size(); i++) { 990 mCallbacks.get(i).remQsTile((ComponentName) msg.obj); 991 } 992 break; 993 case MSG_CLICK_QS_TILE: 994 for (int i = 0; i < mCallbacks.size(); i++) { 995 mCallbacks.get(i).clickTile((ComponentName) msg.obj); 996 } 997 break; 998 case MSG_TOGGLE_APP_SPLIT_SCREEN: 999 for (int i = 0; i < mCallbacks.size(); i++) { 1000 mCallbacks.get(i).toggleSplitScreen(); 1001 } 1002 break; 1003 case MSG_HANDLE_SYSTEM_KEY: 1004 for (int i = 0; i < mCallbacks.size(); i++) { 1005 mCallbacks.get(i).handleSystemKey(msg.arg1); 1006 } 1007 break; 1008 case MSG_SHOW_GLOBAL_ACTIONS: 1009 for (int i = 0; i < mCallbacks.size(); i++) { 1010 mCallbacks.get(i).handleShowGlobalActionsMenu(); 1011 } 1012 break; 1013 case MSG_SHOW_SHUTDOWN_UI: 1014 for (int i = 0; i < mCallbacks.size(); i++) { 1015 mCallbacks.get(i).handleShowShutdownUi(msg.arg1 != 0, (String) msg.obj); 1016 } 1017 break; 1018 case MSG_SET_TOP_APP_HIDES_STATUS_BAR: 1019 for (int i = 0; i < mCallbacks.size(); i++) { 1020 mCallbacks.get(i).setTopAppHidesStatusBar(msg.arg1 != 0); 1021 } 1022 break; 1023 case MSG_ROTATION_PROPOSAL: 1024 for (int i = 0; i < mCallbacks.size(); i++) { 1025 mCallbacks.get(i).onRotationProposal(msg.arg1, msg.arg2 != 0); 1026 } 1027 break; 1028 case MSG_BIOMETRIC_SHOW: { 1029 mHandler.removeMessages(MSG_BIOMETRIC_ERROR); 1030 mHandler.removeMessages(MSG_BIOMETRIC_HELP); 1031 mHandler.removeMessages(MSG_BIOMETRIC_AUTHENTICATED); 1032 SomeArgs someArgs = (SomeArgs) msg.obj; 1033 for (int i = 0; i < mCallbacks.size(); i++) { 1034 mCallbacks.get(i).showBiometricDialog( 1035 (Bundle) someArgs.arg1, 1036 (IBiometricServiceReceiverInternal) someArgs.arg2, 1037 someArgs.argi1 /* type */, 1038 (boolean) someArgs.arg3 /* requireConfirmation */, 1039 someArgs.argi2 /* userId */); 1040 } 1041 someArgs.recycle(); 1042 break; 1043 } 1044 case MSG_BIOMETRIC_AUTHENTICATED: { 1045 SomeArgs someArgs = (SomeArgs) msg.obj; 1046 for (int i = 0; i < mCallbacks.size(); i++) { 1047 mCallbacks.get(i).onBiometricAuthenticated( 1048 (boolean) someArgs.arg1 /* authenticated */, 1049 (String) someArgs.arg2 /* failureReason */); 1050 } 1051 someArgs.recycle(); 1052 break; 1053 } 1054 case MSG_BIOMETRIC_HELP: 1055 for (int i = 0; i < mCallbacks.size(); i++) { 1056 mCallbacks.get(i).onBiometricHelp((String) msg.obj); 1057 } 1058 break; 1059 case MSG_BIOMETRIC_ERROR: 1060 for (int i = 0; i < mCallbacks.size(); i++) { 1061 mCallbacks.get(i).onBiometricError((String) msg.obj); 1062 } 1063 break; 1064 case MSG_BIOMETRIC_HIDE: 1065 for (int i = 0; i < mCallbacks.size(); i++) { 1066 mCallbacks.get(i).hideBiometricDialog(); 1067 } 1068 break; 1069 case MSG_SHOW_CHARGING_ANIMATION: 1070 for (int i = 0; i < mCallbacks.size(); i++) { 1071 mCallbacks.get(i).showWirelessChargingAnimation(msg.arg1); 1072 } 1073 break; 1074 case MSG_SHOW_PINNING_TOAST_ENTER_EXIT: 1075 for (int i = 0; i < mCallbacks.size(); i++) { 1076 mCallbacks.get(i).showPinningEnterExitToast((Boolean) msg.obj); 1077 } 1078 break; 1079 case MSG_SHOW_PINNING_TOAST_ESCAPE: 1080 for (int i = 0; i < mCallbacks.size(); i++) { 1081 mCallbacks.get(i).showPinningEscapeToast(); 1082 } 1083 break; 1084 case MSG_DISPLAY_READY: 1085 for (int i = 0; i < mCallbacks.size(); i++) { 1086 mCallbacks.get(i).onDisplayReady(msg.arg1); 1087 } 1088 break; 1089 case MSG_RECENTS_ANIMATION_STATE_CHANGED: 1090 for (int i = 0; i < mCallbacks.size(); i++) { 1091 mCallbacks.get(i).onRecentsAnimationStateChanged(msg.arg1 > 0); 1092 } 1093 break; 1094 } 1095 } 1096 } 1097 1098 // Need this class since CommandQueue already extends IStatusBar.Stub, so CommandQueueStart 1099 // is needed so it can extend SystemUI. 1100 public static class CommandQueueStart extends SystemUI { 1101 @Override 1102 public void start() { 1103 putComponent(CommandQueue.class, new CommandQueue(mContext)); 1104 } 1105 } 1106 } 1107