blob: 26a41f321144f0d919c7e47ac4a6fe1d2c3e878b [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 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.server.status;
18
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019import android.app.PendingIntent;
20import android.app.StatusBarManager;
21import android.content.BroadcastReceiver;
22import android.content.Context;
23import android.content.Intent;
24import android.content.IntentFilter;
25import android.content.pm.PackageManager;
26import android.content.res.Resources;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.net.Uri;
28import android.os.IBinder;
29import android.os.RemoteException;
30import android.os.Binder;
Joe Onoratof3f0e052010-05-14 18:49:29 -070031import android.os.Handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.os.SystemClock;
Joe Onorato8a9b2202010-02-26 18:56:32 -080033import android.util.Slog;
Joe Onorato0cbda992010-05-02 16:28:15 -070034
35import com.android.internal.statusbar.IStatusBar;
36import com.android.internal.statusbar.IStatusBarService;
37import com.android.internal.statusbar.StatusBarIcon;
38import com.android.internal.statusbar.StatusBarIconList;
Joe Onorato18e69df2010-05-17 22:26:12 -070039import com.android.internal.statusbar.StatusBarNotification;
40import com.android.internal.statusbar.StatusBarNotificationList;
The Android Open Source Project10592532009-03-18 17:39:46 -070041
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import java.io.FileDescriptor;
43import java.io.PrintWriter;
44import java.util.ArrayList;
45import java.util.HashMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046
47
48/**
Joe Onoratof3f0e052010-05-14 18:49:29 -070049 * A note on locking: We rely on the fact that calls onto mBar are oneway or
50 * if they are local, that they just enqueue messages to not deadlock.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051 */
Joe Onorato089de882010-04-12 08:18:45 -070052public class StatusBarManagerService extends IStatusBarService.Stub
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053{
Joe Onorato4762c2d2010-05-17 15:42:59 -070054 static final String TAG = "StatusBarManagerService";
Joe Onoratof3f0e052010-05-14 18:49:29 -070055 static final boolean SPEW = true;
Joe Onoratodf7dbb62009-11-17 10:43:37 -080056
Joe Onorato2314aab2010-04-08 16:41:23 -050057 public static final String ACTION_STATUSBAR_START
58 = "com.android.internal.policy.statusbar.START";
59
Joe Onoratof3f0e052010-05-14 18:49:29 -070060 final Context mContext;
61 Handler mHandler = new Handler();
62 NotificationCallbacks mNotificationCallbacks;
Joe Onorato4762c2d2010-05-17 15:42:59 -070063 volatile IStatusBar mBar;
Joe Onoratof3f0e052010-05-14 18:49:29 -070064 StatusBarIconList mIcons = new StatusBarIconList();
Joe Onorato18e69df2010-05-17 22:26:12 -070065 StatusBarNotificationList mNotifications = new StatusBarNotificationList();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066
Joe Onoratof3f0e052010-05-14 18:49:29 -070067 // for disabling the status bar
68 ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
69 int mDisabled = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070
71 private class DisableRecord implements IBinder.DeathRecipient {
72 String pkg;
73 int what;
74 IBinder token;
75
76 public void binderDied() {
Joe Onorato8a9b2202010-02-26 18:56:32 -080077 Slog.i(TAG, "binder died for pkg=" + pkg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078 disable(0, token, pkg);
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -070079 token.unlinkToDeath(this, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080 }
81 }
82
83 public interface NotificationCallbacks {
84 void onSetDisabled(int status);
85 void onClearAll();
Fred Quintana6ecaff12009-09-25 14:23:13 -070086 void onNotificationClick(String pkg, String tag, int id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 void onPanelRevealed();
88 }
89
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 /**
91 * Construct the service, add the status bar view to the window manager
92 */
Joe Onorato089de882010-04-12 08:18:45 -070093 public StatusBarManagerService(Context context) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 mContext = context;
Joe Onorato0cbda992010-05-02 16:28:15 -070095
96 final Resources res = context.getResources();
97 mIcons.defineSlots(res.getStringArray(com.android.internal.R.array.status_bar_icon_order));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 }
99
100 public void setNotificationCallbacks(NotificationCallbacks listener) {
101 mNotificationCallbacks = listener;
102 }
103
104 // ================================================================================
105 // Constructing the view
106 // ================================================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107
108 public void systemReady() {
Joe Onorato2314aab2010-04-08 16:41:23 -0500109 }
110
111 public void systemReady2() {
112 // Start the status bar app
113 Intent intent = new Intent(ACTION_STATUSBAR_START);
114 mContext.sendBroadcast(intent /** permission **/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115 }
Joe Onorato4762c2d2010-05-17 15:42:59 -0700116
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 // ================================================================================
Joe Onorato25f95f92010-04-08 18:37:10 -0500118 // From IStatusBarService
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 // ================================================================================
Joe Onoratof3f0e052010-05-14 18:49:29 -0700120 public void expand() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 enforceExpandStatusBar();
Joe Onorato4762c2d2010-05-17 15:42:59 -0700122
123 if (mBar != null) {
124 try {
125 mBar.animateExpand();
126 } catch (RemoteException ex) {
127 }
128 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 }
130
Joe Onoratof3f0e052010-05-14 18:49:29 -0700131 public void collapse() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132 enforceExpandStatusBar();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133
Joe Onorato4762c2d2010-05-17 15:42:59 -0700134 if (mBar != null) {
135 try {
136 mBar.animateCollapse();
137 } catch (RemoteException ex) {
138 }
139 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 }
141
142 public void disable(int what, IBinder token, String pkg) {
143 enforceStatusBar();
Joe Onoratof3f0e052010-05-14 18:49:29 -0700144
145 // It's important that the the callback and the call to mBar get done
146 // in the same order when multiple threads are calling this function
147 // so they are paired correctly. The messages on the handler will be
148 // handled in the order they were enqueued, but will be outside the lock.
149 synchronized (mDisableRecords) {
150 manageDisableListLocked(what, token, pkg);
151 final int net = gatherDisableActionsLocked();
152 Slog.d(TAG, "disable... net=0x" + Integer.toHexString(net));
153 if (net != mDisabled) {
154 mDisabled = net;
155 mHandler.post(new Runnable() {
156 public void run() {
157 mNotificationCallbacks.onSetDisabled(net);
158 }
159 });
160 if (mBar != null) {
161 try {
162 mBar.disable(net);
163 } catch (RemoteException ex) {
164 }
165 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 }
168 }
169
Joe Onorato0cbda992010-05-02 16:28:15 -0700170 public void setIcon(String slot, String iconPackage, int iconId, int iconLevel) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 enforceStatusBar();
Joe Onorato0cbda992010-05-02 16:28:15 -0700172
173 synchronized (mIcons) {
174 int index = mIcons.getSlotIndex(slot);
175 if (index < 0) {
176 throw new SecurityException("invalid status bar icon slot: " + slot);
177 }
178
179 StatusBarIcon icon = new StatusBarIcon(iconPackage, iconId, iconLevel);
Joe Onorato66d7d012010-05-14 10:05:10 -0700180 //Slog.d(TAG, "setIcon slot=" + slot + " index=" + index + " icon=" + icon);
Joe Onorato0cbda992010-05-02 16:28:15 -0700181 mIcons.setIcon(index, icon);
182
Joe Onorato0cbda992010-05-02 16:28:15 -0700183 if (mBar != null) {
184 try {
185 mBar.setIcon(index, icon);
186 } catch (RemoteException ex) {
187 }
188 }
189 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 }
191
Joe Onorato0cbda992010-05-02 16:28:15 -0700192 public void setIconVisibility(String slot, boolean visible) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 enforceStatusBar();
Joe Onorato0cbda992010-05-02 16:28:15 -0700194
Joe Onorato514ad6632010-05-13 18:49:00 -0700195 synchronized (mIcons) {
196 int index = mIcons.getSlotIndex(slot);
197 if (index < 0) {
198 throw new SecurityException("invalid status bar icon slot: " + slot);
199 }
200
201 StatusBarIcon icon = mIcons.getIcon(index);
202 if (icon == null) {
203 return;
204 }
205
206 if (icon.visible != visible) {
207 icon.visible = visible;
208
Joe Onorato514ad6632010-05-13 18:49:00 -0700209 if (mBar != null) {
210 try {
211 mBar.setIcon(index, icon);
212 } catch (RemoteException ex) {
213 }
214 }
215 }
216 }
Joe Onorato0cbda992010-05-02 16:28:15 -0700217 }
218
219 public void removeIcon(String slot) {
220 enforceStatusBar();
221
222 synchronized (mIcons) {
223 int index = mIcons.getSlotIndex(slot);
224 if (index < 0) {
225 throw new SecurityException("invalid status bar icon slot: " + slot);
226 }
227
228 mIcons.removeIcon(index);
229
Joe Onorato0cbda992010-05-02 16:28:15 -0700230 if (mBar != null) {
231 try {
232 mBar.removeIcon(index);
233 } catch (RemoteException ex) {
234 }
235 }
236 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 }
238
239 private void enforceStatusBar() {
Joe Onorato0cbda992010-05-02 16:28:15 -0700240 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR,
Joe Onorato089de882010-04-12 08:18:45 -0700241 "StatusBarManagerService");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 }
243
244 private void enforceExpandStatusBar() {
Joe Onorato0cbda992010-05-02 16:28:15 -0700245 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.EXPAND_STATUS_BAR,
Joe Onorato089de882010-04-12 08:18:45 -0700246 "StatusBarManagerService");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 }
248
Joe Onorato4762c2d2010-05-17 15:42:59 -0700249
250 // ================================================================================
251 // Callbacks from the status bar service.
252 // ================================================================================
Joe Onorato0cbda992010-05-02 16:28:15 -0700253 public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList) {
254 Slog.i(TAG, "registerStatusBar bar=" + bar);
255 mBar = bar;
256 iconList.copyFrom(mIcons);
Joe Onorato2314aab2010-04-08 16:41:23 -0500257 }
Joe Onoratoaaba60b2010-05-23 15:18:41 -0400258
Joe Onorato4762c2d2010-05-17 15:42:59 -0700259 /**
260 * The status bar service should call this when the user changes whether
261 * the status bar is visible or not.
262 */
263 public void visibilityChanged(boolean visible) {
264 Slog.d(TAG, "visibilityChanged visible=" + visible);
265 }
266
Joe Onoratoaaba60b2010-05-23 15:18:41 -0400267 public void onNotificationClick(String pkg, String tag, int id) {
268 mNotificationCallbacks.onNotificationClick(pkg, tag, id);
269 }
270
271 public void onClearAllNotifications() {
272 mNotificationCallbacks.onClearAll();
273 }
274
Joe Onorato18e69df2010-05-17 22:26:12 -0700275 // ================================================================================
276 // Callbacks for NotificationManagerService.
277 // ================================================================================
278 public IBinder addNotification(StatusBarNotification notification) {
279 synchronized (mNotifications) {
Joe Onoratoa0c56fe2010-05-20 10:21:52 -0700280 IBinder key = new Binder();
281 mNotifications.add(key, notification);
Joe Onoratoe345fff2010-05-23 15:18:27 -0400282 if (mBar != null) {
283 try {
284 mBar.addNotification(key, notification);
285 } catch (RemoteException ex) {
286 }
287 }
Joe Onorato18e69df2010-05-17 22:26:12 -0700288 return key;
289 }
Joe Onorato0cbda992010-05-02 16:28:15 -0700290 }
291
Joe Onorato18e69df2010-05-17 22:26:12 -0700292 public void updateNotification(IBinder key, StatusBarNotification notification) {
293 synchronized (mNotifications) {
294 mNotifications.update(key, notification);
Joe Onoratoe345fff2010-05-23 15:18:27 -0400295 if (mBar != null) {
296 try {
297 mBar.updateNotification(key, notification);
298 } catch (RemoteException ex) {
299 }
300 }
Joe Onorato18e69df2010-05-17 22:26:12 -0700301 }
Joe Onorato0cbda992010-05-02 16:28:15 -0700302 }
303
304 public void removeNotification(IBinder key) {
Joe Onorato18e69df2010-05-17 22:26:12 -0700305 synchronized (mNotifications) {
306 mNotifications.remove(key);
Joe Onoratoe345fff2010-05-23 15:18:27 -0400307 if (mBar != null) {
308 try {
309 mBar.removeNotification(key);
310 } catch (RemoteException ex) {
311 }
312 }
Joe Onorato18e69df2010-05-17 22:26:12 -0700313 }
Joe Onorato0cbda992010-05-02 16:28:15 -0700314 }
Joe Onorato2314aab2010-04-08 16:41:23 -0500315
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 // ================================================================================
317 // Can be called from any thread
318 // ================================================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800320 // lock on mDisableRecords
321 void manageDisableListLocked(int what, IBinder token, String pkg) {
322 if (SPEW) {
Joe Onoratof3f0e052010-05-14 18:49:29 -0700323 Slog.d(TAG, "manageDisableList what=0x" + Integer.toHexString(what) + " pkg=" + pkg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 }
325 // update the list
326 synchronized (mDisableRecords) {
327 final int N = mDisableRecords.size();
328 DisableRecord tok = null;
329 int i;
330 for (i=0; i<N; i++) {
331 DisableRecord t = mDisableRecords.get(i);
332 if (t.token == token) {
333 tok = t;
334 break;
335 }
336 }
337 if (what == 0 || !token.isBinderAlive()) {
338 if (tok != null) {
339 mDisableRecords.remove(i);
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -0700340 tok.token.unlinkToDeath(tok, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 }
342 } else {
343 if (tok == null) {
344 tok = new DisableRecord();
345 try {
346 token.linkToDeath(tok, 0);
347 }
348 catch (RemoteException ex) {
349 return; // give up
350 }
351 mDisableRecords.add(tok);
352 }
353 tok.what = what;
354 tok.token = token;
355 tok.pkg = pkg;
356 }
357 }
358 }
359
360 // lock on mDisableRecords
361 int gatherDisableActionsLocked() {
362 final int N = mDisableRecords.size();
363 // gather the new net flags
364 int net = 0;
365 for (int i=0; i<N; i++) {
366 net |= mDisableRecords.get(i).what;
367 }
368 return net;
369 }
370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 // ================================================================================
372 // Always called from UI thread
373 // ================================================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
376 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
377 != PackageManager.PERMISSION_GRANTED) {
378 pw.println("Permission Denial: can't dump StatusBar from from pid="
379 + Binder.getCallingPid()
380 + ", uid=" + Binder.getCallingUid());
381 return;
382 }
Joe Onorato0cbda992010-05-02 16:28:15 -0700383
Joe Onorato0cbda992010-05-02 16:28:15 -0700384 synchronized (mIcons) {
385 mIcons.dump(pw);
386 }
Joe Onorato18e69df2010-05-17 22:26:12 -0700387
388 synchronized (mNotifications) {
389 mNotifications.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 }
Joe Onorato18e69df2010-05-17 22:26:12 -0700391
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 synchronized (mDisableRecords) {
393 final int N = mDisableRecords.size();
394 pw.println(" mDisableRecords.size=" + N
395 + " mDisabled=0x" + Integer.toHexString(mDisabled));
396 for (int i=0; i<N; i++) {
397 DisableRecord tok = mDisableRecords.get(i);
398 pw.println(" [" + i + "] what=0x" + Integer.toHexString(tok.what)
399 + " pkg=" + tok.pkg + " token=" + tok.token);
400 }
401 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 }
403
404 /**
405 * The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
406 * This was added last-minute and is inconsistent with the way the rest of the notifications
407 * are handled, because the notification isn't really cancelled. The lights are just
408 * turned off. If any other notifications happen, the lights will turn back on. Steve says
409 * this is what he wants. (see bug 1131461)
410 */
411 private boolean mPanelSlightlyVisible;
412 void panelSlightlyVisible(boolean visible) {
413 if (mPanelSlightlyVisible != visible) {
414 mPanelSlightlyVisible = visible;
415 if (visible) {
416 // tell the notification manager to turn off the lights.
417 mNotificationCallbacks.onPanelRevealed();
418 }
419 }
420 }
421
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422 private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
423 public void onReceive(Context context, Intent intent) {
424 String action = intent.getAction();
Joe Onoratof9e0e6b2009-09-08 16:24:36 -0400425 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
426 || Intent.ACTION_SCREEN_OFF.equals(action)) {
Joe Onoratof3f0e052010-05-14 18:49:29 -0700427 collapse();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 }
Joe Onorato0cbda992010-05-02 16:28:15 -0700429 /*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 else if (Telephony.Intents.SPN_STRINGS_UPDATED_ACTION.equals(action)) {
431 updateNetworkName(intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_SPN, false),
432 intent.getStringExtra(Telephony.Intents.EXTRA_SPN),
433 intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_PLMN, false),
434 intent.getStringExtra(Telephony.Intents.EXTRA_PLMN));
435 }
436 else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
437 updateResources();
438 }
Joe Onorato0cbda992010-05-02 16:28:15 -0700439 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440 }
441 };
442
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443}