blob: 0490190a382896ac0990f91dff35b582f894166a [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);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335 } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800336 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800337 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800338 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800339 String pkgList[] = null;
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800340 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800341 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800342 } else if (queryRestart) {
343 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800344 } else {
345 Uri uri = intent.getData();
346 if (uri == null) {
347 return;
348 }
349 String pkgName = uri.getSchemeSpecificPart();
350 if (pkgName == null) {
351 return;
352 }
353 pkgList = new String[]{pkgName};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800355 if (pkgList != null && (pkgList.length > 0)) {
356 for (String pkgName : pkgList) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800357 cancelAllNotificationsInt(pkgName, 0, 0, !queryRestart);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800358 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500360 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
361 mScreenOn = true;
362 updateNotificationPulse();
363 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
364 mScreenOn = false;
365 updateNotificationPulse();
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500366 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
367 mInCall = (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_OFFHOOK));
368 updateNotificationPulse();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 }
370 }
371 };
372
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700373 class SettingsObserver extends ContentObserver {
374 SettingsObserver(Handler handler) {
375 super(handler);
376 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800377
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700378 void observe() {
379 ContentResolver resolver = mContext.getContentResolver();
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500380 resolver.registerContentObserver(Settings.System.getUriFor(
381 Settings.System.NOTIFICATION_LIGHT_PULSE), false, this);
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700382 update();
383 }
384
385 @Override public void onChange(boolean selfChange) {
386 update();
387 }
388
389 public void update() {
390 ContentResolver resolver = mContext.getContentResolver();
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500391 boolean pulseEnabled = Settings.System.getInt(resolver,
392 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
393 if (mNotificationPulseEnabled != pulseEnabled) {
394 mNotificationPulseEnabled = pulseEnabled;
395 updateNotificationPulse();
396 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700397 }
398 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500399
Joe Onorato089de882010-04-12 08:18:45 -0700400 NotificationManagerService(Context context, StatusBarManagerService statusBar,
Mike Lockwood3a322132009-11-24 00:30:52 -0500401 LightsService lights)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 {
403 super();
404 mContext = context;
405 mAm = ActivityManagerNative.getDefault();
Jean-Michel Trivi211957f2010-03-26 18:19:33 -0700406 mSound = new NotificationPlayer(TAG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407 mSound.setUsesWakeLock(context);
408 mToastQueue = new ArrayList<ToastRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 mHandler = new WorkerHandler();
San Mehat3ee13172010-02-04 20:54:43 -0800410
Joe Onorato089de882010-04-12 08:18:45 -0700411 mStatusBar = statusBar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 statusBar.setNotificationCallbacks(mNotificationCallbacks);
413
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500414 mNotificationLight = lights.getLight(LightsService.LIGHT_ID_NOTIFICATIONS);
415 mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION);
416
Mike Lockwood670f9322010-01-20 12:13:36 -0500417 Resources resources = mContext.getResources();
418 mDefaultNotificationColor = resources.getColor(
419 com.android.internal.R.color.config_defaultNotificationColor);
420 mDefaultNotificationLedOn = resources.getInteger(
421 com.android.internal.R.integer.config_defaultNotificationLedOn);
422 mDefaultNotificationLedOff = resources.getInteger(
423 com.android.internal.R.integer.config_defaultNotificationLedOff);
424
Joe Onorato39f5b6a2009-07-23 12:29:19 -0400425 // Don't start allowing notifications until the setup wizard has run once.
426 // After that, including subsequent boots, init with notifications turned on.
427 // This works on the first boot because the setup wizard will toggle this
428 // flag at least once and we'll go back to 0 after that.
429 if (0 == Settings.Secure.getInt(mContext.getContentResolver(),
430 Settings.Secure.DEVICE_PROVISIONED, 0)) {
431 mDisabledNotifications = StatusBarManager.DISABLE_NOTIFICATION_ALERTS;
432 }
433
Mike Lockwood35e16bf2010-11-30 19:53:36 -0500434 // register for various Intents
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 IntentFilter filter = new IntentFilter();
Mike Lockwood770126a2010-12-09 22:30:37 -0800436 filter.addAction(UsbManager.ACTION_USB_STATE);
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500437 filter.addAction(Intent.ACTION_SCREEN_ON);
438 filter.addAction(Intent.ACTION_SCREEN_OFF);
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500439 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440 mContext.registerReceiver(mIntentReceiver, filter);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800441 IntentFilter pkgFilter = new IntentFilter();
442 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
443 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
444 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
445 pkgFilter.addDataScheme("package");
446 mContext.registerReceiver(mIntentReceiver, pkgFilter);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800447 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800448 mContext.registerReceiver(mIntentReceiver, sdFilter);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800449
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500450 SettingsObserver observer = new SettingsObserver(mHandler);
451 observer.observe();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 }
453
Joe Onorato30275482009-07-08 17:09:14 -0700454 void systemReady() {
455 // no beeping until we're basically done booting
456 mSystemReady = true;
457 }
458
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 // Toasts
460 // ============================================================================
461 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
462 {
Daniel Sandlera7035902010-03-30 15:45:31 -0400463 if (DBG) Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + " duration=" + duration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464
465 if (pkg == null || callback == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800466 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467 return ;
468 }
469
470 synchronized (mToastQueue) {
471 int callingPid = Binder.getCallingPid();
472 long callingId = Binder.clearCallingIdentity();
473 try {
474 ToastRecord record;
475 int index = indexOfToastLocked(pkg, callback);
476 // If it's already in the queue, we update it in place, we don't
477 // move it to the end of the queue.
478 if (index >= 0) {
479 record = mToastQueue.get(index);
480 record.update(duration);
481 } else {
482 record = new ToastRecord(callingPid, pkg, callback, duration);
483 mToastQueue.add(record);
484 index = mToastQueue.size() - 1;
485 keepProcessAliveLocked(callingPid);
486 }
487 // If it's at index 0, it's the current toast. It doesn't matter if it's
488 // new or just been updated. Call back and tell it to show itself.
489 // If the callback fails, this will remove it from the list, so don't
490 // assume that it's valid after this.
491 if (index == 0) {
492 showNextToastLocked();
493 }
494 } finally {
495 Binder.restoreCallingIdentity(callingId);
496 }
497 }
498 }
499
500 public void cancelToast(String pkg, ITransientNotification callback) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800501 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502
503 if (pkg == null || callback == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800504 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 return ;
506 }
507
508 synchronized (mToastQueue) {
509 long callingId = Binder.clearCallingIdentity();
510 try {
511 int index = indexOfToastLocked(pkg, callback);
512 if (index >= 0) {
513 cancelToastLocked(index);
514 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800515 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg + " callback=" + callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 }
517 } finally {
518 Binder.restoreCallingIdentity(callingId);
519 }
520 }
521 }
522
523 private void showNextToastLocked() {
524 ToastRecord record = mToastQueue.get(0);
525 while (record != null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800526 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800527 try {
528 record.callback.show();
529 scheduleTimeoutLocked(record, false);
530 return;
531 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800532 Slog.w(TAG, "Object died trying to show notification " + record.callback
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 + " in package " + record.pkg);
534 // remove it from the list and let the process die
535 int index = mToastQueue.indexOf(record);
536 if (index >= 0) {
537 mToastQueue.remove(index);
538 }
539 keepProcessAliveLocked(record.pid);
540 if (mToastQueue.size() > 0) {
541 record = mToastQueue.get(0);
542 } else {
543 record = null;
544 }
545 }
546 }
547 }
548
549 private void cancelToastLocked(int index) {
550 ToastRecord record = mToastQueue.get(index);
551 try {
552 record.callback.hide();
553 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800554 Slog.w(TAG, "Object died trying to hide notification " + record.callback
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555 + " in package " + record.pkg);
556 // don't worry about this, we're about to remove it from
557 // the list anyway
558 }
559 mToastQueue.remove(index);
560 keepProcessAliveLocked(record.pid);
561 if (mToastQueue.size() > 0) {
562 // Show the next one. If the callback fails, this will remove
563 // it from the list, so don't assume that the list hasn't changed
564 // after this point.
565 showNextToastLocked();
566 }
567 }
568
569 private void scheduleTimeoutLocked(ToastRecord r, boolean immediate)
570 {
571 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
572 long delay = immediate ? 0 : (r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY);
573 mHandler.removeCallbacksAndMessages(r);
574 mHandler.sendMessageDelayed(m, delay);
575 }
576
577 private void handleTimeout(ToastRecord record)
578 {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800579 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 synchronized (mToastQueue) {
581 int index = indexOfToastLocked(record.pkg, record.callback);
582 if (index >= 0) {
583 cancelToastLocked(index);
584 }
585 }
586 }
587
588 // lock on mToastQueue
589 private int indexOfToastLocked(String pkg, ITransientNotification callback)
590 {
591 IBinder cbak = callback.asBinder();
592 ArrayList<ToastRecord> list = mToastQueue;
593 int len = list.size();
594 for (int i=0; i<len; i++) {
595 ToastRecord r = list.get(i);
596 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
597 return i;
598 }
599 }
600 return -1;
601 }
602
603 // lock on mToastQueue
604 private void keepProcessAliveLocked(int pid)
605 {
606 int toastCount = 0; // toasts from this pid
607 ArrayList<ToastRecord> list = mToastQueue;
608 int N = list.size();
609 for (int i=0; i<N; i++) {
610 ToastRecord r = list.get(i);
611 if (r.pid == pid) {
612 toastCount++;
613 }
614 }
615 try {
616 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
617 } catch (RemoteException e) {
618 // Shouldn't happen.
619 }
620 }
621
622 private final class WorkerHandler extends Handler
623 {
624 @Override
625 public void handleMessage(Message msg)
626 {
627 switch (msg.what)
628 {
629 case MESSAGE_TIMEOUT:
630 handleTimeout((ToastRecord)msg.obj);
631 break;
632 }
633 }
634 }
635
636
637 // Notifications
638 // ============================================================================
Andy Stadler110988c2010-12-03 14:29:16 -0800639 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800640 public void enqueueNotification(String pkg, int id, Notification notification, int[] idOut)
641 {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700642 enqueueNotificationWithTag(pkg, null /* tag */, id, notification, idOut);
643 }
644
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400645 public void enqueueNotificationWithTag(String pkg, String tag, int id, Notification notification,
646 int[] idOut)
Fred Quintana6ecaff12009-09-25 14:23:13 -0700647 {
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400648 enqueueNotificationInternal(pkg, Binder.getCallingUid(), Binder.getCallingPid(),
649 tag, id, notification, idOut);
650 }
651
652 // Not exposed via Binder; for system use only (otherwise malicious apps could spoof the
653 // uid/pid of another application)
654 public void enqueueNotificationInternal(String pkg, int callingUid, int callingPid,
655 String tag, int id, Notification notification, int[] idOut)
656 {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700657 checkIncomingCall(pkg);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800658
Joe Onoratobd73d012010-06-04 11:44:54 -0700659 // Limit the number of notifications that any given package except the android
660 // package can enqueue. Prevents DOS attacks and deals with leaks.
661 if (!"android".equals(pkg)) {
662 synchronized (mNotificationList) {
663 int count = 0;
664 final int N = mNotificationList.size();
665 for (int i=0; i<N; i++) {
666 final NotificationRecord r = mNotificationList.get(i);
667 if (r.pkg.equals(pkg)) {
668 count++;
669 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
670 Slog.e(TAG, "Package has already posted " + count
671 + " notifications. Not showing more. package=" + pkg);
672 return;
673 }
674 }
675 }
676 }
677 }
678
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679 // This conditional is a dirty hack to limit the logging done on
680 // behalf of the download manager without affecting other apps.
681 if (!pkg.equals("com.android.providers.downloads")
682 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800683 EventLog.writeEvent(EventLogTags.NOTIFICATION_ENQUEUE, pkg, id, notification.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800684 }
685
686 if (pkg == null || notification == null) {
687 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
688 + " id=" + id + " notification=" + notification);
689 }
690 if (notification.icon != 0) {
691 if (notification.contentView == null) {
692 throw new IllegalArgumentException("contentView required: pkg=" + pkg
693 + " id=" + id + " notification=" + notification);
694 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 }
696
697 synchronized (mNotificationList) {
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700698 NotificationRecord r = new NotificationRecord(pkg, tag, id,
699 callingUid, callingPid, notification);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800700 NotificationRecord old = null;
701
Fred Quintana6ecaff12009-09-25 14:23:13 -0700702 int index = indexOfNotificationLocked(pkg, tag, id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800703 if (index < 0) {
704 mNotificationList.add(r);
705 } else {
706 old = mNotificationList.remove(index);
707 mNotificationList.add(index, r);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700708 // Make sure we don't lose the foreground service state.
709 if (old != null) {
710 notification.flags |=
711 old.notification.flags&Notification.FLAG_FOREGROUND_SERVICE;
712 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800713 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800714
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700715 // Ensure if this is a foreground service that the proper additional
716 // flags are set.
717 if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) {
718 notification.flags |= Notification.FLAG_ONGOING_EVENT
719 | Notification.FLAG_NO_CLEAR;
720 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800721
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800722 if (notification.icon != 0) {
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700723 StatusBarNotification n = new StatusBarNotification(pkg, id, tag,
724 r.uid, r.initialPid, notification);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800725 if (old != null && old.statusBarKey != null) {
726 r.statusBarKey = old.statusBarKey;
727 long identity = Binder.clearCallingIdentity();
728 try {
Joe Onorato18e69df2010-05-17 22:26:12 -0700729 mStatusBar.updateNotification(r.statusBarKey, n);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 }
731 finally {
732 Binder.restoreCallingIdentity(identity);
733 }
734 } else {
735 long identity = Binder.clearCallingIdentity();
736 try {
Joe Onorato18e69df2010-05-17 22:26:12 -0700737 r.statusBarKey = mStatusBar.addNotification(n);
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500738 mAttentionLight.pulse();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800739 }
740 finally {
741 Binder.restoreCallingIdentity(identity);
742 }
743 }
Joe Onorato30275482009-07-08 17:09:14 -0700744 sendAccessibilityEvent(notification, pkg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 } else {
746 if (old != null && old.statusBarKey != null) {
747 long identity = Binder.clearCallingIdentity();
748 try {
Joe Onorato0cbda992010-05-02 16:28:15 -0700749 mStatusBar.removeNotification(old.statusBarKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750 }
751 finally {
752 Binder.restoreCallingIdentity(identity);
753 }
754 }
755 }
756
757 // If we're not supposed to beep, vibrate, etc. then don't.
758 if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
759 && (!(old != null
Joe Onorato30275482009-07-08 17:09:14 -0700760 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
761 && mSystemReady) {
Eric Laurent524dc042009-11-27 05:07:55 -0800762
763 final AudioManager audioManager = (AudioManager) mContext
764 .getSystemService(Context.AUDIO_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 // sound
766 final boolean useDefaultSound =
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800767 (notification.defaults & Notification.DEFAULT_SOUND) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 if (useDefaultSound || notification.sound != null) {
769 Uri uri;
770 if (useDefaultSound) {
771 uri = Settings.System.DEFAULT_NOTIFICATION_URI;
772 } else {
773 uri = notification.sound;
774 }
775 boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0;
776 int audioStreamType;
777 if (notification.audioStreamType >= 0) {
778 audioStreamType = notification.audioStreamType;
779 } else {
780 audioStreamType = DEFAULT_STREAM_TYPE;
781 }
782 mSoundNotification = r;
Eric Laurent524dc042009-11-27 05:07:55 -0800783 // do not play notifications if stream volume is 0
784 // (typically because ringer mode is silent).
785 if (audioManager.getStreamVolume(audioStreamType) != 0) {
786 long identity = Binder.clearCallingIdentity();
787 try {
788 mSound.play(mContext, uri, looping, audioStreamType);
789 }
790 finally {
791 Binder.restoreCallingIdentity(identity);
792 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 }
794 }
795
796 // vibrate
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797 final boolean useDefaultVibrate =
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800798 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 if ((useDefaultVibrate || notification.vibrate != null)
800 && audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_NOTIFICATION)) {
801 mVibrateNotification = r;
802
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800803 mVibrator.vibrate(useDefaultVibrate ? DEFAULT_VIBRATE_PATTERN
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804 : notification.vibrate,
805 ((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
806 }
807 }
808
809 // this option doesn't shut off the lights
810
811 // light
812 // the most recent thing gets the light
813 mLights.remove(old);
814 if (mLedNotification == old) {
815 mLedNotification = null;
816 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800817 //Slog.i(TAG, "notification.lights="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 // + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS) != 0));
819 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {
820 mLights.add(r);
821 updateLightsLocked();
822 } else {
823 if (old != null
824 && ((old.notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0)) {
825 updateLightsLocked();
826 }
827 }
828 }
829
830 idOut[0] = id;
831 }
832
Joe Onorato30275482009-07-08 17:09:14 -0700833 private void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
svetoslavganov75986cf2009-05-14 22:28:01 -0700834 AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
835 if (!manager.isEnabled()) {
836 return;
837 }
838
839 AccessibilityEvent event =
840 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
841 event.setPackageName(packageName);
842 event.setClassName(Notification.class.getName());
843 event.setParcelableData(notification);
844 CharSequence tickerText = notification.tickerText;
845 if (!TextUtils.isEmpty(tickerText)) {
846 event.getText().add(tickerText);
847 }
848
849 manager.sendAccessibilityEvent(event);
850 }
851
Joe Onorato46439ce2010-11-19 13:56:21 -0800852 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete) {
853 // tell the app
854 if (sendDelete) {
855 if (r.notification.deleteIntent != null) {
856 try {
857 r.notification.deleteIntent.send();
858 } catch (PendingIntent.CanceledException ex) {
859 // do nothing - there's no relevant way to recover, and
860 // no reason to let this propagate
861 Slog.w(TAG, "canceled PendingIntent for " + r.pkg, ex);
862 }
863 }
864 }
865
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866 // status bar
867 if (r.notification.icon != 0) {
868 long identity = Binder.clearCallingIdentity();
869 try {
Joe Onorato0cbda992010-05-02 16:28:15 -0700870 mStatusBar.removeNotification(r.statusBarKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871 }
872 finally {
873 Binder.restoreCallingIdentity(identity);
874 }
875 r.statusBarKey = null;
876 }
877
878 // sound
879 if (mSoundNotification == r) {
880 mSoundNotification = null;
881 long identity = Binder.clearCallingIdentity();
882 try {
883 mSound.stop();
884 }
885 finally {
886 Binder.restoreCallingIdentity(identity);
887 }
888 }
889
890 // vibrate
891 if (mVibrateNotification == r) {
892 mVibrateNotification = null;
893 long identity = Binder.clearCallingIdentity();
894 try {
895 mVibrator.cancel();
896 }
897 finally {
898 Binder.restoreCallingIdentity(identity);
899 }
900 }
901
902 // light
903 mLights.remove(r);
904 if (mLedNotification == r) {
905 mLedNotification = null;
906 }
907 }
908
909 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700910 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800911 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800912 */
Fred Quintana6ecaff12009-09-25 14:23:13 -0700913 private void cancelNotification(String pkg, String tag, int id, int mustHaveFlags,
Joe Onorato46439ce2010-11-19 13:56:21 -0800914 int mustNotHaveFlags, boolean sendDelete) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800915 EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL, pkg, id, mustHaveFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800916
917 synchronized (mNotificationList) {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700918 int index = indexOfNotificationLocked(pkg, tag, id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800919 if (index >= 0) {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700920 NotificationRecord r = mNotificationList.get(index);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800921
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800922 if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {
923 return;
924 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700925 if ((r.notification.flags & mustNotHaveFlags) != 0) {
926 return;
927 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800928
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800929 mNotificationList.remove(index);
930
Joe Onorato46439ce2010-11-19 13:56:21 -0800931 cancelNotificationLocked(r, sendDelete);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932 updateLightsLocked();
933 }
934 }
935 }
936
937 /**
938 * Cancels all notifications from a given package that have all of the
939 * {@code mustHaveFlags}.
940 */
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800941 boolean cancelAllNotificationsInt(String pkg, int mustHaveFlags,
942 int mustNotHaveFlags, boolean doit) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800943 EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL_ALL, pkg, mustHaveFlags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800944
945 synchronized (mNotificationList) {
946 final int N = mNotificationList.size();
947 boolean canceledSomething = false;
948 for (int i = N-1; i >= 0; --i) {
949 NotificationRecord r = mNotificationList.get(i);
950 if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {
951 continue;
952 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700953 if ((r.notification.flags & mustNotHaveFlags) != 0) {
954 continue;
955 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 if (!r.pkg.equals(pkg)) {
957 continue;
958 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800959 canceledSomething = true;
960 if (!doit) {
961 return true;
962 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963 mNotificationList.remove(i);
Joe Onorato46439ce2010-11-19 13:56:21 -0800964 cancelNotificationLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 }
966 if (canceledSomething) {
967 updateLightsLocked();
968 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800969 return canceledSomething;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 }
971 }
972
Andy Stadler110988c2010-12-03 14:29:16 -0800973 @Deprecated
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700974 public void cancelNotification(String pkg, int id) {
Fred Quintana6ecaff12009-09-25 14:23:13 -0700975 cancelNotificationWithTag(pkg, null /* tag */, id);
976 }
977
978 public void cancelNotificationWithTag(String pkg, String tag, int id) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700979 checkIncomingCall(pkg);
980 // Don't allow client applications to cancel foreground service notis.
Fred Quintana6ecaff12009-09-25 14:23:13 -0700981 cancelNotification(pkg, tag, id, 0,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700982 Binder.getCallingUid() == Process.SYSTEM_UID
Joe Onorato46439ce2010-11-19 13:56:21 -0800983 ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 }
985
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700986 public void cancelAllNotifications(String pkg) {
987 checkIncomingCall(pkg);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800988
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700989 // Calling from user space, don't allow the canceling of actively
990 // running foreground services.
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800991 cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800992 }
993
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700994 void checkIncomingCall(String pkg) {
995 int uid = Binder.getCallingUid();
996 if (uid == Process.SYSTEM_UID || uid == 0) {
997 return;
998 }
999 try {
1000 ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(
1001 pkg, 0);
1002 if (ai.uid != uid) {
1003 throw new SecurityException("Calling uid " + uid + " gave package"
1004 + pkg + " which is owned by uid " + ai.uid);
1005 }
1006 } catch (PackageManager.NameNotFoundException e) {
1007 throw new SecurityException("Unknown package " + pkg);
1008 }
1009 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001010
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07001011 void cancelAll() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 synchronized (mNotificationList) {
1013 final int N = mNotificationList.size();
1014 for (int i=N-1; i>=0; i--) {
1015 NotificationRecord r = mNotificationList.get(i);
1016
1017 if ((r.notification.flags & (Notification.FLAG_ONGOING_EVENT
1018 | Notification.FLAG_NO_CLEAR)) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 mNotificationList.remove(i);
Joe Onorato46439ce2010-11-19 13:56:21 -08001020 cancelNotificationLocked(r, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021 }
1022 }
1023
1024 updateLightsLocked();
1025 }
1026 }
1027
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 // lock on mNotificationList
1029 private void updateLightsLocked()
1030 {
Mike Lockwood2117f6f2010-09-09 09:48:08 -04001031 // clear pending pulse notification if screen is on
1032 if (mScreenOn || mLedNotification == null) {
1033 mPendingPulseNotification = false;
1034 }
1035
The Android Open Source Project10592532009-03-18 17:39:46 -07001036 // handle notification lights
1037 if (mLedNotification == null) {
1038 // get next notification, if any
1039 int n = mLights.size();
1040 if (n > 0) {
1041 mLedNotification = mLights.get(n-1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001042 }
Mike Lockwood2117f6f2010-09-09 09:48:08 -04001043 if (mLedNotification != null && !mScreenOn) {
1044 mPendingPulseNotification = true;
1045 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001047
1048 // we only flash if screen is off and persistent pulsing is enabled
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001049 // and we are not currently in a call
Mike Lockwood2117f6f2010-09-09 09:48:08 -04001050 if (!mPendingPulseNotification || mScreenOn || mInCall) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001051 mNotificationLight.turnOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07001052 } else {
Mike Lockwood670f9322010-01-20 12:13:36 -05001053 int ledARGB = mLedNotification.notification.ledARGB;
1054 int ledOnMS = mLedNotification.notification.ledOnMS;
1055 int ledOffMS = mLedNotification.notification.ledOffMS;
1056 if ((mLedNotification.notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {
1057 ledARGB = mDefaultNotificationColor;
1058 ledOnMS = mDefaultNotificationLedOn;
1059 ledOffMS = mDefaultNotificationLedOff;
1060 }
1061 if (mNotificationPulseEnabled) {
1062 // pulse repeatedly
1063 mNotificationLight.setFlashing(ledARGB, LightsService.LIGHT_FLASH_TIMED,
1064 ledOnMS, ledOffMS);
1065 } else {
1066 // pulse only once
1067 mNotificationLight.pulse(ledARGB, ledOnMS);
1068 }
The Android Open Source Project10592532009-03-18 17:39:46 -07001069 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001070 }
1071
1072 // lock on mNotificationList
Fred Quintana6ecaff12009-09-25 14:23:13 -07001073 private int indexOfNotificationLocked(String pkg, String tag, int id)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074 {
1075 ArrayList<NotificationRecord> list = mNotificationList;
1076 final int len = list.size();
1077 for (int i=0; i<len; i++) {
1078 NotificationRecord r = list.get(i);
Fred Quintana6ecaff12009-09-25 14:23:13 -07001079 if (tag == null) {
1080 if (r.tag != null) {
1081 continue;
1082 }
1083 } else {
1084 if (!tag.equals(r.tag)) {
1085 continue;
1086 }
1087 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001088 if (r.id == id && r.pkg.equals(pkg)) {
1089 return i;
1090 }
1091 }
1092 return -1;
1093 }
1094
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001095 // This is here instead of StatusBarPolicy because it is an important
1096 // security feature that we don't want people customizing the platform
1097 // to accidentally lose.
Mike Lockwoodff2544c2010-06-28 09:17:50 -04001098 private void updateAdbNotification(boolean adbEnabled) {
1099 if (adbEnabled) {
Mike Lockwooded760372009-07-09 07:07:27 -04001100 if ("0".equals(SystemProperties.get("persist.adb.notify"))) {
1101 return;
1102 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001103 if (!mAdbNotificationShown) {
1104 NotificationManager notificationManager = (NotificationManager) mContext
1105 .getSystemService(Context.NOTIFICATION_SERVICE);
1106 if (notificationManager != null) {
1107 Resources r = mContext.getResources();
1108 CharSequence title = r.getText(
1109 com.android.internal.R.string.adb_active_notification_title);
1110 CharSequence message = r.getText(
1111 com.android.internal.R.string.adb_active_notification_message);
1112
1113 if (mAdbNotification == null) {
1114 mAdbNotification = new Notification();
Daniel Sandler39576c82010-03-25 16:02:33 -04001115 mAdbNotification.icon = com.android.internal.R.drawable.stat_sys_adb;
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001116 mAdbNotification.when = 0;
1117 mAdbNotification.flags = Notification.FLAG_ONGOING_EVENT;
1118 mAdbNotification.tickerText = title;
Daniel Sandler39576c82010-03-25 16:02:33 -04001119 mAdbNotification.defaults = 0; // please be quiet
1120 mAdbNotification.sound = null;
1121 mAdbNotification.vibrate = null;
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001122 }
1123
1124 Intent intent = new Intent(
1125 Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
1126 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
1127 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
1128 // Note: we are hard-coding the component because this is
1129 // an important security UI that we don't want anyone
1130 // intercepting.
1131 intent.setComponent(new ComponentName("com.android.settings",
1132 "com.android.settings.DevelopmentSettings"));
1133 PendingIntent pi = PendingIntent.getActivity(mContext, 0,
1134 intent, 0);
1135
1136 mAdbNotification.setLatestEventInfo(mContext, title, message, pi);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001137
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001138 mAdbNotificationShown = true;
1139 notificationManager.notify(
1140 com.android.internal.R.string.adb_active_notification_title,
1141 mAdbNotification);
1142 }
1143 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001144
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001145 } else if (mAdbNotificationShown) {
1146 NotificationManager notificationManager = (NotificationManager) mContext
1147 .getSystemService(Context.NOTIFICATION_SERVICE);
1148 if (notificationManager != null) {
1149 mAdbNotificationShown = false;
1150 notificationManager.cancel(
1151 com.android.internal.R.string.adb_active_notification_title);
1152 }
1153 }
1154 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001155
1156 private void updateNotificationPulse() {
1157 synchronized (mNotificationList) {
1158 updateLightsLocked();
1159 }
1160 }
1161
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 // ======================================================================
1163 @Override
1164 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1165 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1166 != PackageManager.PERMISSION_GRANTED) {
1167 pw.println("Permission Denial: can't dump NotificationManager from from pid="
1168 + Binder.getCallingPid()
1169 + ", uid=" + Binder.getCallingUid());
1170 return;
1171 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001172
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001173 pw.println("Current Notification Manager state:");
1174
1175 int N;
1176
1177 synchronized (mToastQueue) {
1178 N = mToastQueue.size();
1179 if (N > 0) {
1180 pw.println(" Toast Queue:");
1181 for (int i=0; i<N; i++) {
1182 mToastQueue.get(i).dump(pw, " ");
1183 }
1184 pw.println(" ");
1185 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001187 }
1188
1189 synchronized (mNotificationList) {
1190 N = mNotificationList.size();
1191 if (N > 0) {
1192 pw.println(" Notification List:");
1193 for (int i=0; i<N; i++) {
1194 mNotificationList.get(i).dump(pw, " ", mContext);
1195 }
1196 pw.println(" ");
1197 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001198
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001199 N = mLights.size();
1200 if (N > 0) {
1201 pw.println(" Lights List:");
1202 for (int i=0; i<N; i++) {
1203 mLights.get(i).dump(pw, " ", mContext);
1204 }
1205 pw.println(" ");
1206 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001207
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001208 pw.println(" mSoundNotification=" + mSoundNotification);
1209 pw.println(" mSound=" + mSound);
1210 pw.println(" mVibrateNotification=" + mVibrateNotification);
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001211 pw.println(" mDisabledNotifications=0x" + Integer.toHexString(mDisabledNotifications));
1212 pw.println(" mSystemReady=" + mSystemReady);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001213 }
1214 }
1215}