blob: 147580b6d955d5ee64376b6ebce2c8e47894d56c [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;
Mike Lockwood3a322132009-11-24 00:30:52 -050089 private LightsService mLightsService;
Mike Lockwood3cb67a32009-11-27 14:25:58 -050090 private LightsService.Light mBatteryLight;
91 private LightsService.Light mNotificationLight;
92 private LightsService.Light mAttentionLight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093
94 private NotificationRecord mSoundNotification;
95 private AsyncPlayer mSound;
Joe Onorato30275482009-07-08 17:09:14 -070096 private boolean mSystemReady;
Joe Onorato39f5b6a2009-07-23 12:29:19 -040097 private int mDisabledNotifications;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098
99 private NotificationRecord mVibrateNotification;
100 private Vibrator mVibrator = new Vibrator();
101
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500102 // for enabling and disabling notification pulse behavior
103 private boolean mScreenOn = true;
104 private boolean mNotificationPulseEnabled;
105
106 // for adb connected notifications
Mike Lockwoodea8b7d52009-08-04 17:03:15 -0400107 private boolean mUsbConnected;
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700108 private boolean mAdbEnabled = false;
109 private boolean mAdbNotificationShown = false;
110 private Notification mAdbNotification;
111
Fred Quintana6ecaff12009-09-25 14:23:13 -0700112 private final ArrayList<NotificationRecord> mNotificationList =
113 new ArrayList<NotificationRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114
115 private ArrayList<ToastRecord> mToastQueue;
116
117 private ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>();
118
119 private boolean mBatteryCharging;
120 private boolean mBatteryLow;
121 private boolean mBatteryFull;
122 private NotificationRecord mLedNotification;
svetoslavganov75986cf2009-05-14 22:28:01 -0700123
The Android Open Source Project10592532009-03-18 17:39:46 -0700124 private static final int BATTERY_LOW_ARGB = 0xFFFF0000; // Charging Low - red solid on
125 private static final int BATTERY_MEDIUM_ARGB = 0xFFFFFF00; // Charging - orange solid on
126 private static final int BATTERY_FULL_ARGB = 0xFF00FF00; // Charging Full - green solid on
127 private static final int BATTERY_BLINK_ON = 125;
128 private static final int BATTERY_BLINK_OFF = 2875;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129
130 // Tag IDs for EventLog.
131 private static final int EVENT_LOG_ENQUEUE = 2750;
132 private static final int EVENT_LOG_CANCEL = 2751;
133 private static final int EVENT_LOG_CANCEL_ALL = 2752;
134
135 private static String idDebugString(Context baseContext, String packageName, int id) {
136 Context c = null;
137
138 if (packageName != null) {
139 try {
140 c = baseContext.createPackageContext(packageName, 0);
141 } catch (NameNotFoundException e) {
142 c = baseContext;
143 }
144 } else {
145 c = baseContext;
146 }
147
148 String pkg;
149 String type;
150 String name;
151
152 Resources r = c.getResources();
153 try {
154 return r.getResourceName(id);
155 } catch (Resources.NotFoundException e) {
156 return "<name unknown>";
157 }
158 }
159
160 private static final class NotificationRecord
161 {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700162 final String pkg;
163 final String tag;
164 final int id;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165 ITransientNotification callback;
166 int duration;
Fred Quintana6ecaff12009-09-25 14:23:13 -0700167 final Notification notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168 IBinder statusBarKey;
169
Fred Quintana6ecaff12009-09-25 14:23:13 -0700170 NotificationRecord(String pkg, String tag, int id, Notification notification)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 {
172 this.pkg = pkg;
Fred Quintana6ecaff12009-09-25 14:23:13 -0700173 this.tag = tag;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174 this.id = id;
175 this.notification = notification;
176 }
Fred Quintana6ecaff12009-09-25 14:23:13 -0700177
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 void dump(PrintWriter pw, String prefix, Context baseContext) {
179 pw.println(prefix + this);
180 pw.println(prefix + " icon=0x" + Integer.toHexString(notification.icon)
181 + " / " + idDebugString(baseContext, this.pkg, notification.icon));
182 pw.println(prefix + " contentIntent=" + notification.contentIntent);
183 pw.println(prefix + " deleteIntent=" + notification.deleteIntent);
184 pw.println(prefix + " tickerText=" + notification.tickerText);
185 pw.println(prefix + " contentView=" + notification.contentView);
186 pw.println(prefix + " defaults=0x" + Integer.toHexString(notification.defaults));
187 pw.println(prefix + " flags=0x" + Integer.toHexString(notification.flags));
188 pw.println(prefix + " sound=" + notification.sound);
189 pw.println(prefix + " vibrate=" + Arrays.toString(notification.vibrate));
190 pw.println(prefix + " ledARGB=0x" + Integer.toHexString(notification.ledARGB)
191 + " ledOnMS=" + notification.ledOnMS
192 + " ledOffMS=" + notification.ledOffMS);
193 }
194
195 @Override
196 public final String toString()
197 {
198 return "NotificationRecord{"
199 + Integer.toHexString(System.identityHashCode(this))
200 + " pkg=" + pkg
Fred Quintana6ecaff12009-09-25 14:23:13 -0700201 + " id=" + Integer.toHexString(id)
202 + " tag=" + tag + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 }
204 }
205
206 private static final class ToastRecord
207 {
208 final int pid;
209 final String pkg;
210 final ITransientNotification callback;
211 int duration;
212
213 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
214 {
215 this.pid = pid;
216 this.pkg = pkg;
217 this.callback = callback;
218 this.duration = duration;
219 }
220
221 void update(int duration) {
222 this.duration = duration;
223 }
224
225 void dump(PrintWriter pw, String prefix) {
226 pw.println(prefix + this);
227 }
228
229 @Override
230 public final String toString()
231 {
232 return "ToastRecord{"
233 + Integer.toHexString(System.identityHashCode(this))
234 + " pkg=" + pkg
235 + " callback=" + callback
236 + " duration=" + duration;
237 }
238 }
239
240 private StatusBarService.NotificationCallbacks mNotificationCallbacks
241 = new StatusBarService.NotificationCallbacks() {
242
243 public void onSetDisabled(int status) {
244 synchronized (mNotificationList) {
245 mDisabledNotifications = status;
246 if ((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
247 // cancel whatever's going on
248 long identity = Binder.clearCallingIdentity();
249 try {
250 mSound.stop();
251 }
252 finally {
253 Binder.restoreCallingIdentity(identity);
254 }
255
256 identity = Binder.clearCallingIdentity();
257 try {
258 mVibrator.cancel();
259 }
260 finally {
261 Binder.restoreCallingIdentity(identity);
262 }
263 }
264 }
265 }
266
267 public void onClearAll() {
268 cancelAll();
269 }
270
Fred Quintana6ecaff12009-09-25 14:23:13 -0700271 public void onNotificationClick(String pkg, String tag, int id) {
272 cancelNotification(pkg, tag, id, Notification.FLAG_AUTO_CANCEL,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700273 Notification.FLAG_FOREGROUND_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274 }
275
276 public void onPanelRevealed() {
277 synchronized (mNotificationList) {
278 // sound
279 mSoundNotification = null;
280 long identity = Binder.clearCallingIdentity();
281 try {
282 mSound.stop();
283 }
284 finally {
285 Binder.restoreCallingIdentity(identity);
286 }
287
288 // vibrate
289 mVibrateNotification = null;
290 identity = Binder.clearCallingIdentity();
291 try {
292 mVibrator.cancel();
293 }
294 finally {
295 Binder.restoreCallingIdentity(identity);
296 }
297
298 // light
299 mLights.clear();
300 mLedNotification = null;
301 updateLightsLocked();
302 }
303 }
304 };
305
306 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
307 @Override
308 public void onReceive(Context context, Intent intent) {
309 String action = intent.getAction();
310
311 if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
312 boolean batteryCharging = (intent.getIntExtra("plugged", 0) != 0);
313 int level = intent.getIntExtra("level", -1);
314 boolean batteryLow = (level >= 0 && level <= Power.LOW_BATTERY_THRESHOLD);
315 int status = intent.getIntExtra("status", BatteryManager.BATTERY_STATUS_UNKNOWN);
316 boolean batteryFull = (status == BatteryManager.BATTERY_STATUS_FULL || level >= 90);
317
318 if (batteryCharging != mBatteryCharging ||
319 batteryLow != mBatteryLow ||
320 batteryFull != mBatteryFull) {
321 mBatteryCharging = batteryCharging;
322 mBatteryLow = batteryLow;
323 mBatteryFull = batteryFull;
324 updateLights();
325 }
Mike Lockwoodea8b7d52009-08-04 17:03:15 -0400326 } else if (action.equals(Intent.ACTION_UMS_CONNECTED)) {
327 mUsbConnected = true;
328 updateAdbNotification();
329 } else if (action.equals(Intent.ACTION_UMS_DISCONNECTED)) {
330 mUsbConnected = false;
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700331 updateAdbNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
333 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) {
334 Uri uri = intent.getData();
335 if (uri == null) {
336 return;
337 }
338 String pkgName = uri.getSchemeSpecificPart();
339 if (pkgName == null) {
340 return;
341 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700342 cancelAllNotificationsInt(pkgName, 0, 0);
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500343 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
344 mScreenOn = true;
345 updateNotificationPulse();
346 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
347 mScreenOn = false;
348 updateNotificationPulse();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 }
350 }
351 };
352
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700353 class SettingsObserver extends ContentObserver {
354 SettingsObserver(Handler handler) {
355 super(handler);
356 }
357
358 void observe() {
359 ContentResolver resolver = mContext.getContentResolver();
360 resolver.registerContentObserver(Settings.Secure.getUriFor(
361 Settings.Secure.ADB_ENABLED), false, this);
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500362 resolver.registerContentObserver(Settings.System.getUriFor(
363 Settings.System.NOTIFICATION_LIGHT_PULSE), false, this);
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700364 update();
365 }
366
367 @Override public void onChange(boolean selfChange) {
368 update();
369 }
370
371 public void update() {
372 ContentResolver resolver = mContext.getContentResolver();
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500373 boolean adbEnabled = Settings.Secure.getInt(resolver,
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700374 Settings.Secure.ADB_ENABLED, 0) != 0;
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500375 if (mAdbEnabled != adbEnabled) {
376 mAdbEnabled = adbEnabled;
377 updateAdbNotification();
378 }
379 boolean pulseEnabled = Settings.System.getInt(resolver,
380 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
381 if (mNotificationPulseEnabled != pulseEnabled) {
382 mNotificationPulseEnabled = pulseEnabled;
383 updateNotificationPulse();
384 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700385 }
386 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500387
The Android Open Source Project10592532009-03-18 17:39:46 -0700388 NotificationManagerService(Context context, StatusBarService statusBar,
Mike Lockwood3a322132009-11-24 00:30:52 -0500389 LightsService lights)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 {
391 super();
392 mContext = context;
Mike Lockwood3a322132009-11-24 00:30:52 -0500393 mLightsService = lights;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 mAm = ActivityManagerNative.getDefault();
395 mSound = new AsyncPlayer(TAG);
396 mSound.setUsesWakeLock(context);
397 mToastQueue = new ArrayList<ToastRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 mHandler = new WorkerHandler();
399 mStatusBarService = statusBar;
400 statusBar.setNotificationCallbacks(mNotificationCallbacks);
401
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500402 mBatteryLight = lights.getLight(LightsService.LIGHT_ID_BATTERY);
403 mNotificationLight = lights.getLight(LightsService.LIGHT_ID_NOTIFICATIONS);
404 mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION);
405
Joe Onorato39f5b6a2009-07-23 12:29:19 -0400406 // Don't start allowing notifications until the setup wizard has run once.
407 // After that, including subsequent boots, init with notifications turned on.
408 // This works on the first boot because the setup wizard will toggle this
409 // flag at least once and we'll go back to 0 after that.
410 if (0 == Settings.Secure.getInt(mContext.getContentResolver(),
411 Settings.Secure.DEVICE_PROVISIONED, 0)) {
412 mDisabledNotifications = StatusBarManager.DISABLE_NOTIFICATION_ALERTS;
413 }
414
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 // register for battery changed notifications
416 IntentFilter filter = new IntentFilter();
417 filter.addAction(Intent.ACTION_BATTERY_CHANGED);
Mike Lockwoodea8b7d52009-08-04 17:03:15 -0400418 filter.addAction(Intent.ACTION_UMS_CONNECTED);
419 filter.addAction(Intent.ACTION_UMS_DISCONNECTED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
421 filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500422 filter.addAction(Intent.ACTION_SCREEN_ON);
423 filter.addAction(Intent.ACTION_SCREEN_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 mContext.registerReceiver(mIntentReceiver, filter);
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700425
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500426 SettingsObserver observer = new SettingsObserver(mHandler);
427 observer.observe();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 }
429
Joe Onorato30275482009-07-08 17:09:14 -0700430 void systemReady() {
431 // no beeping until we're basically done booting
432 mSystemReady = true;
433 }
434
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 // Toasts
436 // ============================================================================
437 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
438 {
439 Log.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + " duration=" + duration);
440
441 if (pkg == null || callback == null) {
442 Log.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
443 return ;
444 }
445
446 synchronized (mToastQueue) {
447 int callingPid = Binder.getCallingPid();
448 long callingId = Binder.clearCallingIdentity();
449 try {
450 ToastRecord record;
451 int index = indexOfToastLocked(pkg, callback);
452 // If it's already in the queue, we update it in place, we don't
453 // move it to the end of the queue.
454 if (index >= 0) {
455 record = mToastQueue.get(index);
456 record.update(duration);
457 } else {
458 record = new ToastRecord(callingPid, pkg, callback, duration);
459 mToastQueue.add(record);
460 index = mToastQueue.size() - 1;
461 keepProcessAliveLocked(callingPid);
462 }
463 // If it's at index 0, it's the current toast. It doesn't matter if it's
464 // new or just been updated. Call back and tell it to show itself.
465 // If the callback fails, this will remove it from the list, so don't
466 // assume that it's valid after this.
467 if (index == 0) {
468 showNextToastLocked();
469 }
470 } finally {
471 Binder.restoreCallingIdentity(callingId);
472 }
473 }
474 }
475
476 public void cancelToast(String pkg, ITransientNotification callback) {
477 Log.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
478
479 if (pkg == null || callback == null) {
480 Log.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
481 return ;
482 }
483
484 synchronized (mToastQueue) {
485 long callingId = Binder.clearCallingIdentity();
486 try {
487 int index = indexOfToastLocked(pkg, callback);
488 if (index >= 0) {
489 cancelToastLocked(index);
490 } else {
491 Log.w(TAG, "Toast already cancelled. pkg=" + pkg + " callback=" + callback);
492 }
493 } finally {
494 Binder.restoreCallingIdentity(callingId);
495 }
496 }
497 }
498
499 private void showNextToastLocked() {
500 ToastRecord record = mToastQueue.get(0);
501 while (record != null) {
502 if (DBG) Log.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
503 try {
504 record.callback.show();
505 scheduleTimeoutLocked(record, false);
506 return;
507 } catch (RemoteException e) {
508 Log.w(TAG, "Object died trying to show notification " + record.callback
509 + " in package " + record.pkg);
510 // remove it from the list and let the process die
511 int index = mToastQueue.indexOf(record);
512 if (index >= 0) {
513 mToastQueue.remove(index);
514 }
515 keepProcessAliveLocked(record.pid);
516 if (mToastQueue.size() > 0) {
517 record = mToastQueue.get(0);
518 } else {
519 record = null;
520 }
521 }
522 }
523 }
524
525 private void cancelToastLocked(int index) {
526 ToastRecord record = mToastQueue.get(index);
527 try {
528 record.callback.hide();
529 } catch (RemoteException e) {
530 Log.w(TAG, "Object died trying to hide notification " + record.callback
531 + " in package " + record.pkg);
532 // don't worry about this, we're about to remove it from
533 // the list anyway
534 }
535 mToastQueue.remove(index);
536 keepProcessAliveLocked(record.pid);
537 if (mToastQueue.size() > 0) {
538 // Show the next one. If the callback fails, this will remove
539 // it from the list, so don't assume that the list hasn't changed
540 // after this point.
541 showNextToastLocked();
542 }
543 }
544
545 private void scheduleTimeoutLocked(ToastRecord r, boolean immediate)
546 {
547 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
548 long delay = immediate ? 0 : (r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY);
549 mHandler.removeCallbacksAndMessages(r);
550 mHandler.sendMessageDelayed(m, delay);
551 }
552
553 private void handleTimeout(ToastRecord record)
554 {
555 if (DBG) Log.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
556 synchronized (mToastQueue) {
557 int index = indexOfToastLocked(record.pkg, record.callback);
558 if (index >= 0) {
559 cancelToastLocked(index);
560 }
561 }
562 }
563
564 // lock on mToastQueue
565 private int indexOfToastLocked(String pkg, ITransientNotification callback)
566 {
567 IBinder cbak = callback.asBinder();
568 ArrayList<ToastRecord> list = mToastQueue;
569 int len = list.size();
570 for (int i=0; i<len; i++) {
571 ToastRecord r = list.get(i);
572 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
573 return i;
574 }
575 }
576 return -1;
577 }
578
579 // lock on mToastQueue
580 private void keepProcessAliveLocked(int pid)
581 {
582 int toastCount = 0; // toasts from this pid
583 ArrayList<ToastRecord> list = mToastQueue;
584 int N = list.size();
585 for (int i=0; i<N; i++) {
586 ToastRecord r = list.get(i);
587 if (r.pid == pid) {
588 toastCount++;
589 }
590 }
591 try {
592 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
593 } catch (RemoteException e) {
594 // Shouldn't happen.
595 }
596 }
597
598 private final class WorkerHandler extends Handler
599 {
600 @Override
601 public void handleMessage(Message msg)
602 {
603 switch (msg.what)
604 {
605 case MESSAGE_TIMEOUT:
606 handleTimeout((ToastRecord)msg.obj);
607 break;
608 }
609 }
610 }
611
612
613 // Notifications
614 // ============================================================================
615 public void enqueueNotification(String pkg, int id, Notification notification, int[] idOut)
616 {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700617 enqueueNotificationWithTag(pkg, null /* tag */, id, notification, idOut);
618 }
619
620 public void enqueueNotificationWithTag(String pkg, String tag, int id,
621 Notification notification, int[] idOut)
622 {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700623 checkIncomingCall(pkg);
624
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800625 // This conditional is a dirty hack to limit the logging done on
626 // behalf of the download manager without affecting other apps.
627 if (!pkg.equals("com.android.providers.downloads")
628 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
629 EventLog.writeEvent(EVENT_LOG_ENQUEUE, pkg, id, notification.toString());
630 }
631
632 if (pkg == null || notification == null) {
633 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
634 + " id=" + id + " notification=" + notification);
635 }
636 if (notification.icon != 0) {
637 if (notification.contentView == null) {
638 throw new IllegalArgumentException("contentView required: pkg=" + pkg
639 + " id=" + id + " notification=" + notification);
640 }
641 if (notification.contentIntent == null) {
642 throw new IllegalArgumentException("contentIntent required: pkg=" + pkg
643 + " id=" + id + " notification=" + notification);
644 }
645 }
646
647 synchronized (mNotificationList) {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700648 NotificationRecord r = new NotificationRecord(pkg, tag, id, notification);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800649 NotificationRecord old = null;
650
Fred Quintana6ecaff12009-09-25 14:23:13 -0700651 int index = indexOfNotificationLocked(pkg, tag, id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652 if (index < 0) {
653 mNotificationList.add(r);
654 } else {
655 old = mNotificationList.remove(index);
656 mNotificationList.add(index, r);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700657 // Make sure we don't lose the foreground service state.
658 if (old != null) {
659 notification.flags |=
660 old.notification.flags&Notification.FLAG_FOREGROUND_SERVICE;
661 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800662 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700663
664 // Ensure if this is a foreground service that the proper additional
665 // flags are set.
666 if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) {
667 notification.flags |= Notification.FLAG_ONGOING_EVENT
668 | Notification.FLAG_NO_CLEAR;
669 }
670
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 if (notification.icon != 0) {
672 IconData icon = IconData.makeIcon(null, pkg, notification.icon,
673 notification.iconLevel,
674 notification.number);
675 CharSequence truncatedTicker = notification.tickerText;
676
677 // TODO: make this restriction do something smarter like never fill
678 // more than two screens. "Why would anyone need more than 80 characters." :-/
679 final int maxTickerLen = 80;
680 if (truncatedTicker != null && truncatedTicker.length() > maxTickerLen) {
681 truncatedTicker = truncatedTicker.subSequence(0, maxTickerLen);
682 }
683
684 NotificationData n = new NotificationData();
Fred Quintana6ecaff12009-09-25 14:23:13 -0700685 n.pkg = pkg;
686 n.tag = tag;
687 n.id = id;
688 n.when = notification.when;
689 n.tickerText = truncatedTicker;
690 n.ongoingEvent = (notification.flags & Notification.FLAG_ONGOING_EVENT) != 0;
691 if (!n.ongoingEvent && (notification.flags & Notification.FLAG_NO_CLEAR) == 0) {
692 n.clearable = true;
693 }
694 n.contentView = notification.contentView;
695 n.contentIntent = notification.contentIntent;
696 n.deleteIntent = notification.deleteIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800697 if (old != null && old.statusBarKey != null) {
698 r.statusBarKey = old.statusBarKey;
699 long identity = Binder.clearCallingIdentity();
700 try {
701 mStatusBarService.updateIcon(r.statusBarKey, icon, n);
702 }
703 finally {
704 Binder.restoreCallingIdentity(identity);
705 }
706 } else {
707 long identity = Binder.clearCallingIdentity();
708 try {
709 r.statusBarKey = mStatusBarService.addIcon(icon, n);
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500710 mAttentionLight.pulse();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800711 }
712 finally {
713 Binder.restoreCallingIdentity(identity);
714 }
715 }
svetoslavganov75986cf2009-05-14 22:28:01 -0700716
Joe Onorato30275482009-07-08 17:09:14 -0700717 sendAccessibilityEvent(notification, pkg);
svetoslavganov75986cf2009-05-14 22:28:01 -0700718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800719 } else {
720 if (old != null && old.statusBarKey != null) {
721 long identity = Binder.clearCallingIdentity();
722 try {
723 mStatusBarService.removeIcon(old.statusBarKey);
724 }
725 finally {
726 Binder.restoreCallingIdentity(identity);
727 }
728 }
729 }
730
731 // If we're not supposed to beep, vibrate, etc. then don't.
732 if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
733 && (!(old != null
Joe Onorato30275482009-07-08 17:09:14 -0700734 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
735 && mSystemReady) {
Eric Laurent524dc042009-11-27 05:07:55 -0800736
737 final AudioManager audioManager = (AudioManager) mContext
738 .getSystemService(Context.AUDIO_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800739 // sound
740 final boolean useDefaultSound =
741 (notification.defaults & Notification.DEFAULT_SOUND) != 0;
742 if (useDefaultSound || notification.sound != null) {
743 Uri uri;
744 if (useDefaultSound) {
745 uri = Settings.System.DEFAULT_NOTIFICATION_URI;
746 } else {
747 uri = notification.sound;
748 }
749 boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0;
750 int audioStreamType;
751 if (notification.audioStreamType >= 0) {
752 audioStreamType = notification.audioStreamType;
753 } else {
754 audioStreamType = DEFAULT_STREAM_TYPE;
755 }
756 mSoundNotification = r;
Eric Laurent524dc042009-11-27 05:07:55 -0800757 // do not play notifications if stream volume is 0
758 // (typically because ringer mode is silent).
759 if (audioManager.getStreamVolume(audioStreamType) != 0) {
760 long identity = Binder.clearCallingIdentity();
761 try {
762 mSound.play(mContext, uri, looping, audioStreamType);
763 }
764 finally {
765 Binder.restoreCallingIdentity(identity);
766 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 }
768 }
769
770 // vibrate
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 final boolean useDefaultVibrate =
772 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
773 if ((useDefaultVibrate || notification.vibrate != null)
774 && audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_NOTIFICATION)) {
775 mVibrateNotification = r;
776
777 mVibrator.vibrate(useDefaultVibrate ? DEFAULT_VIBRATE_PATTERN
778 : notification.vibrate,
779 ((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
780 }
781 }
782
783 // this option doesn't shut off the lights
784
785 // light
786 // the most recent thing gets the light
787 mLights.remove(old);
788 if (mLedNotification == old) {
789 mLedNotification = null;
790 }
791 //Log.i(TAG, "notification.lights="
792 // + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS) != 0));
793 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {
794 mLights.add(r);
795 updateLightsLocked();
796 } else {
797 if (old != null
798 && ((old.notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0)) {
799 updateLightsLocked();
800 }
801 }
802 }
803
804 idOut[0] = id;
805 }
806
Joe Onorato30275482009-07-08 17:09:14 -0700807 private void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
svetoslavganov75986cf2009-05-14 22:28:01 -0700808 AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
809 if (!manager.isEnabled()) {
810 return;
811 }
812
813 AccessibilityEvent event =
814 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
815 event.setPackageName(packageName);
816 event.setClassName(Notification.class.getName());
817 event.setParcelableData(notification);
818 CharSequence tickerText = notification.tickerText;
819 if (!TextUtils.isEmpty(tickerText)) {
820 event.getText().add(tickerText);
821 }
822
823 manager.sendAccessibilityEvent(event);
824 }
825
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800826 private void cancelNotificationLocked(NotificationRecord r) {
827 // status bar
828 if (r.notification.icon != 0) {
829 long identity = Binder.clearCallingIdentity();
830 try {
831 mStatusBarService.removeIcon(r.statusBarKey);
832 }
833 finally {
834 Binder.restoreCallingIdentity(identity);
835 }
836 r.statusBarKey = null;
837 }
838
839 // sound
840 if (mSoundNotification == r) {
841 mSoundNotification = null;
842 long identity = Binder.clearCallingIdentity();
843 try {
844 mSound.stop();
845 }
846 finally {
847 Binder.restoreCallingIdentity(identity);
848 }
849 }
850
851 // vibrate
852 if (mVibrateNotification == r) {
853 mVibrateNotification = null;
854 long identity = Binder.clearCallingIdentity();
855 try {
856 mVibrator.cancel();
857 }
858 finally {
859 Binder.restoreCallingIdentity(identity);
860 }
861 }
862
863 // light
864 mLights.remove(r);
865 if (mLedNotification == r) {
866 mLedNotification = null;
867 }
868 }
869
870 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700871 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
872 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 */
Fred Quintana6ecaff12009-09-25 14:23:13 -0700874 private void cancelNotification(String pkg, String tag, int id, int mustHaveFlags,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700875 int mustNotHaveFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 EventLog.writeEvent(EVENT_LOG_CANCEL, pkg, id, mustHaveFlags);
877
878 synchronized (mNotificationList) {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700879 int index = indexOfNotificationLocked(pkg, tag, id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800880 if (index >= 0) {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700881 NotificationRecord r = mNotificationList.get(index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800882
883 if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {
884 return;
885 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700886 if ((r.notification.flags & mustNotHaveFlags) != 0) {
887 return;
888 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889
890 mNotificationList.remove(index);
891
892 cancelNotificationLocked(r);
893 updateLightsLocked();
894 }
895 }
896 }
897
898 /**
899 * Cancels all notifications from a given package that have all of the
900 * {@code mustHaveFlags}.
901 */
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700902 void cancelAllNotificationsInt(String pkg, int mustHaveFlags,
903 int mustNotHaveFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800904 EventLog.writeEvent(EVENT_LOG_CANCEL_ALL, pkg, mustHaveFlags);
905
906 synchronized (mNotificationList) {
907 final int N = mNotificationList.size();
908 boolean canceledSomething = false;
909 for (int i = N-1; i >= 0; --i) {
910 NotificationRecord r = mNotificationList.get(i);
911 if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {
912 continue;
913 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700914 if ((r.notification.flags & mustNotHaveFlags) != 0) {
915 continue;
916 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800917 if (!r.pkg.equals(pkg)) {
918 continue;
919 }
920 mNotificationList.remove(i);
921 cancelNotificationLocked(r);
922 canceledSomething = true;
923 }
924 if (canceledSomething) {
925 updateLightsLocked();
926 }
927 }
928 }
929
930
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700931 public void cancelNotification(String pkg, int id) {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700932 cancelNotificationWithTag(pkg, null /* tag */, id);
933 }
934
935 public void cancelNotificationWithTag(String pkg, String tag, int id) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700936 checkIncomingCall(pkg);
937 // Don't allow client applications to cancel foreground service notis.
Fred Quintana6ecaff12009-09-25 14:23:13 -0700938 cancelNotification(pkg, tag, id, 0,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700939 Binder.getCallingUid() == Process.SYSTEM_UID
940 ? 0 : Notification.FLAG_FOREGROUND_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 }
942
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700943 public void cancelAllNotifications(String pkg) {
944 checkIncomingCall(pkg);
945
946 // Calling from user space, don't allow the canceling of actively
947 // running foreground services.
948 cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800949 }
950
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700951 void checkIncomingCall(String pkg) {
952 int uid = Binder.getCallingUid();
953 if (uid == Process.SYSTEM_UID || uid == 0) {
954 return;
955 }
956 try {
957 ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(
958 pkg, 0);
959 if (ai.uid != uid) {
960 throw new SecurityException("Calling uid " + uid + " gave package"
961 + pkg + " which is owned by uid " + ai.uid);
962 }
963 } catch (PackageManager.NameNotFoundException e) {
964 throw new SecurityException("Unknown package " + pkg);
965 }
966 }
967
968 void cancelAll() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969 synchronized (mNotificationList) {
970 final int N = mNotificationList.size();
971 for (int i=N-1; i>=0; i--) {
972 NotificationRecord r = mNotificationList.get(i);
973
974 if ((r.notification.flags & (Notification.FLAG_ONGOING_EVENT
975 | Notification.FLAG_NO_CLEAR)) == 0) {
976 if (r.notification.deleteIntent != null) {
977 try {
978 r.notification.deleteIntent.send();
979 } catch (PendingIntent.CanceledException ex) {
980 // do nothing - there's no relevant way to recover, and
981 // no reason to let this propagate
982 Log.w(TAG, "canceled PendingIntent for " + r.pkg, ex);
983 }
984 }
985 mNotificationList.remove(i);
986 cancelNotificationLocked(r);
987 }
988 }
989
990 updateLightsLocked();
991 }
992 }
993
994 private void updateLights() {
995 synchronized (mNotificationList) {
996 updateLightsLocked();
997 }
998 }
999
1000 // lock on mNotificationList
1001 private void updateLightsLocked()
1002 {
The Android Open Source Project10592532009-03-18 17:39:46 -07001003 // Battery low always shows, other states only show if charging.
1004 if (mBatteryLow) {
Mike Lockwood445f4302009-09-04 11:06:46 -04001005 if (mBatteryCharging) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001006 mBatteryLight.setColor(BATTERY_LOW_ARGB);
Mike Lockwood445f4302009-09-04 11:06:46 -04001007 } else {
1008 // Flash when battery is low and not charging
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001009 mBatteryLight.setFlashing(BATTERY_LOW_ARGB, LightsService.LIGHT_FLASH_TIMED,
1010 BATTERY_BLINK_ON, BATTERY_BLINK_OFF);
Mike Lockwood445f4302009-09-04 11:06:46 -04001011 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 } else if (mBatteryCharging) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001013 if (mBatteryFull) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001014 mBatteryLight.setColor(BATTERY_FULL_ARGB);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 } else {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001016 mBatteryLight.setColor(BATTERY_MEDIUM_ARGB);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 }
1018 } else {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001019 mBatteryLight.turnOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07001020 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021
The Android Open Source Project10592532009-03-18 17:39:46 -07001022 // handle notification lights
1023 if (mLedNotification == null) {
1024 // get next notification, if any
1025 int n = mLights.size();
1026 if (n > 0) {
1027 mLedNotification = mLights.get(n-1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 }
1029 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001030
1031 // we only flash if screen is off and persistent pulsing is enabled
1032 if (mLedNotification == null || mScreenOn || !mNotificationPulseEnabled) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001033 mNotificationLight.turnOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07001034 } else {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001035 mNotificationLight.setFlashing(
The Android Open Source Project10592532009-03-18 17:39:46 -07001036 mLedNotification.notification.ledARGB,
Mike Lockwood3a322132009-11-24 00:30:52 -05001037 LightsService.LIGHT_FLASH_TIMED,
The Android Open Source Project10592532009-03-18 17:39:46 -07001038 mLedNotification.notification.ledOnMS,
1039 mLedNotification.notification.ledOffMS);
1040 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001041 }
1042
1043 // lock on mNotificationList
Fred Quintana6ecaff12009-09-25 14:23:13 -07001044 private int indexOfNotificationLocked(String pkg, String tag, int id)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001045 {
1046 ArrayList<NotificationRecord> list = mNotificationList;
1047 final int len = list.size();
1048 for (int i=0; i<len; i++) {
1049 NotificationRecord r = list.get(i);
Fred Quintana6ecaff12009-09-25 14:23:13 -07001050 if (tag == null) {
1051 if (r.tag != null) {
1052 continue;
1053 }
1054 } else {
1055 if (!tag.equals(r.tag)) {
1056 continue;
1057 }
1058 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001059 if (r.id == id && r.pkg.equals(pkg)) {
1060 return i;
1061 }
1062 }
1063 return -1;
1064 }
1065
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001066 // This is here instead of StatusBarPolicy because it is an important
1067 // security feature that we don't want people customizing the platform
1068 // to accidentally lose.
1069 private void updateAdbNotification() {
Mike Lockwoodea8b7d52009-08-04 17:03:15 -04001070 if (mAdbEnabled && mUsbConnected) {
Mike Lockwooded760372009-07-09 07:07:27 -04001071 if ("0".equals(SystemProperties.get("persist.adb.notify"))) {
1072 return;
1073 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001074 if (!mAdbNotificationShown) {
1075 NotificationManager notificationManager = (NotificationManager) mContext
1076 .getSystemService(Context.NOTIFICATION_SERVICE);
1077 if (notificationManager != null) {
1078 Resources r = mContext.getResources();
1079 CharSequence title = r.getText(
1080 com.android.internal.R.string.adb_active_notification_title);
1081 CharSequence message = r.getText(
1082 com.android.internal.R.string.adb_active_notification_message);
1083
1084 if (mAdbNotification == null) {
1085 mAdbNotification = new Notification();
1086 mAdbNotification.icon = com.android.internal.R.drawable.stat_sys_warning;
1087 mAdbNotification.when = 0;
1088 mAdbNotification.flags = Notification.FLAG_ONGOING_EVENT;
1089 mAdbNotification.tickerText = title;
1090 mAdbNotification.defaults |= Notification.DEFAULT_SOUND;
1091 }
1092
1093 Intent intent = new Intent(
1094 Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
1095 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
1096 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
1097 // Note: we are hard-coding the component because this is
1098 // an important security UI that we don't want anyone
1099 // intercepting.
1100 intent.setComponent(new ComponentName("com.android.settings",
1101 "com.android.settings.DevelopmentSettings"));
1102 PendingIntent pi = PendingIntent.getActivity(mContext, 0,
1103 intent, 0);
1104
1105 mAdbNotification.setLatestEventInfo(mContext, title, message, pi);
1106
1107 mAdbNotificationShown = true;
1108 notificationManager.notify(
1109 com.android.internal.R.string.adb_active_notification_title,
1110 mAdbNotification);
1111 }
1112 }
1113
1114 } else if (mAdbNotificationShown) {
1115 NotificationManager notificationManager = (NotificationManager) mContext
1116 .getSystemService(Context.NOTIFICATION_SERVICE);
1117 if (notificationManager != null) {
1118 mAdbNotificationShown = false;
1119 notificationManager.cancel(
1120 com.android.internal.R.string.adb_active_notification_title);
1121 }
1122 }
1123 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001124
1125 private void updateNotificationPulse() {
1126 synchronized (mNotificationList) {
1127 updateLightsLocked();
1128 }
1129 }
1130
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001131 // ======================================================================
1132 @Override
1133 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1134 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1135 != PackageManager.PERMISSION_GRANTED) {
1136 pw.println("Permission Denial: can't dump NotificationManager from from pid="
1137 + Binder.getCallingPid()
1138 + ", uid=" + Binder.getCallingUid());
1139 return;
1140 }
1141
1142 pw.println("Current Notification Manager state:");
1143
1144 int N;
1145
1146 synchronized (mToastQueue) {
1147 N = mToastQueue.size();
1148 if (N > 0) {
1149 pw.println(" Toast Queue:");
1150 for (int i=0; i<N; i++) {
1151 mToastQueue.get(i).dump(pw, " ");
1152 }
1153 pw.println(" ");
1154 }
1155
1156 }
1157
1158 synchronized (mNotificationList) {
1159 N = mNotificationList.size();
1160 if (N > 0) {
1161 pw.println(" Notification List:");
1162 for (int i=0; i<N; i++) {
1163 mNotificationList.get(i).dump(pw, " ", mContext);
1164 }
1165 pw.println(" ");
1166 }
1167
1168 N = mLights.size();
1169 if (N > 0) {
1170 pw.println(" Lights List:");
1171 for (int i=0; i<N; i++) {
1172 mLights.get(i).dump(pw, " ", mContext);
1173 }
1174 pw.println(" ");
1175 }
1176
1177 pw.println(" mSoundNotification=" + mSoundNotification);
1178 pw.println(" mSound=" + mSound);
1179 pw.println(" mVibrateNotification=" + mVibrateNotification);
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001180 pw.println(" mDisabledNotifications=0x" + Integer.toHexString(mDisabledNotifications));
1181 pw.println(" mSystemReady=" + mSystemReady);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 }
1183 }
1184}