blob: d7e1d25153c6c5cb362b60a684ecab70988d87fc [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;
18
svetoslavganov75986cf2009-05-14 22:28:01 -070019import com.android.server.status.IconData;
20import com.android.server.status.NotificationData;
21import com.android.server.status.StatusBarService;
22
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.app.ActivityManagerNative;
24import android.app.IActivityManager;
25import android.app.INotificationManager;
26import android.app.ITransientNotification;
27import android.app.Notification;
Dianne Hackborn1dac2772009-06-26 18:16:48 -070028import android.app.NotificationManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.app.PendingIntent;
30import android.app.StatusBarManager;
31import android.content.BroadcastReceiver;
Dianne Hackborn1dac2772009-06-26 18:16:48 -070032import android.content.ComponentName;
Dianne Hackborn1dac2772009-06-26 18:16:48 -070033import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.content.Context;
35import android.content.Intent;
36import android.content.IntentFilter;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070037import android.content.pm.ApplicationInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.content.pm.PackageManager;
39import android.content.pm.PackageManager.NameNotFoundException;
40import android.content.res.Resources;
Dianne Hackborn1dac2772009-06-26 18:16:48 -070041import android.database.ContentObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.media.AsyncPlayer;
svetoslavganov75986cf2009-05-14 22:28:01 -070043import android.media.AudioManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.net.Uri;
45import android.os.BatteryManager;
46import android.os.Binder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.os.Handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.os.IBinder;
49import android.os.Message;
50import android.os.Power;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070051import android.os.Process;
svetoslavganov75986cf2009-05-14 22:28:01 -070052import android.os.RemoteException;
Mike Lockwooded760372009-07-09 07:07:27 -040053import android.os.SystemProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.os.Vibrator;
55import android.provider.Settings;
svetoslavganov75986cf2009-05-14 22:28:01 -070056import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057import android.util.EventLog;
58import android.util.Log;
svetoslavganov75986cf2009-05-14 22:28:01 -070059import android.view.accessibility.AccessibilityEvent;
60import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import android.widget.Toast;
62
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import java.io.FileDescriptor;
64import java.io.PrintWriter;
65import java.util.ArrayList;
66import java.util.Arrays;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067
68class NotificationManagerService extends INotificationManager.Stub
69{
70 private static final String TAG = "NotificationService";
71 private static final boolean DBG = false;
72
73 // message codes
74 private static final int MESSAGE_TIMEOUT = 2;
75
76 private static final int LONG_DELAY = 3500; // 3.5 seconds
77 private static final int SHORT_DELAY = 2000; // 2 seconds
78
79 private static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
80
81 private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
82
83 final Context mContext;
84 final IActivityManager mAm;
85 final IBinder mForegroundToken = new Binder();
86
87 private WorkerHandler mHandler;
88 private StatusBarService mStatusBarService;
The Android Open Source Project10592532009-03-18 17:39:46 -070089 private HardwareService mHardware;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090
91 private NotificationRecord mSoundNotification;
92 private AsyncPlayer mSound;
Joe Onorato30275482009-07-08 17:09:14 -070093 private boolean mSystemReady;
Joe Onorato39f5b6a2009-07-23 12:29:19 -040094 private int mDisabledNotifications;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095
96 private NotificationRecord mVibrateNotification;
97 private Vibrator mVibrator = new Vibrator();
98
Mike Lockwoodc22404a2009-12-02 11:15:02 -050099 // for enabling and disabling notification pulse behavior
100 private boolean mScreenOn = true;
101 private boolean mNotificationPulseEnabled;
102
103 // for adb connected notifications
Mike Lockwoodea8b7d52009-08-04 17:03:15 -0400104 private boolean mUsbConnected;
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700105 private boolean mAdbEnabled = false;
106 private boolean mAdbNotificationShown = false;
107 private Notification mAdbNotification;
108
Fred Quintana6ecaff12009-09-25 14:23:13 -0700109 private final ArrayList<NotificationRecord> mNotificationList =
110 new ArrayList<NotificationRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111
112 private ArrayList<ToastRecord> mToastQueue;
113
114 private ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>();
115
116 private boolean mBatteryCharging;
117 private boolean mBatteryLow;
118 private boolean mBatteryFull;
119 private NotificationRecord mLedNotification;
svetoslavganov75986cf2009-05-14 22:28:01 -0700120
The Android Open Source Project10592532009-03-18 17:39:46 -0700121 private static final int BATTERY_LOW_ARGB = 0xFFFF0000; // Charging Low - red solid on
122 private static final int BATTERY_MEDIUM_ARGB = 0xFFFFFF00; // Charging - orange solid on
123 private static final int BATTERY_FULL_ARGB = 0xFF00FF00; // Charging Full - green solid on
124 private static final int BATTERY_BLINK_ON = 125;
125 private static final int BATTERY_BLINK_OFF = 2875;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126
127 // Tag IDs for EventLog.
128 private static final int EVENT_LOG_ENQUEUE = 2750;
129 private static final int EVENT_LOG_CANCEL = 2751;
130 private static final int EVENT_LOG_CANCEL_ALL = 2752;
131
132 private static String idDebugString(Context baseContext, String packageName, int id) {
133 Context c = null;
134
135 if (packageName != null) {
136 try {
137 c = baseContext.createPackageContext(packageName, 0);
138 } catch (NameNotFoundException e) {
139 c = baseContext;
140 }
141 } else {
142 c = baseContext;
143 }
144
145 String pkg;
146 String type;
147 String name;
148
149 Resources r = c.getResources();
150 try {
151 return r.getResourceName(id);
152 } catch (Resources.NotFoundException e) {
153 return "<name unknown>";
154 }
155 }
156
157 private static final class NotificationRecord
158 {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700159 final String pkg;
160 final String tag;
161 final int id;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 ITransientNotification callback;
163 int duration;
Fred Quintana6ecaff12009-09-25 14:23:13 -0700164 final Notification notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165 IBinder statusBarKey;
166
Fred Quintana6ecaff12009-09-25 14:23:13 -0700167 NotificationRecord(String pkg, String tag, int id, Notification notification)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168 {
169 this.pkg = pkg;
Fred Quintana6ecaff12009-09-25 14:23:13 -0700170 this.tag = tag;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 this.id = id;
172 this.notification = notification;
173 }
Fred Quintana6ecaff12009-09-25 14:23:13 -0700174
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175 void dump(PrintWriter pw, String prefix, Context baseContext) {
176 pw.println(prefix + this);
177 pw.println(prefix + " icon=0x" + Integer.toHexString(notification.icon)
178 + " / " + idDebugString(baseContext, this.pkg, notification.icon));
179 pw.println(prefix + " contentIntent=" + notification.contentIntent);
180 pw.println(prefix + " deleteIntent=" + notification.deleteIntent);
181 pw.println(prefix + " tickerText=" + notification.tickerText);
182 pw.println(prefix + " contentView=" + notification.contentView);
183 pw.println(prefix + " defaults=0x" + Integer.toHexString(notification.defaults));
184 pw.println(prefix + " flags=0x" + Integer.toHexString(notification.flags));
185 pw.println(prefix + " sound=" + notification.sound);
186 pw.println(prefix + " vibrate=" + Arrays.toString(notification.vibrate));
187 pw.println(prefix + " ledARGB=0x" + Integer.toHexString(notification.ledARGB)
188 + " ledOnMS=" + notification.ledOnMS
189 + " ledOffMS=" + notification.ledOffMS);
190 }
191
192 @Override
193 public final String toString()
194 {
195 return "NotificationRecord{"
196 + Integer.toHexString(System.identityHashCode(this))
197 + " pkg=" + pkg
Fred Quintana6ecaff12009-09-25 14:23:13 -0700198 + " id=" + Integer.toHexString(id)
199 + " tag=" + tag + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 }
201 }
202
203 private static final class ToastRecord
204 {
205 final int pid;
206 final String pkg;
207 final ITransientNotification callback;
208 int duration;
209
210 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
211 {
212 this.pid = pid;
213 this.pkg = pkg;
214 this.callback = callback;
215 this.duration = duration;
216 }
217
218 void update(int duration) {
219 this.duration = duration;
220 }
221
222 void dump(PrintWriter pw, String prefix) {
223 pw.println(prefix + this);
224 }
225
226 @Override
227 public final String toString()
228 {
229 return "ToastRecord{"
230 + Integer.toHexString(System.identityHashCode(this))
231 + " pkg=" + pkg
232 + " callback=" + callback
233 + " duration=" + duration;
234 }
235 }
236
237 private StatusBarService.NotificationCallbacks mNotificationCallbacks
238 = new StatusBarService.NotificationCallbacks() {
239
240 public void onSetDisabled(int status) {
241 synchronized (mNotificationList) {
242 mDisabledNotifications = status;
243 if ((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
244 // cancel whatever's going on
245 long identity = Binder.clearCallingIdentity();
246 try {
247 mSound.stop();
248 }
249 finally {
250 Binder.restoreCallingIdentity(identity);
251 }
252
253 identity = Binder.clearCallingIdentity();
254 try {
255 mVibrator.cancel();
256 }
257 finally {
258 Binder.restoreCallingIdentity(identity);
259 }
260 }
261 }
262 }
263
264 public void onClearAll() {
265 cancelAll();
266 }
267
Fred Quintana6ecaff12009-09-25 14:23:13 -0700268 public void onNotificationClick(String pkg, String tag, int id) {
269 cancelNotification(pkg, tag, id, Notification.FLAG_AUTO_CANCEL,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700270 Notification.FLAG_FOREGROUND_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800271 }
272
273 public void onPanelRevealed() {
274 synchronized (mNotificationList) {
275 // sound
276 mSoundNotification = null;
277 long identity = Binder.clearCallingIdentity();
278 try {
279 mSound.stop();
280 }
281 finally {
282 Binder.restoreCallingIdentity(identity);
283 }
284
285 // vibrate
286 mVibrateNotification = null;
287 identity = Binder.clearCallingIdentity();
288 try {
289 mVibrator.cancel();
290 }
291 finally {
292 Binder.restoreCallingIdentity(identity);
293 }
294
295 // light
296 mLights.clear();
297 mLedNotification = null;
298 updateLightsLocked();
299 }
300 }
301 };
302
303 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
304 @Override
305 public void onReceive(Context context, Intent intent) {
306 String action = intent.getAction();
307
308 if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
309 boolean batteryCharging = (intent.getIntExtra("plugged", 0) != 0);
310 int level = intent.getIntExtra("level", -1);
311 boolean batteryLow = (level >= 0 && level <= Power.LOW_BATTERY_THRESHOLD);
312 int status = intent.getIntExtra("status", BatteryManager.BATTERY_STATUS_UNKNOWN);
313 boolean batteryFull = (status == BatteryManager.BATTERY_STATUS_FULL || level >= 90);
314
315 if (batteryCharging != mBatteryCharging ||
316 batteryLow != mBatteryLow ||
317 batteryFull != mBatteryFull) {
318 mBatteryCharging = batteryCharging;
319 mBatteryLow = batteryLow;
320 mBatteryFull = batteryFull;
321 updateLights();
322 }
Mike Lockwoodea8b7d52009-08-04 17:03:15 -0400323 } else if (action.equals(Intent.ACTION_UMS_CONNECTED)) {
324 mUsbConnected = true;
325 updateAdbNotification();
326 } else if (action.equals(Intent.ACTION_UMS_DISCONNECTED)) {
327 mUsbConnected = false;
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700328 updateAdbNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
330 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) {
331 Uri uri = intent.getData();
332 if (uri == null) {
333 return;
334 }
335 String pkgName = uri.getSchemeSpecificPart();
336 if (pkgName == null) {
337 return;
338 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700339 cancelAllNotificationsInt(pkgName, 0, 0);
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500340 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
341 mScreenOn = true;
342 updateNotificationPulse();
343 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
344 mScreenOn = false;
345 updateNotificationPulse();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 }
347 }
348 };
349
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700350 class SettingsObserver extends ContentObserver {
351 SettingsObserver(Handler handler) {
352 super(handler);
353 }
354
355 void observe() {
356 ContentResolver resolver = mContext.getContentResolver();
357 resolver.registerContentObserver(Settings.Secure.getUriFor(
358 Settings.Secure.ADB_ENABLED), false, this);
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500359 resolver.registerContentObserver(Settings.System.getUriFor(
360 Settings.System.NOTIFICATION_LIGHT_PULSE), false, this);
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700361 update();
362 }
363
364 @Override public void onChange(boolean selfChange) {
365 update();
366 }
367
368 public void update() {
369 ContentResolver resolver = mContext.getContentResolver();
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500370 boolean adbEnabled = Settings.Secure.getInt(resolver,
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700371 Settings.Secure.ADB_ENABLED, 0) != 0;
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500372 if (mAdbEnabled != adbEnabled) {
373 mAdbEnabled = adbEnabled;
374 updateAdbNotification();
375 }
376 boolean pulseEnabled = Settings.System.getInt(resolver,
377 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
378 if (mNotificationPulseEnabled != pulseEnabled) {
379 mNotificationPulseEnabled = pulseEnabled;
380 updateNotificationPulse();
381 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700382 }
383 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500384
The Android Open Source Project10592532009-03-18 17:39:46 -0700385 NotificationManagerService(Context context, StatusBarService statusBar,
386 HardwareService hardware)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 {
388 super();
389 mContext = context;
The Android Open Source Project10592532009-03-18 17:39:46 -0700390 mHardware = hardware;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 mAm = ActivityManagerNative.getDefault();
392 mSound = new AsyncPlayer(TAG);
393 mSound.setUsesWakeLock(context);
394 mToastQueue = new ArrayList<ToastRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 mHandler = new WorkerHandler();
396 mStatusBarService = statusBar;
397 statusBar.setNotificationCallbacks(mNotificationCallbacks);
398
Joe Onorato39f5b6a2009-07-23 12:29:19 -0400399 // Don't start allowing notifications until the setup wizard has run once.
400 // After that, including subsequent boots, init with notifications turned on.
401 // This works on the first boot because the setup wizard will toggle this
402 // flag at least once and we'll go back to 0 after that.
403 if (0 == Settings.Secure.getInt(mContext.getContentResolver(),
404 Settings.Secure.DEVICE_PROVISIONED, 0)) {
405 mDisabledNotifications = StatusBarManager.DISABLE_NOTIFICATION_ALERTS;
406 }
407
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800408 // register for battery changed notifications
409 IntentFilter filter = new IntentFilter();
410 filter.addAction(Intent.ACTION_BATTERY_CHANGED);
Mike Lockwoodea8b7d52009-08-04 17:03:15 -0400411 filter.addAction(Intent.ACTION_UMS_CONNECTED);
412 filter.addAction(Intent.ACTION_UMS_DISCONNECTED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
414 filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500415 filter.addAction(Intent.ACTION_SCREEN_ON);
416 filter.addAction(Intent.ACTION_SCREEN_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 mContext.registerReceiver(mIntentReceiver, filter);
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700418
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500419 SettingsObserver observer = new SettingsObserver(mHandler);
420 observer.observe();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421 }
422
Joe Onorato30275482009-07-08 17:09:14 -0700423 void systemReady() {
424 // no beeping until we're basically done booting
425 mSystemReady = true;
426 }
427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 // Toasts
429 // ============================================================================
430 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
431 {
432 Log.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + " duration=" + duration);
433
434 if (pkg == null || callback == null) {
435 Log.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
436 return ;
437 }
438
439 synchronized (mToastQueue) {
440 int callingPid = Binder.getCallingPid();
441 long callingId = Binder.clearCallingIdentity();
442 try {
443 ToastRecord record;
444 int index = indexOfToastLocked(pkg, callback);
445 // If it's already in the queue, we update it in place, we don't
446 // move it to the end of the queue.
447 if (index >= 0) {
448 record = mToastQueue.get(index);
449 record.update(duration);
450 } else {
451 record = new ToastRecord(callingPid, pkg, callback, duration);
452 mToastQueue.add(record);
453 index = mToastQueue.size() - 1;
454 keepProcessAliveLocked(callingPid);
455 }
456 // If it's at index 0, it's the current toast. It doesn't matter if it's
457 // new or just been updated. Call back and tell it to show itself.
458 // If the callback fails, this will remove it from the list, so don't
459 // assume that it's valid after this.
460 if (index == 0) {
461 showNextToastLocked();
462 }
463 } finally {
464 Binder.restoreCallingIdentity(callingId);
465 }
466 }
467 }
468
469 public void cancelToast(String pkg, ITransientNotification callback) {
470 Log.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
471
472 if (pkg == null || callback == null) {
473 Log.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
474 return ;
475 }
476
477 synchronized (mToastQueue) {
478 long callingId = Binder.clearCallingIdentity();
479 try {
480 int index = indexOfToastLocked(pkg, callback);
481 if (index >= 0) {
482 cancelToastLocked(index);
483 } else {
484 Log.w(TAG, "Toast already cancelled. pkg=" + pkg + " callback=" + callback);
485 }
486 } finally {
487 Binder.restoreCallingIdentity(callingId);
488 }
489 }
490 }
491
492 private void showNextToastLocked() {
493 ToastRecord record = mToastQueue.get(0);
494 while (record != null) {
495 if (DBG) Log.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
496 try {
497 record.callback.show();
498 scheduleTimeoutLocked(record, false);
499 return;
500 } catch (RemoteException e) {
501 Log.w(TAG, "Object died trying to show notification " + record.callback
502 + " in package " + record.pkg);
503 // remove it from the list and let the process die
504 int index = mToastQueue.indexOf(record);
505 if (index >= 0) {
506 mToastQueue.remove(index);
507 }
508 keepProcessAliveLocked(record.pid);
509 if (mToastQueue.size() > 0) {
510 record = mToastQueue.get(0);
511 } else {
512 record = null;
513 }
514 }
515 }
516 }
517
518 private void cancelToastLocked(int index) {
519 ToastRecord record = mToastQueue.get(index);
520 try {
521 record.callback.hide();
522 } catch (RemoteException e) {
523 Log.w(TAG, "Object died trying to hide notification " + record.callback
524 + " in package " + record.pkg);
525 // don't worry about this, we're about to remove it from
526 // the list anyway
527 }
528 mToastQueue.remove(index);
529 keepProcessAliveLocked(record.pid);
530 if (mToastQueue.size() > 0) {
531 // Show the next one. If the callback fails, this will remove
532 // it from the list, so don't assume that the list hasn't changed
533 // after this point.
534 showNextToastLocked();
535 }
536 }
537
538 private void scheduleTimeoutLocked(ToastRecord r, boolean immediate)
539 {
540 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
541 long delay = immediate ? 0 : (r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY);
542 mHandler.removeCallbacksAndMessages(r);
543 mHandler.sendMessageDelayed(m, delay);
544 }
545
546 private void handleTimeout(ToastRecord record)
547 {
548 if (DBG) Log.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
549 synchronized (mToastQueue) {
550 int index = indexOfToastLocked(record.pkg, record.callback);
551 if (index >= 0) {
552 cancelToastLocked(index);
553 }
554 }
555 }
556
557 // lock on mToastQueue
558 private int indexOfToastLocked(String pkg, ITransientNotification callback)
559 {
560 IBinder cbak = callback.asBinder();
561 ArrayList<ToastRecord> list = mToastQueue;
562 int len = list.size();
563 for (int i=0; i<len; i++) {
564 ToastRecord r = list.get(i);
565 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
566 return i;
567 }
568 }
569 return -1;
570 }
571
572 // lock on mToastQueue
573 private void keepProcessAliveLocked(int pid)
574 {
575 int toastCount = 0; // toasts from this pid
576 ArrayList<ToastRecord> list = mToastQueue;
577 int N = list.size();
578 for (int i=0; i<N; i++) {
579 ToastRecord r = list.get(i);
580 if (r.pid == pid) {
581 toastCount++;
582 }
583 }
584 try {
585 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
586 } catch (RemoteException e) {
587 // Shouldn't happen.
588 }
589 }
590
591 private final class WorkerHandler extends Handler
592 {
593 @Override
594 public void handleMessage(Message msg)
595 {
596 switch (msg.what)
597 {
598 case MESSAGE_TIMEOUT:
599 handleTimeout((ToastRecord)msg.obj);
600 break;
601 }
602 }
603 }
604
605
606 // Notifications
607 // ============================================================================
608 public void enqueueNotification(String pkg, int id, Notification notification, int[] idOut)
609 {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700610 enqueueNotificationWithTag(pkg, null /* tag */, id, notification, idOut);
611 }
612
613 public void enqueueNotificationWithTag(String pkg, String tag, int id,
614 Notification notification, int[] idOut)
615 {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700616 checkIncomingCall(pkg);
617
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800618 // This conditional is a dirty hack to limit the logging done on
619 // behalf of the download manager without affecting other apps.
620 if (!pkg.equals("com.android.providers.downloads")
621 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
622 EventLog.writeEvent(EVENT_LOG_ENQUEUE, pkg, id, notification.toString());
623 }
624
625 if (pkg == null || notification == null) {
626 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
627 + " id=" + id + " notification=" + notification);
628 }
629 if (notification.icon != 0) {
630 if (notification.contentView == null) {
631 throw new IllegalArgumentException("contentView required: pkg=" + pkg
632 + " id=" + id + " notification=" + notification);
633 }
634 if (notification.contentIntent == null) {
635 throw new IllegalArgumentException("contentIntent required: pkg=" + pkg
636 + " id=" + id + " notification=" + notification);
637 }
638 }
639
640 synchronized (mNotificationList) {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700641 NotificationRecord r = new NotificationRecord(pkg, tag, id, notification);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800642 NotificationRecord old = null;
643
Fred Quintana6ecaff12009-09-25 14:23:13 -0700644 int index = indexOfNotificationLocked(pkg, tag, id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800645 if (index < 0) {
646 mNotificationList.add(r);
647 } else {
648 old = mNotificationList.remove(index);
649 mNotificationList.add(index, r);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700650 // Make sure we don't lose the foreground service state.
651 if (old != null) {
652 notification.flags |=
653 old.notification.flags&Notification.FLAG_FOREGROUND_SERVICE;
654 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800655 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700656
657 // Ensure if this is a foreground service that the proper additional
658 // flags are set.
659 if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) {
660 notification.flags |= Notification.FLAG_ONGOING_EVENT
661 | Notification.FLAG_NO_CLEAR;
662 }
663
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 if (notification.icon != 0) {
665 IconData icon = IconData.makeIcon(null, pkg, notification.icon,
666 notification.iconLevel,
667 notification.number);
668 CharSequence truncatedTicker = notification.tickerText;
669
670 // TODO: make this restriction do something smarter like never fill
671 // more than two screens. "Why would anyone need more than 80 characters." :-/
672 final int maxTickerLen = 80;
673 if (truncatedTicker != null && truncatedTicker.length() > maxTickerLen) {
674 truncatedTicker = truncatedTicker.subSequence(0, maxTickerLen);
675 }
676
677 NotificationData n = new NotificationData();
Fred Quintana6ecaff12009-09-25 14:23:13 -0700678 n.pkg = pkg;
679 n.tag = tag;
680 n.id = id;
681 n.when = notification.when;
682 n.tickerText = truncatedTicker;
683 n.ongoingEvent = (notification.flags & Notification.FLAG_ONGOING_EVENT) != 0;
684 if (!n.ongoingEvent && (notification.flags & Notification.FLAG_NO_CLEAR) == 0) {
685 n.clearable = true;
686 }
687 n.contentView = notification.contentView;
688 n.contentIntent = notification.contentIntent;
689 n.deleteIntent = notification.deleteIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800690 if (old != null && old.statusBarKey != null) {
691 r.statusBarKey = old.statusBarKey;
692 long identity = Binder.clearCallingIdentity();
693 try {
694 mStatusBarService.updateIcon(r.statusBarKey, icon, n);
695 }
696 finally {
697 Binder.restoreCallingIdentity(identity);
698 }
699 } else {
700 long identity = Binder.clearCallingIdentity();
701 try {
702 r.statusBarKey = mStatusBarService.addIcon(icon, n);
Joe Onoratoc1e84462009-03-24 19:29:20 -0700703 mHardware.pulseBreathingLight();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704 }
705 finally {
706 Binder.restoreCallingIdentity(identity);
707 }
708 }
svetoslavganov75986cf2009-05-14 22:28:01 -0700709
Joe Onorato30275482009-07-08 17:09:14 -0700710 sendAccessibilityEvent(notification, pkg);
svetoslavganov75986cf2009-05-14 22:28:01 -0700711
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800712 } else {
713 if (old != null && old.statusBarKey != null) {
714 long identity = Binder.clearCallingIdentity();
715 try {
716 mStatusBarService.removeIcon(old.statusBarKey);
717 }
718 finally {
719 Binder.restoreCallingIdentity(identity);
720 }
721 }
722 }
723
724 // If we're not supposed to beep, vibrate, etc. then don't.
725 if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
726 && (!(old != null
Joe Onorato30275482009-07-08 17:09:14 -0700727 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
728 && mSystemReady) {
Eric Laurent524dc042009-11-27 05:07:55 -0800729
730 final AudioManager audioManager = (AudioManager) mContext
731 .getSystemService(Context.AUDIO_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732 // sound
733 final boolean useDefaultSound =
734 (notification.defaults & Notification.DEFAULT_SOUND) != 0;
735 if (useDefaultSound || notification.sound != null) {
736 Uri uri;
737 if (useDefaultSound) {
738 uri = Settings.System.DEFAULT_NOTIFICATION_URI;
739 } else {
740 uri = notification.sound;
741 }
742 boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0;
743 int audioStreamType;
744 if (notification.audioStreamType >= 0) {
745 audioStreamType = notification.audioStreamType;
746 } else {
747 audioStreamType = DEFAULT_STREAM_TYPE;
748 }
749 mSoundNotification = r;
Eric Laurent524dc042009-11-27 05:07:55 -0800750 // do not play notifications if stream volume is 0
751 // (typically because ringer mode is silent).
752 if (audioManager.getStreamVolume(audioStreamType) != 0) {
753 long identity = Binder.clearCallingIdentity();
754 try {
755 mSound.play(mContext, uri, looping, audioStreamType);
756 }
757 finally {
758 Binder.restoreCallingIdentity(identity);
759 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 }
761 }
762
763 // vibrate
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 final boolean useDefaultVibrate =
765 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
766 if ((useDefaultVibrate || notification.vibrate != null)
767 && audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_NOTIFICATION)) {
768 mVibrateNotification = r;
769
770 mVibrator.vibrate(useDefaultVibrate ? DEFAULT_VIBRATE_PATTERN
771 : notification.vibrate,
772 ((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
773 }
774 }
775
776 // this option doesn't shut off the lights
777
778 // light
779 // the most recent thing gets the light
780 mLights.remove(old);
781 if (mLedNotification == old) {
782 mLedNotification = null;
783 }
784 //Log.i(TAG, "notification.lights="
785 // + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS) != 0));
786 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {
787 mLights.add(r);
788 updateLightsLocked();
789 } else {
790 if (old != null
791 && ((old.notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0)) {
792 updateLightsLocked();
793 }
794 }
795 }
796
797 idOut[0] = id;
798 }
799
Joe Onorato30275482009-07-08 17:09:14 -0700800 private void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
svetoslavganov75986cf2009-05-14 22:28:01 -0700801 AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
802 if (!manager.isEnabled()) {
803 return;
804 }
805
806 AccessibilityEvent event =
807 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
808 event.setPackageName(packageName);
809 event.setClassName(Notification.class.getName());
810 event.setParcelableData(notification);
811 CharSequence tickerText = notification.tickerText;
812 if (!TextUtils.isEmpty(tickerText)) {
813 event.getText().add(tickerText);
814 }
815
816 manager.sendAccessibilityEvent(event);
817 }
818
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819 private void cancelNotificationLocked(NotificationRecord r) {
820 // status bar
821 if (r.notification.icon != 0) {
822 long identity = Binder.clearCallingIdentity();
823 try {
824 mStatusBarService.removeIcon(r.statusBarKey);
825 }
826 finally {
827 Binder.restoreCallingIdentity(identity);
828 }
829 r.statusBarKey = null;
830 }
831
832 // sound
833 if (mSoundNotification == r) {
834 mSoundNotification = null;
835 long identity = Binder.clearCallingIdentity();
836 try {
837 mSound.stop();
838 }
839 finally {
840 Binder.restoreCallingIdentity(identity);
841 }
842 }
843
844 // vibrate
845 if (mVibrateNotification == r) {
846 mVibrateNotification = null;
847 long identity = Binder.clearCallingIdentity();
848 try {
849 mVibrator.cancel();
850 }
851 finally {
852 Binder.restoreCallingIdentity(identity);
853 }
854 }
855
856 // light
857 mLights.remove(r);
858 if (mLedNotification == r) {
859 mLedNotification = null;
860 }
861 }
862
863 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700864 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
865 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866 */
Fred Quintana6ecaff12009-09-25 14:23:13 -0700867 private void cancelNotification(String pkg, String tag, int id, int mustHaveFlags,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700868 int mustNotHaveFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800869 EventLog.writeEvent(EVENT_LOG_CANCEL, pkg, id, mustHaveFlags);
870
871 synchronized (mNotificationList) {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700872 int index = indexOfNotificationLocked(pkg, tag, id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 if (index >= 0) {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700874 NotificationRecord r = mNotificationList.get(index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875
876 if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {
877 return;
878 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700879 if ((r.notification.flags & mustNotHaveFlags) != 0) {
880 return;
881 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800882
883 mNotificationList.remove(index);
884
885 cancelNotificationLocked(r);
886 updateLightsLocked();
887 }
888 }
889 }
890
891 /**
892 * Cancels all notifications from a given package that have all of the
893 * {@code mustHaveFlags}.
894 */
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700895 void cancelAllNotificationsInt(String pkg, int mustHaveFlags,
896 int mustNotHaveFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 EventLog.writeEvent(EVENT_LOG_CANCEL_ALL, pkg, mustHaveFlags);
898
899 synchronized (mNotificationList) {
900 final int N = mNotificationList.size();
901 boolean canceledSomething = false;
902 for (int i = N-1; i >= 0; --i) {
903 NotificationRecord r = mNotificationList.get(i);
904 if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {
905 continue;
906 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700907 if ((r.notification.flags & mustNotHaveFlags) != 0) {
908 continue;
909 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800910 if (!r.pkg.equals(pkg)) {
911 continue;
912 }
913 mNotificationList.remove(i);
914 cancelNotificationLocked(r);
915 canceledSomething = true;
916 }
917 if (canceledSomething) {
918 updateLightsLocked();
919 }
920 }
921 }
922
923
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700924 public void cancelNotification(String pkg, int id) {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700925 cancelNotificationWithTag(pkg, null /* tag */, id);
926 }
927
928 public void cancelNotificationWithTag(String pkg, String tag, int id) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700929 checkIncomingCall(pkg);
930 // Don't allow client applications to cancel foreground service notis.
Fred Quintana6ecaff12009-09-25 14:23:13 -0700931 cancelNotification(pkg, tag, id, 0,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700932 Binder.getCallingUid() == Process.SYSTEM_UID
933 ? 0 : Notification.FLAG_FOREGROUND_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800934 }
935
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700936 public void cancelAllNotifications(String pkg) {
937 checkIncomingCall(pkg);
938
939 // Calling from user space, don't allow the canceling of actively
940 // running foreground services.
941 cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 }
943
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700944 void checkIncomingCall(String pkg) {
945 int uid = Binder.getCallingUid();
946 if (uid == Process.SYSTEM_UID || uid == 0) {
947 return;
948 }
949 try {
950 ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(
951 pkg, 0);
952 if (ai.uid != uid) {
953 throw new SecurityException("Calling uid " + uid + " gave package"
954 + pkg + " which is owned by uid " + ai.uid);
955 }
956 } catch (PackageManager.NameNotFoundException e) {
957 throw new SecurityException("Unknown package " + pkg);
958 }
959 }
960
961 void cancelAll() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800962 synchronized (mNotificationList) {
963 final int N = mNotificationList.size();
964 for (int i=N-1; i>=0; i--) {
965 NotificationRecord r = mNotificationList.get(i);
966
967 if ((r.notification.flags & (Notification.FLAG_ONGOING_EVENT
968 | Notification.FLAG_NO_CLEAR)) == 0) {
969 if (r.notification.deleteIntent != null) {
970 try {
971 r.notification.deleteIntent.send();
972 } catch (PendingIntent.CanceledException ex) {
973 // do nothing - there's no relevant way to recover, and
974 // no reason to let this propagate
975 Log.w(TAG, "canceled PendingIntent for " + r.pkg, ex);
976 }
977 }
978 mNotificationList.remove(i);
979 cancelNotificationLocked(r);
980 }
981 }
982
983 updateLightsLocked();
984 }
985 }
986
987 private void updateLights() {
988 synchronized (mNotificationList) {
989 updateLightsLocked();
990 }
991 }
992
993 // lock on mNotificationList
994 private void updateLightsLocked()
995 {
The Android Open Source Project10592532009-03-18 17:39:46 -0700996 // Battery low always shows, other states only show if charging.
997 if (mBatteryLow) {
Mike Lockwood445f4302009-09-04 11:06:46 -0400998 if (mBatteryCharging) {
999 mHardware.setLightColor_UNCHECKED(HardwareService.LIGHT_ID_BATTERY,
1000 BATTERY_LOW_ARGB);
1001 } else {
1002 // Flash when battery is low and not charging
1003 mHardware.setLightFlashing_UNCHECKED(HardwareService.LIGHT_ID_BATTERY,
1004 BATTERY_LOW_ARGB, HardwareService.LIGHT_FLASH_TIMED,
1005 BATTERY_BLINK_ON, BATTERY_BLINK_OFF);
1006 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 } else if (mBatteryCharging) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001008 if (mBatteryFull) {
1009 mHardware.setLightColor_UNCHECKED(HardwareService.LIGHT_ID_BATTERY,
1010 BATTERY_FULL_ARGB);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001011 } else {
The Android Open Source Project10592532009-03-18 17:39:46 -07001012 mHardware.setLightColor_UNCHECKED(HardwareService.LIGHT_ID_BATTERY,
1013 BATTERY_MEDIUM_ARGB);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001014 }
1015 } else {
The Android Open Source Project10592532009-03-18 17:39:46 -07001016 mHardware.setLightOff_UNCHECKED(HardwareService.LIGHT_ID_BATTERY);
1017 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001018
The Android Open Source Project10592532009-03-18 17:39:46 -07001019 // handle notification lights
1020 if (mLedNotification == null) {
1021 // get next notification, if any
1022 int n = mLights.size();
1023 if (n > 0) {
1024 mLedNotification = mLights.get(n-1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 }
1026 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001027
1028 // we only flash if screen is off and persistent pulsing is enabled
1029 if (mLedNotification == null || mScreenOn || !mNotificationPulseEnabled) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001030 mHardware.setLightOff_UNCHECKED(HardwareService.LIGHT_ID_NOTIFICATIONS);
1031 } else {
1032 mHardware.setLightFlashing_UNCHECKED(
1033 HardwareService.LIGHT_ID_NOTIFICATIONS,
1034 mLedNotification.notification.ledARGB,
1035 HardwareService.LIGHT_FLASH_TIMED,
1036 mLedNotification.notification.ledOnMS,
1037 mLedNotification.notification.ledOffMS);
1038 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001039 }
1040
1041 // lock on mNotificationList
Fred Quintana6ecaff12009-09-25 14:23:13 -07001042 private int indexOfNotificationLocked(String pkg, String tag, int id)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 {
1044 ArrayList<NotificationRecord> list = mNotificationList;
1045 final int len = list.size();
1046 for (int i=0; i<len; i++) {
1047 NotificationRecord r = list.get(i);
Fred Quintana6ecaff12009-09-25 14:23:13 -07001048 if (tag == null) {
1049 if (r.tag != null) {
1050 continue;
1051 }
1052 } else {
1053 if (!tag.equals(r.tag)) {
1054 continue;
1055 }
1056 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057 if (r.id == id && r.pkg.equals(pkg)) {
1058 return i;
1059 }
1060 }
1061 return -1;
1062 }
1063
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001064 // This is here instead of StatusBarPolicy because it is an important
1065 // security feature that we don't want people customizing the platform
1066 // to accidentally lose.
1067 private void updateAdbNotification() {
Mike Lockwoodea8b7d52009-08-04 17:03:15 -04001068 if (mAdbEnabled && mUsbConnected) {
Mike Lockwooded760372009-07-09 07:07:27 -04001069 if ("0".equals(SystemProperties.get("persist.adb.notify"))) {
1070 return;
1071 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001072 if (!mAdbNotificationShown) {
1073 NotificationManager notificationManager = (NotificationManager) mContext
1074 .getSystemService(Context.NOTIFICATION_SERVICE);
1075 if (notificationManager != null) {
1076 Resources r = mContext.getResources();
1077 CharSequence title = r.getText(
1078 com.android.internal.R.string.adb_active_notification_title);
1079 CharSequence message = r.getText(
1080 com.android.internal.R.string.adb_active_notification_message);
1081
1082 if (mAdbNotification == null) {
1083 mAdbNotification = new Notification();
1084 mAdbNotification.icon = com.android.internal.R.drawable.stat_sys_warning;
1085 mAdbNotification.when = 0;
1086 mAdbNotification.flags = Notification.FLAG_ONGOING_EVENT;
1087 mAdbNotification.tickerText = title;
1088 mAdbNotification.defaults |= Notification.DEFAULT_SOUND;
1089 }
1090
1091 Intent intent = new Intent(
1092 Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
1093 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
1094 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
1095 // Note: we are hard-coding the component because this is
1096 // an important security UI that we don't want anyone
1097 // intercepting.
1098 intent.setComponent(new ComponentName("com.android.settings",
1099 "com.android.settings.DevelopmentSettings"));
1100 PendingIntent pi = PendingIntent.getActivity(mContext, 0,
1101 intent, 0);
1102
1103 mAdbNotification.setLatestEventInfo(mContext, title, message, pi);
1104
1105 mAdbNotificationShown = true;
1106 notificationManager.notify(
1107 com.android.internal.R.string.adb_active_notification_title,
1108 mAdbNotification);
1109 }
1110 }
1111
1112 } else if (mAdbNotificationShown) {
1113 NotificationManager notificationManager = (NotificationManager) mContext
1114 .getSystemService(Context.NOTIFICATION_SERVICE);
1115 if (notificationManager != null) {
1116 mAdbNotificationShown = false;
1117 notificationManager.cancel(
1118 com.android.internal.R.string.adb_active_notification_title);
1119 }
1120 }
1121 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001122
1123 private void updateNotificationPulse() {
1124 synchronized (mNotificationList) {
1125 updateLightsLocked();
1126 }
1127 }
1128
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001129 // ======================================================================
1130 @Override
1131 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1132 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1133 != PackageManager.PERMISSION_GRANTED) {
1134 pw.println("Permission Denial: can't dump NotificationManager from from pid="
1135 + Binder.getCallingPid()
1136 + ", uid=" + Binder.getCallingUid());
1137 return;
1138 }
1139
1140 pw.println("Current Notification Manager state:");
1141
1142 int N;
1143
1144 synchronized (mToastQueue) {
1145 N = mToastQueue.size();
1146 if (N > 0) {
1147 pw.println(" Toast Queue:");
1148 for (int i=0; i<N; i++) {
1149 mToastQueue.get(i).dump(pw, " ");
1150 }
1151 pw.println(" ");
1152 }
1153
1154 }
1155
1156 synchronized (mNotificationList) {
1157 N = mNotificationList.size();
1158 if (N > 0) {
1159 pw.println(" Notification List:");
1160 for (int i=0; i<N; i++) {
1161 mNotificationList.get(i).dump(pw, " ", mContext);
1162 }
1163 pw.println(" ");
1164 }
1165
1166 N = mLights.size();
1167 if (N > 0) {
1168 pw.println(" Lights List:");
1169 for (int i=0; i<N; i++) {
1170 mLights.get(i).dump(pw, " ", mContext);
1171 }
1172 pw.println(" ");
1173 }
1174
1175 pw.println(" mSoundNotification=" + mSoundNotification);
1176 pw.println(" mSound=" + mSound);
1177 pw.println(" mVibrateNotification=" + mVibrateNotification);
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001178 pw.println(" mDisabledNotifications=0x" + Integer.toHexString(mDisabledNotifications));
1179 pw.println(" mSystemReady=" + mSystemReady);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 }
1181 }
1182}