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.os.Handler;
     20 import android.os.IBinder;
     21 import android.os.Message;
     22 
     23 import com.android.internal.statusbar.IStatusBar;
     24 import com.android.internal.statusbar.StatusBarIcon;
     25 import com.android.internal.statusbar.StatusBarIconList;
     26 import com.android.internal.statusbar.StatusBarNotification;
     27 
     28 /**
     29  * This class takes the functions from IStatusBar that come in on
     30  * binder pool threads and posts messages to get them onto the main
     31  * thread, and calls onto Callbacks.  It also takes care of
     32  * coalescing these calls so they don't stack up.  For the calls
     33  * are coalesced, note that they are all idempotent.
     34  */
     35 public class CommandQueue extends IStatusBar.Stub {
     36     private static final String TAG = "StatusBar.CommandQueue";
     37 
     38     private static final int INDEX_MASK = 0xffff;
     39     private static final int MSG_SHIFT  = 16;
     40     private static final int MSG_MASK   = 0xffff << MSG_SHIFT;
     41 
     42 
     43     private static final int MSG_ICON                   = 1 << MSG_SHIFT;
     44     private static final int OP_SET_ICON    = 1;
     45     private static final int OP_REMOVE_ICON = 2;
     46 
     47     private static final int MSG_ADD_NOTIFICATION       = 2 << MSG_SHIFT;
     48     private static final int MSG_UPDATE_NOTIFICATION    = 3 << MSG_SHIFT;
     49     private static final int MSG_REMOVE_NOTIFICATION    = 4 << MSG_SHIFT;
     50 
     51     private static final int MSG_DISABLE                = 5 << MSG_SHIFT;
     52 
     53     private static final int MSG_SET_VISIBILITY         = 6 << MSG_SHIFT;
     54     private static final int OP_EXPAND      = 1;
     55     private static final int OP_COLLAPSE    = 2;
     56 
     57     private static final int MSG_SET_SYSTEMUI_VISIBILITY          = 7 << MSG_SHIFT;
     58 
     59     private static final int MSG_TOP_APP_WINDOW_CHANGED = 8 << MSG_SHIFT;
     60     private static final int MSG_SHOW_IME_BUTTON        = 9 << MSG_SHIFT;
     61     private static final int MSG_SET_HARD_KEYBOARD_STATUS = 10 << MSG_SHIFT;
     62 
     63     private static final int MSG_TOGGLE_RECENT_APPS       = 11 << MSG_SHIFT;
     64     private static final int MSG_PRELOAD_RECENT_APPS      = 12 << MSG_SHIFT;
     65     private static final int MSG_CANCEL_PRELOAD_RECENT_APPS       = 13 << MSG_SHIFT;
     66 
     67     private static final int MSG_SET_NAVIGATION_ICON_HINTS = 14 << MSG_SHIFT;
     68 
     69     public static final int FLAG_EXCLUDE_NONE = 0;
     70     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
     71     public static final int FLAG_EXCLUDE_RECENTS_PANEL = 1 << 1;
     72     public static final int FLAG_EXCLUDE_NOTIFICATION_PANEL = 1 << 2;
     73     public static final int FLAG_EXCLUDE_INPUT_METHODS_PANEL = 1 << 3;
     74     public static final int FLAG_EXCLUDE_COMPAT_MODE_PANEL = 1 << 4;
     75 
     76     private StatusBarIconList mList;
     77     private Callbacks mCallbacks;
     78     private Handler mHandler = new H();
     79 
     80     private class NotificationQueueEntry {
     81         IBinder key;
     82         StatusBarNotification notification;
     83     }
     84 
     85     /**
     86      * These methods are called back on the main thread.
     87      */
     88     public interface Callbacks {
     89         public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon);
     90         public void updateIcon(String slot, int index, int viewIndex,
     91                 StatusBarIcon old, StatusBarIcon icon);
     92         public void removeIcon(String slot, int index, int viewIndex);
     93         public void addNotification(IBinder key, StatusBarNotification notification);
     94         public void updateNotification(IBinder key, StatusBarNotification notification);
     95         public void removeNotification(IBinder key);
     96         public void disable(int state);
     97         public void animateExpand();
     98         public void animateCollapse(int flags);
     99         public void setSystemUiVisibility(int vis, int mask);
    100         public void topAppWindowChanged(boolean visible);
    101         public void setImeWindowStatus(IBinder token, int vis, int backDisposition);
    102         public void setHardKeyboardStatus(boolean available, boolean enabled);
    103         public void toggleRecentApps();
    104         public void preloadRecentApps();
    105         public void showSearchPanel();
    106         public void hideSearchPanel();
    107         public void cancelPreloadRecentApps();
    108         public void setNavigationIconHints(int hints);
    109     }
    110 
    111     public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
    112         mCallbacks = callbacks;
    113         mList = list;
    114     }
    115 
    116     public void setIcon(int index, StatusBarIcon icon) {
    117         synchronized (mList) {
    118             int what = MSG_ICON | index;
    119             mHandler.removeMessages(what);
    120             mHandler.obtainMessage(what, OP_SET_ICON, 0, icon.clone()).sendToTarget();
    121         }
    122     }
    123 
    124     public void removeIcon(int index) {
    125         synchronized (mList) {
    126             int what = MSG_ICON | index;
    127             mHandler.removeMessages(what);
    128             mHandler.obtainMessage(what, OP_REMOVE_ICON, 0, null).sendToTarget();
    129         }
    130     }
    131 
    132     public void addNotification(IBinder key, StatusBarNotification notification) {
    133         synchronized (mList) {
    134             NotificationQueueEntry ne = new NotificationQueueEntry();
    135             ne.key = key;
    136             ne.notification = notification;
    137             mHandler.obtainMessage(MSG_ADD_NOTIFICATION, 0, 0, ne).sendToTarget();
    138         }
    139     }
    140 
    141     public void updateNotification(IBinder key, StatusBarNotification notification) {
    142         synchronized (mList) {
    143             NotificationQueueEntry ne = new NotificationQueueEntry();
    144             ne.key = key;
    145             ne.notification = notification;
    146             mHandler.obtainMessage(MSG_UPDATE_NOTIFICATION, 0, 0, ne).sendToTarget();
    147         }
    148     }
    149 
    150     public void removeNotification(IBinder key) {
    151         synchronized (mList) {
    152             mHandler.obtainMessage(MSG_REMOVE_NOTIFICATION, 0, 0, key).sendToTarget();
    153         }
    154     }
    155 
    156     public void disable(int state) {
    157         synchronized (mList) {
    158             mHandler.removeMessages(MSG_DISABLE);
    159             mHandler.obtainMessage(MSG_DISABLE, state, 0, null).sendToTarget();
    160         }
    161     }
    162 
    163     public void animateExpand() {
    164         synchronized (mList) {
    165             mHandler.removeMessages(MSG_SET_VISIBILITY);
    166             mHandler.obtainMessage(MSG_SET_VISIBILITY, OP_EXPAND, 0, null).sendToTarget();
    167         }
    168     }
    169 
    170     public void animateCollapse() {
    171         animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
    172     }
    173 
    174     public void animateCollapse(int flags) {
    175         synchronized (mList) {
    176             mHandler.removeMessages(MSG_SET_VISIBILITY);
    177             mHandler.obtainMessage(MSG_SET_VISIBILITY, OP_COLLAPSE, flags, null).sendToTarget();
    178         }
    179     }
    180 
    181     public void setSystemUiVisibility(int vis, int mask) {
    182         synchronized (mList) {
    183             mHandler.removeMessages(MSG_SET_SYSTEMUI_VISIBILITY);
    184             mHandler.obtainMessage(MSG_SET_SYSTEMUI_VISIBILITY, vis, mask, null).sendToTarget();
    185         }
    186     }
    187 
    188     public void topAppWindowChanged(boolean menuVisible) {
    189         synchronized (mList) {
    190             mHandler.removeMessages(MSG_TOP_APP_WINDOW_CHANGED);
    191             mHandler.obtainMessage(MSG_TOP_APP_WINDOW_CHANGED, menuVisible ? 1 : 0, 0,
    192                     null).sendToTarget();
    193         }
    194     }
    195 
    196     public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
    197         synchronized (mList) {
    198             mHandler.removeMessages(MSG_SHOW_IME_BUTTON);
    199             mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, vis, backDisposition, token)
    200                     .sendToTarget();
    201         }
    202     }
    203 
    204     public void setHardKeyboardStatus(boolean available, boolean enabled) {
    205         synchronized (mList) {
    206             mHandler.removeMessages(MSG_SET_HARD_KEYBOARD_STATUS);
    207             mHandler.obtainMessage(MSG_SET_HARD_KEYBOARD_STATUS,
    208                     available ? 1 : 0, enabled ? 1 : 0).sendToTarget();
    209         }
    210     }
    211 
    212     public void toggleRecentApps() {
    213         synchronized (mList) {
    214             mHandler.removeMessages(MSG_TOGGLE_RECENT_APPS);
    215             mHandler.obtainMessage(MSG_TOGGLE_RECENT_APPS, 0, 0, null).sendToTarget();
    216         }
    217     }
    218 
    219     public void preloadRecentApps() {
    220         synchronized (mList) {
    221             mHandler.removeMessages(MSG_PRELOAD_RECENT_APPS);
    222             mHandler.obtainMessage(MSG_PRELOAD_RECENT_APPS, 0, 0, null).sendToTarget();
    223         }
    224     }
    225 
    226     public void cancelPreloadRecentApps() {
    227         synchronized (mList) {
    228             mHandler.removeMessages(MSG_CANCEL_PRELOAD_RECENT_APPS);
    229             mHandler.obtainMessage(MSG_CANCEL_PRELOAD_RECENT_APPS, 0, 0, null).sendToTarget();
    230         }
    231     }
    232 
    233     public void setNavigationIconHints(int hints) {
    234         synchronized (mList) {
    235             mHandler.removeMessages(MSG_SET_NAVIGATION_ICON_HINTS);
    236             mHandler.obtainMessage(MSG_SET_NAVIGATION_ICON_HINTS, hints, 0, null).sendToTarget();
    237         }
    238     }
    239 
    240     private final class H extends Handler {
    241         public void handleMessage(Message msg) {
    242             final int what = msg.what & MSG_MASK;
    243             switch (what) {
    244                 case MSG_ICON: {
    245                     final int index = msg.what & INDEX_MASK;
    246                     final int viewIndex = mList.getViewIndex(index);
    247                     switch (msg.arg1) {
    248                         case OP_SET_ICON: {
    249                             StatusBarIcon icon = (StatusBarIcon)msg.obj;
    250                             StatusBarIcon old = mList.getIcon(index);
    251                             if (old == null) {
    252                                 mList.setIcon(index, icon);
    253                                 mCallbacks.addIcon(mList.getSlot(index), index, viewIndex, icon);
    254                             } else {
    255                                 mList.setIcon(index, icon);
    256                                 mCallbacks.updateIcon(mList.getSlot(index), index, viewIndex,
    257                                         old, icon);
    258                             }
    259                             break;
    260                         }
    261                         case OP_REMOVE_ICON:
    262                             if (mList.getIcon(index) != null) {
    263                                 mList.removeIcon(index);
    264                                 mCallbacks.removeIcon(mList.getSlot(index), index, viewIndex);
    265                             }
    266                             break;
    267                     }
    268                     break;
    269                 }
    270                 case MSG_ADD_NOTIFICATION: {
    271                     final NotificationQueueEntry ne = (NotificationQueueEntry)msg.obj;
    272                     mCallbacks.addNotification(ne.key, ne.notification);
    273                     break;
    274                 }
    275                 case MSG_UPDATE_NOTIFICATION: {
    276                     final NotificationQueueEntry ne = (NotificationQueueEntry)msg.obj;
    277                     mCallbacks.updateNotification(ne.key, ne.notification);
    278                     break;
    279                 }
    280                 case MSG_REMOVE_NOTIFICATION: {
    281                     mCallbacks.removeNotification((IBinder)msg.obj);
    282                     break;
    283                 }
    284                 case MSG_DISABLE:
    285                     mCallbacks.disable(msg.arg1);
    286                     break;
    287                 case MSG_SET_VISIBILITY:
    288                     if (msg.arg1 == OP_EXPAND) {
    289                         mCallbacks.animateExpand();
    290                     } else {
    291                         mCallbacks.animateCollapse(msg.arg2);
    292                     }
    293                     break;
    294                 case MSG_SET_SYSTEMUI_VISIBILITY:
    295                     mCallbacks.setSystemUiVisibility(msg.arg1, msg.arg2);
    296                     break;
    297                 case MSG_TOP_APP_WINDOW_CHANGED:
    298                     mCallbacks.topAppWindowChanged(msg.arg1 != 0);
    299                     break;
    300                 case MSG_SHOW_IME_BUTTON:
    301                     mCallbacks.setImeWindowStatus((IBinder)msg.obj, msg.arg1, msg.arg2);
    302                     break;
    303                 case MSG_SET_HARD_KEYBOARD_STATUS:
    304                     mCallbacks.setHardKeyboardStatus(msg.arg1 != 0, msg.arg2 != 0);
    305                     break;
    306                 case MSG_TOGGLE_RECENT_APPS:
    307                     mCallbacks.toggleRecentApps();
    308                     break;
    309                 case MSG_PRELOAD_RECENT_APPS:
    310                     mCallbacks.preloadRecentApps();
    311                     break;
    312                 case MSG_CANCEL_PRELOAD_RECENT_APPS:
    313                     mCallbacks.cancelPreloadRecentApps();
    314                     break;
    315                 case MSG_SET_NAVIGATION_ICON_HINTS:
    316                     mCallbacks.setNavigationIconHints(msg.arg1);
    317                     break;
    318             }
    319         }
    320     }
    321 }
    322 
    323