blob: c83471e8831b96186b9b7b1347d0dd8b2b588aad [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
Joe Onorato18e69df2010-05-17 22:26:12 -070019import com.android.internal.statusbar.StatusBarNotification;
svetoslavganov75986cf2009-05-14 22:28:01 -070020
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.app.ActivityManagerNative;
22import android.app.IActivityManager;
23import android.app.INotificationManager;
24import android.app.ITransientNotification;
25import android.app.Notification;
Dianne Hackborn1dac2772009-06-26 18:16:48 -070026import android.app.NotificationManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.app.PendingIntent;
28import android.app.StatusBarManager;
29import android.content.BroadcastReceiver;
Dianne Hackborn1dac2772009-06-26 18:16:48 -070030import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.content.Context;
32import android.content.Intent;
33import android.content.IntentFilter;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070034import android.content.pm.ApplicationInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.content.pm.PackageManager;
36import android.content.pm.PackageManager.NameNotFoundException;
37import android.content.res.Resources;
Dianne Hackborn1dac2772009-06-26 18:16:48 -070038import android.database.ContentObserver;
svetoslavganov75986cf2009-05-14 22:28:01 -070039import android.media.AudioManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.os.Binder;
Andy Stadler110988c2010-12-03 14:29:16 -080042import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.os.Handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.os.IBinder;
45import android.os.Message;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070046import android.os.Process;
svetoslavganov75986cf2009-05-14 22:28:01 -070047import android.os.RemoteException;
Amith Yamasani742a6712011-05-04 14:49:28 -070048import android.os.UserId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.os.Vibrator;
50import android.provider.Settings;
Daniel Sandlere96ffb12010-03-11 13:38:06 -050051import android.telephony.TelephonyManager;
svetoslavganov75986cf2009-05-14 22:28:01 -070052import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.util.EventLog;
54import android.util.Log;
Andy Stadler110988c2010-12-03 14:29:16 -080055import android.util.Slog;
svetoslavganov75986cf2009-05-14 22:28:01 -070056import android.view.accessibility.AccessibilityEvent;
57import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.widget.Toast;
59
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import java.io.FileDescriptor;
61import java.io.PrintWriter;
62import java.util.ArrayList;
63import java.util.Arrays;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064
Daniel Sandlerd0a2f862010-08-03 15:29:31 -040065/** {@hide} */
66public class NotificationManagerService extends INotificationManager.Stub
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067{
68 private static final String TAG = "NotificationService";
69 private static final boolean DBG = false;
70
Joe Onoratobd73d012010-06-04 11:44:54 -070071 private static final int MAX_PACKAGE_NOTIFICATIONS = 50;
72
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073 // 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
Doug Zongkerab5c49c2009-12-04 10:31:43 -080078
79 private static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080
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;
Joe Onorato089de882010-04-12 08:18:45 -070088 private StatusBarManagerService mStatusBar;
Mike Lockwood3cb67a32009-11-27 14:25:58 -050089 private LightsService.Light mNotificationLight;
90 private LightsService.Light mAttentionLight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091
Mike Lockwood670f9322010-01-20 12:13:36 -050092 private int mDefaultNotificationColor;
93 private int mDefaultNotificationLedOn;
94 private int mDefaultNotificationLedOff;
95
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 private NotificationRecord mSoundNotification;
Jean-Michel Trivi211957f2010-03-26 18:19:33 -070097 private NotificationPlayer mSound;
Joe Onorato30275482009-07-08 17:09:14 -070098 private boolean mSystemReady;
Joe Onorato39f5b6a2009-07-23 12:29:19 -040099 private int mDisabledNotifications;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100
101 private NotificationRecord mVibrateNotification;
102 private Vibrator mVibrator = new Vibrator();
103
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500104 // for enabling and disabling notification pulse behavior
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400105 private boolean mScreenOn = true;
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500106 private boolean mInCall = false;
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500107 private boolean mNotificationPulseEnabled;
108
Fred Quintana6ecaff12009-09-25 14:23:13 -0700109 private final ArrayList<NotificationRecord> mNotificationList =
110 new ArrayList<NotificationRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111
112 private ArrayList<ToastRecord> mToastQueue;
113
114 private ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115 private NotificationRecord mLedNotification;
svetoslavganov75986cf2009-05-14 22:28:01 -0700116
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 private static String idDebugString(Context baseContext, String packageName, int id) {
118 Context c = null;
119
120 if (packageName != null) {
121 try {
122 c = baseContext.createPackageContext(packageName, 0);
123 } catch (NameNotFoundException e) {
124 c = baseContext;
125 }
126 } else {
127 c = baseContext;
128 }
129
130 String pkg;
131 String type;
132 String name;
133
134 Resources r = c.getResources();
135 try {
136 return r.getResourceName(id);
137 } catch (Resources.NotFoundException e) {
138 return "<name unknown>";
139 }
140 }
141
142 private static final class NotificationRecord
143 {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700144 final String pkg;
145 final String tag;
146 final int id;
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700147 final int uid;
148 final int initialPid;
Fred Quintana6ecaff12009-09-25 14:23:13 -0700149 final Notification notification;
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500150 final int score;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151 IBinder statusBarKey;
152
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500153 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 -0800154 {
155 this.pkg = pkg;
Fred Quintana6ecaff12009-09-25 14:23:13 -0700156 this.tag = tag;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 this.id = id;
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700158 this.uid = uid;
159 this.initialPid = initialPid;
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500160 this.score = score;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161 this.notification = notification;
162 }
Fred Quintana6ecaff12009-09-25 14:23:13 -0700163
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 void dump(PrintWriter pw, String prefix, Context baseContext) {
165 pw.println(prefix + this);
166 pw.println(prefix + " icon=0x" + Integer.toHexString(notification.icon)
167 + " / " + idDebugString(baseContext, this.pkg, notification.icon));
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500168 pw.println(prefix + " pri=" + notification.priority);
169 pw.println(prefix + " score=" + this.score);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 pw.println(prefix + " contentIntent=" + notification.contentIntent);
171 pw.println(prefix + " deleteIntent=" + notification.deleteIntent);
172 pw.println(prefix + " tickerText=" + notification.tickerText);
173 pw.println(prefix + " contentView=" + notification.contentView);
174 pw.println(prefix + " defaults=0x" + Integer.toHexString(notification.defaults));
175 pw.println(prefix + " flags=0x" + Integer.toHexString(notification.flags));
176 pw.println(prefix + " sound=" + notification.sound);
177 pw.println(prefix + " vibrate=" + Arrays.toString(notification.vibrate));
178 pw.println(prefix + " ledARGB=0x" + Integer.toHexString(notification.ledARGB)
179 + " ledOnMS=" + notification.ledOnMS
180 + " ledOffMS=" + notification.ledOffMS);
181 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800182
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183 @Override
184 public final String toString()
185 {
186 return "NotificationRecord{"
187 + Integer.toHexString(System.identityHashCode(this))
188 + " pkg=" + pkg
Fred Quintana6ecaff12009-09-25 14:23:13 -0700189 + " id=" + Integer.toHexString(id)
Daniel Sandlere40451a2011-02-03 14:51:35 -0500190 + " tag=" + tag
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500191 + " score=" + score
Daniel Sandlere40451a2011-02-03 14:51:35 -0500192 + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 }
194 }
195
196 private static final class ToastRecord
197 {
198 final int pid;
199 final String pkg;
200 final ITransientNotification callback;
201 int duration;
202
203 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
204 {
205 this.pid = pid;
206 this.pkg = pkg;
207 this.callback = callback;
208 this.duration = duration;
209 }
210
211 void update(int duration) {
212 this.duration = duration;
213 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800214
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 void dump(PrintWriter pw, String prefix) {
216 pw.println(prefix + this);
217 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800218
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 @Override
220 public final String toString()
221 {
222 return "ToastRecord{"
223 + Integer.toHexString(System.identityHashCode(this))
224 + " pkg=" + pkg
225 + " callback=" + callback
226 + " duration=" + duration;
227 }
228 }
229
Joe Onorato089de882010-04-12 08:18:45 -0700230 private StatusBarManagerService.NotificationCallbacks mNotificationCallbacks
231 = new StatusBarManagerService.NotificationCallbacks() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232
233 public void onSetDisabled(int status) {
234 synchronized (mNotificationList) {
235 mDisabledNotifications = status;
236 if ((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
237 // cancel whatever's going on
238 long identity = Binder.clearCallingIdentity();
239 try {
240 mSound.stop();
241 }
242 finally {
243 Binder.restoreCallingIdentity(identity);
244 }
245
246 identity = Binder.clearCallingIdentity();
247 try {
248 mVibrator.cancel();
249 }
250 finally {
251 Binder.restoreCallingIdentity(identity);
252 }
253 }
254 }
255 }
256
257 public void onClearAll() {
258 cancelAll();
259 }
260
Fred Quintana6ecaff12009-09-25 14:23:13 -0700261 public void onNotificationClick(String pkg, String tag, int id) {
262 cancelNotification(pkg, tag, id, Notification.FLAG_AUTO_CANCEL,
jhtop.kim2e448f72011-07-13 17:15:32 +0900263 Notification.FLAG_FOREGROUND_SERVICE, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 }
265
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400266 public void onNotificationClear(String pkg, String tag, int id) {
Joe Onorato46439ce2010-11-19 13:56:21 -0800267 cancelNotification(pkg, tag, id, 0,
268 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
269 true);
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400270 }
271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 public void onPanelRevealed() {
273 synchronized (mNotificationList) {
274 // sound
275 mSoundNotification = null;
276 long identity = Binder.clearCallingIdentity();
277 try {
278 mSound.stop();
279 }
280 finally {
281 Binder.restoreCallingIdentity(identity);
282 }
283
284 // vibrate
285 mVibrateNotification = null;
286 identity = Binder.clearCallingIdentity();
287 try {
288 mVibrator.cancel();
289 }
290 finally {
291 Binder.restoreCallingIdentity(identity);
292 }
293
294 // light
295 mLights.clear();
296 mLedNotification = null;
297 updateLightsLocked();
298 }
299 }
Joe Onorato005847b2010-06-04 16:08:02 -0400300
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700301 public void onNotificationError(String pkg, String tag, int id,
302 int uid, int initialPid, String message) {
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400303 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
304 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
Joe Onorato46439ce2010-11-19 13:56:21 -0800305 cancelNotification(pkg, tag, id, 0, 0, false);
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700306 long ident = Binder.clearCallingIdentity();
307 try {
308 ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,
309 "Bad notification posted from package " + pkg
310 + ": " + message);
311 } catch (RemoteException e) {
312 }
313 Binder.restoreCallingIdentity(ident);
Joe Onorato005847b2010-06-04 16:08:02 -0400314 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315 };
316
317 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
318 @Override
319 public void onReceive(Context context, Intent intent) {
320 String action = intent.getAction();
321
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800322 boolean queryRestart = false;
323
Mike Lockwood541c9942011-06-12 19:35:45 -0400324 if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800325 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
Daniel Sandleraac0eb02011-08-06 22:51:56 -0400326 || action.equals(Intent.ACTION_PACKAGE_CHANGED)
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800327 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800328 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800329 String pkgList[] = null;
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800330 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800331 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800332 } else if (queryRestart) {
333 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800334 } else {
335 Uri uri = intent.getData();
336 if (uri == null) {
337 return;
338 }
339 String pkgName = uri.getSchemeSpecificPart();
340 if (pkgName == null) {
341 return;
342 }
343 pkgList = new String[]{pkgName};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800345 if (pkgList != null && (pkgList.length > 0)) {
346 for (String pkgName : pkgList) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800347 cancelAllNotificationsInt(pkgName, 0, 0, !queryRestart);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800348 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 }
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400350 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
351 // Keep track of screen on/off state, but do not turn off the notification light
352 // until user passes through the lock screen or views the notification.
353 mScreenOn = true;
354 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
355 mScreenOn = false;
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500356 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400357 mInCall = (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(
358 TelephonyManager.EXTRA_STATE_OFFHOOK));
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500359 updateNotificationPulse();
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400360 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
361 // turn off LED when user passes through lock screen
362 mNotificationLight.turnOff();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 }
364 }
365 };
366
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700367 class SettingsObserver extends ContentObserver {
368 SettingsObserver(Handler handler) {
369 super(handler);
370 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800371
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700372 void observe() {
373 ContentResolver resolver = mContext.getContentResolver();
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500374 resolver.registerContentObserver(Settings.System.getUriFor(
375 Settings.System.NOTIFICATION_LIGHT_PULSE), false, this);
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700376 update();
377 }
378
379 @Override public void onChange(boolean selfChange) {
380 update();
381 }
382
383 public void update() {
384 ContentResolver resolver = mContext.getContentResolver();
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500385 boolean pulseEnabled = Settings.System.getInt(resolver,
386 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
387 if (mNotificationPulseEnabled != pulseEnabled) {
388 mNotificationPulseEnabled = pulseEnabled;
389 updateNotificationPulse();
390 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700391 }
392 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500393
Joe Onorato089de882010-04-12 08:18:45 -0700394 NotificationManagerService(Context context, StatusBarManagerService statusBar,
Mike Lockwood3a322132009-11-24 00:30:52 -0500395 LightsService lights)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 {
397 super();
398 mContext = context;
399 mAm = ActivityManagerNative.getDefault();
Jean-Michel Trivi211957f2010-03-26 18:19:33 -0700400 mSound = new NotificationPlayer(TAG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 mSound.setUsesWakeLock(context);
402 mToastQueue = new ArrayList<ToastRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403 mHandler = new WorkerHandler();
San Mehat3ee13172010-02-04 20:54:43 -0800404
Joe Onorato089de882010-04-12 08:18:45 -0700405 mStatusBar = statusBar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406 statusBar.setNotificationCallbacks(mNotificationCallbacks);
407
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500408 mNotificationLight = lights.getLight(LightsService.LIGHT_ID_NOTIFICATIONS);
409 mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION);
410
Mike Lockwood670f9322010-01-20 12:13:36 -0500411 Resources resources = mContext.getResources();
412 mDefaultNotificationColor = resources.getColor(
413 com.android.internal.R.color.config_defaultNotificationColor);
414 mDefaultNotificationLedOn = resources.getInteger(
415 com.android.internal.R.integer.config_defaultNotificationLedOn);
416 mDefaultNotificationLedOff = resources.getInteger(
417 com.android.internal.R.integer.config_defaultNotificationLedOff);
418
Joe Onorato39f5b6a2009-07-23 12:29:19 -0400419 // Don't start allowing notifications until the setup wizard has run once.
420 // After that, including subsequent boots, init with notifications turned on.
421 // This works on the first boot because the setup wizard will toggle this
422 // flag at least once and we'll go back to 0 after that.
423 if (0 == Settings.Secure.getInt(mContext.getContentResolver(),
424 Settings.Secure.DEVICE_PROVISIONED, 0)) {
425 mDisabledNotifications = StatusBarManager.DISABLE_NOTIFICATION_ALERTS;
426 }
427
Mike Lockwood35e16bf2010-11-30 19:53:36 -0500428 // register for various Intents
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 IntentFilter filter = new IntentFilter();
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500430 filter.addAction(Intent.ACTION_SCREEN_ON);
431 filter.addAction(Intent.ACTION_SCREEN_OFF);
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500432 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400433 filter.addAction(Intent.ACTION_USER_PRESENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434 mContext.registerReceiver(mIntentReceiver, filter);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800435 IntentFilter pkgFilter = new IntentFilter();
436 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
Daniel Sandleraac0eb02011-08-06 22:51:56 -0400437 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800438 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
439 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
440 pkgFilter.addDataScheme("package");
441 mContext.registerReceiver(mIntentReceiver, pkgFilter);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800442 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800443 mContext.registerReceiver(mIntentReceiver, sdFilter);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800444
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500445 SettingsObserver observer = new SettingsObserver(mHandler);
446 observer.observe();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447 }
448
Joe Onorato30275482009-07-08 17:09:14 -0700449 void systemReady() {
450 // no beeping until we're basically done booting
451 mSystemReady = true;
452 }
453
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800454 // Toasts
455 // ============================================================================
456 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
457 {
Daniel Sandlera7035902010-03-30 15:45:31 -0400458 if (DBG) Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + " duration=" + duration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459
460 if (pkg == null || callback == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800461 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800462 return ;
463 }
464
465 synchronized (mToastQueue) {
466 int callingPid = Binder.getCallingPid();
467 long callingId = Binder.clearCallingIdentity();
468 try {
469 ToastRecord record;
470 int index = indexOfToastLocked(pkg, callback);
471 // If it's already in the queue, we update it in place, we don't
472 // move it to the end of the queue.
473 if (index >= 0) {
474 record = mToastQueue.get(index);
475 record.update(duration);
476 } else {
Vairavan Srinivasanf9eb06c2011-01-21 18:08:36 -0800477 // Limit the number of toasts that any given package except the android
478 // package can enqueue. Prevents DOS attacks and deals with leaks.
479 if (!"android".equals(pkg)) {
480 int count = 0;
481 final int N = mToastQueue.size();
482 for (int i=0; i<N; i++) {
483 final ToastRecord r = mToastQueue.get(i);
484 if (r.pkg.equals(pkg)) {
485 count++;
486 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
487 Slog.e(TAG, "Package has already posted " + count
488 + " toasts. Not showing more. Package=" + pkg);
489 return;
490 }
491 }
492 }
493 }
494
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 record = new ToastRecord(callingPid, pkg, callback, duration);
496 mToastQueue.add(record);
497 index = mToastQueue.size() - 1;
498 keepProcessAliveLocked(callingPid);
499 }
500 // If it's at index 0, it's the current toast. It doesn't matter if it's
501 // new or just been updated. Call back and tell it to show itself.
502 // If the callback fails, this will remove it from the list, so don't
503 // assume that it's valid after this.
504 if (index == 0) {
505 showNextToastLocked();
506 }
507 } finally {
508 Binder.restoreCallingIdentity(callingId);
509 }
510 }
511 }
512
513 public void cancelToast(String pkg, ITransientNotification callback) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800514 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800515
516 if (pkg == null || callback == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800517 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 return ;
519 }
520
521 synchronized (mToastQueue) {
522 long callingId = Binder.clearCallingIdentity();
523 try {
524 int index = indexOfToastLocked(pkg, callback);
525 if (index >= 0) {
526 cancelToastLocked(index);
527 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800528 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg + " callback=" + callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529 }
530 } finally {
531 Binder.restoreCallingIdentity(callingId);
532 }
533 }
534 }
535
536 private void showNextToastLocked() {
537 ToastRecord record = mToastQueue.get(0);
538 while (record != null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800539 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800540 try {
541 record.callback.show();
542 scheduleTimeoutLocked(record, false);
543 return;
544 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800545 Slog.w(TAG, "Object died trying to show notification " + record.callback
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800546 + " in package " + record.pkg);
547 // remove it from the list and let the process die
548 int index = mToastQueue.indexOf(record);
549 if (index >= 0) {
550 mToastQueue.remove(index);
551 }
552 keepProcessAliveLocked(record.pid);
553 if (mToastQueue.size() > 0) {
554 record = mToastQueue.get(0);
555 } else {
556 record = null;
557 }
558 }
559 }
560 }
561
562 private void cancelToastLocked(int index) {
563 ToastRecord record = mToastQueue.get(index);
564 try {
565 record.callback.hide();
566 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800567 Slog.w(TAG, "Object died trying to hide notification " + record.callback
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 + " in package " + record.pkg);
569 // don't worry about this, we're about to remove it from
570 // the list anyway
571 }
572 mToastQueue.remove(index);
573 keepProcessAliveLocked(record.pid);
574 if (mToastQueue.size() > 0) {
575 // Show the next one. If the callback fails, this will remove
576 // it from the list, so don't assume that the list hasn't changed
577 // after this point.
578 showNextToastLocked();
579 }
580 }
581
582 private void scheduleTimeoutLocked(ToastRecord r, boolean immediate)
583 {
584 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
585 long delay = immediate ? 0 : (r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY);
586 mHandler.removeCallbacksAndMessages(r);
587 mHandler.sendMessageDelayed(m, delay);
588 }
589
590 private void handleTimeout(ToastRecord record)
591 {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800592 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 synchronized (mToastQueue) {
594 int index = indexOfToastLocked(record.pkg, record.callback);
595 if (index >= 0) {
596 cancelToastLocked(index);
597 }
598 }
599 }
600
601 // lock on mToastQueue
602 private int indexOfToastLocked(String pkg, ITransientNotification callback)
603 {
604 IBinder cbak = callback.asBinder();
605 ArrayList<ToastRecord> list = mToastQueue;
606 int len = list.size();
607 for (int i=0; i<len; i++) {
608 ToastRecord r = list.get(i);
609 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
610 return i;
611 }
612 }
613 return -1;
614 }
615
616 // lock on mToastQueue
617 private void keepProcessAliveLocked(int pid)
618 {
619 int toastCount = 0; // toasts from this pid
620 ArrayList<ToastRecord> list = mToastQueue;
621 int N = list.size();
622 for (int i=0; i<N; i++) {
623 ToastRecord r = list.get(i);
624 if (r.pid == pid) {
625 toastCount++;
626 }
627 }
628 try {
629 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
630 } catch (RemoteException e) {
631 // Shouldn't happen.
632 }
633 }
634
635 private final class WorkerHandler extends Handler
636 {
637 @Override
638 public void handleMessage(Message msg)
639 {
640 switch (msg.what)
641 {
642 case MESSAGE_TIMEOUT:
643 handleTimeout((ToastRecord)msg.obj);
644 break;
645 }
646 }
647 }
648
649
650 // Notifications
651 // ============================================================================
Andy Stadler110988c2010-12-03 14:29:16 -0800652 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 public void enqueueNotification(String pkg, int id, Notification notification, int[] idOut)
654 {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700655 enqueueNotificationWithTag(pkg, null /* tag */, id, notification, idOut);
656 }
657
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400658 public void enqueueNotificationWithTag(String pkg, String tag, int id, Notification notification,
659 int[] idOut)
Fred Quintana6ecaff12009-09-25 14:23:13 -0700660 {
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400661 enqueueNotificationInternal(pkg, Binder.getCallingUid(), Binder.getCallingPid(),
662 tag, id, notification, idOut);
663 }
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500664
665 private final static int clamp(int x, int low, int high) {
666 return (x < low) ? low : ((x > high) ? high : x);
Daniel Sandlere40451a2011-02-03 14:51:35 -0500667 }
668
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500669
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400670 // Not exposed via Binder; for system use only (otherwise malicious apps could spoof the
671 // uid/pid of another application)
672 public void enqueueNotificationInternal(String pkg, int callingUid, int callingPid,
673 String tag, int id, Notification notification, int[] idOut)
674 {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700675 checkIncomingCall(pkg);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800676
Joe Onoratobd73d012010-06-04 11:44:54 -0700677 // Limit the number of notifications that any given package except the android
678 // package can enqueue. Prevents DOS attacks and deals with leaks.
679 if (!"android".equals(pkg)) {
680 synchronized (mNotificationList) {
681 int count = 0;
682 final int N = mNotificationList.size();
683 for (int i=0; i<N; i++) {
684 final NotificationRecord r = mNotificationList.get(i);
685 if (r.pkg.equals(pkg)) {
686 count++;
687 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
688 Slog.e(TAG, "Package has already posted " + count
689 + " notifications. Not showing more. package=" + pkg);
690 return;
691 }
692 }
693 }
694 }
695 }
696
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800697 // This conditional is a dirty hack to limit the logging done on
698 // behalf of the download manager without affecting other apps.
699 if (!pkg.equals("com.android.providers.downloads")
700 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
Daniel Sandlerb64cb882011-11-29 23:48:29 -0500701 EventLog.writeEvent(EventLogTags.NOTIFICATION_ENQUEUE, pkg, id, tag,
702 notification.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800703 }
704
705 if (pkg == null || notification == null) {
706 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
707 + " id=" + id + " notification=" + notification);
708 }
709 if (notification.icon != 0) {
710 if (notification.contentView == null) {
711 throw new IllegalArgumentException("contentView required: pkg=" + pkg
712 + " id=" + id + " notification=" + notification);
713 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714 }
715
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500716 // === Scoring ===
717
718 // 0. Sanitize inputs
719 notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN, Notification.PRIORITY_MAX);
720 // Migrate notification flags to scores
721 if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) {
722 if (notification.priority < Notification.PRIORITY_MAX) notification.priority = Notification.PRIORITY_MAX;
723 } else if (0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) {
724 if (notification.priority < Notification.PRIORITY_HIGH) notification.priority = Notification.PRIORITY_HIGH;
725 }
726
727 // 1. initial score: buckets of 10, around the app
728 int score = notification.priority * 10; //[-20..20]
729
730 // 2. Consult oracles (external heuristics)
731 // TODO(dsandler): oracles
732
733 // 3. Apply local heuristics & overrides
734
735 // blocked apps
736 // TODO(dsandler): add block db
737 if (pkg.startsWith("com.test.spammer.")) {
738 score = -1000;
739 }
740
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741 synchronized (mNotificationList) {
Daniel Sandlere40451a2011-02-03 14:51:35 -0500742 NotificationRecord r = new NotificationRecord(pkg, tag, id,
743 callingUid, callingPid,
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500744 score,
Daniel Sandlere40451a2011-02-03 14:51:35 -0500745 notification);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800746 NotificationRecord old = null;
747
Fred Quintana6ecaff12009-09-25 14:23:13 -0700748 int index = indexOfNotificationLocked(pkg, tag, id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800749 if (index < 0) {
750 mNotificationList.add(r);
751 } else {
752 old = mNotificationList.remove(index);
753 mNotificationList.add(index, r);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700754 // Make sure we don't lose the foreground service state.
755 if (old != null) {
756 notification.flags |=
757 old.notification.flags&Notification.FLAG_FOREGROUND_SERVICE;
758 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800760
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700761 // Ensure if this is a foreground service that the proper additional
762 // flags are set.
763 if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) {
764 notification.flags |= Notification.FLAG_ONGOING_EVENT
765 | Notification.FLAG_NO_CLEAR;
766 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800767
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 if (notification.icon != 0) {
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700769 StatusBarNotification n = new StatusBarNotification(pkg, id, tag,
Daniel Sandler2561b0b2012-02-13 21:04:12 -0500770 r.uid, r.initialPid, score, notification);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 if (old != null && old.statusBarKey != null) {
772 r.statusBarKey = old.statusBarKey;
773 long identity = Binder.clearCallingIdentity();
774 try {
Joe Onorato18e69df2010-05-17 22:26:12 -0700775 mStatusBar.updateNotification(r.statusBarKey, n);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 }
777 finally {
778 Binder.restoreCallingIdentity(identity);
779 }
780 } else {
781 long identity = Binder.clearCallingIdentity();
782 try {
Joe Onorato18e69df2010-05-17 22:26:12 -0700783 r.statusBarKey = mStatusBar.addNotification(n);
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500784 mAttentionLight.pulse();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 }
786 finally {
787 Binder.restoreCallingIdentity(identity);
788 }
789 }
Joe Onorato30275482009-07-08 17:09:14 -0700790 sendAccessibilityEvent(notification, pkg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800791 } else {
Daniel Sandlere40451a2011-02-03 14:51:35 -0500792 Slog.e(TAG, "Ignoring notification with icon==0: " + notification);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 if (old != null && old.statusBarKey != null) {
794 long identity = Binder.clearCallingIdentity();
795 try {
Joe Onorato0cbda992010-05-02 16:28:15 -0700796 mStatusBar.removeNotification(old.statusBarKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797 }
798 finally {
799 Binder.restoreCallingIdentity(identity);
800 }
801 }
802 }
803
804 // If we're not supposed to beep, vibrate, etc. then don't.
805 if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
806 && (!(old != null
Joe Onorato30275482009-07-08 17:09:14 -0700807 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
808 && mSystemReady) {
Eric Laurent524dc042009-11-27 05:07:55 -0800809
810 final AudioManager audioManager = (AudioManager) mContext
811 .getSystemService(Context.AUDIO_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 // sound
813 final boolean useDefaultSound =
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800814 (notification.defaults & Notification.DEFAULT_SOUND) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 if (useDefaultSound || notification.sound != null) {
816 Uri uri;
817 if (useDefaultSound) {
818 uri = Settings.System.DEFAULT_NOTIFICATION_URI;
819 } else {
820 uri = notification.sound;
821 }
822 boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0;
823 int audioStreamType;
824 if (notification.audioStreamType >= 0) {
825 audioStreamType = notification.audioStreamType;
826 } else {
827 audioStreamType = DEFAULT_STREAM_TYPE;
828 }
829 mSoundNotification = r;
Eric Laurent524dc042009-11-27 05:07:55 -0800830 // do not play notifications if stream volume is 0
831 // (typically because ringer mode is silent).
832 if (audioManager.getStreamVolume(audioStreamType) != 0) {
833 long identity = Binder.clearCallingIdentity();
834 try {
835 mSound.play(mContext, uri, looping, audioStreamType);
836 }
837 finally {
838 Binder.restoreCallingIdentity(identity);
839 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800840 }
841 }
842
843 // vibrate
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844 final boolean useDefaultVibrate =
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800845 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846 if ((useDefaultVibrate || notification.vibrate != null)
847 && audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_NOTIFICATION)) {
848 mVibrateNotification = r;
849
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800850 mVibrator.vibrate(useDefaultVibrate ? DEFAULT_VIBRATE_PATTERN
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800851 : notification.vibrate,
852 ((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
853 }
854 }
855
856 // this option doesn't shut off the lights
857
858 // light
859 // the most recent thing gets the light
860 mLights.remove(old);
861 if (mLedNotification == old) {
862 mLedNotification = null;
863 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800864 //Slog.i(TAG, "notification.lights="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800865 // + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS) != 0));
866 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {
867 mLights.add(r);
868 updateLightsLocked();
869 } else {
870 if (old != null
871 && ((old.notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0)) {
872 updateLightsLocked();
873 }
874 }
875 }
876
877 idOut[0] = id;
878 }
879
Joe Onorato30275482009-07-08 17:09:14 -0700880 private void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
svetoslavganov75986cf2009-05-14 22:28:01 -0700881 AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
882 if (!manager.isEnabled()) {
883 return;
884 }
885
886 AccessibilityEvent event =
887 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
888 event.setPackageName(packageName);
889 event.setClassName(Notification.class.getName());
890 event.setParcelableData(notification);
891 CharSequence tickerText = notification.tickerText;
892 if (!TextUtils.isEmpty(tickerText)) {
893 event.getText().add(tickerText);
894 }
895
896 manager.sendAccessibilityEvent(event);
897 }
898
Joe Onorato46439ce2010-11-19 13:56:21 -0800899 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete) {
900 // tell the app
901 if (sendDelete) {
902 if (r.notification.deleteIntent != null) {
903 try {
904 r.notification.deleteIntent.send();
905 } catch (PendingIntent.CanceledException ex) {
906 // do nothing - there's no relevant way to recover, and
907 // no reason to let this propagate
908 Slog.w(TAG, "canceled PendingIntent for " + r.pkg, ex);
909 }
910 }
911 }
912
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800913 // status bar
914 if (r.notification.icon != 0) {
915 long identity = Binder.clearCallingIdentity();
916 try {
Joe Onorato0cbda992010-05-02 16:28:15 -0700917 mStatusBar.removeNotification(r.statusBarKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800918 }
919 finally {
920 Binder.restoreCallingIdentity(identity);
921 }
922 r.statusBarKey = null;
923 }
924
925 // sound
926 if (mSoundNotification == r) {
927 mSoundNotification = null;
928 long identity = Binder.clearCallingIdentity();
929 try {
930 mSound.stop();
931 }
932 finally {
933 Binder.restoreCallingIdentity(identity);
934 }
935 }
936
937 // vibrate
938 if (mVibrateNotification == r) {
939 mVibrateNotification = null;
940 long identity = Binder.clearCallingIdentity();
941 try {
942 mVibrator.cancel();
943 }
944 finally {
945 Binder.restoreCallingIdentity(identity);
946 }
947 }
948
949 // light
950 mLights.remove(r);
951 if (mLedNotification == r) {
952 mLedNotification = null;
953 }
954 }
955
956 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700957 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800958 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800959 */
Fred Quintana6ecaff12009-09-25 14:23:13 -0700960 private void cancelNotification(String pkg, String tag, int id, int mustHaveFlags,
Joe Onorato46439ce2010-11-19 13:56:21 -0800961 int mustNotHaveFlags, boolean sendDelete) {
Daniel Sandlerb64cb882011-11-29 23:48:29 -0500962 EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL, pkg, id, tag,
963 mustHaveFlags, mustNotHaveFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800964
965 synchronized (mNotificationList) {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700966 int index = indexOfNotificationLocked(pkg, tag, id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967 if (index >= 0) {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700968 NotificationRecord r = mNotificationList.get(index);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800969
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {
971 return;
972 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700973 if ((r.notification.flags & mustNotHaveFlags) != 0) {
974 return;
975 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800976
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800977 mNotificationList.remove(index);
978
Joe Onorato46439ce2010-11-19 13:56:21 -0800979 cancelNotificationLocked(r, sendDelete);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 updateLightsLocked();
981 }
982 }
983 }
984
985 /**
986 * Cancels all notifications from a given package that have all of the
987 * {@code mustHaveFlags}.
988 */
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800989 boolean cancelAllNotificationsInt(String pkg, int mustHaveFlags,
990 int mustNotHaveFlags, boolean doit) {
Daniel Sandlerb64cb882011-11-29 23:48:29 -0500991 EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL_ALL, pkg, mustHaveFlags,
992 mustNotHaveFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800993
994 synchronized (mNotificationList) {
995 final int N = mNotificationList.size();
996 boolean canceledSomething = false;
997 for (int i = N-1; i >= 0; --i) {
998 NotificationRecord r = mNotificationList.get(i);
999 if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {
1000 continue;
1001 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001002 if ((r.notification.flags & mustNotHaveFlags) != 0) {
1003 continue;
1004 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001005 if (!r.pkg.equals(pkg)) {
1006 continue;
1007 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001008 canceledSomething = true;
1009 if (!doit) {
1010 return true;
1011 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 mNotificationList.remove(i);
Joe Onorato46439ce2010-11-19 13:56:21 -08001013 cancelNotificationLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001014 }
1015 if (canceledSomething) {
1016 updateLightsLocked();
1017 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001018 return canceledSomething;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 }
1020 }
1021
Andy Stadler110988c2010-12-03 14:29:16 -08001022 @Deprecated
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001023 public void cancelNotification(String pkg, int id) {
Fred Quintana6ecaff12009-09-25 14:23:13 -07001024 cancelNotificationWithTag(pkg, null /* tag */, id);
1025 }
1026
1027 public void cancelNotificationWithTag(String pkg, String tag, int id) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001028 checkIncomingCall(pkg);
1029 // Don't allow client applications to cancel foreground service notis.
Fred Quintana6ecaff12009-09-25 14:23:13 -07001030 cancelNotification(pkg, tag, id, 0,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001031 Binder.getCallingUid() == Process.SYSTEM_UID
Joe Onorato46439ce2010-11-19 13:56:21 -08001032 ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033 }
1034
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001035 public void cancelAllNotifications(String pkg) {
1036 checkIncomingCall(pkg);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001037
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001038 // Calling from user space, don't allow the canceling of actively
1039 // running foreground services.
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001040 cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001041 }
1042
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001043 void checkIncomingCall(String pkg) {
1044 int uid = Binder.getCallingUid();
1045 if (uid == Process.SYSTEM_UID || uid == 0) {
1046 return;
1047 }
1048 try {
1049 ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(
1050 pkg, 0);
Amith Yamasani742a6712011-05-04 14:49:28 -07001051 if (!UserId.isSameApp(ai.uid, uid)) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001052 throw new SecurityException("Calling uid " + uid + " gave package"
1053 + pkg + " which is owned by uid " + ai.uid);
1054 }
1055 } catch (PackageManager.NameNotFoundException e) {
1056 throw new SecurityException("Unknown package " + pkg);
1057 }
1058 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001059
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001060 void cancelAll() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 synchronized (mNotificationList) {
1062 final int N = mNotificationList.size();
1063 for (int i=N-1; i>=0; i--) {
1064 NotificationRecord r = mNotificationList.get(i);
1065
1066 if ((r.notification.flags & (Notification.FLAG_ONGOING_EVENT
1067 | Notification.FLAG_NO_CLEAR)) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001068 mNotificationList.remove(i);
Joe Onorato46439ce2010-11-19 13:56:21 -08001069 cancelNotificationLocked(r, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001070 }
1071 }
1072
1073 updateLightsLocked();
1074 }
1075 }
1076
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077 // lock on mNotificationList
1078 private void updateLightsLocked()
1079 {
The Android Open Source Project10592532009-03-18 17:39:46 -07001080 // handle notification lights
1081 if (mLedNotification == null) {
1082 // get next notification, if any
1083 int n = mLights.size();
1084 if (n > 0) {
1085 mLedNotification = mLights.get(n-1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 }
1087 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001088
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001089 // Don't flash while we are in a call or screen is on
1090 if (mLedNotification == null || mInCall || mScreenOn) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001091 mNotificationLight.turnOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07001092 } else {
Mike Lockwood670f9322010-01-20 12:13:36 -05001093 int ledARGB = mLedNotification.notification.ledARGB;
1094 int ledOnMS = mLedNotification.notification.ledOnMS;
1095 int ledOffMS = mLedNotification.notification.ledOffMS;
1096 if ((mLedNotification.notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {
1097 ledARGB = mDefaultNotificationColor;
1098 ledOnMS = mDefaultNotificationLedOn;
1099 ledOffMS = mDefaultNotificationLedOff;
1100 }
1101 if (mNotificationPulseEnabled) {
1102 // pulse repeatedly
1103 mNotificationLight.setFlashing(ledARGB, LightsService.LIGHT_FLASH_TIMED,
1104 ledOnMS, ledOffMS);
Mike Lockwood670f9322010-01-20 12:13:36 -05001105 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001106 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107 }
1108
1109 // lock on mNotificationList
Fred Quintana6ecaff12009-09-25 14:23:13 -07001110 private int indexOfNotificationLocked(String pkg, String tag, int id)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001111 {
1112 ArrayList<NotificationRecord> list = mNotificationList;
1113 final int len = list.size();
1114 for (int i=0; i<len; i++) {
1115 NotificationRecord r = list.get(i);
Fred Quintana6ecaff12009-09-25 14:23:13 -07001116 if (tag == null) {
1117 if (r.tag != null) {
1118 continue;
1119 }
1120 } else {
1121 if (!tag.equals(r.tag)) {
1122 continue;
1123 }
1124 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 if (r.id == id && r.pkg.equals(pkg)) {
1126 return i;
1127 }
1128 }
1129 return -1;
1130 }
1131
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001132 private void updateNotificationPulse() {
1133 synchronized (mNotificationList) {
1134 updateLightsLocked();
1135 }
1136 }
1137
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001138 // ======================================================================
1139 @Override
1140 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1141 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1142 != PackageManager.PERMISSION_GRANTED) {
1143 pw.println("Permission Denial: can't dump NotificationManager from from pid="
1144 + Binder.getCallingPid()
1145 + ", uid=" + Binder.getCallingUid());
1146 return;
1147 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001148
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001149 pw.println("Current Notification Manager state:");
1150
1151 int N;
1152
1153 synchronized (mToastQueue) {
1154 N = mToastQueue.size();
1155 if (N > 0) {
1156 pw.println(" Toast Queue:");
1157 for (int i=0; i<N; i++) {
1158 mToastQueue.get(i).dump(pw, " ");
1159 }
1160 pw.println(" ");
1161 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001162
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001163 }
1164
1165 synchronized (mNotificationList) {
1166 N = mNotificationList.size();
1167 if (N > 0) {
1168 pw.println(" Notification List:");
1169 for (int i=0; i<N; i++) {
1170 mNotificationList.get(i).dump(pw, " ", mContext);
1171 }
1172 pw.println(" ");
1173 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001174
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001175 N = mLights.size();
1176 if (N > 0) {
1177 pw.println(" Lights List:");
1178 for (int i=0; i<N; i++) {
1179 mLights.get(i).dump(pw, " ", mContext);
1180 }
1181 pw.println(" ");
1182 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 pw.println(" mSoundNotification=" + mSoundNotification);
1185 pw.println(" mSound=" + mSound);
1186 pw.println(" mVibrateNotification=" + mVibrateNotification);
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001187 pw.println(" mDisabledNotifications=0x" + Integer.toHexString(mDisabledNotifications));
1188 pw.println(" mSystemReady=" + mSystemReady);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001189 }
1190 }
1191}