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