CommandQueue.java revision 165ce066b701ba0153000f0692bfc7032655d17d
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
17package com.android.systemui.statusbar;
18
19import android.os.Bundle;
20import android.os.Handler;
21import android.os.IBinder;
22import android.os.Message;
23import android.util.Pair;
24
25import com.android.internal.statusbar.IStatusBar;
26import com.android.internal.statusbar.StatusBarIcon;
27import 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 */
36public 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 {
85        public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon);
86        public void updateIcon(String slot, int index, int viewIndex,
87                StatusBarIcon old, StatusBarIcon icon);
88        public void removeIcon(String slot, int index, int viewIndex);
89        public void disable(int state1, int state2, boolean animate);
90        public void animateExpandNotificationsPanel();
91        public void animateCollapsePanels(int flags);
92        public void animateExpandSettingsPanel();
93        public void setSystemUiVisibility(int vis, int mask);
94        public void topAppWindowChanged(boolean visible);
95        public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
96                boolean showImeSwitcher);
97        public void showRecentApps(boolean triggeredFromAltTab);
98        public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
99        public void toggleRecentApps();
100        public void preloadRecentApps();
101        public void cancelPreloadRecentApps();
102        public void setWindowState(int window, int state);
103        public void buzzBeepBlinked();
104        public void notificationLightOff();
105        public void notificationLightPulse(int argb, int onMillis, int offMillis);
106        public void showScreenPinningRequest();
107        public void appTransitionPending();
108        public void appTransitionCancelled();
109        public void appTransitionStarting(long startTime, long duration);
110        public void showAssistDisclosure();
111        public void startAssist(Bundle args);
112    }
113
114    public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
115        mCallbacks = callbacks;
116        mList = list;
117    }
118
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
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
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
142    public void animateExpandNotificationsPanel() {
143        synchronized (mList) {
144            mHandler.removeMessages(MSG_EXPAND_NOTIFICATIONS);
145            mHandler.sendEmptyMessage(MSG_EXPAND_NOTIFICATIONS);
146        }
147    }
148
149    public void animateCollapsePanels() {
150        synchronized (mList) {
151            mHandler.removeMessages(MSG_COLLAPSE_PANELS);
152            mHandler.sendEmptyMessage(MSG_COLLAPSE_PANELS);
153        }
154    }
155
156    public void animateExpandSettingsPanel() {
157        synchronized (mList) {
158            mHandler.removeMessages(MSG_EXPAND_SETTINGS);
159            mHandler.sendEmptyMessage(MSG_EXPAND_SETTINGS);
160        }
161    }
162
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
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
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
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
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
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
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
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
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
234    public void buzzBeepBlinked() {
235        synchronized (mList) {
236            mHandler.removeMessages(MSG_BUZZ_BEEP_BLINKED);
237            mHandler.sendEmptyMessage(MSG_BUZZ_BEEP_BLINKED);
238        }
239    }
240
241    public void notificationLightOff() {
242        synchronized (mList) {
243            mHandler.sendEmptyMessage(MSG_NOTIFICATION_LIGHT_OFF);
244        }
245    }
246
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
254    public void showScreenPinningRequest() {
255        synchronized (mList) {
256            mHandler.sendEmptyMessage(MSG_SHOW_SCREEN_PIN_REQUEST);
257        }
258    }
259
260    public void appTransitionPending() {
261        synchronized (mList) {
262            mHandler.removeMessages(MSG_APP_TRANSITION_PENDING);
263            mHandler.sendEmptyMessage(MSG_APP_TRANSITION_PENDING);
264        }
265    }
266
267    public void appTransitionCancelled() {
268        synchronized (mList) {
269            mHandler.removeMessages(MSG_APP_TRANSITION_PENDING);
270            mHandler.sendEmptyMessage(MSG_APP_TRANSITION_PENDING);
271        }
272    }
273
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
282    public void showAssistDisclosure() {
283        synchronized (mList) {
284            mHandler.removeMessages(MSG_ASSIST_DISCLOSURE);
285            mHandler.obtainMessage(MSG_ASSIST_DISCLOSURE).sendToTarget();
286        }
287    }
288
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 {
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