BaseStatusBar.java revision 0424716328a7d0f7bb794d24f7481a76be08d379
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 java.util.ArrayList;
20
21import android.content.Context;
22import android.content.pm.ApplicationInfo;
23import android.content.pm.PackageManager.NameNotFoundException;
24import android.os.Build;
25import android.os.Handler;
26import android.os.IBinder;
27import android.os.Message;
28import android.os.RemoteException;
29import android.os.ServiceManager;
30import android.util.Log;
31import android.util.Slog;
32import android.view.Display;
33import android.view.IWindowManager;
34import android.view.LayoutInflater;
35import android.view.MotionEvent;
36import android.view.View;
37import android.view.ViewGroup.LayoutParams;
38import android.view.WindowManager;
39import android.view.WindowManagerImpl;
40import android.widget.LinearLayout;
41
42import com.android.internal.statusbar.IStatusBarService;
43import com.android.internal.statusbar.StatusBarIcon;
44import com.android.internal.statusbar.StatusBarIconList;
45import com.android.internal.statusbar.StatusBarNotification;
46import com.android.systemui.SystemUI;
47import com.android.systemui.recent.RecentsPanelView;
48import com.android.systemui.recent.RecentTasksLoader;
49import com.android.systemui.recent.TaskDescription;
50import com.android.systemui.statusbar.CommandQueue;
51import com.android.systemui.statusbar.tablet.StatusBarPanel;
52
53import com.android.systemui.R;
54
55public abstract class BaseStatusBar extends SystemUI implements
56    CommandQueue.Callbacks, RecentsPanelView.OnRecentsPanelVisibilityChangedListener {
57    static final String TAG = "StatusBar";
58    private static final boolean DEBUG = false;
59
60    protected static final int MSG_OPEN_RECENTS_PANEL = 1020;
61    protected static final int MSG_CLOSE_RECENTS_PANEL = 1021;
62    protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
63    protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
64
65    protected CommandQueue mCommandQueue;
66    protected IStatusBarService mBarService;
67    protected H mHandler = createHandler();
68
69    // Recent apps
70    protected RecentsPanelView mRecentsPanel;
71    protected RecentTasksLoader mRecentTasksLoader;
72
73    // UI-specific methods
74
75    /**
76     * Create all windows necessary for the status bar (including navigation, overlay panels, etc)
77     * and add them to the window manager.
78     */
79    protected abstract void createAndAddWindows();
80
81    protected Display mDisplay;
82    private IWindowManager mWindowManager;
83
84
85    public IWindowManager getWindowManager() {
86        return mWindowManager;
87    }
88
89    public Display getDisplay() {
90        return mDisplay;
91    }
92
93    public IStatusBarService getStatusBarService() {
94        return mBarService;
95    }
96
97    public void start() {
98        mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
99                .getDefaultDisplay();
100
101        mWindowManager = IWindowManager.Stub.asInterface(
102                ServiceManager.getService(Context.WINDOW_SERVICE));
103
104        mBarService = IStatusBarService.Stub.asInterface(
105                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
106
107        // Connect in to the status bar manager service
108        StatusBarIconList iconList = new StatusBarIconList();
109        ArrayList<IBinder> notificationKeys = new ArrayList<IBinder>();
110        ArrayList<StatusBarNotification> notifications = new ArrayList<StatusBarNotification>();
111        mCommandQueue = new CommandQueue(this, iconList);
112
113        int[] switches = new int[7];
114        ArrayList<IBinder> binders = new ArrayList<IBinder>();
115        try {
116            mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications,
117                    switches, binders);
118        } catch (RemoteException ex) {
119            // If the system process isn't there we're doomed anyway.
120        }
121
122        createAndAddWindows();
123
124        disable(switches[0]);
125        setSystemUiVisibility(switches[1], 0xffffffff);
126        topAppWindowChanged(switches[2] != 0);
127        // StatusBarManagerService has a back up of IME token and it's restored here.
128        setImeWindowStatus(binders.get(0), switches[3], switches[4]);
129        setHardKeyboardStatus(switches[5] != 0, switches[6] != 0);
130
131        // Set up the initial icon state
132        int N = iconList.size();
133        int viewIndex = 0;
134        for (int i=0; i<N; i++) {
135            StatusBarIcon icon = iconList.getIcon(i);
136            if (icon != null) {
137                addIcon(iconList.getSlot(i), i, viewIndex, icon);
138                viewIndex++;
139            }
140        }
141
142        // Set up the initial notification state
143        N = notificationKeys.size();
144        if (N == notifications.size()) {
145            for (int i=0; i<N; i++) {
146                addNotification(notificationKeys.get(i), notifications.get(i));
147            }
148        } else {
149            Log.wtf(TAG, "Notification list length mismatch: keys=" + N
150                    + " notifications=" + notifications.size());
151        }
152
153        if (DEBUG) {
154            Slog.d(TAG, String.format(
155                    "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
156                   iconList.size(),
157                   switches[0],
158                   switches[1],
159                   switches[2],
160                   switches[3]
161                   ));
162        }
163    }
164
165    protected View updateNotificationVetoButton(View row, StatusBarNotification n) {
166        View vetoButton = row.findViewById(R.id.veto);
167        if (n.isClearable()) {
168            final String _pkg = n.pkg;
169            final String _tag = n.tag;
170            final int _id = n.id;
171            vetoButton.setOnClickListener(new View.OnClickListener() {
172                    public void onClick(View v) {
173                        try {
174                            mBarService.onNotificationClear(_pkg, _tag, _id);
175                        } catch (RemoteException ex) {
176                            // system process is dead if we're here.
177                        }
178                    }
179                });
180            vetoButton.setVisibility(View.VISIBLE);
181        } else {
182            vetoButton.setVisibility(View.GONE);
183        }
184        return vetoButton;
185    }
186
187
188    protected void applyLegacyRowBackground(StatusBarNotification sbn, View content) {
189        if (sbn.notification.contentView.getLayoutId() !=
190                com.android.internal.R.layout.notification_template_base) {
191            int version = 0;
192            try {
193                ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(sbn.pkg, 0);
194                version = info.targetSdkVersion;
195            } catch (NameNotFoundException ex) {
196                Slog.e(TAG, "Failed looking up ApplicationInfo for " + sbn.pkg, ex);
197            }
198            if (version > 0 && version < Build.VERSION_CODES.GINGERBREAD) {
199                content.setBackgroundResource(R.drawable.notification_row_legacy_bg);
200            } else {
201                content.setBackgroundResource(R.drawable.notification_row_bg);
202            }
203        }
204    }
205
206    public void dismissIntruder() {
207        // pass
208    }
209
210    @Override
211    public void toggleRecentApps() {
212        int msg = (mRecentsPanel.getVisibility() == View.VISIBLE)
213            ? MSG_CLOSE_RECENTS_PANEL : MSG_OPEN_RECENTS_PANEL;
214        mHandler.removeMessages(msg);
215        mHandler.sendEmptyMessage(msg);
216    }
217
218    @Override
219    public void preloadRecentApps() {
220        int msg = MSG_PRELOAD_RECENT_APPS;
221        mHandler.removeMessages(msg);
222        mHandler.sendEmptyMessage(msg);
223    }
224
225    @Override
226    public void cancelPreloadRecentApps() {
227        int msg = MSG_CANCEL_PRELOAD_RECENT_APPS;
228        mHandler.removeMessages(msg);
229        mHandler.sendEmptyMessage(msg);
230    }
231
232    @Override
233    public void onRecentsPanelVisibilityChanged(boolean visible) {
234    }
235
236    protected abstract WindowManager.LayoutParams getRecentsLayoutParams(
237            LayoutParams layoutParams);
238
239    protected void updateRecentsPanel() {
240        // Recents Panel
241        boolean visible = false;
242        ArrayList<TaskDescription> recentTasksList = null;
243        boolean firstScreenful = false;
244        if (mRecentsPanel != null) {
245            visible = mRecentsPanel.isShowing();
246            WindowManagerImpl.getDefault().removeView(mRecentsPanel);
247            if (visible) {
248                recentTasksList = mRecentsPanel.getRecentTasksList();
249                firstScreenful = mRecentsPanel.getFirstScreenful();
250            }
251        }
252
253        // Provide RecentsPanelView with a temporary parent to allow layout params to work.
254        LinearLayout tmpRoot = new LinearLayout(mContext);
255        mRecentsPanel = (RecentsPanelView) LayoutInflater.from(mContext).inflate(
256                 R.layout.status_bar_recent_panel, tmpRoot, false);
257        mRecentsPanel.setRecentTasksLoader(mRecentTasksLoader);
258        mRecentTasksLoader.setRecentsPanel(mRecentsPanel);
259        mRecentsPanel.setOnTouchListener(
260                 new TouchOutsideListener(MSG_CLOSE_RECENTS_PANEL, mRecentsPanel));
261        mRecentsPanel.setVisibility(View.GONE);
262
263
264        WindowManager.LayoutParams lp = getRecentsLayoutParams(mRecentsPanel.getLayoutParams());
265
266        WindowManagerImpl.getDefault().addView(mRecentsPanel, lp);
267        mRecentsPanel.setBar(this);
268        if (visible) {
269            mRecentsPanel.show(true, false, recentTasksList, firstScreenful);
270        }
271
272    }
273
274    protected H createHandler() {
275         return new H();
276    }
277
278    protected class H extends Handler {
279        public void handleMessage(Message m) {
280            switch (m.what) {
281             case MSG_OPEN_RECENTS_PANEL:
282                  if (DEBUG) Slog.d(TAG, "opening recents panel");
283                  if (mRecentsPanel != null) {
284                      mRecentsPanel.show(true, true);
285                  }
286                  break;
287             case MSG_CLOSE_RECENTS_PANEL:
288                  if (DEBUG) Slog.d(TAG, "closing recents panel");
289                  if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
290                      mRecentsPanel.show(false, true);
291                  }
292                  break;
293             case MSG_PRELOAD_RECENT_APPS:
294                  if (DEBUG) Slog.d(TAG, "preloading recents");
295                  mRecentsPanel.preloadRecentTasksList();
296                  break;
297             case MSG_CANCEL_PRELOAD_RECENT_APPS:
298                  if (DEBUG) Slog.d(TAG, "cancel preloading recents");
299                  mRecentsPanel.clearRecentTasksList();
300                  break;
301            }
302        }
303    }
304
305    public class TouchOutsideListener implements View.OnTouchListener {
306        private int mMsg;
307        private StatusBarPanel mPanel;
308
309        public TouchOutsideListener(int msg, StatusBarPanel panel) {
310            mMsg = msg;
311            mPanel = panel;
312        }
313
314        public boolean onTouch(View v, MotionEvent ev) {
315            final int action = ev.getAction();
316            if (action == MotionEvent.ACTION_OUTSIDE
317                || (action == MotionEvent.ACTION_DOWN
318                    && !mPanel.isInContentArea((int)ev.getX(), (int)ev.getY()))) {
319                mHandler.removeMessages(mMsg);
320                mHandler.sendEmptyMessage(mMsg);
321                return true;
322            }
323            return false;
324        }
325    }
326}
327