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 {
setIcon(String slot, StatusBarIcon icon)144         default void setIcon(String slot, StatusBarIcon icon) { }
removeIcon(String slot)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          */
disable(int displayId, @DisableFlags int state1, @Disable2Flags int state2, boolean animate)156         default void disable(int displayId, @DisableFlags int state1, @Disable2Flags int state2,
157                 boolean animate) { }
animateExpandNotificationsPanel()158         default void animateExpandNotificationsPanel() { }
animateCollapsePanels(int flags, boolean force)159         default void animateCollapsePanels(int flags, boolean force) { }
togglePanel()160         default void togglePanel() { }
animateExpandSettingsPanel(String obj)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          */
setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, boolean navbarColorManagedByIme)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          */
setImeWindowStatus(int displayId, IBinder token, int vis, @BackDispositionMode int backDisposition, boolean showImeSwitcher)194         default void setImeWindowStatus(int displayId, IBinder token,  int vis,
195                 @BackDispositionMode int backDisposition, boolean showImeSwitcher) { }
showRecentApps(boolean triggeredFromAltTab)196         default void showRecentApps(boolean triggeredFromAltTab) { }
hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey)197         default void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { }
toggleRecentApps()198         default void toggleRecentApps() { }
toggleSplitScreen()199         default void toggleSplitScreen() { }
preloadRecentApps()200         default void preloadRecentApps() { }
dismissKeyboardShortcutsMenu()201         default void dismissKeyboardShortcutsMenu() { }
toggleKeyboardShortcutsMenu(int deviceId)202         default void toggleKeyboardShortcutsMenu(int deviceId) { }
cancelPreloadRecentApps()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          */
setWindowState(int displayId, @WindowType int window, @WindowVisibleState int state)214         default void setWindowState(int displayId, @WindowType int window,
215                 @WindowVisibleState int state) { }
showScreenPinningRequest(int taskId)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          */
appTransitionPending(int displayId, boolean forced)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          */
appTransitionCancelled(int displayId)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          */
appTransitionStarting( int displayId, long startTime, long duration, boolean forced)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          */
appTransitionFinished(int displayId)253         default void appTransitionFinished(int displayId) { }
showAssistDisclosure()254         default void showAssistDisclosure() { }
startAssist(Bundle args)255         default void startAssist(Bundle args) { }
onCameraLaunchGestureDetected(int source)256         default void onCameraLaunchGestureDetected(int source) { }
showPictureInPictureMenu()257         default void showPictureInPictureMenu() { }
setTopAppHidesStatusBar(boolean topAppHidesStatusBar)258         default void setTopAppHidesStatusBar(boolean topAppHidesStatusBar) { }
259 
addQsTile(ComponentName tile)260         default void addQsTile(ComponentName tile) { }
remQsTile(ComponentName tile)261         default void remQsTile(ComponentName tile) { }
clickTile(ComponentName tile)262         default void clickTile(ComponentName tile) { }
263 
handleSystemKey(int arg1)264         default void handleSystemKey(int arg1) { }
showPinningEnterExitToast(boolean entering)265         default void showPinningEnterExitToast(boolean entering) { }
showPinningEscapeToast()266         default void showPinningEscapeToast() { }
handleShowGlobalActionsMenu()267         default void handleShowGlobalActionsMenu() { }
handleShowShutdownUi(boolean isReboot, String reason)268         default void handleShowShutdownUi(boolean isReboot, String reason) { }
269 
showWirelessChargingAnimation(int batteryLevel)270         default void showWirelessChargingAnimation(int batteryLevel) {  }
271 
onRotationProposal(int rotation, boolean isValid)272         default void onRotationProposal(int rotation, boolean isValid) { }
273 
showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver, int type, boolean requireConfirmation, int userId)274         default void showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
275                 int type, boolean requireConfirmation, int userId) { }
onBiometricAuthenticated(boolean authenticated, String failureReason)276         default void onBiometricAuthenticated(boolean authenticated, String failureReason) { }
onBiometricHelp(String message)277         default void onBiometricHelp(String message) { }
onBiometricError(String error)278         default void onBiometricError(String error) { }
hideBiometricDialog()279         default void hideBiometricDialog() { }
280 
281         /**
282          * @see IStatusBar#onDisplayReady(int)
283          */
onDisplayReady(int displayId)284         default void onDisplayReady(int displayId) { }
285 
286         /**
287          * @see DisplayManager.DisplayListener#onDisplayRemoved(int)
288          */
onDisplayRemoved(int displayId)289         default void onDisplayRemoved(int displayId) { }
290 
291         /**
292          * @see IStatusBar#onRecentsAnimationStateChanged(boolean)
293          */
onRecentsAnimationStateChanged(boolean running)294         default void onRecentsAnimationStateChanged(boolean running) { }
295     }
296 
297     @VisibleForTesting
CommandQueue(Context context)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
onDisplayAdded(int displayId)305     public void onDisplayAdded(int displayId) { }
306 
307     @Override
onDisplayRemoved(int displayId)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
onDisplayChanged(int displayId)320     public void onDisplayChanged(int displayId) { }
321 
322     // TODO(b/118592525): add multi-display support if needed.
panelsEnabled()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 
addCallback(Callbacks callbacks)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 
removeCallback(Callbacks callbacks)342     public void removeCallback(Callbacks callbacks) {
343         mCallbacks.remove(callbacks);
344     }
345 
setIcon(String slot, StatusBarIcon icon)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 
removeIcon(String slot)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      */
disable(int displayId, @DisableFlags int state1, @Disable2Flags int state2, boolean animate)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
disable(int displayId, @DisableFlags int state1, @Disable2Flags int state2)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      */
recomputeDisableFlags(int displayId, boolean animate)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 
setDisabled(int displayId, int disabled1, int disabled2)403     private void setDisabled(int displayId, int disabled1, int disabled2) {
404         mDisplayDisabled.put(displayId, new Pair<>(disabled1, disabled2));
405     }
406 
getDisabled1(int displayId)407     private int getDisabled1(int displayId) {
408         return getDisabled(displayId).first;
409     }
410 
getDisabled2(int displayId)411     private int getDisabled2(int displayId) {
412         return getDisabled(displayId).second;
413     }
414 
getDisabled(int displayId)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 
animateExpandNotificationsPanel()424     public void animateExpandNotificationsPanel() {
425         synchronized (mLock) {
426             mHandler.removeMessages(MSG_EXPAND_NOTIFICATIONS);
427             mHandler.sendEmptyMessage(MSG_EXPAND_NOTIFICATIONS);
428         }
429     }
430 
animateCollapsePanels()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 
animateCollapsePanels(int flags, boolean force)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 
togglePanel()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 
animateExpandSettingsPanel(String subPanel)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
setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, boolean navbarColorManagedByIme)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
topAppWindowChanged(int displayId, boolean menuVisible)480     public void topAppWindowChanged(int displayId, boolean menuVisible) { }
481 
482     @Override
setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition, boolean showImeSwitcher)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 
showRecentApps(boolean triggeredFromAltTab)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 
hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey)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 
toggleSplitScreen()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 
toggleRecentApps()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 
preloadRecentApps()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 
cancelPreloadRecentApps()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
dismissKeyboardShortcutsMenu()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
toggleKeyboardShortcutsMenu(int deviceId)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
showPictureInPictureMenu()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
setWindowState(int displayId, int window, int state)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 
showScreenPinningRequest(int taskId)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
appTransitionPending(int displayId)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      */
appTransitionPending(int displayId, boolean forced)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
appTransitionCancelled(int displayId)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
appTransitionStarting(int displayId, long startTime, long duration)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      */
appTransitionStarting(int displayId, long startTime, long duration, boolean forced)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
appTransitionFinished(int displayId)630     public void appTransitionFinished(int displayId) {
631         synchronized (mLock) {
632             mHandler.obtainMessage(MSG_APP_TRANSITION_FINISHED, displayId, 0 /* unused */)
633                     .sendToTarget();
634         }
635     }
636 
showAssistDisclosure()637     public void showAssistDisclosure() {
638         synchronized (mLock) {
639             mHandler.removeMessages(MSG_ASSIST_DISCLOSURE);
640             mHandler.obtainMessage(MSG_ASSIST_DISCLOSURE).sendToTarget();
641         }
642     }
643 
startAssist(Bundle args)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
onCameraLaunchGestureDetected(int source)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
addQsTile(ComponentName tile)660     public void addQsTile(ComponentName tile) {
661         synchronized (mLock) {
662             mHandler.obtainMessage(MSG_ADD_QS_TILE, tile).sendToTarget();
663         }
664     }
665 
666     @Override
remQsTile(ComponentName tile)667     public void remQsTile(ComponentName tile) {
668         synchronized (mLock) {
669             mHandler.obtainMessage(MSG_REMOVE_QS_TILE, tile).sendToTarget();
670         }
671     }
672 
673     @Override
clickQsTile(ComponentName tile)674     public void clickQsTile(ComponentName tile) {
675         synchronized (mLock) {
676             mHandler.obtainMessage(MSG_CLICK_QS_TILE, tile).sendToTarget();
677         }
678     }
679 
680     @Override
handleSystemKey(int key)681     public void handleSystemKey(int key) {
682         synchronized (mLock) {
683             mHandler.obtainMessage(MSG_HANDLE_SYSTEM_KEY, key, 0).sendToTarget();
684         }
685     }
686 
687     @Override
showPinningEnterExitToast(boolean entering)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
showPinningEscapeToast()695     public void showPinningEscapeToast() {
696         synchronized (mLock) {
697             mHandler.obtainMessage(MSG_SHOW_PINNING_TOAST_ESCAPE).sendToTarget();
698         }
699     }
700 
701 
702     @Override
showGlobalActionsMenu()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
setTopAppHidesStatusBar(boolean hidesStatusBar)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
showShutdownUi(boolean isReboot, String reason)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
showWirelessChargingAnimation(int batteryLevel)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
onProposedRotationChanged(int rotation, boolean isValid)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
showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver, int type, boolean requireConfirmation, int userId)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
onBiometricAuthenticated(boolean authenticated, String failureReason)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
onBiometricHelp(String message)768     public void onBiometricHelp(String message) {
769         synchronized (mLock) {
770             mHandler.obtainMessage(MSG_BIOMETRIC_HELP, message).sendToTarget();
771         }
772     }
773 
774     @Override
onBiometricError(String error)775     public void onBiometricError(String error) {
776         synchronized (mLock) {
777             mHandler.obtainMessage(MSG_BIOMETRIC_ERROR, error).sendToTarget();
778         }
779     }
780 
781     @Override
hideBiometricDialog()782     public void hideBiometricDialog() {
783         synchronized (mLock) {
784             mHandler.obtainMessage(MSG_BIOMETRIC_HIDE).sendToTarget();
785         }
786     }
787 
788     @Override
onDisplayReady(int displayId)789     public void onDisplayReady(int displayId) {
790         synchronized (mLock) {
791             mHandler.obtainMessage(MSG_DISPLAY_READY, displayId, 0).sendToTarget();
792         }
793     }
794 
795     @Override
onRecentsAnimationStateChanged(boolean running)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 
handleShowImeButton(int displayId, IBinder token, int vis, int backDisposition, boolean showImeSwitcher)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 
sendImeInvisibleStatusForPrevNavBar()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 {
H(Looper l)830         private H(Looper l) {
831             super(l);
832         }
833 
handleMessage(Message msg)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
start()1102         public void start() {
1103             putComponent(CommandQueue.class, new CommandQueue(mContext));
1104         }
1105     }
1106 }
1107