blob: 1ba7e792c77a89af7561c76cfc55a3bf78b5d150 [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
Daniel Sandler0da673f2012-04-11 12:33:16 -040019import com.android.internal.os.AtomicFile;
Joe Onorato18e69df2010-05-17 22:26:12 -070020import com.android.internal.statusbar.StatusBarNotification;
Daniel Sandler0da673f2012-04-11 12:33:16 -040021import com.android.internal.util.FastXmlSerializer;
svetoslavganov75986cf2009-05-14 22:28:01 -070022
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.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.content.Context;
34import android.content.Intent;
35import android.content.IntentFilter;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070036import android.content.pm.ApplicationInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.content.pm.PackageManager;
38import android.content.pm.PackageManager.NameNotFoundException;
39import android.content.res.Resources;
Dianne Hackborn1dac2772009-06-26 18:16:48 -070040import android.database.ContentObserver;
svetoslavganov75986cf2009-05-14 22:28:01 -070041import android.media.AudioManager;
Daniel Sandler0da673f2012-04-11 12:33:16 -040042import android.net.NetworkPolicy;
43import android.net.NetworkTemplate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.os.Binder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.os.Handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.os.IBinder;
48import android.os.Message;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070049import android.os.Process;
svetoslavganov75986cf2009-05-14 22:28:01 -070050import android.os.RemoteException;
Amith Yamasani742a6712011-05-04 14:49:28 -070051import android.os.UserId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.os.Vibrator;
53import android.provider.Settings;
Daniel Sandlere96ffb12010-03-11 13:38:06 -050054import android.telephony.TelephonyManager;
svetoslavganov75986cf2009-05-14 22:28:01 -070055import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.util.EventLog;
57import android.util.Log;
Andy Stadler110988c2010-12-03 14:29:16 -080058import android.util.Slog;
Daniel Sandler0da673f2012-04-11 12:33:16 -040059import android.util.Xml;
svetoslavganov75986cf2009-05-14 22:28:01 -070060import android.view.accessibility.AccessibilityEvent;
61import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.widget.Toast;
63
Daniel Sandler0da673f2012-04-11 12:33:16 -040064import java.io.File;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065import java.io.FileDescriptor;
Daniel Sandler0da673f2012-04-11 12:33:16 -040066import java.io.FileInputStream;
67import java.io.FileNotFoundException;
68import java.io.FileOutputStream;
69import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070import java.io.PrintWriter;
71import java.util.ArrayList;
72import java.util.Arrays;
Daniel Sandler0da673f2012-04-11 12:33:16 -040073import java.util.HashSet;
74
75import libcore.io.IoUtils;
76
77import org.xmlpull.v1.XmlPullParser;
78import org.xmlpull.v1.XmlPullParserException;
79import org.xmlpull.v1.XmlSerializer;
80
81import static android.net.NetworkPolicyManager.POLICY_NONE;
82import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeBooleanAttribute;
83import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeIntAttribute;
84import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeLongAttribute;
85import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
86import static org.xmlpull.v1.XmlPullParser.END_TAG;
87import static org.xmlpull.v1.XmlPullParser.START_TAG;
88
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089
Daniel Sandlerd0a2f862010-08-03 15:29:31 -040090/** {@hide} */
91public class NotificationManagerService extends INotificationManager.Stub
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092{
93 private static final String TAG = "NotificationService";
94 private static final boolean DBG = false;
95
Joe Onoratobd73d012010-06-04 11:44:54 -070096 private static final int MAX_PACKAGE_NOTIFICATIONS = 50;
97
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 // message codes
99 private static final int MESSAGE_TIMEOUT = 2;
100
101 private static final int LONG_DELAY = 3500; // 3.5 seconds
102 private static final int SHORT_DELAY = 2000; // 2 seconds
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800103
104 private static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105
106 private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
Daniel Sandler49a2ad12012-03-28 15:46:39 -0400107 private static final boolean SCORE_ONGOING_HIGHER = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108
Daniel Sandler0da673f2012-04-11 12:33:16 -0400109 private static final int JUNK_SCORE = -1000;
110 private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
111 private static final int SCORE_DISPLAY_THRESHOLD = Notification.PRIORITY_MIN * NOTIFICATION_PRIORITY_MULTIPLIER;
112
113 private static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
114 private static final boolean ENABLE_BLOCKED_TOASTS = true;
115
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 final Context mContext;
117 final IActivityManager mAm;
118 final IBinder mForegroundToken = new Binder();
119
120 private WorkerHandler mHandler;
Joe Onorato089de882010-04-12 08:18:45 -0700121 private StatusBarManagerService mStatusBar;
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500122 private LightsService.Light mNotificationLight;
123 private LightsService.Light mAttentionLight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124
Mike Lockwood670f9322010-01-20 12:13:36 -0500125 private int mDefaultNotificationColor;
126 private int mDefaultNotificationLedOn;
127 private int mDefaultNotificationLedOff;
128
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 private NotificationRecord mSoundNotification;
Jean-Michel Trivi211957f2010-03-26 18:19:33 -0700130 private NotificationPlayer mSound;
Joe Onorato30275482009-07-08 17:09:14 -0700131 private boolean mSystemReady;
Joe Onorato39f5b6a2009-07-23 12:29:19 -0400132 private int mDisabledNotifications;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133
134 private NotificationRecord mVibrateNotification;
Jeff Brownc2346132012-04-13 01:55:38 -0700135 private Vibrator mVibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500137 // for enabling and disabling notification pulse behavior
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400138 private boolean mScreenOn = true;
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500139 private boolean mInCall = false;
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500140 private boolean mNotificationPulseEnabled;
141
Fred Quintana6ecaff12009-09-25 14:23:13 -0700142 private final ArrayList<NotificationRecord> mNotificationList =
143 new ArrayList<NotificationRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144
145 private ArrayList<ToastRecord> mToastQueue;
146
147 private ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148 private NotificationRecord mLedNotification;
svetoslavganov75986cf2009-05-14 22:28:01 -0700149
Daniel Sandler0da673f2012-04-11 12:33:16 -0400150 // Notification control database. For now just contains disabled packages.
151 private AtomicFile mPolicyFile;
152 private HashSet<String> mBlockedPackages = new HashSet<String>();
153
154 private static final int DB_VERSION = 1;
155
156 private static final String TAG_BODY = "notification-policy";
157 private static final String ATTR_VERSION = "version";
158
159 private static final String TAG_BLOCKED_PKGS = "blocked-packages";
160 private static final String TAG_PACKAGE = "package";
161 private static final String ATTR_NAME = "name";
162
163 private void loadBlockDb() {
164 synchronized(mBlockedPackages) {
165 if (mPolicyFile == null) {
166 File dir = new File("/data/system");
167 mPolicyFile = new AtomicFile(new File(dir, "notification_policy.xml"));
168
169 mBlockedPackages.clear();
170
171 FileInputStream infile = null;
172 try {
173 infile = mPolicyFile.openRead();
174 final XmlPullParser parser = Xml.newPullParser();
175 parser.setInput(infile, null);
176
177 int type;
178 String tag;
179 int version = DB_VERSION;
180 while ((type = parser.next()) != END_DOCUMENT) {
181 tag = parser.getName();
182 if (type == START_TAG) {
183 if (TAG_BODY.equals(tag)) {
184 version = Integer.parseInt(parser.getAttributeValue(null, ATTR_VERSION));
185 } else if (TAG_BLOCKED_PKGS.equals(tag)) {
186 while ((type = parser.next()) != END_DOCUMENT) {
187 tag = parser.getName();
188 if (TAG_PACKAGE.equals(tag)) {
189 mBlockedPackages.add(parser.getAttributeValue(null, ATTR_NAME));
190 } else if (TAG_BLOCKED_PKGS.equals(tag) && type == END_TAG) {
191 break;
192 }
193 }
194 }
195 }
196 }
197 } catch (FileNotFoundException e) {
198 // No data yet
199 } catch (IOException e) {
200 Log.wtf(TAG, "Unable to read blocked notifications database", e);
201 } catch (NumberFormatException e) {
202 Log.wtf(TAG, "Unable to parse blocked notifications database", e);
203 } catch (XmlPullParserException e) {
204 Log.wtf(TAG, "Unable to parse blocked notifications database", e);
205 } finally {
206 IoUtils.closeQuietly(infile);
207 }
208 }
209 }
210 }
211
212 private void writeBlockDb() {
213 synchronized(mBlockedPackages) {
214 FileOutputStream outfile = null;
215 try {
216 outfile = mPolicyFile.startWrite();
217
218 XmlSerializer out = new FastXmlSerializer();
219 out.setOutput(outfile, "utf-8");
220
221 out.startDocument(null, true);
222
223 out.startTag(null, TAG_BODY); {
224 out.attribute(null, ATTR_VERSION, String.valueOf(DB_VERSION));
225 out.startTag(null, TAG_BLOCKED_PKGS); {
226 // write all known network policies
227 for (String pkg : mBlockedPackages) {
228 out.startTag(null, TAG_PACKAGE); {
229 out.attribute(null, ATTR_NAME, pkg);
230 } out.endTag(null, TAG_PACKAGE);
231 }
232 } out.endTag(null, TAG_BLOCKED_PKGS);
233 } out.endTag(null, TAG_BODY);
234
235 out.endDocument();
236
237 mPolicyFile.finishWrite(outfile);
238 } catch (IOException e) {
239 if (outfile != null) {
240 mPolicyFile.failWrite(outfile);
241 }
242 }
243 }
244 }
245
246 public boolean areNotificationsEnabledForPackage(String pkg) {
247 checkCallerIsSystem();
248 return areNotificationsEnabledForPackageInt(pkg);
249 }
250
251 // Unchecked. Not exposed via Binder, but can be called in the course of enqueue*().
252 private boolean areNotificationsEnabledForPackageInt(String pkg) {
253 final boolean enabled = !mBlockedPackages.contains(pkg);
254 if (DBG) {
255 Slog.v(TAG, "notifications are " + (enabled?"en":"dis") + "abled for " + pkg);
256 }
257 return enabled;
258 }
259
260 public void setNotificationsEnabledForPackage(String pkg, boolean enabled) {
261 checkCallerIsSystem();
262 if (DBG) {
263 Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
264 }
265 if (enabled) {
266 mBlockedPackages.remove(pkg);
267 } else {
268 mBlockedPackages.add(pkg);
269
270 // Now, cancel any outstanding notifications that are part of a just-disabled app
271 if (ENABLE_BLOCKED_NOTIFICATIONS) {
272 synchronized (mNotificationList) {
273 final int N = mNotificationList.size();
274 for (int i=0; i<N; i++) {
275 final NotificationRecord r = mNotificationList.get(i);
276 if (r.pkg.equals(pkg)) {
277 cancelNotificationLocked(r, false);
278 }
279 }
280 }
281 }
282 // Don't bother canceling toasts, they'll go away soon enough.
283 }
284 writeBlockDb();
285 }
286
287
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288 private static String idDebugString(Context baseContext, String packageName, int id) {
289 Context c = null;
290
291 if (packageName != null) {
292 try {
293 c = baseContext.createPackageContext(packageName, 0);
294 } catch (NameNotFoundException e) {
295 c = baseContext;
296 }
297 } else {
298 c = baseContext;
299 }
300
301 String pkg;
302 String type;
303 String name;
304
305 Resources r = c.getResources();
306 try {
307 return r.getResourceName(id);
308 } catch (Resources.NotFoundException e) {
309 return "<name unknown>";
310 }
311 }
312
313 private static final class NotificationRecord
314 {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700315 final String pkg;
316 final String tag;
317 final int id;
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700318 final int uid;
319 final int initialPid;
Fred Quintana6ecaff12009-09-25 14:23:13 -0700320 final Notification notification;
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500321 final int score;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322 IBinder statusBarKey;
323
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500324 NotificationRecord(String pkg, String tag, int id, int uid, int initialPid, int score, Notification notification)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 {
326 this.pkg = pkg;
Fred Quintana6ecaff12009-09-25 14:23:13 -0700327 this.tag = tag;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328 this.id = id;
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700329 this.uid = uid;
330 this.initialPid = initialPid;
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500331 this.score = score;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 this.notification = notification;
333 }
Fred Quintana6ecaff12009-09-25 14:23:13 -0700334
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335 void dump(PrintWriter pw, String prefix, Context baseContext) {
336 pw.println(prefix + this);
337 pw.println(prefix + " icon=0x" + Integer.toHexString(notification.icon)
338 + " / " + idDebugString(baseContext, this.pkg, notification.icon));
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500339 pw.println(prefix + " pri=" + notification.priority);
340 pw.println(prefix + " score=" + this.score);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 pw.println(prefix + " contentIntent=" + notification.contentIntent);
342 pw.println(prefix + " deleteIntent=" + notification.deleteIntent);
343 pw.println(prefix + " tickerText=" + notification.tickerText);
344 pw.println(prefix + " contentView=" + notification.contentView);
Amith Yamasani0dedffd2012-03-30 10:47:23 -0700345 pw.println(prefix + " uid=" + uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 pw.println(prefix + " defaults=0x" + Integer.toHexString(notification.defaults));
347 pw.println(prefix + " flags=0x" + Integer.toHexString(notification.flags));
348 pw.println(prefix + " sound=" + notification.sound);
349 pw.println(prefix + " vibrate=" + Arrays.toString(notification.vibrate));
350 pw.println(prefix + " ledARGB=0x" + Integer.toHexString(notification.ledARGB)
351 + " ledOnMS=" + notification.ledOnMS
352 + " ledOffMS=" + notification.ledOffMS);
353 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800354
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 @Override
356 public final String toString()
357 {
358 return "NotificationRecord{"
359 + Integer.toHexString(System.identityHashCode(this))
360 + " pkg=" + pkg
Fred Quintana6ecaff12009-09-25 14:23:13 -0700361 + " id=" + Integer.toHexString(id)
Daniel Sandlere40451a2011-02-03 14:51:35 -0500362 + " tag=" + tag
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500363 + " score=" + score
Daniel Sandlere40451a2011-02-03 14:51:35 -0500364 + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 }
366 }
367
368 private static final class ToastRecord
369 {
370 final int pid;
371 final String pkg;
372 final ITransientNotification callback;
373 int duration;
374
375 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
376 {
377 this.pid = pid;
378 this.pkg = pkg;
379 this.callback = callback;
380 this.duration = duration;
381 }
382
383 void update(int duration) {
384 this.duration = duration;
385 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800386
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 void dump(PrintWriter pw, String prefix) {
388 pw.println(prefix + this);
389 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800390
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 @Override
392 public final String toString()
393 {
394 return "ToastRecord{"
395 + Integer.toHexString(System.identityHashCode(this))
396 + " pkg=" + pkg
397 + " callback=" + callback
398 + " duration=" + duration;
399 }
400 }
401
Joe Onorato089de882010-04-12 08:18:45 -0700402 private StatusBarManagerService.NotificationCallbacks mNotificationCallbacks
403 = new StatusBarManagerService.NotificationCallbacks() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404
405 public void onSetDisabled(int status) {
406 synchronized (mNotificationList) {
407 mDisabledNotifications = status;
408 if ((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
409 // cancel whatever's going on
410 long identity = Binder.clearCallingIdentity();
411 try {
412 mSound.stop();
413 }
414 finally {
415 Binder.restoreCallingIdentity(identity);
416 }
417
418 identity = Binder.clearCallingIdentity();
419 try {
420 mVibrator.cancel();
421 }
422 finally {
423 Binder.restoreCallingIdentity(identity);
424 }
425 }
426 }
427 }
428
429 public void onClearAll() {
430 cancelAll();
431 }
432
Fred Quintana6ecaff12009-09-25 14:23:13 -0700433 public void onNotificationClick(String pkg, String tag, int id) {
434 cancelNotification(pkg, tag, id, Notification.FLAG_AUTO_CANCEL,
jhtop.kim2e448f72011-07-13 17:15:32 +0900435 Notification.FLAG_FOREGROUND_SERVICE, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 }
437
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400438 public void onNotificationClear(String pkg, String tag, int id) {
Joe Onorato46439ce2010-11-19 13:56:21 -0800439 cancelNotification(pkg, tag, id, 0,
440 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
441 true);
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400442 }
443
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444 public void onPanelRevealed() {
445 synchronized (mNotificationList) {
446 // sound
447 mSoundNotification = null;
448 long identity = Binder.clearCallingIdentity();
449 try {
450 mSound.stop();
451 }
452 finally {
453 Binder.restoreCallingIdentity(identity);
454 }
455
456 // vibrate
457 mVibrateNotification = null;
458 identity = Binder.clearCallingIdentity();
459 try {
460 mVibrator.cancel();
461 }
462 finally {
463 Binder.restoreCallingIdentity(identity);
464 }
465
466 // light
467 mLights.clear();
468 mLedNotification = null;
469 updateLightsLocked();
470 }
471 }
Joe Onorato005847b2010-06-04 16:08:02 -0400472
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700473 public void onNotificationError(String pkg, String tag, int id,
474 int uid, int initialPid, String message) {
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400475 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
476 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
Joe Onorato46439ce2010-11-19 13:56:21 -0800477 cancelNotification(pkg, tag, id, 0, 0, false);
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700478 long ident = Binder.clearCallingIdentity();
479 try {
480 ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,
481 "Bad notification posted from package " + pkg
482 + ": " + message);
483 } catch (RemoteException e) {
484 }
485 Binder.restoreCallingIdentity(ident);
Joe Onorato005847b2010-06-04 16:08:02 -0400486 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 };
488
489 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
490 @Override
491 public void onReceive(Context context, Intent intent) {
492 String action = intent.getAction();
493
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800494 boolean queryRestart = false;
495
Mike Lockwood541c9942011-06-12 19:35:45 -0400496 if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800497 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
Daniel Sandleraac0eb02011-08-06 22:51:56 -0400498 || action.equals(Intent.ACTION_PACKAGE_CHANGED)
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800499 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800500 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800501 String pkgList[] = null;
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800502 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800503 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800504 } else if (queryRestart) {
505 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800506 } else {
507 Uri uri = intent.getData();
508 if (uri == null) {
509 return;
510 }
511 String pkgName = uri.getSchemeSpecificPart();
512 if (pkgName == null) {
513 return;
514 }
515 pkgList = new String[]{pkgName};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800517 if (pkgList != null && (pkgList.length > 0)) {
518 for (String pkgName : pkgList) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800519 cancelAllNotificationsInt(pkgName, 0, 0, !queryRestart);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800520 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800521 }
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400522 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
523 // Keep track of screen on/off state, but do not turn off the notification light
524 // until user passes through the lock screen or views the notification.
525 mScreenOn = true;
526 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
527 mScreenOn = false;
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500528 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400529 mInCall = (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(
530 TelephonyManager.EXTRA_STATE_OFFHOOK));
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500531 updateNotificationPulse();
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400532 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
533 // turn off LED when user passes through lock screen
534 mNotificationLight.turnOff();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 }
536 }
537 };
538
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700539 class SettingsObserver extends ContentObserver {
540 SettingsObserver(Handler handler) {
541 super(handler);
542 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800543
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700544 void observe() {
545 ContentResolver resolver = mContext.getContentResolver();
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500546 resolver.registerContentObserver(Settings.System.getUriFor(
547 Settings.System.NOTIFICATION_LIGHT_PULSE), false, this);
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700548 update();
549 }
550
551 @Override public void onChange(boolean selfChange) {
552 update();
553 }
554
555 public void update() {
556 ContentResolver resolver = mContext.getContentResolver();
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500557 boolean pulseEnabled = Settings.System.getInt(resolver,
558 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
559 if (mNotificationPulseEnabled != pulseEnabled) {
560 mNotificationPulseEnabled = pulseEnabled;
561 updateNotificationPulse();
562 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700563 }
564 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500565
Joe Onorato089de882010-04-12 08:18:45 -0700566 NotificationManagerService(Context context, StatusBarManagerService statusBar,
Mike Lockwood3a322132009-11-24 00:30:52 -0500567 LightsService lights)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 {
569 super();
570 mContext = context;
Jeff Brownc2346132012-04-13 01:55:38 -0700571 mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 mAm = ActivityManagerNative.getDefault();
Jean-Michel Trivi211957f2010-03-26 18:19:33 -0700573 mSound = new NotificationPlayer(TAG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800574 mSound.setUsesWakeLock(context);
575 mToastQueue = new ArrayList<ToastRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576 mHandler = new WorkerHandler();
San Mehat3ee13172010-02-04 20:54:43 -0800577
Daniel Sandler0da673f2012-04-11 12:33:16 -0400578 loadBlockDb();
579
Joe Onorato089de882010-04-12 08:18:45 -0700580 mStatusBar = statusBar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 statusBar.setNotificationCallbacks(mNotificationCallbacks);
582
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500583 mNotificationLight = lights.getLight(LightsService.LIGHT_ID_NOTIFICATIONS);
584 mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION);
585
Mike Lockwood670f9322010-01-20 12:13:36 -0500586 Resources resources = mContext.getResources();
587 mDefaultNotificationColor = resources.getColor(
588 com.android.internal.R.color.config_defaultNotificationColor);
589 mDefaultNotificationLedOn = resources.getInteger(
590 com.android.internal.R.integer.config_defaultNotificationLedOn);
591 mDefaultNotificationLedOff = resources.getInteger(
592 com.android.internal.R.integer.config_defaultNotificationLedOff);
593
Joe Onorato39f5b6a2009-07-23 12:29:19 -0400594 // Don't start allowing notifications until the setup wizard has run once.
595 // After that, including subsequent boots, init with notifications turned on.
596 // This works on the first boot because the setup wizard will toggle this
597 // flag at least once and we'll go back to 0 after that.
598 if (0 == Settings.Secure.getInt(mContext.getContentResolver(),
599 Settings.Secure.DEVICE_PROVISIONED, 0)) {
600 mDisabledNotifications = StatusBarManager.DISABLE_NOTIFICATION_ALERTS;
601 }
602
Mike Lockwood35e16bf2010-11-30 19:53:36 -0500603 // register for various Intents
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604 IntentFilter filter = new IntentFilter();
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500605 filter.addAction(Intent.ACTION_SCREEN_ON);
606 filter.addAction(Intent.ACTION_SCREEN_OFF);
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500607 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400608 filter.addAction(Intent.ACTION_USER_PRESENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 mContext.registerReceiver(mIntentReceiver, filter);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800610 IntentFilter pkgFilter = new IntentFilter();
611 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
Daniel Sandleraac0eb02011-08-06 22:51:56 -0400612 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800613 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
614 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
615 pkgFilter.addDataScheme("package");
616 mContext.registerReceiver(mIntentReceiver, pkgFilter);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800617 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800618 mContext.registerReceiver(mIntentReceiver, sdFilter);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800619
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500620 SettingsObserver observer = new SettingsObserver(mHandler);
621 observer.observe();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800622 }
623
Joe Onorato30275482009-07-08 17:09:14 -0700624 void systemReady() {
625 // no beeping until we're basically done booting
626 mSystemReady = true;
627 }
628
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629 // Toasts
630 // ============================================================================
631 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
632 {
Daniel Sandlera7035902010-03-30 15:45:31 -0400633 if (DBG) Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + " duration=" + duration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800634
635 if (pkg == null || callback == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800636 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 return ;
638 }
639
Daniel Sandler0da673f2012-04-11 12:33:16 -0400640 final boolean isSystemToast = ("android".equals(pkg));
641
642 if (ENABLE_BLOCKED_TOASTS && !isSystemToast && !areNotificationsEnabledForPackageInt(pkg)) {
643 Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request.");
644 return;
645 }
646
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647 synchronized (mToastQueue) {
648 int callingPid = Binder.getCallingPid();
649 long callingId = Binder.clearCallingIdentity();
650 try {
651 ToastRecord record;
652 int index = indexOfToastLocked(pkg, callback);
653 // If it's already in the queue, we update it in place, we don't
654 // move it to the end of the queue.
655 if (index >= 0) {
656 record = mToastQueue.get(index);
657 record.update(duration);
658 } else {
Vairavan Srinivasanf9eb06c2011-01-21 18:08:36 -0800659 // Limit the number of toasts that any given package except the android
660 // package can enqueue. Prevents DOS attacks and deals with leaks.
Daniel Sandler0da673f2012-04-11 12:33:16 -0400661 if (!isSystemToast) {
Vairavan Srinivasanf9eb06c2011-01-21 18:08:36 -0800662 int count = 0;
663 final int N = mToastQueue.size();
664 for (int i=0; i<N; i++) {
665 final ToastRecord r = mToastQueue.get(i);
666 if (r.pkg.equals(pkg)) {
667 count++;
668 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
669 Slog.e(TAG, "Package has already posted " + count
670 + " toasts. Not showing more. Package=" + pkg);
671 return;
672 }
673 }
674 }
675 }
676
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677 record = new ToastRecord(callingPid, pkg, callback, duration);
678 mToastQueue.add(record);
679 index = mToastQueue.size() - 1;
680 keepProcessAliveLocked(callingPid);
681 }
682 // If it's at index 0, it's the current toast. It doesn't matter if it's
683 // new or just been updated. Call back and tell it to show itself.
684 // If the callback fails, this will remove it from the list, so don't
685 // assume that it's valid after this.
686 if (index == 0) {
687 showNextToastLocked();
688 }
689 } finally {
690 Binder.restoreCallingIdentity(callingId);
691 }
692 }
693 }
694
695 public void cancelToast(String pkg, ITransientNotification callback) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800696 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800697
698 if (pkg == null || callback == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800699 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800700 return ;
701 }
702
703 synchronized (mToastQueue) {
704 long callingId = Binder.clearCallingIdentity();
705 try {
706 int index = indexOfToastLocked(pkg, callback);
707 if (index >= 0) {
708 cancelToastLocked(index);
709 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800710 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg + " callback=" + callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800711 }
712 } finally {
713 Binder.restoreCallingIdentity(callingId);
714 }
715 }
716 }
717
718 private void showNextToastLocked() {
719 ToastRecord record = mToastQueue.get(0);
720 while (record != null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800721 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800722 try {
723 record.callback.show();
724 scheduleTimeoutLocked(record, false);
725 return;
726 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800727 Slog.w(TAG, "Object died trying to show notification " + record.callback
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800728 + " in package " + record.pkg);
729 // remove it from the list and let the process die
730 int index = mToastQueue.indexOf(record);
731 if (index >= 0) {
732 mToastQueue.remove(index);
733 }
734 keepProcessAliveLocked(record.pid);
735 if (mToastQueue.size() > 0) {
736 record = mToastQueue.get(0);
737 } else {
738 record = null;
739 }
740 }
741 }
742 }
743
744 private void cancelToastLocked(int index) {
745 ToastRecord record = mToastQueue.get(index);
746 try {
747 record.callback.hide();
748 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800749 Slog.w(TAG, "Object died trying to hide notification " + record.callback
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750 + " in package " + record.pkg);
751 // don't worry about this, we're about to remove it from
752 // the list anyway
753 }
754 mToastQueue.remove(index);
755 keepProcessAliveLocked(record.pid);
756 if (mToastQueue.size() > 0) {
757 // Show the next one. If the callback fails, this will remove
758 // it from the list, so don't assume that the list hasn't changed
759 // after this point.
760 showNextToastLocked();
761 }
762 }
763
764 private void scheduleTimeoutLocked(ToastRecord r, boolean immediate)
765 {
766 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
767 long delay = immediate ? 0 : (r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY);
768 mHandler.removeCallbacksAndMessages(r);
769 mHandler.sendMessageDelayed(m, delay);
770 }
771
772 private void handleTimeout(ToastRecord record)
773 {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800774 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800775 synchronized (mToastQueue) {
776 int index = indexOfToastLocked(record.pkg, record.callback);
777 if (index >= 0) {
778 cancelToastLocked(index);
779 }
780 }
781 }
782
783 // lock on mToastQueue
784 private int indexOfToastLocked(String pkg, ITransientNotification callback)
785 {
786 IBinder cbak = callback.asBinder();
787 ArrayList<ToastRecord> list = mToastQueue;
788 int len = list.size();
789 for (int i=0; i<len; i++) {
790 ToastRecord r = list.get(i);
791 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
792 return i;
793 }
794 }
795 return -1;
796 }
797
798 // lock on mToastQueue
799 private void keepProcessAliveLocked(int pid)
800 {
801 int toastCount = 0; // toasts from this pid
802 ArrayList<ToastRecord> list = mToastQueue;
803 int N = list.size();
804 for (int i=0; i<N; i++) {
805 ToastRecord r = list.get(i);
806 if (r.pid == pid) {
807 toastCount++;
808 }
809 }
810 try {
811 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
812 } catch (RemoteException e) {
813 // Shouldn't happen.
814 }
815 }
816
817 private final class WorkerHandler extends Handler
818 {
819 @Override
820 public void handleMessage(Message msg)
821 {
822 switch (msg.what)
823 {
824 case MESSAGE_TIMEOUT:
825 handleTimeout((ToastRecord)msg.obj);
826 break;
827 }
828 }
829 }
830
831
832 // Notifications
833 // ============================================================================
Andy Stadler110988c2010-12-03 14:29:16 -0800834 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835 public void enqueueNotification(String pkg, int id, Notification notification, int[] idOut)
836 {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700837 enqueueNotificationWithTag(pkg, null /* tag */, id, notification, idOut);
838 }
839
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400840 public void enqueueNotificationWithTag(String pkg, String tag, int id, Notification notification,
841 int[] idOut)
Fred Quintana6ecaff12009-09-25 14:23:13 -0700842 {
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400843 enqueueNotificationInternal(pkg, Binder.getCallingUid(), Binder.getCallingPid(),
844 tag, id, notification, idOut);
845 }
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500846
847 private final static int clamp(int x, int low, int high) {
848 return (x < low) ? low : ((x > high) ? high : x);
Daniel Sandlere40451a2011-02-03 14:51:35 -0500849 }
850
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500851
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400852 // Not exposed via Binder; for system use only (otherwise malicious apps could spoof the
853 // uid/pid of another application)
854 public void enqueueNotificationInternal(String pkg, int callingUid, int callingPid,
855 String tag, int id, Notification notification, int[] idOut)
856 {
Daniel Sandler0da673f2012-04-11 12:33:16 -0400857 if (DBG) {
858 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id + " notification=" + notification);
859 }
860 checkCallerIsSystemOrSameApp(pkg);
861 final boolean isSystemNotification = ("android".equals(pkg));
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800862
Joe Onoratobd73d012010-06-04 11:44:54 -0700863 // Limit the number of notifications that any given package except the android
864 // package can enqueue. Prevents DOS attacks and deals with leaks.
Daniel Sandler0da673f2012-04-11 12:33:16 -0400865 if (!isSystemNotification) {
Joe Onoratobd73d012010-06-04 11:44:54 -0700866 synchronized (mNotificationList) {
867 int count = 0;
868 final int N = mNotificationList.size();
869 for (int i=0; i<N; i++) {
870 final NotificationRecord r = mNotificationList.get(i);
871 if (r.pkg.equals(pkg)) {
872 count++;
873 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
874 Slog.e(TAG, "Package has already posted " + count
875 + " notifications. Not showing more. package=" + pkg);
876 return;
877 }
878 }
879 }
880 }
881 }
882
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 // This conditional is a dirty hack to limit the logging done on
884 // behalf of the download manager without affecting other apps.
885 if (!pkg.equals("com.android.providers.downloads")
886 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
Daniel Sandlerb64cb882011-11-29 23:48:29 -0500887 EventLog.writeEvent(EventLogTags.NOTIFICATION_ENQUEUE, pkg, id, tag,
888 notification.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889 }
890
891 if (pkg == null || notification == null) {
892 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
893 + " id=" + id + " notification=" + notification);
894 }
895 if (notification.icon != 0) {
896 if (notification.contentView == null) {
897 throw new IllegalArgumentException("contentView required: pkg=" + pkg
898 + " id=" + id + " notification=" + notification);
899 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800900 }
901
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500902 // === Scoring ===
Daniel Sandler0da673f2012-04-11 12:33:16 -0400903
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500904 // 0. Sanitize inputs
905 notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN, Notification.PRIORITY_MAX);
906 // Migrate notification flags to scores
907 if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) {
908 if (notification.priority < Notification.PRIORITY_MAX) notification.priority = Notification.PRIORITY_MAX;
Daniel Sandler49a2ad12012-03-28 15:46:39 -0400909 } else if (SCORE_ONGOING_HIGHER && 0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) {
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500910 if (notification.priority < Notification.PRIORITY_HIGH) notification.priority = Notification.PRIORITY_HIGH;
911 }
Daniel Sandler0da673f2012-04-11 12:33:16 -0400912
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500913 // 1. initial score: buckets of 10, around the app
Daniel Sandler0da673f2012-04-11 12:33:16 -0400914 int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER; //[-20..20]
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500915
Daniel Sandler0da673f2012-04-11 12:33:16 -0400916 // 2. Consult external heuristics (TBD)
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500917
Daniel Sandler0da673f2012-04-11 12:33:16 -0400918 // 3. Apply local rules
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500919
920 // blocked apps
Daniel Sandler0da673f2012-04-11 12:33:16 -0400921 if (ENABLE_BLOCKED_NOTIFICATIONS && !isSystemNotification && !areNotificationsEnabledForPackageInt(pkg)) {
922 score = JUNK_SCORE;
923 Slog.e(TAG, "Suppressing notification from package " + pkg + " by user request.");
924 }
925
926 if (DBG) {
927 Slog.v(TAG, "Assigned score=" + score + " to " + notification);
928 }
929
930 if (score < SCORE_DISPLAY_THRESHOLD) {
931 // Notification will be blocked because the score is too low.
932 return;
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500933 }
934
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935 synchronized (mNotificationList) {
Daniel Sandlere40451a2011-02-03 14:51:35 -0500936 NotificationRecord r = new NotificationRecord(pkg, tag, id,
937 callingUid, callingPid,
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500938 score,
Daniel Sandlere40451a2011-02-03 14:51:35 -0500939 notification);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940 NotificationRecord old = null;
941
Fred Quintana6ecaff12009-09-25 14:23:13 -0700942 int index = indexOfNotificationLocked(pkg, tag, id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800943 if (index < 0) {
944 mNotificationList.add(r);
945 } else {
946 old = mNotificationList.remove(index);
947 mNotificationList.add(index, r);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700948 // Make sure we don't lose the foreground service state.
949 if (old != null) {
950 notification.flags |=
951 old.notification.flags&Notification.FLAG_FOREGROUND_SERVICE;
952 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800954
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700955 // Ensure if this is a foreground service that the proper additional
956 // flags are set.
957 if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) {
958 notification.flags |= Notification.FLAG_ONGOING_EVENT
959 | Notification.FLAG_NO_CLEAR;
960 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800961
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800962 if (notification.icon != 0) {
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700963 StatusBarNotification n = new StatusBarNotification(pkg, id, tag,
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500964 r.uid, r.initialPid, score, notification);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 if (old != null && old.statusBarKey != null) {
966 r.statusBarKey = old.statusBarKey;
967 long identity = Binder.clearCallingIdentity();
968 try {
Joe Onorato18e69df2010-05-17 22:26:12 -0700969 mStatusBar.updateNotification(r.statusBarKey, n);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 }
971 finally {
972 Binder.restoreCallingIdentity(identity);
973 }
974 } else {
975 long identity = Binder.clearCallingIdentity();
976 try {
Joe Onorato18e69df2010-05-17 22:26:12 -0700977 r.statusBarKey = mStatusBar.addNotification(n);
Mike Lockwoodece18ef2012-02-13 20:42:19 -0800978 if ((n.notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {
979 mAttentionLight.pulse();
980 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800981 }
982 finally {
983 Binder.restoreCallingIdentity(identity);
984 }
985 }
Joe Onorato30275482009-07-08 17:09:14 -0700986 sendAccessibilityEvent(notification, pkg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987 } else {
Daniel Sandlere40451a2011-02-03 14:51:35 -0500988 Slog.e(TAG, "Ignoring notification with icon==0: " + notification);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800989 if (old != null && old.statusBarKey != null) {
990 long identity = Binder.clearCallingIdentity();
991 try {
Joe Onorato0cbda992010-05-02 16:28:15 -0700992 mStatusBar.removeNotification(old.statusBarKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800993 }
994 finally {
995 Binder.restoreCallingIdentity(identity);
996 }
997 }
998 }
999
1000 // If we're not supposed to beep, vibrate, etc. then don't.
1001 if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
1002 && (!(old != null
Joe Onorato30275482009-07-08 17:09:14 -07001003 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
1004 && mSystemReady) {
Eric Laurent524dc042009-11-27 05:07:55 -08001005
1006 final AudioManager audioManager = (AudioManager) mContext
1007 .getSystemService(Context.AUDIO_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001008 // sound
1009 final boolean useDefaultSound =
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001010 (notification.defaults & Notification.DEFAULT_SOUND) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001011 if (useDefaultSound || notification.sound != null) {
1012 Uri uri;
1013 if (useDefaultSound) {
1014 uri = Settings.System.DEFAULT_NOTIFICATION_URI;
1015 } else {
1016 uri = notification.sound;
1017 }
1018 boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0;
1019 int audioStreamType;
1020 if (notification.audioStreamType >= 0) {
1021 audioStreamType = notification.audioStreamType;
1022 } else {
1023 audioStreamType = DEFAULT_STREAM_TYPE;
1024 }
1025 mSoundNotification = r;
Eric Laurent524dc042009-11-27 05:07:55 -08001026 // do not play notifications if stream volume is 0
1027 // (typically because ringer mode is silent).
1028 if (audioManager.getStreamVolume(audioStreamType) != 0) {
1029 long identity = Binder.clearCallingIdentity();
1030 try {
1031 mSound.play(mContext, uri, looping, audioStreamType);
1032 }
1033 finally {
1034 Binder.restoreCallingIdentity(identity);
1035 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 }
1037 }
1038
1039 // vibrate
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001040 final boolean useDefaultVibrate =
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001041 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001042 if ((useDefaultVibrate || notification.vibrate != null)
1043 && audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_NOTIFICATION)) {
1044 mVibrateNotification = r;
1045
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001046 mVibrator.vibrate(useDefaultVibrate ? DEFAULT_VIBRATE_PATTERN
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001047 : notification.vibrate,
1048 ((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
1049 }
1050 }
1051
1052 // this option doesn't shut off the lights
1053
1054 // light
1055 // the most recent thing gets the light
1056 mLights.remove(old);
1057 if (mLedNotification == old) {
1058 mLedNotification = null;
1059 }
Joe Onorato8a9b2202010-02-26 18:56:32 -08001060 //Slog.i(TAG, "notification.lights="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 // + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS) != 0));
1062 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {
1063 mLights.add(r);
1064 updateLightsLocked();
1065 } else {
1066 if (old != null
1067 && ((old.notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0)) {
1068 updateLightsLocked();
1069 }
1070 }
1071 }
1072
1073 idOut[0] = id;
1074 }
1075
Joe Onorato30275482009-07-08 17:09:14 -07001076 private void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
svetoslavganov75986cf2009-05-14 22:28:01 -07001077 AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
1078 if (!manager.isEnabled()) {
1079 return;
1080 }
1081
1082 AccessibilityEvent event =
1083 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
1084 event.setPackageName(packageName);
1085 event.setClassName(Notification.class.getName());
1086 event.setParcelableData(notification);
1087 CharSequence tickerText = notification.tickerText;
1088 if (!TextUtils.isEmpty(tickerText)) {
1089 event.getText().add(tickerText);
1090 }
1091
1092 manager.sendAccessibilityEvent(event);
1093 }
1094
Joe Onorato46439ce2010-11-19 13:56:21 -08001095 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete) {
1096 // tell the app
1097 if (sendDelete) {
1098 if (r.notification.deleteIntent != null) {
1099 try {
1100 r.notification.deleteIntent.send();
1101 } catch (PendingIntent.CanceledException ex) {
1102 // do nothing - there's no relevant way to recover, and
1103 // no reason to let this propagate
1104 Slog.w(TAG, "canceled PendingIntent for " + r.pkg, ex);
1105 }
1106 }
1107 }
1108
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109 // status bar
1110 if (r.notification.icon != 0) {
1111 long identity = Binder.clearCallingIdentity();
1112 try {
Joe Onorato0cbda992010-05-02 16:28:15 -07001113 mStatusBar.removeNotification(r.statusBarKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 }
1115 finally {
1116 Binder.restoreCallingIdentity(identity);
1117 }
1118 r.statusBarKey = null;
1119 }
1120
1121 // sound
1122 if (mSoundNotification == r) {
1123 mSoundNotification = null;
1124 long identity = Binder.clearCallingIdentity();
1125 try {
1126 mSound.stop();
1127 }
1128 finally {
1129 Binder.restoreCallingIdentity(identity);
1130 }
1131 }
1132
1133 // vibrate
1134 if (mVibrateNotification == r) {
1135 mVibrateNotification = null;
1136 long identity = Binder.clearCallingIdentity();
1137 try {
1138 mVibrator.cancel();
1139 }
1140 finally {
1141 Binder.restoreCallingIdentity(identity);
1142 }
1143 }
1144
1145 // light
1146 mLights.remove(r);
1147 if (mLedNotification == r) {
1148 mLedNotification = null;
1149 }
1150 }
1151
1152 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001153 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001154 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001155 */
Fred Quintana6ecaff12009-09-25 14:23:13 -07001156 private void cancelNotification(String pkg, String tag, int id, int mustHaveFlags,
Joe Onorato46439ce2010-11-19 13:56:21 -08001157 int mustNotHaveFlags, boolean sendDelete) {
Daniel Sandlerb64cb882011-11-29 23:48:29 -05001158 EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL, pkg, id, tag,
1159 mustHaveFlags, mustNotHaveFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001160
1161 synchronized (mNotificationList) {
Fred Quintana6ecaff12009-09-25 14:23:13 -07001162 int index = indexOfNotificationLocked(pkg, tag, id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001163 if (index >= 0) {
Fred Quintana6ecaff12009-09-25 14:23:13 -07001164 NotificationRecord r = mNotificationList.get(index);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001165
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001166 if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {
1167 return;
1168 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001169 if ((r.notification.flags & mustNotHaveFlags) != 0) {
1170 return;
1171 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001172
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001173 mNotificationList.remove(index);
1174
Joe Onorato46439ce2010-11-19 13:56:21 -08001175 cancelNotificationLocked(r, sendDelete);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 updateLightsLocked();
1177 }
1178 }
1179 }
1180
1181 /**
1182 * Cancels all notifications from a given package that have all of the
1183 * {@code mustHaveFlags}.
1184 */
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001185 boolean cancelAllNotificationsInt(String pkg, int mustHaveFlags,
1186 int mustNotHaveFlags, boolean doit) {
Daniel Sandlerb64cb882011-11-29 23:48:29 -05001187 EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL_ALL, pkg, mustHaveFlags,
1188 mustNotHaveFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001189
1190 synchronized (mNotificationList) {
1191 final int N = mNotificationList.size();
1192 boolean canceledSomething = false;
1193 for (int i = N-1; i >= 0; --i) {
1194 NotificationRecord r = mNotificationList.get(i);
1195 if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {
1196 continue;
1197 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001198 if ((r.notification.flags & mustNotHaveFlags) != 0) {
1199 continue;
1200 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001201 if (!r.pkg.equals(pkg)) {
1202 continue;
1203 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001204 canceledSomething = true;
1205 if (!doit) {
1206 return true;
1207 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001208 mNotificationList.remove(i);
Joe Onorato46439ce2010-11-19 13:56:21 -08001209 cancelNotificationLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001210 }
1211 if (canceledSomething) {
1212 updateLightsLocked();
1213 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001214 return canceledSomething;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215 }
1216 }
1217
Andy Stadler110988c2010-12-03 14:29:16 -08001218 @Deprecated
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001219 public void cancelNotification(String pkg, int id) {
Fred Quintana6ecaff12009-09-25 14:23:13 -07001220 cancelNotificationWithTag(pkg, null /* tag */, id);
1221 }
1222
1223 public void cancelNotificationWithTag(String pkg, String tag, int id) {
Daniel Sandler0da673f2012-04-11 12:33:16 -04001224 checkCallerIsSystemOrSameApp(pkg);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001225 // Don't allow client applications to cancel foreground service notis.
Fred Quintana6ecaff12009-09-25 14:23:13 -07001226 cancelNotification(pkg, tag, id, 0,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001227 Binder.getCallingUid() == Process.SYSTEM_UID
Joe Onorato46439ce2010-11-19 13:56:21 -08001228 ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001229 }
1230
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001231 public void cancelAllNotifications(String pkg) {
Daniel Sandler0da673f2012-04-11 12:33:16 -04001232 checkCallerIsSystemOrSameApp(pkg);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001233
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001234 // Calling from user space, don't allow the canceling of actively
1235 // running foreground services.
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001236 cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001237 }
1238
Daniel Sandler0da673f2012-04-11 12:33:16 -04001239 void checkCallerIsSystem() {
1240 int uid = Binder.getCallingUid();
1241 if (uid == Process.SYSTEM_UID || uid == 0) {
1242 return;
1243 }
1244 throw new SecurityException("Disallowed call for uid " + uid);
1245 }
1246
1247 void checkCallerIsSystemOrSameApp(String pkg) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001248 int uid = Binder.getCallingUid();
1249 if (uid == Process.SYSTEM_UID || uid == 0) {
1250 return;
1251 }
1252 try {
1253 ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(
1254 pkg, 0);
Amith Yamasani742a6712011-05-04 14:49:28 -07001255 if (!UserId.isSameApp(ai.uid, uid)) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001256 throw new SecurityException("Calling uid " + uid + " gave package"
1257 + pkg + " which is owned by uid " + ai.uid);
1258 }
1259 } catch (PackageManager.NameNotFoundException e) {
1260 throw new SecurityException("Unknown package " + pkg);
1261 }
1262 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001263
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001264 void cancelAll() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001265 synchronized (mNotificationList) {
1266 final int N = mNotificationList.size();
1267 for (int i=N-1; i>=0; i--) {
1268 NotificationRecord r = mNotificationList.get(i);
1269
1270 if ((r.notification.flags & (Notification.FLAG_ONGOING_EVENT
1271 | Notification.FLAG_NO_CLEAR)) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001272 mNotificationList.remove(i);
Joe Onorato46439ce2010-11-19 13:56:21 -08001273 cancelNotificationLocked(r, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001274 }
1275 }
1276
1277 updateLightsLocked();
1278 }
1279 }
1280
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001281 // lock on mNotificationList
1282 private void updateLightsLocked()
1283 {
The Android Open Source Project10592532009-03-18 17:39:46 -07001284 // handle notification lights
1285 if (mLedNotification == null) {
1286 // get next notification, if any
1287 int n = mLights.size();
1288 if (n > 0) {
1289 mLedNotification = mLights.get(n-1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001290 }
1291 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001292
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001293 // Don't flash while we are in a call or screen is on
1294 if (mLedNotification == null || mInCall || mScreenOn) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001295 mNotificationLight.turnOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07001296 } else {
Mike Lockwood670f9322010-01-20 12:13:36 -05001297 int ledARGB = mLedNotification.notification.ledARGB;
1298 int ledOnMS = mLedNotification.notification.ledOnMS;
1299 int ledOffMS = mLedNotification.notification.ledOffMS;
1300 if ((mLedNotification.notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {
1301 ledARGB = mDefaultNotificationColor;
1302 ledOnMS = mDefaultNotificationLedOn;
1303 ledOffMS = mDefaultNotificationLedOff;
1304 }
1305 if (mNotificationPulseEnabled) {
1306 // pulse repeatedly
1307 mNotificationLight.setFlashing(ledARGB, LightsService.LIGHT_FLASH_TIMED,
1308 ledOnMS, ledOffMS);
Mike Lockwood670f9322010-01-20 12:13:36 -05001309 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001310 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001311 }
1312
1313 // lock on mNotificationList
Fred Quintana6ecaff12009-09-25 14:23:13 -07001314 private int indexOfNotificationLocked(String pkg, String tag, int id)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001315 {
1316 ArrayList<NotificationRecord> list = mNotificationList;
1317 final int len = list.size();
1318 for (int i=0; i<len; i++) {
1319 NotificationRecord r = list.get(i);
Fred Quintana6ecaff12009-09-25 14:23:13 -07001320 if (tag == null) {
1321 if (r.tag != null) {
1322 continue;
1323 }
1324 } else {
1325 if (!tag.equals(r.tag)) {
1326 continue;
1327 }
1328 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001329 if (r.id == id && r.pkg.equals(pkg)) {
1330 return i;
1331 }
1332 }
1333 return -1;
1334 }
1335
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001336 private void updateNotificationPulse() {
1337 synchronized (mNotificationList) {
1338 updateLightsLocked();
1339 }
1340 }
1341
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001342 // ======================================================================
1343 @Override
1344 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1345 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1346 != PackageManager.PERMISSION_GRANTED) {
1347 pw.println("Permission Denial: can't dump NotificationManager from from pid="
1348 + Binder.getCallingPid()
1349 + ", uid=" + Binder.getCallingUid());
1350 return;
1351 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001352
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001353 pw.println("Current Notification Manager state:");
1354
1355 int N;
1356
1357 synchronized (mToastQueue) {
1358 N = mToastQueue.size();
1359 if (N > 0) {
1360 pw.println(" Toast Queue:");
1361 for (int i=0; i<N; i++) {
1362 mToastQueue.get(i).dump(pw, " ");
1363 }
1364 pw.println(" ");
1365 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001366
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001367 }
1368
1369 synchronized (mNotificationList) {
1370 N = mNotificationList.size();
1371 if (N > 0) {
1372 pw.println(" Notification List:");
1373 for (int i=0; i<N; i++) {
1374 mNotificationList.get(i).dump(pw, " ", mContext);
1375 }
1376 pw.println(" ");
1377 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001378
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001379 N = mLights.size();
1380 if (N > 0) {
1381 pw.println(" Lights List:");
1382 for (int i=0; i<N; i++) {
1383 mLights.get(i).dump(pw, " ", mContext);
1384 }
1385 pw.println(" ");
1386 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001387
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001388 pw.println(" mSoundNotification=" + mSoundNotification);
1389 pw.println(" mSound=" + mSound);
1390 pw.println(" mVibrateNotification=" + mVibrateNotification);
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001391 pw.println(" mDisabledNotifications=0x" + Integer.toHexString(mDisabledNotifications));
1392 pw.println(" mSystemReady=" + mSystemReady);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001393 }
1394 }
1395}