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.Bundle;
20 import android.os.Handler;
21 import android.os.IBinder;
22 import android.os.Message;
23 import android.util.Pair;
24 
25 import com.android.internal.statusbar.IStatusBar;
26 import com.android.internal.statusbar.StatusBarIcon;
27 import com.android.internal.statusbar.StatusBarIconList;
28 
29 /**
30  * This class takes the functions from IStatusBar that come in on
31  * binder pool threads and posts messages to get them onto the main
32  * thread, and calls onto Callbacks.  It also takes care of
33  * coalescing these calls so they don't stack up.  For the calls
34  * are coalesced, note that they are all idempotent.
35  */
36 public class CommandQueue extends IStatusBar.Stub {
37     private static final int INDEX_MASK = 0xffff;
38     private static final int MSG_SHIFT  = 16;
39     private static final int MSG_MASK   = 0xffff << MSG_SHIFT;
40 
41     private static final int OP_SET_ICON    = 1;
42     private static final int OP_REMOVE_ICON = 2;
43 
44     private static final int MSG_ICON                       = 1 << MSG_SHIFT;
45     private static final int MSG_DISABLE                    = 2 << MSG_SHIFT;
46     private static final int MSG_EXPAND_NOTIFICATIONS       = 3 << MSG_SHIFT;
47     private static final int MSG_COLLAPSE_PANELS            = 4 << MSG_SHIFT;
48     private static final int MSG_EXPAND_SETTINGS            = 5 << MSG_SHIFT;
49     private static final int MSG_SET_SYSTEMUI_VISIBILITY    = 6 << MSG_SHIFT;
50     private static final int MSG_TOP_APP_WINDOW_CHANGED     = 7 << MSG_SHIFT;
51     private static final int MSG_SHOW_IME_BUTTON            = 8 << MSG_SHIFT;
52     private static final int MSG_TOGGLE_RECENT_APPS         = 9 << MSG_SHIFT;
53     private static final int MSG_PRELOAD_RECENT_APPS        = 10 << MSG_SHIFT;
54     private static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 11 << MSG_SHIFT;
55     private static final int MSG_SET_WINDOW_STATE           = 12 << MSG_SHIFT;
56     private static final int MSG_SHOW_RECENT_APPS           = 13 << MSG_SHIFT;
57     private static final int MSG_HIDE_RECENT_APPS           = 14 << MSG_SHIFT;
58     private static final int MSG_BUZZ_BEEP_BLINKED          = 15 << MSG_SHIFT;
59     private static final int MSG_NOTIFICATION_LIGHT_OFF     = 16 << MSG_SHIFT;
60     private static final int MSG_NOTIFICATION_LIGHT_PULSE   = 17 << MSG_SHIFT;
61     private static final int MSG_SHOW_SCREEN_PIN_REQUEST    = 18 << MSG_SHIFT;
62     private static final int MSG_APP_TRANSITION_PENDING     = 19 << MSG_SHIFT;
63     private static final int MSG_APP_TRANSITION_CANCELLED   = 20 << MSG_SHIFT;
64     private static final int MSG_APP_TRANSITION_STARTING    = 21 << MSG_SHIFT;
65     private static final int MSG_ASSIST_DISCLOSURE          = 22 << MSG_SHIFT;
66     private static final int MSG_START_ASSIST               = 23 << MSG_SHIFT;
67 
68     public static final int FLAG_EXCLUDE_NONE = 0;
69     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
70     public static final int FLAG_EXCLUDE_RECENTS_PANEL = 1 << 1;
71     public static final int FLAG_EXCLUDE_NOTIFICATION_PANEL = 1 << 2;
72     public static final int FLAG_EXCLUDE_INPUT_METHODS_PANEL = 1 << 3;
73     public static final int FLAG_EXCLUDE_COMPAT_MODE_PANEL = 1 << 4;
74 
75     private static final String SHOW_IME_SWITCHER_KEY = "showImeSwitcherKey";
76 
77     private StatusBarIconList mList;
78     private Callbacks mCallbacks;
79     private Handler mHandler = new H();
80 
81     /**
82      * These methods are called back on the main thread.
83      */
84     public interface Callbacks {
addIcon(String slot, int index, int viewIndex, StatusBarIcon icon)85         public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon);
updateIcon(String slot, int index, int viewIndex, StatusBarIcon old, StatusBarIcon icon)86         public void updateIcon(String slot, int index, int viewIndex,
87                 StatusBarIcon old, StatusBarIcon icon);
removeIcon(String slot, int index, int viewIndex)88         public void removeIcon(String slot, int index, int viewIndex);
disable(int state1, int state2, boolean animate)89         public void disable(int state1, int state2, boolean animate);
animateExpandNotificationsPanel()90         public void animateExpandNotificationsPanel();
animateCollapsePanels(int flags)91         public void animateCollapsePanels(int flags);
animateExpandSettingsPanel()92         public void animateExpandSettingsPanel();
setSystemUiVisibility(int vis, int mask)93         public void setSystemUiVisibility(int vis, int mask);
topAppWindowChanged(boolean visible)94         public void topAppWindowChanged(boolean visible);
setImeWindowStatus(IBinder token, int vis, int backDisposition, boolean showImeSwitcher)95         public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
96                 boolean showImeSwitcher);
showRecentApps(boolean triggeredFromAltTab)97         public void showRecentApps(boolean triggeredFromAltTab);
hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey)98         public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
toggleRecentApps()99         public void toggleRecentApps();
preloadRecentApps()100         public void preloadRecentApps();
cancelPreloadRecentApps()101         public void cancelPreloadRecentApps();
setWindowState(int window, int state)102         public void setWindowState(int window, int state);
buzzBeepBlinked()103         public void buzzBeepBlinked();
notificationLightOff()104         public void notificationLightOff();
notificationLightPulse(int argb, int onMillis, int offMillis)105         public void notificationLightPulse(int argb, int onMillis, int offMillis);
showScreenPinningRequest()106         public void showScreenPinningRequest();
appTransitionPending()107         public void appTransitionPending();
appTransitionCancelled()108         public void appTransitionCancelled();
appTransitionStarting(long startTime, long duration)109         public void appTransitionStarting(long startTime, long duration);
showAssistDisclosure()110         public void showAssistDisclosure();
startAssist(Bundle args)111         public void startAssist(Bundle args);
112     }
113 
CommandQueue(Callbacks callbacks, StatusBarIconList list)114     public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
115         mCallbacks = callbacks;
116         mList = list;
117     }
118 
setIcon(int index, StatusBarIcon icon)119     public void setIcon(int index, StatusBarIcon icon) {
120         synchronized (mList) {
121             int what = MSG_ICON | index;
122             mHandler.removeMessages(what);
123             mHandler.obtainMessage(what, OP_SET_ICON, 0, icon.clone()).sendToTarget();
124         }
125     }
126 
removeIcon(int index)127     public void removeIcon(int index) {
128         synchronized (mList) {
129             int what = MSG_ICON | index;
130             mHandler.removeMessages(what);
131             mHandler.obtainMessage(what, OP_REMOVE_ICON, 0, null).sendToTarget();
132         }
133     }
134 
disable(int state1, int state2)135     public void disable(int state1, int state2) {
136         synchronized (mList) {
137             mHandler.removeMessages(MSG_DISABLE);
138             mHandler.obtainMessage(MSG_DISABLE, state1, state2, null).sendToTarget();
139         }
140     }
141 
animateExpandNotificationsPanel()142     public void animateExpandNotificationsPanel() {
143         synchronized (mList) {
144             mHandler.removeMessages(MSG_EXPAND_NOTIFICATIONS);
145             mHandler.sendEmptyMessage(MSG_EXPAND_NOTIFICATIONS);
146         }
147     }
148 
animateCollapsePanels()149     public void animateCollapsePanels() {
150         synchronized (mList) {
151             mHandler.removeMessages(MSG_COLLAPSE_PANELS);
152             mHandler.sendEmptyMessage(MSG_COLLAPSE_PANELS);
153         }
154     }
155 
animateExpandSettingsPanel()156     public void animateExpandSettingsPanel() {
157         synchronized (mList) {
158             mHandler.removeMessages(MSG_EXPAND_SETTINGS);
159             mHandler.sendEmptyMessage(MSG_EXPAND_SETTINGS);
160         }
161     }
162 
setSystemUiVisibility(int vis, int mask)163     public void setSystemUiVisibility(int vis, int mask) {
164         synchronized (mList) {
165             // Don't coalesce these, since it might have one time flags set such as
166             // STATUS_BAR_UNHIDE which might get lost.
167             mHandler.obtainMessage(MSG_SET_SYSTEMUI_VISIBILITY, vis, mask, null).sendToTarget();
168         }
169     }
170 
topAppWindowChanged(boolean menuVisible)171     public void topAppWindowChanged(boolean menuVisible) {
172         synchronized (mList) {
173             mHandler.removeMessages(MSG_TOP_APP_WINDOW_CHANGED);
174             mHandler.obtainMessage(MSG_TOP_APP_WINDOW_CHANGED, menuVisible ? 1 : 0, 0,
175                     null).sendToTarget();
176         }
177     }
178 
setImeWindowStatus(IBinder token, int vis, int backDisposition, boolean showImeSwitcher)179     public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
180             boolean showImeSwitcher) {
181         synchronized (mList) {
182             mHandler.removeMessages(MSG_SHOW_IME_BUTTON);
183             Message m = mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, vis, backDisposition, token);
184             m.getData().putBoolean(SHOW_IME_SWITCHER_KEY, showImeSwitcher);
185             m.sendToTarget();
186         }
187     }
188 
showRecentApps(boolean triggeredFromAltTab)189     public void showRecentApps(boolean triggeredFromAltTab) {
190         synchronized (mList) {
191             mHandler.removeMessages(MSG_SHOW_RECENT_APPS);
192             mHandler.obtainMessage(MSG_SHOW_RECENT_APPS,
193                     triggeredFromAltTab ? 1 : 0, 0, null).sendToTarget();
194         }
195     }
196 
hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey)197     public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
198         synchronized (mList) {
199             mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
200             mHandler.obtainMessage(MSG_HIDE_RECENT_APPS,
201                     triggeredFromAltTab ? 1 : 0, triggeredFromHomeKey ? 1 : 0,
202                     null).sendToTarget();
203         }
204     }
205 
toggleRecentApps()206     public void toggleRecentApps() {
207         synchronized (mList) {
208             mHandler.removeMessages(MSG_TOGGLE_RECENT_APPS);
209             mHandler.obtainMessage(MSG_TOGGLE_RECENT_APPS, 0, 0, null).sendToTarget();
210         }
211     }
212 
preloadRecentApps()213     public void preloadRecentApps() {
214         synchronized (mList) {
215             mHandler.removeMessages(MSG_PRELOAD_RECENT_APPS);
216             mHandler.obtainMessage(MSG_PRELOAD_RECENT_APPS, 0, 0, null).sendToTarget();
217         }
218     }
219 
cancelPreloadRecentApps()220     public void cancelPreloadRecentApps() {
221         synchronized (mList) {
222             mHandler.removeMessages(MSG_CANCEL_PRELOAD_RECENT_APPS);
223             mHandler.obtainMessage(MSG_CANCEL_PRELOAD_RECENT_APPS, 0, 0, null).sendToTarget();
224         }
225     }
226 
setWindowState(int window, int state)227     public void setWindowState(int window, int state) {
228         synchronized (mList) {
229             // don't coalesce these
230             mHandler.obtainMessage(MSG_SET_WINDOW_STATE, window, state, null).sendToTarget();
231         }
232     }
233 
buzzBeepBlinked()234     public void buzzBeepBlinked() {
235         synchronized (mList) {
236             mHandler.removeMessages(MSG_BUZZ_BEEP_BLINKED);
237             mHandler.sendEmptyMessage(MSG_BUZZ_BEEP_BLINKED);
238         }
239     }
240 
notificationLightOff()241     public void notificationLightOff() {
242         synchronized (mList) {
243             mHandler.sendEmptyMessage(MSG_NOTIFICATION_LIGHT_OFF);
244         }
245     }
246 
notificationLightPulse(int argb, int onMillis, int offMillis)247     public void notificationLightPulse(int argb, int onMillis, int offMillis) {
248         synchronized (mList) {
249             mHandler.obtainMessage(MSG_NOTIFICATION_LIGHT_PULSE, onMillis, offMillis, argb)
250                     .sendToTarget();
251         }
252     }
253 
showScreenPinningRequest()254     public void showScreenPinningRequest() {
255         synchronized (mList) {
256             mHandler.sendEmptyMessage(MSG_SHOW_SCREEN_PIN_REQUEST);
257         }
258     }
259 
appTransitionPending()260     public void appTransitionPending() {
261         synchronized (mList) {
262             mHandler.removeMessages(MSG_APP_TRANSITION_PENDING);
263             mHandler.sendEmptyMessage(MSG_APP_TRANSITION_PENDING);
264         }
265     }
266 
appTransitionCancelled()267     public void appTransitionCancelled() {
268         synchronized (mList) {
269             mHandler.removeMessages(MSG_APP_TRANSITION_PENDING);
270             mHandler.sendEmptyMessage(MSG_APP_TRANSITION_PENDING);
271         }
272     }
273 
appTransitionStarting(long startTime, long duration)274     public void appTransitionStarting(long startTime, long duration) {
275         synchronized (mList) {
276             mHandler.removeMessages(MSG_APP_TRANSITION_STARTING);
277             mHandler.obtainMessage(MSG_APP_TRANSITION_STARTING, Pair.create(startTime, duration))
278                     .sendToTarget();
279         }
280     }
281 
showAssistDisclosure()282     public void showAssistDisclosure() {
283         synchronized (mList) {
284             mHandler.removeMessages(MSG_ASSIST_DISCLOSURE);
285             mHandler.obtainMessage(MSG_ASSIST_DISCLOSURE).sendToTarget();
286         }
287     }
288 
startAssist(Bundle args)289     public void startAssist(Bundle args) {
290         synchronized (mList) {
291             mHandler.removeMessages(MSG_START_ASSIST);
292             mHandler.obtainMessage(MSG_START_ASSIST, args).sendToTarget();
293         }
294     }
295 
296     private final class H extends Handler {
handleMessage(Message msg)297         public void handleMessage(Message msg) {
298             final int what = msg.what & MSG_MASK;
299             switch (what) {
300                 case MSG_ICON: {
301                     final int index = msg.what & INDEX_MASK;
302                     final int viewIndex = mList.getViewIndex(index);
303                     switch (msg.arg1) {
304                         case OP_SET_ICON: {
305                             StatusBarIcon icon = (StatusBarIcon)msg.obj;
306                             StatusBarIcon old = mList.getIcon(index);
307                             if (old == null) {
308                                 mList.setIcon(index, icon);
309                                 mCallbacks.addIcon(mList.getSlot(index), index, viewIndex, icon);
310                             } else {
311                                 mList.setIcon(index, icon);
312                                 mCallbacks.updateIcon(mList.getSlot(index), index, viewIndex,
313                                         old, icon);
314                             }
315                             break;
316                         }
317                         case OP_REMOVE_ICON:
318                             if (mList.getIcon(index) != null) {
319                                 mList.removeIcon(index);
320                                 mCallbacks.removeIcon(mList.getSlot(index), index, viewIndex);
321                             }
322                             break;
323                     }
324                     break;
325                 }
326                 case MSG_DISABLE:
327                     mCallbacks.disable(msg.arg1, msg.arg2, true /* animate */);
328                     break;
329                 case MSG_EXPAND_NOTIFICATIONS:
330                     mCallbacks.animateExpandNotificationsPanel();
331                     break;
332                 case MSG_COLLAPSE_PANELS:
333                     mCallbacks.animateCollapsePanels(0);
334                     break;
335                 case MSG_EXPAND_SETTINGS:
336                     mCallbacks.animateExpandSettingsPanel();
337                     break;
338                 case MSG_SET_SYSTEMUI_VISIBILITY:
339                     mCallbacks.setSystemUiVisibility(msg.arg1, msg.arg2);
340                     break;
341                 case MSG_TOP_APP_WINDOW_CHANGED:
342                     mCallbacks.topAppWindowChanged(msg.arg1 != 0);
343                     break;
344                 case MSG_SHOW_IME_BUTTON:
345                     mCallbacks.setImeWindowStatus((IBinder) msg.obj, msg.arg1, msg.arg2,
346                             msg.getData().getBoolean(SHOW_IME_SWITCHER_KEY, false));
347                     break;
348                 case MSG_SHOW_RECENT_APPS:
349                     mCallbacks.showRecentApps(msg.arg1 != 0);
350                     break;
351                 case MSG_HIDE_RECENT_APPS:
352                     mCallbacks.hideRecentApps(msg.arg1 != 0, msg.arg2 != 0);
353                     break;
354                 case MSG_TOGGLE_RECENT_APPS:
355                     mCallbacks.toggleRecentApps();
356                     break;
357                 case MSG_PRELOAD_RECENT_APPS:
358                     mCallbacks.preloadRecentApps();
359                     break;
360                 case MSG_CANCEL_PRELOAD_RECENT_APPS:
361                     mCallbacks.cancelPreloadRecentApps();
362                     break;
363                 case MSG_SET_WINDOW_STATE:
364                     mCallbacks.setWindowState(msg.arg1, msg.arg2);
365                     break;
366                 case MSG_BUZZ_BEEP_BLINKED:
367                     mCallbacks.buzzBeepBlinked();
368                     break;
369                 case MSG_NOTIFICATION_LIGHT_OFF:
370                     mCallbacks.notificationLightOff();
371                     break;
372                 case MSG_NOTIFICATION_LIGHT_PULSE:
373                     mCallbacks.notificationLightPulse((Integer) msg.obj, msg.arg1, msg.arg2);
374                     break;
375                 case MSG_SHOW_SCREEN_PIN_REQUEST:
376                     mCallbacks.showScreenPinningRequest();
377                     break;
378                 case MSG_APP_TRANSITION_PENDING:
379                     mCallbacks.appTransitionPending();
380                     break;
381                 case MSG_APP_TRANSITION_CANCELLED:
382                     mCallbacks.appTransitionCancelled();
383                     break;
384                 case MSG_APP_TRANSITION_STARTING:
385                     Pair<Long, Long> data = (Pair<Long, Long>) msg.obj;
386                     mCallbacks.appTransitionStarting(data.first, data.second);
387                     break;
388                 case MSG_ASSIST_DISCLOSURE:
389                     mCallbacks.showAssistDisclosure();
390                     break;
391                 case MSG_START_ASSIST:
392                     mCallbacks.startAssist((Bundle) msg.obj);
393                     break;
394             }
395         }
396     }
397 }
398 
399