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