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