blob: 7101bb0928e001fb947d1e797234844c9641bacd [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;
Joe Onorato7a0f36b2010-06-07 10:24:36 -070020import com.android.server.StatusBarManagerService;
svetoslavganov75986cf2009-05-14 22:28:01 -070021
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.app.ActivityManagerNative;
23import android.app.IActivityManager;
24import android.app.INotificationManager;
25import android.app.ITransientNotification;
26import android.app.Notification;
Dianne Hackborn1dac2772009-06-26 18:16:48 -070027import android.app.NotificationManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.app.PendingIntent;
29import android.app.StatusBarManager;
30import android.content.BroadcastReceiver;
Dianne Hackborn1dac2772009-06-26 18:16:48 -070031import android.content.ComponentName;
Dianne Hackborn1dac2772009-06-26 18:16:48 -070032import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.content.Context;
34import android.content.Intent;
35import android.content.IntentFilter;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070036import android.content.pm.ApplicationInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.content.pm.PackageManager;
38import android.content.pm.PackageManager.NameNotFoundException;
39import android.content.res.Resources;
Dianne Hackborn1dac2772009-06-26 18:16:48 -070040import android.database.ContentObserver;
Mike Lockwoodff2544c2010-06-28 09:17:50 -040041import android.hardware.Usb;
svetoslavganov75986cf2009-05-14 22:28:01 -070042import android.media.AudioManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.net.Uri;
Mike Lockwoodff2544c2010-06-28 09:17:50 -040044import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.os.Binder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.os.Handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.os.IBinder;
48import android.os.Message;
49import android.os.Power;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070050import android.os.Process;
svetoslavganov75986cf2009-05-14 22:28:01 -070051import android.os.RemoteException;
Mike Lockwooded760372009-07-09 07:07:27 -040052import android.os.SystemProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.os.Vibrator;
54import android.provider.Settings;
Daniel Sandlere96ffb12010-03-11 13:38:06 -050055import android.telephony.TelephonyManager;
svetoslavganov75986cf2009-05-14 22:28:01 -070056import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057import android.util.EventLog;
Joe Onorato8a9b2202010-02-26 18:56:32 -080058import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.util.Log;
svetoslavganov75986cf2009-05-14 22:28:01 -070060import android.view.accessibility.AccessibilityEvent;
61import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.widget.Toast;
63
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import java.io.FileDescriptor;
65import java.io.PrintWriter;
66import java.util.ArrayList;
67import java.util.Arrays;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068
Daniel Sandlerd0a2f862010-08-03 15:29:31 -040069/** {@hide} */
70public class NotificationManagerService extends INotificationManager.Stub
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071{
72 private static final String TAG = "NotificationService";
73 private static final boolean DBG = false;
74
Joe Onoratobd73d012010-06-04 11:44:54 -070075 private static final int MAX_PACKAGE_NOTIFICATIONS = 50;
76
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077 // message codes
78 private static final int MESSAGE_TIMEOUT = 2;
79
80 private static final int LONG_DELAY = 3500; // 3.5 seconds
81 private static final int SHORT_DELAY = 2000; // 2 seconds
Doug Zongkerab5c49c2009-12-04 10:31:43 -080082
83 private static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084
85 private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
86
87 final Context mContext;
88 final IActivityManager mAm;
89 final IBinder mForegroundToken = new Binder();
90
91 private WorkerHandler mHandler;
Joe Onorato089de882010-04-12 08:18:45 -070092 private StatusBarManagerService mStatusBar;
Mike Lockwood3cb67a32009-11-27 14:25:58 -050093 private LightsService.Light mNotificationLight;
94 private LightsService.Light mAttentionLight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095
Mike Lockwood670f9322010-01-20 12:13:36 -050096 private int mDefaultNotificationColor;
97 private int mDefaultNotificationLedOn;
98 private int mDefaultNotificationLedOff;
99
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 private NotificationRecord mSoundNotification;
Jean-Michel Trivi211957f2010-03-26 18:19:33 -0700101 private NotificationPlayer mSound;
Joe Onorato30275482009-07-08 17:09:14 -0700102 private boolean mSystemReady;
Joe Onorato39f5b6a2009-07-23 12:29:19 -0400103 private int mDisabledNotifications;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104
105 private NotificationRecord mVibrateNotification;
106 private Vibrator mVibrator = new Vibrator();
107
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500108 // for enabling and disabling notification pulse behavior
109 private boolean mScreenOn = true;
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500110 private boolean mInCall = false;
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500111 private boolean mNotificationPulseEnabled;
Mike Lockwood2117f6f2010-09-09 09:48:08 -0400112 // This is true if we have received a new notification while the screen is off
113 // (that is, if mLedNotification was set while the screen was off)
114 // This is reset to false when the screen is turned on.
115 private boolean mPendingPulseNotification;
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500116
117 // for adb connected notifications
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700118 private boolean mAdbNotificationShown = false;
119 private Notification mAdbNotification;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800120
Fred Quintana6ecaff12009-09-25 14:23:13 -0700121 private final ArrayList<NotificationRecord> mNotificationList =
122 new ArrayList<NotificationRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123
124 private ArrayList<ToastRecord> mToastQueue;
125
126 private ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 private NotificationRecord mLedNotification;
svetoslavganov75986cf2009-05-14 22:28:01 -0700128
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 private static String idDebugString(Context baseContext, String packageName, int id) {
130 Context c = null;
131
132 if (packageName != null) {
133 try {
134 c = baseContext.createPackageContext(packageName, 0);
135 } catch (NameNotFoundException e) {
136 c = baseContext;
137 }
138 } else {
139 c = baseContext;
140 }
141
142 String pkg;
143 String type;
144 String name;
145
146 Resources r = c.getResources();
147 try {
148 return r.getResourceName(id);
149 } catch (Resources.NotFoundException e) {
150 return "<name unknown>";
151 }
152 }
153
154 private static final class NotificationRecord
155 {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700156 final String pkg;
157 final String tag;
158 final int id;
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700159 final int uid;
160 final int initialPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161 ITransientNotification callback;
162 int duration;
Fred Quintana6ecaff12009-09-25 14:23:13 -0700163 final Notification notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 IBinder statusBarKey;
165
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700166 NotificationRecord(String pkg, String tag, int id, int uid, int initialPid,
167 Notification notification)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168 {
169 this.pkg = pkg;
Fred Quintana6ecaff12009-09-25 14:23:13 -0700170 this.tag = tag;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 this.id = id;
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700172 this.uid = uid;
173 this.initialPid = initialPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174 this.notification = notification;
175 }
Fred Quintana6ecaff12009-09-25 14:23:13 -0700176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 void dump(PrintWriter pw, String prefix, Context baseContext) {
178 pw.println(prefix + this);
179 pw.println(prefix + " icon=0x" + Integer.toHexString(notification.icon)
180 + " / " + idDebugString(baseContext, this.pkg, notification.icon));
181 pw.println(prefix + " contentIntent=" + notification.contentIntent);
182 pw.println(prefix + " deleteIntent=" + notification.deleteIntent);
183 pw.println(prefix + " tickerText=" + notification.tickerText);
184 pw.println(prefix + " contentView=" + notification.contentView);
185 pw.println(prefix + " defaults=0x" + Integer.toHexString(notification.defaults));
186 pw.println(prefix + " flags=0x" + Integer.toHexString(notification.flags));
187 pw.println(prefix + " sound=" + notification.sound);
188 pw.println(prefix + " vibrate=" + Arrays.toString(notification.vibrate));
189 pw.println(prefix + " ledARGB=0x" + Integer.toHexString(notification.ledARGB)
190 + " ledOnMS=" + notification.ledOnMS
191 + " ledOffMS=" + notification.ledOffMS);
192 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800193
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 @Override
195 public final String toString()
196 {
197 return "NotificationRecord{"
198 + Integer.toHexString(System.identityHashCode(this))
199 + " pkg=" + pkg
Fred Quintana6ecaff12009-09-25 14:23:13 -0700200 + " id=" + Integer.toHexString(id)
201 + " tag=" + tag + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 }
203 }
204
205 private static final class ToastRecord
206 {
207 final int pid;
208 final String pkg;
209 final ITransientNotification callback;
210 int duration;
211
212 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
213 {
214 this.pid = pid;
215 this.pkg = pkg;
216 this.callback = callback;
217 this.duration = duration;
218 }
219
220 void update(int duration) {
221 this.duration = duration;
222 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800223
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 void dump(PrintWriter pw, String prefix) {
225 pw.println(prefix + this);
226 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 @Override
229 public final String toString()
230 {
231 return "ToastRecord{"
232 + Integer.toHexString(System.identityHashCode(this))
233 + " pkg=" + pkg
234 + " callback=" + callback
235 + " duration=" + duration;
236 }
237 }
238
Joe Onorato089de882010-04-12 08:18:45 -0700239 private StatusBarManagerService.NotificationCallbacks mNotificationCallbacks
240 = new StatusBarManagerService.NotificationCallbacks() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241
242 public void onSetDisabled(int status) {
243 synchronized (mNotificationList) {
244 mDisabledNotifications = status;
245 if ((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
246 // cancel whatever's going on
247 long identity = Binder.clearCallingIdentity();
248 try {
249 mSound.stop();
250 }
251 finally {
252 Binder.restoreCallingIdentity(identity);
253 }
254
255 identity = Binder.clearCallingIdentity();
256 try {
257 mVibrator.cancel();
258 }
259 finally {
260 Binder.restoreCallingIdentity(identity);
261 }
262 }
263 }
264 }
265
266 public void onClearAll() {
267 cancelAll();
268 }
269
Fred Quintana6ecaff12009-09-25 14:23:13 -0700270 public void onNotificationClick(String pkg, String tag, int id) {
271 cancelNotification(pkg, tag, id, Notification.FLAG_AUTO_CANCEL,
Joe Onorato46439ce2010-11-19 13:56:21 -0800272 Notification.FLAG_FOREGROUND_SERVICE, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 }
274
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400275 public void onNotificationClear(String pkg, String tag, int id) {
Joe Onorato46439ce2010-11-19 13:56:21 -0800276 cancelNotification(pkg, tag, id, 0,
277 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
278 true);
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400279 }
280
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 public void onPanelRevealed() {
282 synchronized (mNotificationList) {
283 // sound
284 mSoundNotification = null;
285 long identity = Binder.clearCallingIdentity();
286 try {
287 mSound.stop();
288 }
289 finally {
290 Binder.restoreCallingIdentity(identity);
291 }
292
293 // vibrate
294 mVibrateNotification = null;
295 identity = Binder.clearCallingIdentity();
296 try {
297 mVibrator.cancel();
298 }
299 finally {
300 Binder.restoreCallingIdentity(identity);
301 }
302
303 // light
304 mLights.clear();
305 mLedNotification = null;
306 updateLightsLocked();
307 }
308 }
Joe Onorato005847b2010-06-04 16:08:02 -0400309
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700310 public void onNotificationError(String pkg, String tag, int id,
311 int uid, int initialPid, String message) {
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400312 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
313 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
Joe Onorato46439ce2010-11-19 13:56:21 -0800314 cancelNotification(pkg, tag, id, 0, 0, false);
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700315 long ident = Binder.clearCallingIdentity();
316 try {
317 ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,
318 "Bad notification posted from package " + pkg
319 + ": " + message);
320 } catch (RemoteException e) {
321 }
322 Binder.restoreCallingIdentity(ident);
Joe Onorato005847b2010-06-04 16:08:02 -0400323 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 };
325
326 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
327 @Override
328 public void onReceive(Context context, Intent intent) {
329 String action = intent.getAction();
330
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800331 boolean queryRestart = false;
332
Joe Onoratode1b3592010-10-25 20:36:47 -0700333 if (action.equals(Usb.ACTION_USB_STATE)) {
Mike Lockwoodff2544c2010-06-28 09:17:50 -0400334 Bundle extras = intent.getExtras();
335 boolean usbConnected = extras.getBoolean(Usb.USB_CONNECTED);
336 boolean adbEnabled = (Usb.USB_FUNCTION_ENABLED.equals(
337 extras.getString(Usb.USB_FUNCTION_ADB)));
338 updateAdbNotification(usbConnected && adbEnabled);
339 } else if (action.equals(Usb.ACTION_USB_DISCONNECTED)) {
340 updateAdbNotification(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800342 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800343 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800344 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800345 String pkgList[] = null;
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800346 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800347 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800348 } else if (queryRestart) {
349 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800350 } else {
351 Uri uri = intent.getData();
352 if (uri == null) {
353 return;
354 }
355 String pkgName = uri.getSchemeSpecificPart();
356 if (pkgName == null) {
357 return;
358 }
359 pkgList = new String[]{pkgName};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800361 if (pkgList != null && (pkgList.length > 0)) {
362 for (String pkgName : pkgList) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800363 cancelAllNotificationsInt(pkgName, 0, 0, !queryRestart);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800364 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500366 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
367 mScreenOn = true;
368 updateNotificationPulse();
369 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
370 mScreenOn = false;
371 updateNotificationPulse();
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500372 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
373 mInCall = (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_OFFHOOK));
374 updateNotificationPulse();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 }
376 }
377 };
378
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700379 class SettingsObserver extends ContentObserver {
380 SettingsObserver(Handler handler) {
381 super(handler);
382 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800383
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700384 void observe() {
385 ContentResolver resolver = mContext.getContentResolver();
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500386 resolver.registerContentObserver(Settings.System.getUriFor(
387 Settings.System.NOTIFICATION_LIGHT_PULSE), false, this);
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700388 update();
389 }
390
391 @Override public void onChange(boolean selfChange) {
392 update();
393 }
394
395 public void update() {
396 ContentResolver resolver = mContext.getContentResolver();
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500397 boolean pulseEnabled = Settings.System.getInt(resolver,
398 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
399 if (mNotificationPulseEnabled != pulseEnabled) {
400 mNotificationPulseEnabled = pulseEnabled;
401 updateNotificationPulse();
402 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700403 }
404 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500405
Joe Onorato089de882010-04-12 08:18:45 -0700406 NotificationManagerService(Context context, StatusBarManagerService statusBar,
Mike Lockwood3a322132009-11-24 00:30:52 -0500407 LightsService lights)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800408 {
409 super();
410 mContext = context;
411 mAm = ActivityManagerNative.getDefault();
Jean-Michel Trivi211957f2010-03-26 18:19:33 -0700412 mSound = new NotificationPlayer(TAG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 mSound.setUsesWakeLock(context);
414 mToastQueue = new ArrayList<ToastRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 mHandler = new WorkerHandler();
San Mehat3ee13172010-02-04 20:54:43 -0800416
Joe Onorato089de882010-04-12 08:18:45 -0700417 mStatusBar = statusBar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 statusBar.setNotificationCallbacks(mNotificationCallbacks);
419
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500420 mNotificationLight = lights.getLight(LightsService.LIGHT_ID_NOTIFICATIONS);
421 mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION);
422
Mike Lockwood670f9322010-01-20 12:13:36 -0500423 Resources resources = mContext.getResources();
424 mDefaultNotificationColor = resources.getColor(
425 com.android.internal.R.color.config_defaultNotificationColor);
426 mDefaultNotificationLedOn = resources.getInteger(
427 com.android.internal.R.integer.config_defaultNotificationLedOn);
428 mDefaultNotificationLedOff = resources.getInteger(
429 com.android.internal.R.integer.config_defaultNotificationLedOff);
430
Joe Onorato39f5b6a2009-07-23 12:29:19 -0400431 // Don't start allowing notifications until the setup wizard has run once.
432 // After that, including subsequent boots, init with notifications turned on.
433 // This works on the first boot because the setup wizard will toggle this
434 // flag at least once and we'll go back to 0 after that.
435 if (0 == Settings.Secure.getInt(mContext.getContentResolver(),
436 Settings.Secure.DEVICE_PROVISIONED, 0)) {
437 mDisabledNotifications = StatusBarManager.DISABLE_NOTIFICATION_ALERTS;
438 }
439
Mike Lockwood35e16bf2010-11-30 19:53:36 -0500440 // register for various Intents
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441 IntentFilter filter = new IntentFilter();
Mike Lockwoodff2544c2010-06-28 09:17:50 -0400442 filter.addAction(Usb.ACTION_USB_STATE);
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500443 filter.addAction(Intent.ACTION_SCREEN_ON);
444 filter.addAction(Intent.ACTION_SCREEN_OFF);
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500445 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446 mContext.registerReceiver(mIntentReceiver, filter);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800447 IntentFilter pkgFilter = new IntentFilter();
448 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
449 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
450 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
451 pkgFilter.addDataScheme("package");
452 mContext.registerReceiver(mIntentReceiver, pkgFilter);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800453 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800454 mContext.registerReceiver(mIntentReceiver, sdFilter);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800455
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500456 SettingsObserver observer = new SettingsObserver(mHandler);
457 observer.observe();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800458 }
459
Joe Onorato30275482009-07-08 17:09:14 -0700460 void systemReady() {
461 // no beeping until we're basically done booting
462 mSystemReady = true;
463 }
464
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 // Toasts
466 // ============================================================================
467 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
468 {
Daniel Sandlera7035902010-03-30 15:45:31 -0400469 if (DBG) Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + " duration=" + duration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470
471 if (pkg == null || callback == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800472 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 return ;
474 }
475
476 synchronized (mToastQueue) {
477 int callingPid = Binder.getCallingPid();
478 long callingId = Binder.clearCallingIdentity();
479 try {
480 ToastRecord record;
481 int index = indexOfToastLocked(pkg, callback);
482 // If it's already in the queue, we update it in place, we don't
483 // move it to the end of the queue.
484 if (index >= 0) {
485 record = mToastQueue.get(index);
486 record.update(duration);
487 } else {
488 record = new ToastRecord(callingPid, pkg, callback, duration);
489 mToastQueue.add(record);
490 index = mToastQueue.size() - 1;
491 keepProcessAliveLocked(callingPid);
492 }
493 // If it's at index 0, it's the current toast. It doesn't matter if it's
494 // new or just been updated. Call back and tell it to show itself.
495 // If the callback fails, this will remove it from the list, so don't
496 // assume that it's valid after this.
497 if (index == 0) {
498 showNextToastLocked();
499 }
500 } finally {
501 Binder.restoreCallingIdentity(callingId);
502 }
503 }
504 }
505
506 public void cancelToast(String pkg, ITransientNotification callback) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800507 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508
509 if (pkg == null || callback == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800510 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 return ;
512 }
513
514 synchronized (mToastQueue) {
515 long callingId = Binder.clearCallingIdentity();
516 try {
517 int index = indexOfToastLocked(pkg, callback);
518 if (index >= 0) {
519 cancelToastLocked(index);
520 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800521 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg + " callback=" + callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 }
523 } finally {
524 Binder.restoreCallingIdentity(callingId);
525 }
526 }
527 }
528
529 private void showNextToastLocked() {
530 ToastRecord record = mToastQueue.get(0);
531 while (record != null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800532 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 try {
534 record.callback.show();
535 scheduleTimeoutLocked(record, false);
536 return;
537 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800538 Slog.w(TAG, "Object died trying to show notification " + record.callback
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 + " in package " + record.pkg);
540 // remove it from the list and let the process die
541 int index = mToastQueue.indexOf(record);
542 if (index >= 0) {
543 mToastQueue.remove(index);
544 }
545 keepProcessAliveLocked(record.pid);
546 if (mToastQueue.size() > 0) {
547 record = mToastQueue.get(0);
548 } else {
549 record = null;
550 }
551 }
552 }
553 }
554
555 private void cancelToastLocked(int index) {
556 ToastRecord record = mToastQueue.get(index);
557 try {
558 record.callback.hide();
559 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800560 Slog.w(TAG, "Object died trying to hide notification " + record.callback
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 + " in package " + record.pkg);
562 // don't worry about this, we're about to remove it from
563 // the list anyway
564 }
565 mToastQueue.remove(index);
566 keepProcessAliveLocked(record.pid);
567 if (mToastQueue.size() > 0) {
568 // Show the next one. If the callback fails, this will remove
569 // it from the list, so don't assume that the list hasn't changed
570 // after this point.
571 showNextToastLocked();
572 }
573 }
574
575 private void scheduleTimeoutLocked(ToastRecord r, boolean immediate)
576 {
577 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
578 long delay = immediate ? 0 : (r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY);
579 mHandler.removeCallbacksAndMessages(r);
580 mHandler.sendMessageDelayed(m, delay);
581 }
582
583 private void handleTimeout(ToastRecord record)
584 {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800585 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 synchronized (mToastQueue) {
587 int index = indexOfToastLocked(record.pkg, record.callback);
588 if (index >= 0) {
589 cancelToastLocked(index);
590 }
591 }
592 }
593
594 // lock on mToastQueue
595 private int indexOfToastLocked(String pkg, ITransientNotification callback)
596 {
597 IBinder cbak = callback.asBinder();
598 ArrayList<ToastRecord> list = mToastQueue;
599 int len = list.size();
600 for (int i=0; i<len; i++) {
601 ToastRecord r = list.get(i);
602 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
603 return i;
604 }
605 }
606 return -1;
607 }
608
609 // lock on mToastQueue
610 private void keepProcessAliveLocked(int pid)
611 {
612 int toastCount = 0; // toasts from this pid
613 ArrayList<ToastRecord> list = mToastQueue;
614 int N = list.size();
615 for (int i=0; i<N; i++) {
616 ToastRecord r = list.get(i);
617 if (r.pid == pid) {
618 toastCount++;
619 }
620 }
621 try {
622 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
623 } catch (RemoteException e) {
624 // Shouldn't happen.
625 }
626 }
627
628 private final class WorkerHandler extends Handler
629 {
630 @Override
631 public void handleMessage(Message msg)
632 {
633 switch (msg.what)
634 {
635 case MESSAGE_TIMEOUT:
636 handleTimeout((ToastRecord)msg.obj);
637 break;
638 }
639 }
640 }
641
642
643 // Notifications
644 // ============================================================================
645 public void enqueueNotification(String pkg, int id, Notification notification, int[] idOut)
646 {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700647 enqueueNotificationWithTag(pkg, null /* tag */, id, notification, idOut);
648 }
649
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400650 public void enqueueNotificationWithTag(String pkg, String tag, int id, Notification notification,
651 int[] idOut)
Fred Quintana6ecaff12009-09-25 14:23:13 -0700652 {
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400653 enqueueNotificationInternal(pkg, Binder.getCallingUid(), Binder.getCallingPid(),
654 tag, id, notification, idOut);
655 }
656
657 // Not exposed via Binder; for system use only (otherwise malicious apps could spoof the
658 // uid/pid of another application)
659 public void enqueueNotificationInternal(String pkg, int callingUid, int callingPid,
660 String tag, int id, Notification notification, int[] idOut)
661 {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700662 checkIncomingCall(pkg);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800663
Joe Onoratobd73d012010-06-04 11:44:54 -0700664 // Limit the number of notifications that any given package except the android
665 // package can enqueue. Prevents DOS attacks and deals with leaks.
666 if (!"android".equals(pkg)) {
667 synchronized (mNotificationList) {
668 int count = 0;
669 final int N = mNotificationList.size();
670 for (int i=0; i<N; i++) {
671 final NotificationRecord r = mNotificationList.get(i);
672 if (r.pkg.equals(pkg)) {
673 count++;
674 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
675 Slog.e(TAG, "Package has already posted " + count
676 + " notifications. Not showing more. package=" + pkg);
677 return;
678 }
679 }
680 }
681 }
682 }
683
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800684 // This conditional is a dirty hack to limit the logging done on
685 // behalf of the download manager without affecting other apps.
686 if (!pkg.equals("com.android.providers.downloads")
687 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800688 EventLog.writeEvent(EventLogTags.NOTIFICATION_ENQUEUE, pkg, id, notification.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800689 }
690
691 if (pkg == null || notification == null) {
692 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
693 + " id=" + id + " notification=" + notification);
694 }
695 if (notification.icon != 0) {
696 if (notification.contentView == null) {
697 throw new IllegalArgumentException("contentView required: pkg=" + pkg
698 + " id=" + id + " notification=" + notification);
699 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800700 }
701
702 synchronized (mNotificationList) {
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700703 NotificationRecord r = new NotificationRecord(pkg, tag, id,
704 callingUid, callingPid, notification);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800705 NotificationRecord old = null;
706
Fred Quintana6ecaff12009-09-25 14:23:13 -0700707 int index = indexOfNotificationLocked(pkg, tag, id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800708 if (index < 0) {
709 mNotificationList.add(r);
710 } else {
711 old = mNotificationList.remove(index);
712 mNotificationList.add(index, r);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700713 // Make sure we don't lose the foreground service state.
714 if (old != null) {
715 notification.flags |=
716 old.notification.flags&Notification.FLAG_FOREGROUND_SERVICE;
717 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800718 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800719
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700720 // Ensure if this is a foreground service that the proper additional
721 // flags are set.
722 if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) {
723 notification.flags |= Notification.FLAG_ONGOING_EVENT
724 | Notification.FLAG_NO_CLEAR;
725 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800726
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800727 if (notification.icon != 0) {
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700728 StatusBarNotification n = new StatusBarNotification(pkg, id, tag,
729 r.uid, r.initialPid, notification);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 if (old != null && old.statusBarKey != null) {
731 r.statusBarKey = old.statusBarKey;
732 long identity = Binder.clearCallingIdentity();
733 try {
Joe Onorato18e69df2010-05-17 22:26:12 -0700734 mStatusBar.updateNotification(r.statusBarKey, n);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800735 }
736 finally {
737 Binder.restoreCallingIdentity(identity);
738 }
739 } else {
740 long identity = Binder.clearCallingIdentity();
741 try {
Joe Onorato18e69df2010-05-17 22:26:12 -0700742 r.statusBarKey = mStatusBar.addNotification(n);
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500743 mAttentionLight.pulse();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800744 }
745 finally {
746 Binder.restoreCallingIdentity(identity);
747 }
748 }
Joe Onorato30275482009-07-08 17:09:14 -0700749 sendAccessibilityEvent(notification, pkg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750 } else {
751 if (old != null && old.statusBarKey != null) {
752 long identity = Binder.clearCallingIdentity();
753 try {
Joe Onorato0cbda992010-05-02 16:28:15 -0700754 mStatusBar.removeNotification(old.statusBarKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800755 }
756 finally {
757 Binder.restoreCallingIdentity(identity);
758 }
759 }
760 }
761
762 // If we're not supposed to beep, vibrate, etc. then don't.
763 if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
764 && (!(old != null
Joe Onorato30275482009-07-08 17:09:14 -0700765 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
766 && mSystemReady) {
Eric Laurent524dc042009-11-27 05:07:55 -0800767
768 final AudioManager audioManager = (AudioManager) mContext
769 .getSystemService(Context.AUDIO_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 // sound
771 final boolean useDefaultSound =
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800772 (notification.defaults & Notification.DEFAULT_SOUND) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 if (useDefaultSound || notification.sound != null) {
774 Uri uri;
775 if (useDefaultSound) {
776 uri = Settings.System.DEFAULT_NOTIFICATION_URI;
777 } else {
778 uri = notification.sound;
779 }
780 boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0;
781 int audioStreamType;
782 if (notification.audioStreamType >= 0) {
783 audioStreamType = notification.audioStreamType;
784 } else {
785 audioStreamType = DEFAULT_STREAM_TYPE;
786 }
787 mSoundNotification = r;
Eric Laurent524dc042009-11-27 05:07:55 -0800788 // do not play notifications if stream volume is 0
789 // (typically because ringer mode is silent).
790 if (audioManager.getStreamVolume(audioStreamType) != 0) {
791 long identity = Binder.clearCallingIdentity();
792 try {
793 mSound.play(mContext, uri, looping, audioStreamType);
794 }
795 finally {
796 Binder.restoreCallingIdentity(identity);
797 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798 }
799 }
800
801 // vibrate
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 final boolean useDefaultVibrate =
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800803 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804 if ((useDefaultVibrate || notification.vibrate != null)
805 && audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_NOTIFICATION)) {
806 mVibrateNotification = r;
807
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800808 mVibrator.vibrate(useDefaultVibrate ? DEFAULT_VIBRATE_PATTERN
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 : notification.vibrate,
810 ((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
811 }
812 }
813
814 // this option doesn't shut off the lights
815
816 // light
817 // the most recent thing gets the light
818 mLights.remove(old);
819 if (mLedNotification == old) {
820 mLedNotification = null;
821 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800822 //Slog.i(TAG, "notification.lights="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 // + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS) != 0));
824 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {
825 mLights.add(r);
826 updateLightsLocked();
827 } else {
828 if (old != null
829 && ((old.notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0)) {
830 updateLightsLocked();
831 }
832 }
833 }
834
835 idOut[0] = id;
836 }
837
Joe Onorato30275482009-07-08 17:09:14 -0700838 private void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
svetoslavganov75986cf2009-05-14 22:28:01 -0700839 AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
840 if (!manager.isEnabled()) {
841 return;
842 }
843
844 AccessibilityEvent event =
845 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
846 event.setPackageName(packageName);
847 event.setClassName(Notification.class.getName());
848 event.setParcelableData(notification);
849 CharSequence tickerText = notification.tickerText;
850 if (!TextUtils.isEmpty(tickerText)) {
851 event.getText().add(tickerText);
852 }
853
854 manager.sendAccessibilityEvent(event);
855 }
856
Joe Onorato46439ce2010-11-19 13:56:21 -0800857 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete) {
858 // tell the app
859 if (sendDelete) {
860 if (r.notification.deleteIntent != null) {
861 try {
862 r.notification.deleteIntent.send();
863 } catch (PendingIntent.CanceledException ex) {
864 // do nothing - there's no relevant way to recover, and
865 // no reason to let this propagate
866 Slog.w(TAG, "canceled PendingIntent for " + r.pkg, ex);
867 }
868 }
869 }
870
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871 // status bar
872 if (r.notification.icon != 0) {
873 long identity = Binder.clearCallingIdentity();
874 try {
Joe Onorato0cbda992010-05-02 16:28:15 -0700875 mStatusBar.removeNotification(r.statusBarKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 }
877 finally {
878 Binder.restoreCallingIdentity(identity);
879 }
880 r.statusBarKey = null;
881 }
882
883 // sound
884 if (mSoundNotification == r) {
885 mSoundNotification = null;
886 long identity = Binder.clearCallingIdentity();
887 try {
888 mSound.stop();
889 }
890 finally {
891 Binder.restoreCallingIdentity(identity);
892 }
893 }
894
895 // vibrate
896 if (mVibrateNotification == r) {
897 mVibrateNotification = null;
898 long identity = Binder.clearCallingIdentity();
899 try {
900 mVibrator.cancel();
901 }
902 finally {
903 Binder.restoreCallingIdentity(identity);
904 }
905 }
906
907 // light
908 mLights.remove(r);
909 if (mLedNotification == r) {
910 mLedNotification = null;
911 }
912 }
913
914 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700915 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800916 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800917 */
Fred Quintana6ecaff12009-09-25 14:23:13 -0700918 private void cancelNotification(String pkg, String tag, int id, int mustHaveFlags,
Joe Onorato46439ce2010-11-19 13:56:21 -0800919 int mustNotHaveFlags, boolean sendDelete) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800920 EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL, pkg, id, mustHaveFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800921
922 synchronized (mNotificationList) {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700923 int index = indexOfNotificationLocked(pkg, tag, id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924 if (index >= 0) {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700925 NotificationRecord r = mNotificationList.get(index);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800926
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800927 if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {
928 return;
929 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700930 if ((r.notification.flags & mustNotHaveFlags) != 0) {
931 return;
932 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800933
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800934 mNotificationList.remove(index);
935
Joe Onorato46439ce2010-11-19 13:56:21 -0800936 cancelNotificationLocked(r, sendDelete);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 updateLightsLocked();
938 }
939 }
940 }
941
942 /**
943 * Cancels all notifications from a given package that have all of the
944 * {@code mustHaveFlags}.
945 */
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800946 boolean cancelAllNotificationsInt(String pkg, int mustHaveFlags,
947 int mustNotHaveFlags, boolean doit) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800948 EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL_ALL, pkg, mustHaveFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800949
950 synchronized (mNotificationList) {
951 final int N = mNotificationList.size();
952 boolean canceledSomething = false;
953 for (int i = N-1; i >= 0; --i) {
954 NotificationRecord r = mNotificationList.get(i);
955 if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {
956 continue;
957 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700958 if ((r.notification.flags & mustNotHaveFlags) != 0) {
959 continue;
960 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961 if (!r.pkg.equals(pkg)) {
962 continue;
963 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800964 canceledSomething = true;
965 if (!doit) {
966 return true;
967 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968 mNotificationList.remove(i);
Joe Onorato46439ce2010-11-19 13:56:21 -0800969 cancelNotificationLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 }
971 if (canceledSomething) {
972 updateLightsLocked();
973 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800974 return canceledSomething;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800975 }
976 }
977
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800978
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700979 public void cancelNotification(String pkg, int id) {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700980 cancelNotificationWithTag(pkg, null /* tag */, id);
981 }
982
983 public void cancelNotificationWithTag(String pkg, String tag, int id) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700984 checkIncomingCall(pkg);
985 // Don't allow client applications to cancel foreground service notis.
Fred Quintana6ecaff12009-09-25 14:23:13 -0700986 cancelNotification(pkg, tag, id, 0,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700987 Binder.getCallingUid() == Process.SYSTEM_UID
Joe Onorato46439ce2010-11-19 13:56:21 -0800988 ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800989 }
990
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700991 public void cancelAllNotifications(String pkg) {
992 checkIncomingCall(pkg);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800993
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700994 // Calling from user space, don't allow the canceling of actively
995 // running foreground services.
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800996 cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 }
998
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700999 void checkIncomingCall(String pkg) {
1000 int uid = Binder.getCallingUid();
1001 if (uid == Process.SYSTEM_UID || uid == 0) {
1002 return;
1003 }
1004 try {
1005 ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(
1006 pkg, 0);
1007 if (ai.uid != uid) {
1008 throw new SecurityException("Calling uid " + uid + " gave package"
1009 + pkg + " which is owned by uid " + ai.uid);
1010 }
1011 } catch (PackageManager.NameNotFoundException e) {
1012 throw new SecurityException("Unknown package " + pkg);
1013 }
1014 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001015
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001016 void cancelAll() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 synchronized (mNotificationList) {
1018 final int N = mNotificationList.size();
1019 for (int i=N-1; i>=0; i--) {
1020 NotificationRecord r = mNotificationList.get(i);
1021
1022 if ((r.notification.flags & (Notification.FLAG_ONGOING_EVENT
1023 | Notification.FLAG_NO_CLEAR)) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001024 mNotificationList.remove(i);
Joe Onorato46439ce2010-11-19 13:56:21 -08001025 cancelNotificationLocked(r, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 }
1027 }
1028
1029 updateLightsLocked();
1030 }
1031 }
1032
1033 private void updateLights() {
1034 synchronized (mNotificationList) {
1035 updateLightsLocked();
1036 }
1037 }
1038
1039 // lock on mNotificationList
1040 private void updateLightsLocked()
1041 {
Mike Lockwood2117f6f2010-09-09 09:48:08 -04001042 // clear pending pulse notification if screen is on
1043 if (mScreenOn || mLedNotification == null) {
1044 mPendingPulseNotification = false;
1045 }
1046
The Android Open Source Project10592532009-03-18 17:39:46 -07001047 // handle notification lights
1048 if (mLedNotification == null) {
1049 // get next notification, if any
1050 int n = mLights.size();
1051 if (n > 0) {
1052 mLedNotification = mLights.get(n-1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001053 }
Mike Lockwood2117f6f2010-09-09 09:48:08 -04001054 if (mLedNotification != null && !mScreenOn) {
1055 mPendingPulseNotification = true;
1056 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001058
1059 // we only flash if screen is off and persistent pulsing is enabled
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001060 // and we are not currently in a call
Mike Lockwood2117f6f2010-09-09 09:48:08 -04001061 if (!mPendingPulseNotification || mScreenOn || mInCall) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001062 mNotificationLight.turnOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07001063 } else {
Mike Lockwood670f9322010-01-20 12:13:36 -05001064 int ledARGB = mLedNotification.notification.ledARGB;
1065 int ledOnMS = mLedNotification.notification.ledOnMS;
1066 int ledOffMS = mLedNotification.notification.ledOffMS;
1067 if ((mLedNotification.notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {
1068 ledARGB = mDefaultNotificationColor;
1069 ledOnMS = mDefaultNotificationLedOn;
1070 ledOffMS = mDefaultNotificationLedOff;
1071 }
1072 if (mNotificationPulseEnabled) {
1073 // pulse repeatedly
1074 mNotificationLight.setFlashing(ledARGB, LightsService.LIGHT_FLASH_TIMED,
1075 ledOnMS, ledOffMS);
1076 } else {
1077 // pulse only once
1078 mNotificationLight.pulse(ledARGB, ledOnMS);
1079 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001080 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001081 }
1082
1083 // lock on mNotificationList
Fred Quintana6ecaff12009-09-25 14:23:13 -07001084 private int indexOfNotificationLocked(String pkg, String tag, int id)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001085 {
1086 ArrayList<NotificationRecord> list = mNotificationList;
1087 final int len = list.size();
1088 for (int i=0; i<len; i++) {
1089 NotificationRecord r = list.get(i);
Fred Quintana6ecaff12009-09-25 14:23:13 -07001090 if (tag == null) {
1091 if (r.tag != null) {
1092 continue;
1093 }
1094 } else {
1095 if (!tag.equals(r.tag)) {
1096 continue;
1097 }
1098 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001099 if (r.id == id && r.pkg.equals(pkg)) {
1100 return i;
1101 }
1102 }
1103 return -1;
1104 }
1105
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001106 // This is here instead of StatusBarPolicy because it is an important
1107 // security feature that we don't want people customizing the platform
1108 // to accidentally lose.
Mike Lockwoodff2544c2010-06-28 09:17:50 -04001109 private void updateAdbNotification(boolean adbEnabled) {
1110 if (adbEnabled) {
Mike Lockwooded760372009-07-09 07:07:27 -04001111 if ("0".equals(SystemProperties.get("persist.adb.notify"))) {
1112 return;
1113 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001114 if (!mAdbNotificationShown) {
1115 NotificationManager notificationManager = (NotificationManager) mContext
1116 .getSystemService(Context.NOTIFICATION_SERVICE);
1117 if (notificationManager != null) {
1118 Resources r = mContext.getResources();
1119 CharSequence title = r.getText(
1120 com.android.internal.R.string.adb_active_notification_title);
1121 CharSequence message = r.getText(
1122 com.android.internal.R.string.adb_active_notification_message);
1123
1124 if (mAdbNotification == null) {
1125 mAdbNotification = new Notification();
Daniel Sandler39576c82010-03-25 16:02:33 -04001126 mAdbNotification.icon = com.android.internal.R.drawable.stat_sys_adb;
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001127 mAdbNotification.when = 0;
1128 mAdbNotification.flags = Notification.FLAG_ONGOING_EVENT;
1129 mAdbNotification.tickerText = title;
Daniel Sandler39576c82010-03-25 16:02:33 -04001130 mAdbNotification.defaults = 0; // please be quiet
1131 mAdbNotification.sound = null;
1132 mAdbNotification.vibrate = null;
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001133 }
1134
1135 Intent intent = new Intent(
1136 Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
1137 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
1138 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
1139 // Note: we are hard-coding the component because this is
1140 // an important security UI that we don't want anyone
1141 // intercepting.
1142 intent.setComponent(new ComponentName("com.android.settings",
1143 "com.android.settings.DevelopmentSettings"));
1144 PendingIntent pi = PendingIntent.getActivity(mContext, 0,
1145 intent, 0);
1146
1147 mAdbNotification.setLatestEventInfo(mContext, title, message, pi);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001148
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001149 mAdbNotificationShown = true;
1150 notificationManager.notify(
1151 com.android.internal.R.string.adb_active_notification_title,
1152 mAdbNotification);
1153 }
1154 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001155
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001156 } else if (mAdbNotificationShown) {
1157 NotificationManager notificationManager = (NotificationManager) mContext
1158 .getSystemService(Context.NOTIFICATION_SERVICE);
1159 if (notificationManager != null) {
1160 mAdbNotificationShown = false;
1161 notificationManager.cancel(
1162 com.android.internal.R.string.adb_active_notification_title);
1163 }
1164 }
1165 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001166
1167 private void updateNotificationPulse() {
1168 synchronized (mNotificationList) {
1169 updateLightsLocked();
1170 }
1171 }
1172
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001173 // ======================================================================
1174 @Override
1175 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1176 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1177 != PackageManager.PERMISSION_GRANTED) {
1178 pw.println("Permission Denial: can't dump NotificationManager from from pid="
1179 + Binder.getCallingPid()
1180 + ", uid=" + Binder.getCallingUid());
1181 return;
1182 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 pw.println("Current Notification Manager state:");
1185
1186 int N;
1187
1188 synchronized (mToastQueue) {
1189 N = mToastQueue.size();
1190 if (N > 0) {
1191 pw.println(" Toast Queue:");
1192 for (int i=0; i<N; i++) {
1193 mToastQueue.get(i).dump(pw, " ");
1194 }
1195 pw.println(" ");
1196 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001197
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001198 }
1199
1200 synchronized (mNotificationList) {
1201 N = mNotificationList.size();
1202 if (N > 0) {
1203 pw.println(" Notification List:");
1204 for (int i=0; i<N; i++) {
1205 mNotificationList.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 N = mLights.size();
1211 if (N > 0) {
1212 pw.println(" Lights List:");
1213 for (int i=0; i<N; i++) {
1214 mLights.get(i).dump(pw, " ", mContext);
1215 }
1216 pw.println(" ");
1217 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001218
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001219 pw.println(" mSoundNotification=" + mSoundNotification);
1220 pw.println(" mSound=" + mSound);
1221 pw.println(" mVibrateNotification=" + mVibrateNotification);
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001222 pw.println(" mDisabledNotifications=0x" + Integer.toHexString(mDisabledNotifications));
1223 pw.println(" mSystemReady=" + mSystemReady);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001224 }
1225 }
1226}