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