blob: 4fbdb2df33f8295eb8f33c8805fde76175648108 [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.ComponentName;
Dianne Hackborn1dac2772009-06-26 18:16:48 -070031import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.content.Context;
33import android.content.Intent;
34import android.content.IntentFilter;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070035import android.content.pm.ApplicationInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.content.pm.PackageManager;
37import android.content.pm.PackageManager.NameNotFoundException;
38import android.content.res.Resources;
Dianne Hackborn1dac2772009-06-26 18:16:48 -070039import android.database.ContentObserver;
Mike Lockwood770126a2010-12-09 22:30:37 -080040import android.hardware.UsbManager;
svetoslavganov75986cf2009-05-14 22:28:01 -070041import android.media.AudioManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.os.Binder;
Andy Stadler110988c2010-12-03 14:29:16 -080044import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.os.Handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.os.IBinder;
47import android.os.Message;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070048import android.os.Process;
svetoslavganov75986cf2009-05-14 22:28:01 -070049import android.os.RemoteException;
Mike Lockwooded760372009-07-09 07:07:27 -040050import android.os.SystemProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.os.Vibrator;
52import android.provider.Settings;
Daniel Sandlere96ffb12010-03-11 13:38:06 -050053import android.telephony.TelephonyManager;
svetoslavganov75986cf2009-05-14 22:28:01 -070054import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.util.EventLog;
56import android.util.Log;
Andy Stadler110988c2010-12-03 14:29:16 -080057import android.util.Slog;
svetoslavganov75986cf2009-05-14 22:28:01 -070058import android.view.accessibility.AccessibilityEvent;
59import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import android.widget.Toast;
61
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import java.io.FileDescriptor;
63import java.io.PrintWriter;
64import java.util.ArrayList;
65import java.util.Arrays;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066
Daniel Sandlerd0a2f862010-08-03 15:29:31 -040067/** {@hide} */
68public class NotificationManagerService extends INotificationManager.Stub
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069{
70 private static final String TAG = "NotificationService";
71 private static final boolean DBG = false;
72
Joe Onoratobd73d012010-06-04 11:44:54 -070073 private static final int MAX_PACKAGE_NOTIFICATIONS = 50;
74
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075 // message codes
76 private static final int MESSAGE_TIMEOUT = 2;
77
78 private static final int LONG_DELAY = 3500; // 3.5 seconds
79 private static final int SHORT_DELAY = 2000; // 2 seconds
Doug Zongkerab5c49c2009-12-04 10:31:43 -080080
81 private static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082
83 private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
84
85 final Context mContext;
86 final IActivityManager mAm;
87 final IBinder mForegroundToken = new Binder();
88
89 private WorkerHandler mHandler;
Joe Onorato089de882010-04-12 08:18:45 -070090 private StatusBarManagerService mStatusBar;
Mike Lockwood3cb67a32009-11-27 14:25:58 -050091 private LightsService.Light mNotificationLight;
92 private LightsService.Light mAttentionLight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093
Mike Lockwood670f9322010-01-20 12:13:36 -050094 private int mDefaultNotificationColor;
95 private int mDefaultNotificationLedOn;
96 private int mDefaultNotificationLedOff;
97
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 private NotificationRecord mSoundNotification;
Jean-Michel Trivi211957f2010-03-26 18:19:33 -070099 private NotificationPlayer mSound;
Joe Onorato30275482009-07-08 17:09:14 -0700100 private boolean mSystemReady;
Joe Onorato39f5b6a2009-07-23 12:29:19 -0400101 private int mDisabledNotifications;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102
103 private NotificationRecord mVibrateNotification;
104 private Vibrator mVibrator = new Vibrator();
105
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500106 // for enabling and disabling notification pulse behavior
107 private boolean mScreenOn = true;
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500108 private boolean mInCall = false;
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500109 private boolean mNotificationPulseEnabled;
Mike Lockwood2117f6f2010-09-09 09:48:08 -0400110 // This is true if we have received a new notification while the screen is off
111 // (that is, if mLedNotification was set while the screen was off)
112 // This is reset to false when the screen is turned on.
113 private boolean mPendingPulseNotification;
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500114
115 // for adb connected notifications
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700116 private boolean mAdbNotificationShown = false;
117 private Notification mAdbNotification;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800118
Fred Quintana6ecaff12009-09-25 14:23:13 -0700119 private final ArrayList<NotificationRecord> mNotificationList =
120 new ArrayList<NotificationRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121
122 private ArrayList<ToastRecord> mToastQueue;
123
124 private ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 private NotificationRecord mLedNotification;
svetoslavganov75986cf2009-05-14 22:28:01 -0700126
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 private static String idDebugString(Context baseContext, String packageName, int id) {
128 Context c = null;
129
130 if (packageName != null) {
131 try {
132 c = baseContext.createPackageContext(packageName, 0);
133 } catch (NameNotFoundException e) {
134 c = baseContext;
135 }
136 } else {
137 c = baseContext;
138 }
139
140 String pkg;
141 String type;
142 String name;
143
144 Resources r = c.getResources();
145 try {
146 return r.getResourceName(id);
147 } catch (Resources.NotFoundException e) {
148 return "<name unknown>";
149 }
150 }
151
152 private static final class NotificationRecord
153 {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700154 final String pkg;
155 final String tag;
156 final int id;
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700157 final int uid;
158 final int initialPid;
Fred Quintana6ecaff12009-09-25 14:23:13 -0700159 final Notification notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 IBinder statusBarKey;
161
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700162 NotificationRecord(String pkg, String tag, int id, int uid, int initialPid,
163 Notification notification)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 {
165 this.pkg = pkg;
Fred Quintana6ecaff12009-09-25 14:23:13 -0700166 this.tag = tag;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 this.id = id;
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700168 this.uid = uid;
169 this.initialPid = initialPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 this.notification = notification;
171 }
Fred Quintana6ecaff12009-09-25 14:23:13 -0700172
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173 void dump(PrintWriter pw, String prefix, Context baseContext) {
174 pw.println(prefix + this);
175 pw.println(prefix + " icon=0x" + Integer.toHexString(notification.icon)
176 + " / " + idDebugString(baseContext, this.pkg, notification.icon));
177 pw.println(prefix + " contentIntent=" + notification.contentIntent);
178 pw.println(prefix + " deleteIntent=" + notification.deleteIntent);
179 pw.println(prefix + " tickerText=" + notification.tickerText);
180 pw.println(prefix + " contentView=" + notification.contentView);
181 pw.println(prefix + " defaults=0x" + Integer.toHexString(notification.defaults));
182 pw.println(prefix + " flags=0x" + Integer.toHexString(notification.flags));
183 pw.println(prefix + " sound=" + notification.sound);
184 pw.println(prefix + " vibrate=" + Arrays.toString(notification.vibrate));
185 pw.println(prefix + " ledARGB=0x" + Integer.toHexString(notification.ledARGB)
186 + " ledOnMS=" + notification.ledOnMS
187 + " ledOffMS=" + notification.ledOffMS);
188 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800189
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 @Override
191 public final String toString()
192 {
193 return "NotificationRecord{"
194 + Integer.toHexString(System.identityHashCode(this))
195 + " pkg=" + pkg
Fred Quintana6ecaff12009-09-25 14:23:13 -0700196 + " id=" + Integer.toHexString(id)
197 + " tag=" + tag + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 }
199 }
200
201 private static final class ToastRecord
202 {
203 final int pid;
204 final String pkg;
205 final ITransientNotification callback;
206 int duration;
207
208 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
209 {
210 this.pid = pid;
211 this.pkg = pkg;
212 this.callback = callback;
213 this.duration = duration;
214 }
215
216 void update(int duration) {
217 this.duration = duration;
218 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 void dump(PrintWriter pw, String prefix) {
221 pw.println(prefix + this);
222 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800223
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 @Override
225 public final String toString()
226 {
227 return "ToastRecord{"
228 + Integer.toHexString(System.identityHashCode(this))
229 + " pkg=" + pkg
230 + " callback=" + callback
231 + " duration=" + duration;
232 }
233 }
234
Joe Onorato089de882010-04-12 08:18:45 -0700235 private StatusBarManagerService.NotificationCallbacks mNotificationCallbacks
236 = new StatusBarManagerService.NotificationCallbacks() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237
238 public void onSetDisabled(int status) {
239 synchronized (mNotificationList) {
240 mDisabledNotifications = status;
241 if ((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
242 // cancel whatever's going on
243 long identity = Binder.clearCallingIdentity();
244 try {
245 mSound.stop();
246 }
247 finally {
248 Binder.restoreCallingIdentity(identity);
249 }
250
251 identity = Binder.clearCallingIdentity();
252 try {
253 mVibrator.cancel();
254 }
255 finally {
256 Binder.restoreCallingIdentity(identity);
257 }
258 }
259 }
260 }
261
262 public void onClearAll() {
263 cancelAll();
264 }
265
Fred Quintana6ecaff12009-09-25 14:23:13 -0700266 public void onNotificationClick(String pkg, String tag, int id) {
267 cancelNotification(pkg, tag, id, Notification.FLAG_AUTO_CANCEL,
Joe Onorato46439ce2010-11-19 13:56:21 -0800268 Notification.FLAG_FOREGROUND_SERVICE, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269 }
270
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400271 public void onNotificationClear(String pkg, String tag, int id) {
Joe Onorato46439ce2010-11-19 13:56:21 -0800272 cancelNotification(pkg, tag, id, 0,
273 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
274 true);
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400275 }
276
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277 public void onPanelRevealed() {
278 synchronized (mNotificationList) {
279 // sound
280 mSoundNotification = null;
281 long identity = Binder.clearCallingIdentity();
282 try {
283 mSound.stop();
284 }
285 finally {
286 Binder.restoreCallingIdentity(identity);
287 }
288
289 // vibrate
290 mVibrateNotification = null;
291 identity = Binder.clearCallingIdentity();
292 try {
293 mVibrator.cancel();
294 }
295 finally {
296 Binder.restoreCallingIdentity(identity);
297 }
298
299 // light
300 mLights.clear();
301 mLedNotification = null;
302 updateLightsLocked();
303 }
304 }
Joe Onorato005847b2010-06-04 16:08:02 -0400305
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700306 public void onNotificationError(String pkg, String tag, int id,
307 int uid, int initialPid, String message) {
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400308 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
309 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
Joe Onorato46439ce2010-11-19 13:56:21 -0800310 cancelNotification(pkg, tag, id, 0, 0, false);
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700311 long ident = Binder.clearCallingIdentity();
312 try {
313 ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,
314 "Bad notification posted from package " + pkg
315 + ": " + message);
316 } catch (RemoteException e) {
317 }
318 Binder.restoreCallingIdentity(ident);
Joe Onorato005847b2010-06-04 16:08:02 -0400319 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800320 };
321
322 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
323 @Override
324 public void onReceive(Context context, Intent intent) {
325 String action = intent.getAction();
326
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800327 boolean queryRestart = false;
328
Mike Lockwood770126a2010-12-09 22:30:37 -0800329 if (action.equals(UsbManager.ACTION_USB_STATE)) {
Mike Lockwoodff2544c2010-06-28 09:17:50 -0400330 Bundle extras = intent.getExtras();
Mike Lockwood770126a2010-12-09 22:30:37 -0800331 boolean usbConnected = extras.getBoolean(UsbManager.USB_CONNECTED);
332 boolean adbEnabled = (UsbManager.USB_FUNCTION_ENABLED.equals(
333 extras.getString(UsbManager.USB_FUNCTION_ADB)));
Mike Lockwoodff2544c2010-06-28 09:17:50 -0400334 updateAdbNotification(usbConnected && adbEnabled);
Mike Lockwood770126a2010-12-09 22:30:37 -0800335 } else if (action.equals(UsbManager.ACTION_USB_DISCONNECTED)) {
Mike Lockwoodff2544c2010-06-28 09:17:50 -0400336 updateAdbNotification(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800338 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800339 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800340 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800341 String pkgList[] = null;
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800342 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800343 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800344 } else if (queryRestart) {
345 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800346 } else {
347 Uri uri = intent.getData();
348 if (uri == null) {
349 return;
350 }
351 String pkgName = uri.getSchemeSpecificPart();
352 if (pkgName == null) {
353 return;
354 }
355 pkgList = new String[]{pkgName};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800357 if (pkgList != null && (pkgList.length > 0)) {
358 for (String pkgName : pkgList) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800359 cancelAllNotificationsInt(pkgName, 0, 0, !queryRestart);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800360 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500362 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
363 mScreenOn = true;
364 updateNotificationPulse();
365 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
366 mScreenOn = false;
367 updateNotificationPulse();
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500368 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
369 mInCall = (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_OFFHOOK));
370 updateNotificationPulse();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 }
372 }
373 };
374
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700375 class SettingsObserver extends ContentObserver {
376 SettingsObserver(Handler handler) {
377 super(handler);
378 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800379
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700380 void observe() {
381 ContentResolver resolver = mContext.getContentResolver();
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500382 resolver.registerContentObserver(Settings.System.getUriFor(
383 Settings.System.NOTIFICATION_LIGHT_PULSE), false, this);
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700384 update();
385 }
386
387 @Override public void onChange(boolean selfChange) {
388 update();
389 }
390
391 public void update() {
392 ContentResolver resolver = mContext.getContentResolver();
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500393 boolean pulseEnabled = Settings.System.getInt(resolver,
394 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
395 if (mNotificationPulseEnabled != pulseEnabled) {
396 mNotificationPulseEnabled = pulseEnabled;
397 updateNotificationPulse();
398 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700399 }
400 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500401
Joe Onorato089de882010-04-12 08:18:45 -0700402 NotificationManagerService(Context context, StatusBarManagerService statusBar,
Mike Lockwood3a322132009-11-24 00:30:52 -0500403 LightsService lights)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 {
405 super();
406 mContext = context;
407 mAm = ActivityManagerNative.getDefault();
Jean-Michel Trivi211957f2010-03-26 18:19:33 -0700408 mSound = new NotificationPlayer(TAG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 mSound.setUsesWakeLock(context);
410 mToastQueue = new ArrayList<ToastRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 mHandler = new WorkerHandler();
San Mehat3ee13172010-02-04 20:54:43 -0800412
Joe Onorato089de882010-04-12 08:18:45 -0700413 mStatusBar = statusBar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 statusBar.setNotificationCallbacks(mNotificationCallbacks);
415
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500416 mNotificationLight = lights.getLight(LightsService.LIGHT_ID_NOTIFICATIONS);
417 mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION);
418
Mike Lockwood670f9322010-01-20 12:13:36 -0500419 Resources resources = mContext.getResources();
420 mDefaultNotificationColor = resources.getColor(
421 com.android.internal.R.color.config_defaultNotificationColor);
422 mDefaultNotificationLedOn = resources.getInteger(
423 com.android.internal.R.integer.config_defaultNotificationLedOn);
424 mDefaultNotificationLedOff = resources.getInteger(
425 com.android.internal.R.integer.config_defaultNotificationLedOff);
426
Joe Onorato39f5b6a2009-07-23 12:29:19 -0400427 // Don't start allowing notifications until the setup wizard has run once.
428 // After that, including subsequent boots, init with notifications turned on.
429 // This works on the first boot because the setup wizard will toggle this
430 // flag at least once and we'll go back to 0 after that.
431 if (0 == Settings.Secure.getInt(mContext.getContentResolver(),
432 Settings.Secure.DEVICE_PROVISIONED, 0)) {
433 mDisabledNotifications = StatusBarManager.DISABLE_NOTIFICATION_ALERTS;
434 }
435
Mike Lockwood35e16bf2010-11-30 19:53:36 -0500436 // register for various Intents
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800437 IntentFilter filter = new IntentFilter();
Mike Lockwood770126a2010-12-09 22:30:37 -0800438 filter.addAction(UsbManager.ACTION_USB_STATE);
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500439 filter.addAction(Intent.ACTION_SCREEN_ON);
440 filter.addAction(Intent.ACTION_SCREEN_OFF);
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500441 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800442 mContext.registerReceiver(mIntentReceiver, filter);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800443 IntentFilter pkgFilter = new IntentFilter();
444 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
445 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
446 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
447 pkgFilter.addDataScheme("package");
448 mContext.registerReceiver(mIntentReceiver, pkgFilter);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800449 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800450 mContext.registerReceiver(mIntentReceiver, sdFilter);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800451
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500452 SettingsObserver observer = new SettingsObserver(mHandler);
453 observer.observe();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800454 }
455
Joe Onorato30275482009-07-08 17:09:14 -0700456 void systemReady() {
457 // no beeping until we're basically done booting
458 mSystemReady = true;
459 }
460
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 // Toasts
462 // ============================================================================
463 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
464 {
Daniel Sandlera7035902010-03-30 15:45:31 -0400465 if (DBG) Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + " duration=" + duration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466
467 if (pkg == null || callback == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800468 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 return ;
470 }
471
472 synchronized (mToastQueue) {
473 int callingPid = Binder.getCallingPid();
474 long callingId = Binder.clearCallingIdentity();
475 try {
476 ToastRecord record;
477 int index = indexOfToastLocked(pkg, callback);
478 // If it's already in the queue, we update it in place, we don't
479 // move it to the end of the queue.
480 if (index >= 0) {
481 record = mToastQueue.get(index);
482 record.update(duration);
483 } else {
484 record = new ToastRecord(callingPid, pkg, callback, duration);
485 mToastQueue.add(record);
486 index = mToastQueue.size() - 1;
487 keepProcessAliveLocked(callingPid);
488 }
489 // If it's at index 0, it's the current toast. It doesn't matter if it's
490 // new or just been updated. Call back and tell it to show itself.
491 // If the callback fails, this will remove it from the list, so don't
492 // assume that it's valid after this.
493 if (index == 0) {
494 showNextToastLocked();
495 }
496 } finally {
497 Binder.restoreCallingIdentity(callingId);
498 }
499 }
500 }
501
502 public void cancelToast(String pkg, ITransientNotification callback) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800503 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504
505 if (pkg == null || callback == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800506 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507 return ;
508 }
509
510 synchronized (mToastQueue) {
511 long callingId = Binder.clearCallingIdentity();
512 try {
513 int index = indexOfToastLocked(pkg, callback);
514 if (index >= 0) {
515 cancelToastLocked(index);
516 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800517 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg + " callback=" + callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 }
519 } finally {
520 Binder.restoreCallingIdentity(callingId);
521 }
522 }
523 }
524
525 private void showNextToastLocked() {
526 ToastRecord record = mToastQueue.get(0);
527 while (record != null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800528 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529 try {
530 record.callback.show();
531 scheduleTimeoutLocked(record, false);
532 return;
533 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800534 Slog.w(TAG, "Object died trying to show notification " + record.callback
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 + " in package " + record.pkg);
536 // remove it from the list and let the process die
537 int index = mToastQueue.indexOf(record);
538 if (index >= 0) {
539 mToastQueue.remove(index);
540 }
541 keepProcessAliveLocked(record.pid);
542 if (mToastQueue.size() > 0) {
543 record = mToastQueue.get(0);
544 } else {
545 record = null;
546 }
547 }
548 }
549 }
550
551 private void cancelToastLocked(int index) {
552 ToastRecord record = mToastQueue.get(index);
553 try {
554 record.callback.hide();
555 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800556 Slog.w(TAG, "Object died trying to hide notification " + record.callback
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 + " in package " + record.pkg);
558 // don't worry about this, we're about to remove it from
559 // the list anyway
560 }
561 mToastQueue.remove(index);
562 keepProcessAliveLocked(record.pid);
563 if (mToastQueue.size() > 0) {
564 // Show the next one. If the callback fails, this will remove
565 // it from the list, so don't assume that the list hasn't changed
566 // after this point.
567 showNextToastLocked();
568 }
569 }
570
571 private void scheduleTimeoutLocked(ToastRecord r, boolean immediate)
572 {
573 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
574 long delay = immediate ? 0 : (r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY);
575 mHandler.removeCallbacksAndMessages(r);
576 mHandler.sendMessageDelayed(m, delay);
577 }
578
579 private void handleTimeout(ToastRecord record)
580 {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800581 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582 synchronized (mToastQueue) {
583 int index = indexOfToastLocked(record.pkg, record.callback);
584 if (index >= 0) {
585 cancelToastLocked(index);
586 }
587 }
588 }
589
590 // lock on mToastQueue
591 private int indexOfToastLocked(String pkg, ITransientNotification callback)
592 {
593 IBinder cbak = callback.asBinder();
594 ArrayList<ToastRecord> list = mToastQueue;
595 int len = list.size();
596 for (int i=0; i<len; i++) {
597 ToastRecord r = list.get(i);
598 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
599 return i;
600 }
601 }
602 return -1;
603 }
604
605 // lock on mToastQueue
606 private void keepProcessAliveLocked(int pid)
607 {
608 int toastCount = 0; // toasts from this pid
609 ArrayList<ToastRecord> list = mToastQueue;
610 int N = list.size();
611 for (int i=0; i<N; i++) {
612 ToastRecord r = list.get(i);
613 if (r.pid == pid) {
614 toastCount++;
615 }
616 }
617 try {
618 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
619 } catch (RemoteException e) {
620 // Shouldn't happen.
621 }
622 }
623
624 private final class WorkerHandler extends Handler
625 {
626 @Override
627 public void handleMessage(Message msg)
628 {
629 switch (msg.what)
630 {
631 case MESSAGE_TIMEOUT:
632 handleTimeout((ToastRecord)msg.obj);
633 break;
634 }
635 }
636 }
637
638
639 // Notifications
640 // ============================================================================
Andy Stadler110988c2010-12-03 14:29:16 -0800641 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800642 public void enqueueNotification(String pkg, int id, Notification notification, int[] idOut)
643 {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700644 enqueueNotificationWithTag(pkg, null /* tag */, id, notification, idOut);
645 }
646
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400647 public void enqueueNotificationWithTag(String pkg, String tag, int id, Notification notification,
648 int[] idOut)
Fred Quintana6ecaff12009-09-25 14:23:13 -0700649 {
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400650 enqueueNotificationInternal(pkg, Binder.getCallingUid(), Binder.getCallingPid(),
651 tag, id, notification, idOut);
652 }
653
654 // Not exposed via Binder; for system use only (otherwise malicious apps could spoof the
655 // uid/pid of another application)
656 public void enqueueNotificationInternal(String pkg, int callingUid, int callingPid,
657 String tag, int id, Notification notification, int[] idOut)
658 {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700659 checkIncomingCall(pkg);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800660
Joe Onoratobd73d012010-06-04 11:44:54 -0700661 // Limit the number of notifications that any given package except the android
662 // package can enqueue. Prevents DOS attacks and deals with leaks.
663 if (!"android".equals(pkg)) {
664 synchronized (mNotificationList) {
665 int count = 0;
666 final int N = mNotificationList.size();
667 for (int i=0; i<N; i++) {
668 final NotificationRecord r = mNotificationList.get(i);
669 if (r.pkg.equals(pkg)) {
670 count++;
671 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
672 Slog.e(TAG, "Package has already posted " + count
673 + " notifications. Not showing more. package=" + pkg);
674 return;
675 }
676 }
677 }
678 }
679 }
680
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800681 // This conditional is a dirty hack to limit the logging done on
682 // behalf of the download manager without affecting other apps.
683 if (!pkg.equals("com.android.providers.downloads")
684 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800685 EventLog.writeEvent(EventLogTags.NOTIFICATION_ENQUEUE, pkg, id, notification.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 }
687
688 if (pkg == null || notification == null) {
689 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
690 + " id=" + id + " notification=" + notification);
691 }
692 if (notification.icon != 0) {
693 if (notification.contentView == null) {
694 throw new IllegalArgumentException("contentView required: pkg=" + pkg
695 + " id=" + id + " notification=" + notification);
696 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800697 }
698
699 synchronized (mNotificationList) {
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700700 NotificationRecord r = new NotificationRecord(pkg, tag, id,
701 callingUid, callingPid, notification);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800702 NotificationRecord old = null;
703
Fred Quintana6ecaff12009-09-25 14:23:13 -0700704 int index = indexOfNotificationLocked(pkg, tag, id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800705 if (index < 0) {
706 mNotificationList.add(r);
707 } else {
708 old = mNotificationList.remove(index);
709 mNotificationList.add(index, r);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700710 // Make sure we don't lose the foreground service state.
711 if (old != null) {
712 notification.flags |=
713 old.notification.flags&Notification.FLAG_FOREGROUND_SERVICE;
714 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800716
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700717 // Ensure if this is a foreground service that the proper additional
718 // flags are set.
719 if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) {
720 notification.flags |= Notification.FLAG_ONGOING_EVENT
721 | Notification.FLAG_NO_CLEAR;
722 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 if (notification.icon != 0) {
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700725 StatusBarNotification n = new StatusBarNotification(pkg, id, tag,
726 r.uid, r.initialPid, notification);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800727 if (old != null && old.statusBarKey != null) {
728 r.statusBarKey = old.statusBarKey;
729 long identity = Binder.clearCallingIdentity();
730 try {
Joe Onorato18e69df2010-05-17 22:26:12 -0700731 mStatusBar.updateNotification(r.statusBarKey, n);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732 }
733 finally {
734 Binder.restoreCallingIdentity(identity);
735 }
736 } else {
737 long identity = Binder.clearCallingIdentity();
738 try {
Joe Onorato18e69df2010-05-17 22:26:12 -0700739 r.statusBarKey = mStatusBar.addNotification(n);
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500740 mAttentionLight.pulse();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741 }
742 finally {
743 Binder.restoreCallingIdentity(identity);
744 }
745 }
Joe Onorato30275482009-07-08 17:09:14 -0700746 sendAccessibilityEvent(notification, pkg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 } else {
748 if (old != null && old.statusBarKey != null) {
749 long identity = Binder.clearCallingIdentity();
750 try {
Joe Onorato0cbda992010-05-02 16:28:15 -0700751 mStatusBar.removeNotification(old.statusBarKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752 }
753 finally {
754 Binder.restoreCallingIdentity(identity);
755 }
756 }
757 }
758
759 // If we're not supposed to beep, vibrate, etc. then don't.
760 if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
761 && (!(old != null
Joe Onorato30275482009-07-08 17:09:14 -0700762 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
763 && mSystemReady) {
Eric Laurent524dc042009-11-27 05:07:55 -0800764
765 final AudioManager audioManager = (AudioManager) mContext
766 .getSystemService(Context.AUDIO_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 // sound
768 final boolean useDefaultSound =
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800769 (notification.defaults & Notification.DEFAULT_SOUND) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 if (useDefaultSound || notification.sound != null) {
771 Uri uri;
772 if (useDefaultSound) {
773 uri = Settings.System.DEFAULT_NOTIFICATION_URI;
774 } else {
775 uri = notification.sound;
776 }
777 boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0;
778 int audioStreamType;
779 if (notification.audioStreamType >= 0) {
780 audioStreamType = notification.audioStreamType;
781 } else {
782 audioStreamType = DEFAULT_STREAM_TYPE;
783 }
784 mSoundNotification = r;
Eric Laurent524dc042009-11-27 05:07:55 -0800785 // do not play notifications if stream volume is 0
786 // (typically because ringer mode is silent).
787 if (audioManager.getStreamVolume(audioStreamType) != 0) {
788 long identity = Binder.clearCallingIdentity();
789 try {
790 mSound.play(mContext, uri, looping, audioStreamType);
791 }
792 finally {
793 Binder.restoreCallingIdentity(identity);
794 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 }
796 }
797
798 // vibrate
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 final boolean useDefaultVibrate =
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800800 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800801 if ((useDefaultVibrate || notification.vibrate != null)
802 && audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_NOTIFICATION)) {
803 mVibrateNotification = r;
804
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800805 mVibrator.vibrate(useDefaultVibrate ? DEFAULT_VIBRATE_PATTERN
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800806 : notification.vibrate,
807 ((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
808 }
809 }
810
811 // this option doesn't shut off the lights
812
813 // light
814 // the most recent thing gets the light
815 mLights.remove(old);
816 if (mLedNotification == old) {
817 mLedNotification = null;
818 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800819 //Slog.i(TAG, "notification.lights="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820 // + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS) != 0));
821 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {
822 mLights.add(r);
823 updateLightsLocked();
824 } else {
825 if (old != null
826 && ((old.notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0)) {
827 updateLightsLocked();
828 }
829 }
830 }
831
832 idOut[0] = id;
833 }
834
Joe Onorato30275482009-07-08 17:09:14 -0700835 private void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
svetoslavganov75986cf2009-05-14 22:28:01 -0700836 AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
837 if (!manager.isEnabled()) {
838 return;
839 }
840
841 AccessibilityEvent event =
842 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
843 event.setPackageName(packageName);
844 event.setClassName(Notification.class.getName());
845 event.setParcelableData(notification);
846 CharSequence tickerText = notification.tickerText;
847 if (!TextUtils.isEmpty(tickerText)) {
848 event.getText().add(tickerText);
849 }
850
851 manager.sendAccessibilityEvent(event);
852 }
853
Joe Onorato46439ce2010-11-19 13:56:21 -0800854 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete) {
855 // tell the app
856 if (sendDelete) {
857 if (r.notification.deleteIntent != null) {
858 try {
859 r.notification.deleteIntent.send();
860 } catch (PendingIntent.CanceledException ex) {
861 // do nothing - there's no relevant way to recover, and
862 // no reason to let this propagate
863 Slog.w(TAG, "canceled PendingIntent for " + r.pkg, ex);
864 }
865 }
866 }
867
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 // status bar
869 if (r.notification.icon != 0) {
870 long identity = Binder.clearCallingIdentity();
871 try {
Joe Onorato0cbda992010-05-02 16:28:15 -0700872 mStatusBar.removeNotification(r.statusBarKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 }
874 finally {
875 Binder.restoreCallingIdentity(identity);
876 }
877 r.statusBarKey = null;
878 }
879
880 // sound
881 if (mSoundNotification == r) {
882 mSoundNotification = null;
883 long identity = Binder.clearCallingIdentity();
884 try {
885 mSound.stop();
886 }
887 finally {
888 Binder.restoreCallingIdentity(identity);
889 }
890 }
891
892 // vibrate
893 if (mVibrateNotification == r) {
894 mVibrateNotification = null;
895 long identity = Binder.clearCallingIdentity();
896 try {
897 mVibrator.cancel();
898 }
899 finally {
900 Binder.restoreCallingIdentity(identity);
901 }
902 }
903
904 // light
905 mLights.remove(r);
906 if (mLedNotification == r) {
907 mLedNotification = null;
908 }
909 }
910
911 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700912 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800913 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800914 */
Fred Quintana6ecaff12009-09-25 14:23:13 -0700915 private void cancelNotification(String pkg, String tag, int id, int mustHaveFlags,
Joe Onorato46439ce2010-11-19 13:56:21 -0800916 int mustNotHaveFlags, boolean sendDelete) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800917 EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL, pkg, id, mustHaveFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800918
919 synchronized (mNotificationList) {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700920 int index = indexOfNotificationLocked(pkg, tag, id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800921 if (index >= 0) {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700922 NotificationRecord r = mNotificationList.get(index);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800923
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924 if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {
925 return;
926 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700927 if ((r.notification.flags & mustNotHaveFlags) != 0) {
928 return;
929 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800930
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800931 mNotificationList.remove(index);
932
Joe Onorato46439ce2010-11-19 13:56:21 -0800933 cancelNotificationLocked(r, sendDelete);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800934 updateLightsLocked();
935 }
936 }
937 }
938
939 /**
940 * Cancels all notifications from a given package that have all of the
941 * {@code mustHaveFlags}.
942 */
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800943 boolean cancelAllNotificationsInt(String pkg, int mustHaveFlags,
944 int mustNotHaveFlags, boolean doit) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800945 EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL_ALL, pkg, mustHaveFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800946
947 synchronized (mNotificationList) {
948 final int N = mNotificationList.size();
949 boolean canceledSomething = false;
950 for (int i = N-1; i >= 0; --i) {
951 NotificationRecord r = mNotificationList.get(i);
952 if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {
953 continue;
954 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700955 if ((r.notification.flags & mustNotHaveFlags) != 0) {
956 continue;
957 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800958 if (!r.pkg.equals(pkg)) {
959 continue;
960 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800961 canceledSomething = true;
962 if (!doit) {
963 return true;
964 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 mNotificationList.remove(i);
Joe Onorato46439ce2010-11-19 13:56:21 -0800966 cancelNotificationLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967 }
968 if (canceledSomething) {
969 updateLightsLocked();
970 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800971 return canceledSomething;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972 }
973 }
974
Andy Stadler110988c2010-12-03 14:29:16 -0800975 @Deprecated
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700976 public void cancelNotification(String pkg, int id) {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700977 cancelNotificationWithTag(pkg, null /* tag */, id);
978 }
979
980 public void cancelNotificationWithTag(String pkg, String tag, int id) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700981 checkIncomingCall(pkg);
982 // Don't allow client applications to cancel foreground service notis.
Fred Quintana6ecaff12009-09-25 14:23:13 -0700983 cancelNotification(pkg, tag, id, 0,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700984 Binder.getCallingUid() == Process.SYSTEM_UID
Joe Onorato46439ce2010-11-19 13:56:21 -0800985 ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 }
987
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700988 public void cancelAllNotifications(String pkg) {
989 checkIncomingCall(pkg);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800990
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700991 // Calling from user space, don't allow the canceling of actively
992 // running foreground services.
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800993 cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994 }
995
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700996 void checkIncomingCall(String pkg) {
997 int uid = Binder.getCallingUid();
998 if (uid == Process.SYSTEM_UID || uid == 0) {
999 return;
1000 }
1001 try {
1002 ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(
1003 pkg, 0);
1004 if (ai.uid != uid) {
1005 throw new SecurityException("Calling uid " + uid + " gave package"
1006 + pkg + " which is owned by uid " + ai.uid);
1007 }
1008 } catch (PackageManager.NameNotFoundException e) {
1009 throw new SecurityException("Unknown package " + pkg);
1010 }
1011 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001012
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001013 void cancelAll() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001014 synchronized (mNotificationList) {
1015 final int N = mNotificationList.size();
1016 for (int i=N-1; i>=0; i--) {
1017 NotificationRecord r = mNotificationList.get(i);
1018
1019 if ((r.notification.flags & (Notification.FLAG_ONGOING_EVENT
1020 | Notification.FLAG_NO_CLEAR)) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021 mNotificationList.remove(i);
Joe Onorato46439ce2010-11-19 13:56:21 -08001022 cancelNotificationLocked(r, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 }
1024 }
1025
1026 updateLightsLocked();
1027 }
1028 }
1029
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001030 // lock on mNotificationList
1031 private void updateLightsLocked()
1032 {
Mike Lockwood2117f6f2010-09-09 09:48:08 -04001033 // clear pending pulse notification if screen is on
1034 if (mScreenOn || mLedNotification == null) {
1035 mPendingPulseNotification = false;
1036 }
1037
The Android Open Source Project10592532009-03-18 17:39:46 -07001038 // handle notification lights
1039 if (mLedNotification == null) {
1040 // get next notification, if any
1041 int n = mLights.size();
1042 if (n > 0) {
1043 mLedNotification = mLights.get(n-1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001044 }
Mike Lockwood2117f6f2010-09-09 09:48:08 -04001045 if (mLedNotification != null && !mScreenOn) {
1046 mPendingPulseNotification = true;
1047 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001049
1050 // we only flash if screen is off and persistent pulsing is enabled
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001051 // and we are not currently in a call
Mike Lockwood2117f6f2010-09-09 09:48:08 -04001052 if (!mPendingPulseNotification || mScreenOn || mInCall) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001053 mNotificationLight.turnOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07001054 } else {
Mike Lockwood670f9322010-01-20 12:13:36 -05001055 int ledARGB = mLedNotification.notification.ledARGB;
1056 int ledOnMS = mLedNotification.notification.ledOnMS;
1057 int ledOffMS = mLedNotification.notification.ledOffMS;
1058 if ((mLedNotification.notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {
1059 ledARGB = mDefaultNotificationColor;
1060 ledOnMS = mDefaultNotificationLedOn;
1061 ledOffMS = mDefaultNotificationLedOff;
1062 }
1063 if (mNotificationPulseEnabled) {
1064 // pulse repeatedly
1065 mNotificationLight.setFlashing(ledARGB, LightsService.LIGHT_FLASH_TIMED,
1066 ledOnMS, ledOffMS);
1067 } else {
1068 // pulse only once
1069 mNotificationLight.pulse(ledARGB, ledOnMS);
1070 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001071 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 }
1073
1074 // lock on mNotificationList
Fred Quintana6ecaff12009-09-25 14:23:13 -07001075 private int indexOfNotificationLocked(String pkg, String tag, int id)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001076 {
1077 ArrayList<NotificationRecord> list = mNotificationList;
1078 final int len = list.size();
1079 for (int i=0; i<len; i++) {
1080 NotificationRecord r = list.get(i);
Fred Quintana6ecaff12009-09-25 14:23:13 -07001081 if (tag == null) {
1082 if (r.tag != null) {
1083 continue;
1084 }
1085 } else {
1086 if (!tag.equals(r.tag)) {
1087 continue;
1088 }
1089 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001090 if (r.id == id && r.pkg.equals(pkg)) {
1091 return i;
1092 }
1093 }
1094 return -1;
1095 }
1096
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001097 // This is here instead of StatusBarPolicy because it is an important
1098 // security feature that we don't want people customizing the platform
1099 // to accidentally lose.
Mike Lockwoodff2544c2010-06-28 09:17:50 -04001100 private void updateAdbNotification(boolean adbEnabled) {
1101 if (adbEnabled) {
Mike Lockwooded760372009-07-09 07:07:27 -04001102 if ("0".equals(SystemProperties.get("persist.adb.notify"))) {
1103 return;
1104 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001105 if (!mAdbNotificationShown) {
1106 NotificationManager notificationManager = (NotificationManager) mContext
1107 .getSystemService(Context.NOTIFICATION_SERVICE);
1108 if (notificationManager != null) {
1109 Resources r = mContext.getResources();
1110 CharSequence title = r.getText(
1111 com.android.internal.R.string.adb_active_notification_title);
1112 CharSequence message = r.getText(
1113 com.android.internal.R.string.adb_active_notification_message);
1114
1115 if (mAdbNotification == null) {
1116 mAdbNotification = new Notification();
Daniel Sandler39576c82010-03-25 16:02:33 -04001117 mAdbNotification.icon = com.android.internal.R.drawable.stat_sys_adb;
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001118 mAdbNotification.when = 0;
1119 mAdbNotification.flags = Notification.FLAG_ONGOING_EVENT;
1120 mAdbNotification.tickerText = title;
Daniel Sandler39576c82010-03-25 16:02:33 -04001121 mAdbNotification.defaults = 0; // please be quiet
1122 mAdbNotification.sound = null;
1123 mAdbNotification.vibrate = null;
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001124 }
1125
1126 Intent intent = new Intent(
1127 Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
1128 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
1129 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
1130 // Note: we are hard-coding the component because this is
1131 // an important security UI that we don't want anyone
1132 // intercepting.
1133 intent.setComponent(new ComponentName("com.android.settings",
1134 "com.android.settings.DevelopmentSettings"));
1135 PendingIntent pi = PendingIntent.getActivity(mContext, 0,
1136 intent, 0);
1137
1138 mAdbNotification.setLatestEventInfo(mContext, title, message, pi);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001139
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001140 mAdbNotificationShown = true;
1141 notificationManager.notify(
1142 com.android.internal.R.string.adb_active_notification_title,
1143 mAdbNotification);
1144 }
1145 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001146
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001147 } else if (mAdbNotificationShown) {
1148 NotificationManager notificationManager = (NotificationManager) mContext
1149 .getSystemService(Context.NOTIFICATION_SERVICE);
1150 if (notificationManager != null) {
1151 mAdbNotificationShown = false;
1152 notificationManager.cancel(
1153 com.android.internal.R.string.adb_active_notification_title);
1154 }
1155 }
1156 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001157
1158 private void updateNotificationPulse() {
1159 synchronized (mNotificationList) {
1160 updateLightsLocked();
1161 }
1162 }
1163
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001164 // ======================================================================
1165 @Override
1166 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1167 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1168 != PackageManager.PERMISSION_GRANTED) {
1169 pw.println("Permission Denial: can't dump NotificationManager from from pid="
1170 + Binder.getCallingPid()
1171 + ", uid=" + Binder.getCallingUid());
1172 return;
1173 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001174
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001175 pw.println("Current Notification Manager state:");
1176
1177 int N;
1178
1179 synchronized (mToastQueue) {
1180 N = mToastQueue.size();
1181 if (N > 0) {
1182 pw.println(" Toast Queue:");
1183 for (int i=0; i<N; i++) {
1184 mToastQueue.get(i).dump(pw, " ");
1185 }
1186 pw.println(" ");
1187 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001188
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001189 }
1190
1191 synchronized (mNotificationList) {
1192 N = mNotificationList.size();
1193 if (N > 0) {
1194 pw.println(" Notification List:");
1195 for (int i=0; i<N; i++) {
1196 mNotificationList.get(i).dump(pw, " ", mContext);
1197 }
1198 pw.println(" ");
1199 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001200
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001201 N = mLights.size();
1202 if (N > 0) {
1203 pw.println(" Lights List:");
1204 for (int i=0; i<N; i++) {
1205 mLights.get(i).dump(pw, " ", mContext);
1206 }
1207 pw.println(" ");
1208 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001210 pw.println(" mSoundNotification=" + mSoundNotification);
1211 pw.println(" mSound=" + mSound);
1212 pw.println(" mVibrateNotification=" + mVibrateNotification);
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001213 pw.println(" mDisabledNotifications=0x" + Integer.toHexString(mDisabledNotifications));
1214 pw.println(" mSystemReady=" + mSystemReady);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215 }
1216 }
1217}