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