NotificationManagerService.java revision 760ea554d0022fd88bbe13e3ef7c75cbe8613af6
1/* 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.notification; 18 19import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; 20import static org.xmlpull.v1.XmlPullParser.END_TAG; 21import static org.xmlpull.v1.XmlPullParser.START_TAG; 22 23import android.app.ActivityManager; 24import android.app.ActivityManagerNative; 25import android.app.AppGlobals; 26import android.app.AppOpsManager; 27import android.app.IActivityManager; 28import android.app.INotificationManager; 29import android.app.ITransientNotification; 30import android.app.Notification; 31import android.app.PendingIntent; 32import android.app.StatusBarManager; 33import android.content.BroadcastReceiver; 34import android.content.ComponentName; 35import android.content.ContentResolver; 36import android.content.Context; 37import android.content.Intent; 38import android.content.IntentFilter; 39import android.content.ServiceConnection; 40import android.content.pm.ApplicationInfo; 41import android.content.pm.PackageInfo; 42import android.content.pm.PackageManager; 43import android.content.pm.ResolveInfo; 44import android.content.pm.ServiceInfo; 45import android.content.pm.PackageManager.NameNotFoundException; 46import android.content.pm.UserInfo; 47import android.content.res.Resources; 48import android.database.ContentObserver; 49import android.graphics.Bitmap; 50import android.media.AudioManager; 51import android.media.IRingtonePlayer; 52import android.net.Uri; 53import android.os.Binder; 54import android.os.Handler; 55import android.os.IBinder; 56import android.os.Message; 57import android.os.Process; 58import android.os.RemoteException; 59import android.os.UserHandle; 60import android.os.UserManager; 61import android.os.Vibrator; 62import android.provider.Settings; 63import android.service.notification.INotificationListener; 64import android.service.notification.NotificationListenerService; 65import android.service.notification.StatusBarNotification; 66import android.telephony.TelephonyManager; 67import android.text.TextUtils; 68import android.util.ArrayMap; 69import android.util.AtomicFile; 70import android.util.Log; 71import android.util.Slog; 72import android.util.SparseArray; 73import android.util.Xml; 74import android.view.accessibility.AccessibilityEvent; 75import android.view.accessibility.AccessibilityManager; 76import android.widget.Toast; 77 78import com.android.internal.R; 79import com.android.internal.notification.NotificationScorer; 80import com.android.server.EventLogTags; 81import com.android.server.notification.NotificationUsageStats.SingleNotificationStats; 82import com.android.server.statusbar.StatusBarManagerInternal; 83import com.android.server.SystemService; 84import com.android.server.lights.Light; 85import com.android.server.lights.LightsManager; 86 87import org.xmlpull.v1.XmlPullParser; 88import org.xmlpull.v1.XmlPullParserException; 89 90import java.io.File; 91import java.io.FileDescriptor; 92import java.io.FileInputStream; 93import java.io.FileNotFoundException; 94import java.io.IOException; 95import java.io.PrintWriter; 96import java.lang.reflect.Array; 97import java.util.ArrayDeque; 98import java.util.ArrayList; 99import java.util.Arrays; 100import java.util.HashSet; 101import java.util.Iterator; 102import java.util.List; 103import java.util.NoSuchElementException; 104import java.util.Set; 105 106import libcore.io.IoUtils; 107 108/** {@hide} */ 109public class NotificationManagerService extends SystemService { 110 static final String TAG = "NotificationService"; 111 static final boolean DBG = false; 112 113 static final int MAX_PACKAGE_NOTIFICATIONS = 50; 114 115 // message codes 116 static final int MESSAGE_TIMEOUT = 2; 117 118 static final int LONG_DELAY = 3500; // 3.5 seconds 119 static final int SHORT_DELAY = 2000; // 2 seconds 120 121 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250}; 122 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps 123 124 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION; 125 static final boolean SCORE_ONGOING_HIGHER = false; 126 127 static final int JUNK_SCORE = -1000; 128 static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; 129 static final int SCORE_DISPLAY_THRESHOLD = Notification.PRIORITY_MIN * NOTIFICATION_PRIORITY_MULTIPLIER; 130 131 // Notifications with scores below this will not interrupt the user, either via LED or 132 // sound or vibration 133 static final int SCORE_INTERRUPTION_THRESHOLD = 134 Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER; 135 136 static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true; 137 static final boolean ENABLE_BLOCKED_TOASTS = true; 138 139 static final String ENABLED_NOTIFICATION_LISTENERS_SEPARATOR = ":"; 140 141 private IActivityManager mAm; 142 AudioManager mAudioManager; 143 StatusBarManagerInternal mStatusBar; 144 Vibrator mVibrator; 145 146 final IBinder mForegroundToken = new Binder(); 147 private WorkerHandler mHandler; 148 149 private Light mNotificationLight; 150 Light mAttentionLight; 151 private int mDefaultNotificationColor; 152 private int mDefaultNotificationLedOn; 153 154 private int mDefaultNotificationLedOff; 155 private long[] mDefaultVibrationPattern; 156 157 private long[] mFallbackVibrationPattern; 158 boolean mSystemReady; 159 160 private boolean mDisableNotificationAlerts; 161 NotificationRecord mSoundNotification; 162 NotificationRecord mVibrateNotification; 163 164 // for enabling and disabling notification pulse behavior 165 private boolean mScreenOn = true; 166 private boolean mInCall = false; 167 private boolean mNotificationPulseEnabled; 168 169 // used as a mutex for access to all active notifications & listeners 170 final ArrayList<NotificationRecord> mNotificationList = 171 new ArrayList<NotificationRecord>(); 172 final ArrayMap<String, NotificationRecord> mNotificationsByKey = 173 new ArrayMap<String, NotificationRecord>(); 174 final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>(); 175 176 ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>(); 177 NotificationRecord mLedNotification; 178 179 private AppOpsManager mAppOps; 180 181 // contains connections to all connected listeners, including app services 182 // and system listeners 183 private ArrayList<NotificationListenerInfo> mListeners 184 = new ArrayList<NotificationListenerInfo>(); 185 // things that will be put into mListeners as soon as they're ready 186 private ArrayList<String> mServicesBinding = new ArrayList<String>(); 187 // lists the component names of all enabled (and therefore connected) listener 188 // app services for the current user only 189 private HashSet<ComponentName> mEnabledListenersForCurrentUser 190 = new HashSet<ComponentName>(); 191 // Just the packages from mEnabledListenersForCurrentUser 192 private HashSet<String> mEnabledListenerPackageNames = new HashSet<String>(); 193 194 // Notification control database. For now just contains disabled packages. 195 private AtomicFile mPolicyFile; 196 private HashSet<String> mBlockedPackages = new HashSet<String>(); 197 198 private static final int DB_VERSION = 1; 199 200 private static final String TAG_BODY = "notification-policy"; 201 private static final String ATTR_VERSION = "version"; 202 203 private static final String TAG_BLOCKED_PKGS = "blocked-packages"; 204 private static final String TAG_PACKAGE = "package"; 205 private static final String ATTR_NAME = "name"; 206 207 final ArrayList<NotificationScorer> mScorers = new ArrayList<NotificationScorer>(); 208 209 private final NotificationUsageStats mUsageStats = new NotificationUsageStats(); 210 211 private int mZenMode; 212 // temporary, until we update apps to provide metadata 213 private static final Set<String> CALL_PACKAGES = new HashSet<String>(Arrays.asList( 214 "com.google.android.dialer", 215 "com.android.phone" 216 )); 217 private static final Set<String> ALARM_PACKAGES = new HashSet<String>(Arrays.asList( 218 "com.google.android.deskclock" 219 )); 220 private static final String EXTRA_INTERCEPT = "android.intercept"; 221 222 // Profiles of the current user. 223 final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>(); 224 225 private static final int MY_UID = Process.myUid(); 226 private static final int MY_PID = Process.myPid(); 227 private static final int REASON_DELEGATE_CLICK = 1; 228 private static final int REASON_DELEGATE_CANCEL = 2; 229 private static final int REASON_DELEGATE_CANCEL_ALL = 3; 230 private static final int REASON_DELEGATE_ERROR = 4; 231 private static final int REASON_PACKAGE_CHANGED = 5; 232 private static final int REASON_USER_STOPPED = 6; 233 private static final int REASON_PACKAGE_BANNED = 7; 234 private static final int REASON_NOMAN_CANCEL = 8; 235 private static final int REASON_NOMAN_CANCEL_ALL = 9; 236 private static final int REASON_LISTENER_CANCEL = 10; 237 private static final int REASON_LISTENER_CANCEL_ALL = 11; 238 239 private class NotificationListenerInfo implements IBinder.DeathRecipient { 240 INotificationListener listener; 241 ComponentName component; 242 int userid; 243 boolean isSystem; 244 ServiceConnection connection; 245 246 public NotificationListenerInfo(INotificationListener listener, ComponentName component, 247 int userid, boolean isSystem) { 248 this.listener = listener; 249 this.component = component; 250 this.userid = userid; 251 this.isSystem = isSystem; 252 this.connection = null; 253 } 254 255 public NotificationListenerInfo(INotificationListener listener, ComponentName component, 256 int userid, ServiceConnection connection) { 257 this.listener = listener; 258 this.component = component; 259 this.userid = userid; 260 this.isSystem = false; 261 this.connection = connection; 262 } 263 264 boolean enabledAndUserMatches(StatusBarNotification sbn) { 265 final int nid = sbn.getUserId(); 266 if (!isEnabledForCurrentUser()) { 267 return false; 268 } 269 if (this.userid == UserHandle.USER_ALL) return true; 270 return (nid == UserHandle.USER_ALL || nid == this.userid); 271 } 272 273 public void notifyPostedIfUserMatch(StatusBarNotification sbn) { 274 if (!enabledAndUserMatches(sbn)) { 275 return; 276 } 277 try { 278 listener.onNotificationPosted(sbn); 279 } catch (RemoteException ex) { 280 Log.e(TAG, "unable to notify listener (posted): " + listener, ex); 281 } 282 } 283 284 public void notifyRemovedIfUserMatch(StatusBarNotification sbn) { 285 if (!enabledAndUserMatches(sbn)) return; 286 try { 287 listener.onNotificationRemoved(sbn); 288 } catch (RemoteException ex) { 289 Log.e(TAG, "unable to notify listener (removed): " + listener, ex); 290 } 291 } 292 293 @Override 294 public void binderDied() { 295 // Remove the listener, but don't unbind from the service. The system will bring the 296 // service back up, and the onServiceConnected handler will readd the listener with the 297 // new binding. If this isn't a bound service, and is just a registered 298 // INotificationListener, just removing it from the list is all we need to do anyway. 299 removeListenerImpl(this.listener, this.userid); 300 } 301 302 /** convenience method for looking in mEnabledListenersForCurrentUser */ 303 public boolean isEnabledForCurrentUser() { 304 if (this.isSystem) return true; 305 if (this.connection == null) return false; 306 return mEnabledListenersForCurrentUser.contains(this.component); 307 } 308 } 309 310 private static class Archive { 311 static final int BUFFER_SIZE = 250; 312 ArrayDeque<StatusBarNotification> mBuffer = new ArrayDeque<StatusBarNotification>(BUFFER_SIZE); 313 314 public Archive() { 315 } 316 317 public String toString() { 318 final StringBuilder sb = new StringBuilder(); 319 final int N = mBuffer.size(); 320 sb.append("Archive ("); 321 sb.append(N); 322 sb.append(" notification"); 323 sb.append((N==1)?")":"s)"); 324 return sb.toString(); 325 } 326 327 public void record(StatusBarNotification nr) { 328 if (mBuffer.size() == BUFFER_SIZE) { 329 mBuffer.removeFirst(); 330 } 331 332 // We don't want to store the heavy bits of the notification in the archive, 333 // but other clients in the system process might be using the object, so we 334 // store a (lightened) copy. 335 mBuffer.addLast(nr.cloneLight()); 336 } 337 338 339 public void clear() { 340 mBuffer.clear(); 341 } 342 343 public Iterator<StatusBarNotification> descendingIterator() { 344 return mBuffer.descendingIterator(); 345 } 346 public Iterator<StatusBarNotification> ascendingIterator() { 347 return mBuffer.iterator(); 348 } 349 public Iterator<StatusBarNotification> filter( 350 final Iterator<StatusBarNotification> iter, final String pkg, final int userId) { 351 return new Iterator<StatusBarNotification>() { 352 StatusBarNotification mNext = findNext(); 353 354 private StatusBarNotification findNext() { 355 while (iter.hasNext()) { 356 StatusBarNotification nr = iter.next(); 357 if ((pkg == null || nr.getPackageName() == pkg) 358 && (userId == UserHandle.USER_ALL || nr.getUserId() == userId)) { 359 return nr; 360 } 361 } 362 return null; 363 } 364 365 @Override 366 public boolean hasNext() { 367 return mNext == null; 368 } 369 370 @Override 371 public StatusBarNotification next() { 372 StatusBarNotification next = mNext; 373 if (next == null) { 374 throw new NoSuchElementException(); 375 } 376 mNext = findNext(); 377 return next; 378 } 379 380 @Override 381 public void remove() { 382 iter.remove(); 383 } 384 }; 385 } 386 387 public StatusBarNotification[] getArray(int count) { 388 if (count == 0) count = Archive.BUFFER_SIZE; 389 final StatusBarNotification[] a 390 = new StatusBarNotification[Math.min(count, mBuffer.size())]; 391 Iterator<StatusBarNotification> iter = descendingIterator(); 392 int i=0; 393 while (iter.hasNext() && i < count) { 394 a[i++] = iter.next(); 395 } 396 return a; 397 } 398 399 public StatusBarNotification[] getArray(int count, String pkg, int userId) { 400 if (count == 0) count = Archive.BUFFER_SIZE; 401 final StatusBarNotification[] a 402 = new StatusBarNotification[Math.min(count, mBuffer.size())]; 403 Iterator<StatusBarNotification> iter = filter(descendingIterator(), pkg, userId); 404 int i=0; 405 while (iter.hasNext() && i < count) { 406 a[i++] = iter.next(); 407 } 408 return a; 409 } 410 411 } 412 413 Archive mArchive = new Archive(); 414 415 private void loadBlockDb() { 416 synchronized(mBlockedPackages) { 417 if (mPolicyFile == null) { 418 File dir = new File("/data/system"); 419 mPolicyFile = new AtomicFile(new File(dir, "notification_policy.xml")); 420 421 mBlockedPackages.clear(); 422 423 FileInputStream infile = null; 424 try { 425 infile = mPolicyFile.openRead(); 426 final XmlPullParser parser = Xml.newPullParser(); 427 parser.setInput(infile, null); 428 429 int type; 430 String tag; 431 int version = DB_VERSION; 432 while ((type = parser.next()) != END_DOCUMENT) { 433 tag = parser.getName(); 434 if (type == START_TAG) { 435 if (TAG_BODY.equals(tag)) { 436 version = Integer.parseInt( 437 parser.getAttributeValue(null, ATTR_VERSION)); 438 } else if (TAG_BLOCKED_PKGS.equals(tag)) { 439 while ((type = parser.next()) != END_DOCUMENT) { 440 tag = parser.getName(); 441 if (TAG_PACKAGE.equals(tag)) { 442 mBlockedPackages.add( 443 parser.getAttributeValue(null, ATTR_NAME)); 444 } else if (TAG_BLOCKED_PKGS.equals(tag) && type == END_TAG) { 445 break; 446 } 447 } 448 } 449 } 450 } 451 } catch (FileNotFoundException e) { 452 // No data yet 453 } catch (IOException e) { 454 Log.wtf(TAG, "Unable to read blocked notifications database", e); 455 } catch (NumberFormatException e) { 456 Log.wtf(TAG, "Unable to parse blocked notifications database", e); 457 } catch (XmlPullParserException e) { 458 Log.wtf(TAG, "Unable to parse blocked notifications database", e); 459 } finally { 460 IoUtils.closeQuietly(infile); 461 } 462 } 463 } 464 } 465 466 /** Use this when you actually want to post a notification or toast. 467 * 468 * Unchecked. Not exposed via Binder, but can be called in the course of enqueue*(). 469 */ 470 private boolean noteNotificationOp(String pkg, int uid) { 471 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg) 472 != AppOpsManager.MODE_ALLOWED) { 473 Slog.v(TAG, "notifications are disabled by AppOps for " + pkg); 474 return false; 475 } 476 return true; 477 } 478 479 private static String idDebugString(Context baseContext, String packageName, int id) { 480 Context c = null; 481 482 if (packageName != null) { 483 try { 484 c = baseContext.createPackageContext(packageName, 0); 485 } catch (NameNotFoundException e) { 486 c = baseContext; 487 } 488 } else { 489 c = baseContext; 490 } 491 492 String pkg; 493 String type; 494 String name; 495 496 Resources r = c.getResources(); 497 try { 498 return r.getResourceName(id); 499 } catch (Resources.NotFoundException e) { 500 return "<name unknown>"; 501 } 502 } 503 504 505 /** 506 * Remove notification access for any services that no longer exist. 507 */ 508 void disableNonexistentListeners() { 509 int currentUser = ActivityManager.getCurrentUser(); 510 String flatIn = Settings.Secure.getStringForUser( 511 getContext().getContentResolver(), 512 Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, 513 currentUser); 514 if (!TextUtils.isEmpty(flatIn)) { 515 if (DBG) Slog.v(TAG, "flat before: " + flatIn); 516 PackageManager pm = getContext().getPackageManager(); 517 List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser( 518 new Intent(NotificationListenerService.SERVICE_INTERFACE), 519 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA, 520 currentUser); 521 522 Set<ComponentName> installed = new HashSet<ComponentName>(); 523 for (int i = 0, count = installedServices.size(); i < count; i++) { 524 ResolveInfo resolveInfo = installedServices.get(i); 525 ServiceInfo info = resolveInfo.serviceInfo; 526 527 if (!android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE.equals( 528 info.permission)) { 529 Slog.w(TAG, "Skipping notification listener service " 530 + info.packageName + "/" + info.name 531 + ": it does not require the permission " 532 + android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE); 533 continue; 534 } 535 installed.add(new ComponentName(info.packageName, info.name)); 536 } 537 538 String flatOut = ""; 539 if (!installed.isEmpty()) { 540 String[] enabled = flatIn.split(ENABLED_NOTIFICATION_LISTENERS_SEPARATOR); 541 ArrayList<String> remaining = new ArrayList<String>(enabled.length); 542 for (int i = 0; i < enabled.length; i++) { 543 ComponentName enabledComponent = ComponentName.unflattenFromString(enabled[i]); 544 if (installed.contains(enabledComponent)) { 545 remaining.add(enabled[i]); 546 } 547 } 548 flatOut = TextUtils.join(ENABLED_NOTIFICATION_LISTENERS_SEPARATOR, remaining); 549 } 550 if (DBG) Slog.v(TAG, "flat after: " + flatOut); 551 if (!flatIn.equals(flatOut)) { 552 Settings.Secure.putStringForUser(getContext().getContentResolver(), 553 Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, 554 flatOut, currentUser); 555 } 556 } 557 } 558 559 /** 560 * Called whenever packages change, the user switches, or ENABLED_NOTIFICATION_LISTENERS 561 * is altered. (For example in response to USER_SWITCHED in our broadcast receiver) 562 */ 563 void rebindListenerServices() { 564 final int currentUser = ActivityManager.getCurrentUser(); 565 String flat = Settings.Secure.getStringForUser( 566 getContext().getContentResolver(), 567 Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, 568 currentUser); 569 570 NotificationListenerInfo[] toRemove = new NotificationListenerInfo[mListeners.size()]; 571 final ArrayList<ComponentName> toAdd; 572 573 synchronized (mNotificationList) { 574 // unbind and remove all existing listeners 575 toRemove = mListeners.toArray(toRemove); 576 577 toAdd = new ArrayList<ComponentName>(); 578 final HashSet<ComponentName> newEnabled = new HashSet<ComponentName>(); 579 final HashSet<String> newPackages = new HashSet<String>(); 580 581 // decode the list of components 582 if (flat != null) { 583 String[] components = flat.split(ENABLED_NOTIFICATION_LISTENERS_SEPARATOR); 584 for (int i=0; i<components.length; i++) { 585 final ComponentName component 586 = ComponentName.unflattenFromString(components[i]); 587 if (component != null) { 588 newEnabled.add(component); 589 toAdd.add(component); 590 newPackages.add(component.getPackageName()); 591 } 592 } 593 594 mEnabledListenersForCurrentUser = newEnabled; 595 mEnabledListenerPackageNames = newPackages; 596 } 597 } 598 599 for (NotificationListenerInfo info : toRemove) { 600 final ComponentName component = info.component; 601 final int oldUser = info.userid; 602 Slog.v(TAG, "disabling notification listener for user " + oldUser + ": " + component); 603 unregisterListenerService(component, info.userid); 604 } 605 606 final int N = toAdd.size(); 607 for (int i=0; i<N; i++) { 608 final ComponentName component = toAdd.get(i); 609 Slog.v(TAG, "enabling notification listener for user " + currentUser + ": " 610 + component); 611 registerListenerService(component, currentUser); 612 } 613 } 614 615 616 /** 617 * Version of registerListener that takes the name of a 618 * {@link android.service.notification.NotificationListenerService} to bind to. 619 * 620 * This is the mechanism by which third parties may subscribe to notifications. 621 */ 622 private void registerListenerService(final ComponentName name, final int userid) { 623 checkCallerIsSystem(); 624 625 if (DBG) Slog.v(TAG, "registerListenerService: " + name + " u=" + userid); 626 627 synchronized (mNotificationList) { 628 final String servicesBindingTag = name.toString() + "/" + userid; 629 if (mServicesBinding.contains(servicesBindingTag)) { 630 // stop registering this thing already! we're working on it 631 return; 632 } 633 mServicesBinding.add(servicesBindingTag); 634 635 final int N = mListeners.size(); 636 for (int i=N-1; i>=0; i--) { 637 final NotificationListenerInfo info = mListeners.get(i); 638 if (name.equals(info.component) 639 && info.userid == userid) { 640 // cut old connections 641 if (DBG) Slog.v(TAG, " disconnecting old listener: " + info.listener); 642 mListeners.remove(i); 643 if (info.connection != null) { 644 getContext().unbindService(info.connection); 645 } 646 } 647 } 648 649 Intent intent = new Intent(NotificationListenerService.SERVICE_INTERFACE); 650 intent.setComponent(name); 651 652 intent.putExtra(Intent.EXTRA_CLIENT_LABEL, 653 R.string.notification_listener_binding_label); 654 655 final PendingIntent pendingIntent = PendingIntent.getActivity( 656 getContext(), 0, new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS), 0); 657 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent); 658 659 try { 660 if (DBG) Slog.v(TAG, "binding: " + intent); 661 if (!getContext().bindServiceAsUser(intent, 662 new ServiceConnection() { 663 INotificationListener mListener; 664 665 @Override 666 public void onServiceConnected(ComponentName name, IBinder service) { 667 boolean added = false; 668 synchronized (mNotificationList) { 669 mServicesBinding.remove(servicesBindingTag); 670 try { 671 mListener = INotificationListener.Stub.asInterface(service); 672 NotificationListenerInfo info 673 = new NotificationListenerInfo( 674 mListener, name, userid, this); 675 service.linkToDeath(info, 0); 676 added = mListeners.add(info); 677 } catch (RemoteException e) { 678 // already dead 679 } 680 } 681 if (added) { 682 final String[] keys = 683 getActiveNotificationKeysFromListener(mListener); 684 try { 685 mListener.onListenerConnected(keys); 686 } catch (RemoteException e) { 687 // we tried 688 } 689 } 690 } 691 692 @Override 693 public void onServiceDisconnected(ComponentName name) { 694 Slog.v(TAG, "notification listener connection lost: " + name); 695 } 696 }, 697 Context.BIND_AUTO_CREATE, 698 new UserHandle(userid))) 699 { 700 mServicesBinding.remove(servicesBindingTag); 701 Slog.w(TAG, "Unable to bind listener service: " + intent); 702 return; 703 } 704 } catch (SecurityException ex) { 705 Slog.e(TAG, "Unable to bind listener service: " + intent, ex); 706 return; 707 } 708 } 709 } 710 711 712 /** 713 * Remove a listener service for the given user by ComponentName 714 */ 715 private void unregisterListenerService(ComponentName name, int userid) { 716 checkCallerIsSystem(); 717 718 synchronized (mNotificationList) { 719 final int N = mListeners.size(); 720 for (int i=N-1; i>=0; i--) { 721 final NotificationListenerInfo info = mListeners.get(i); 722 if (name.equals(info.component) 723 && info.userid == userid) { 724 mListeners.remove(i); 725 if (info.connection != null) { 726 try { 727 getContext().unbindService(info.connection); 728 } catch (IllegalArgumentException ex) { 729 // something happened to the service: we think we have a connection 730 // but it's bogus. 731 Slog.e(TAG, "Listener " + name + " could not be unbound: " + ex); 732 } 733 } 734 } 735 } 736 } 737 } 738 739 /** 740 * asynchronously notify all listeners about a new notification 741 */ 742 void notifyPostedLocked(NotificationRecord n) { 743 // make a copy in case changes are made to the underlying Notification object 744 final StatusBarNotification sbn = n.sbn.clone(); 745 for (final NotificationListenerInfo info : mListeners) { 746 mHandler.post(new Runnable() { 747 @Override 748 public void run() { 749 info.notifyPostedIfUserMatch(sbn); 750 }}); 751 } 752 } 753 754 /** 755 * asynchronously notify all listeners about a removed notification 756 */ 757 void notifyRemovedLocked(NotificationRecord n) { 758 // make a copy in case changes are made to the underlying Notification object 759 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the notification 760 final StatusBarNotification sbn_light = n.sbn.cloneLight(); 761 762 for (final NotificationListenerInfo info : mListeners) { 763 mHandler.post(new Runnable() { 764 @Override 765 public void run() { 766 info.notifyRemovedIfUserMatch(sbn_light); 767 }}); 768 } 769 } 770 771 // -- APIs to support listeners clicking/clearing notifications -- 772 773 private void checkNullListener(INotificationListener listener) { 774 if (listener == null) { 775 throw new IllegalArgumentException("Listener must not be null"); 776 } 777 } 778 779 private NotificationListenerInfo checkListenerTokenLocked(INotificationListener listener) { 780 checkNullListener(listener); 781 final IBinder token = listener.asBinder(); 782 final int N = mListeners.size(); 783 for (int i=0; i<N; i++) { 784 final NotificationListenerInfo info = mListeners.get(i); 785 if (info.listener.asBinder() == token) return info; 786 } 787 throw new SecurityException("Disallowed call from unknown listener: " + listener); 788 } 789 790 791 792 // -- end of listener APIs -- 793 794 public static final class NotificationRecord 795 { 796 final StatusBarNotification sbn; 797 final SingleNotificationStats stats = new SingleNotificationStats(); 798 IBinder statusBarKey; 799 800 NotificationRecord(StatusBarNotification sbn) 801 { 802 this.sbn = sbn; 803 } 804 805 public Notification getNotification() { return sbn.getNotification(); } 806 public int getFlags() { return sbn.getNotification().flags; } 807 public int getUserId() { return sbn.getUserId(); } 808 809 void dump(PrintWriter pw, String prefix, Context baseContext) { 810 final Notification notification = sbn.getNotification(); 811 pw.println(prefix + this); 812 pw.println(prefix + " uid=" + sbn.getUid() + " userId=" + sbn.getUserId()); 813 pw.println(prefix + " icon=0x" + Integer.toHexString(notification.icon) 814 + " / " + idDebugString(baseContext, sbn.getPackageName(), notification.icon)); 815 pw.println(prefix + " pri=" + notification.priority + " score=" + sbn.getScore()); 816 pw.println(prefix + " key=" + sbn.getKey()); 817 pw.println(prefix + " contentIntent=" + notification.contentIntent); 818 pw.println(prefix + " deleteIntent=" + notification.deleteIntent); 819 pw.println(prefix + " tickerText=" + notification.tickerText); 820 pw.println(prefix + " contentView=" + notification.contentView); 821 pw.println(prefix + String.format(" defaults=0x%08x flags=0x%08x", 822 notification.defaults, notification.flags)); 823 pw.println(prefix + " sound=" + notification.sound); 824 pw.println(prefix + " vibrate=" + Arrays.toString(notification.vibrate)); 825 pw.println(prefix + String.format(" led=0x%08x onMs=%d offMs=%d", 826 notification.ledARGB, notification.ledOnMS, notification.ledOffMS)); 827 if (notification.actions != null && notification.actions.length > 0) { 828 pw.println(prefix + " actions={"); 829 final int N = notification.actions.length; 830 for (int i=0; i<N; i++) { 831 final Notification.Action action = notification.actions[i]; 832 pw.println(String.format("%s [%d] \"%s\" -> %s", 833 prefix, 834 i, 835 action.title, 836 action.actionIntent.toString() 837 )); 838 } 839 pw.println(prefix + " }"); 840 } 841 if (notification.extras != null && notification.extras.size() > 0) { 842 pw.println(prefix + " extras={"); 843 for (String key : notification.extras.keySet()) { 844 pw.print(prefix + " " + key + "="); 845 Object val = notification.extras.get(key); 846 if (val == null) { 847 pw.println("null"); 848 } else { 849 pw.print(val.toString()); 850 if (val instanceof Bitmap) { 851 pw.print(String.format(" (%dx%d)", 852 ((Bitmap) val).getWidth(), 853 ((Bitmap) val).getHeight())); 854 } else if (val.getClass().isArray()) { 855 pw.println(" {"); 856 final int N = Array.getLength(val); 857 for (int i=0; i<N; i++) { 858 if (i > 0) pw.println(","); 859 pw.print(prefix + " " + Array.get(val, i)); 860 } 861 pw.print("\n" + prefix + " }"); 862 } 863 pw.println(); 864 } 865 } 866 pw.println(prefix + " }"); 867 } 868 pw.println(prefix + " stats=" + stats.toString()); 869 } 870 871 @Override 872 public final String toString() { 873 return String.format( 874 "NotificationRecord(0x%08x: pkg=%s user=%s id=%d tag=%s score=%d key=%s: %s)", 875 System.identityHashCode(this), 876 this.sbn.getPackageName(), this.sbn.getUser(), this.sbn.getId(), 877 this.sbn.getTag(), this.sbn.getScore(), this.sbn.getKey(), 878 this.sbn.getNotification()); 879 } 880 } 881 882 private static final class ToastRecord 883 { 884 final int pid; 885 final String pkg; 886 final ITransientNotification callback; 887 int duration; 888 889 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration) 890 { 891 this.pid = pid; 892 this.pkg = pkg; 893 this.callback = callback; 894 this.duration = duration; 895 } 896 897 void update(int duration) { 898 this.duration = duration; 899 } 900 901 void dump(PrintWriter pw, String prefix) { 902 pw.println(prefix + this); 903 } 904 905 @Override 906 public final String toString() 907 { 908 return "ToastRecord{" 909 + Integer.toHexString(System.identityHashCode(this)) 910 + " pkg=" + pkg 911 + " callback=" + callback 912 + " duration=" + duration; 913 } 914 } 915 916 private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() { 917 918 @Override 919 public void onSetDisabled(int status) { 920 synchronized (mNotificationList) { 921 mDisableNotificationAlerts = (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0; 922 if (mDisableNotificationAlerts) { 923 // cancel whatever's going on 924 long identity = Binder.clearCallingIdentity(); 925 try { 926 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 927 if (player != null) { 928 player.stopAsync(); 929 } 930 } catch (RemoteException e) { 931 } finally { 932 Binder.restoreCallingIdentity(identity); 933 } 934 935 identity = Binder.clearCallingIdentity(); 936 try { 937 mVibrator.cancel(); 938 } finally { 939 Binder.restoreCallingIdentity(identity); 940 } 941 } 942 } 943 } 944 945 @Override 946 public void onClearAll(int callingUid, int callingPid, int userId) { 947 synchronized (mNotificationList) { 948 cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null); 949 } 950 } 951 952 @Override 953 public void onNotificationClick(int callingUid, int callingPid, 954 String pkg, String tag, int id, int userId) { 955 cancelNotification(callingUid, callingPid, pkg, tag, id, Notification.FLAG_AUTO_CANCEL, 956 Notification.FLAG_FOREGROUND_SERVICE, false, userId, REASON_DELEGATE_CLICK, null); 957 } 958 959 @Override 960 public void onNotificationClear(int callingUid, int callingPid, 961 String pkg, String tag, int id, int userId) { 962 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 963 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE, 964 true, userId, REASON_DELEGATE_CANCEL, null); 965 } 966 967 @Override 968 public void onPanelRevealed() { 969 EventLogTags.writeNotificationPanelRevealed(); 970 synchronized (mNotificationList) { 971 // sound 972 mSoundNotification = null; 973 974 long identity = Binder.clearCallingIdentity(); 975 try { 976 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 977 if (player != null) { 978 player.stopAsync(); 979 } 980 } catch (RemoteException e) { 981 } finally { 982 Binder.restoreCallingIdentity(identity); 983 } 984 985 // vibrate 986 mVibrateNotification = null; 987 identity = Binder.clearCallingIdentity(); 988 try { 989 mVibrator.cancel(); 990 } finally { 991 Binder.restoreCallingIdentity(identity); 992 } 993 994 // light 995 mLights.clear(); 996 mLedNotification = null; 997 updateLightsLocked(); 998 } 999 } 1000 1001 @Override 1002 public void onPanelHidden() { 1003 EventLogTags.writeNotificationPanelHidden(); 1004 } 1005 1006 @Override 1007 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id, 1008 int uid, int initialPid, String message, int userId) { 1009 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id 1010 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")"); 1011 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId, 1012 REASON_DELEGATE_ERROR, null); 1013 long ident = Binder.clearCallingIdentity(); 1014 try { 1015 ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg, 1016 "Bad notification posted from package " + pkg 1017 + ": " + message); 1018 } catch (RemoteException e) { 1019 } 1020 Binder.restoreCallingIdentity(ident); 1021 } 1022 1023 @Override 1024 public boolean allowDisable(int what, IBinder token, String pkg) { 1025 if (isCall(pkg, null)) { 1026 return mZenMode == Settings.Global.ZEN_MODE_OFF; 1027 } 1028 return true; 1029 } 1030 }; 1031 1032 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 1033 @Override 1034 public void onReceive(Context context, Intent intent) { 1035 String action = intent.getAction(); 1036 1037 boolean queryRestart = false; 1038 boolean queryRemove = false; 1039 boolean packageChanged = false; 1040 boolean cancelNotifications = true; 1041 1042 if (action.equals(Intent.ACTION_PACKAGE_ADDED) 1043 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED)) 1044 || action.equals(Intent.ACTION_PACKAGE_RESTARTED) 1045 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED)) 1046 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART)) 1047 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { 1048 String pkgList[] = null; 1049 boolean queryReplace = queryRemove && 1050 intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); 1051 if (DBG) Slog.i(TAG, "queryReplace=" + queryReplace); 1052 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { 1053 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1054 } else if (queryRestart) { 1055 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); 1056 } else { 1057 Uri uri = intent.getData(); 1058 if (uri == null) { 1059 return; 1060 } 1061 String pkgName = uri.getSchemeSpecificPart(); 1062 if (pkgName == null) { 1063 return; 1064 } 1065 if (packageChanged) { 1066 // We cancel notifications for packages which have just been disabled 1067 try { 1068 final int enabled = getContext().getPackageManager() 1069 .getApplicationEnabledSetting(pkgName); 1070 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED 1071 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { 1072 cancelNotifications = false; 1073 } 1074 } catch (IllegalArgumentException e) { 1075 // Package doesn't exist; probably racing with uninstall. 1076 // cancelNotifications is already true, so nothing to do here. 1077 if (DBG) { 1078 Slog.i(TAG, "Exception trying to look up app enabled setting", e); 1079 } 1080 } 1081 } 1082 pkgList = new String[]{pkgName}; 1083 } 1084 1085 boolean anyListenersInvolved = false; 1086 if (pkgList != null && (pkgList.length > 0)) { 1087 for (String pkgName : pkgList) { 1088 if (cancelNotifications) { 1089 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart, 1090 UserHandle.USER_ALL, REASON_PACKAGE_CHANGED, null); 1091 } 1092 if (mEnabledListenerPackageNames.contains(pkgName)) { 1093 anyListenersInvolved = true; 1094 } 1095 } 1096 } 1097 1098 if (anyListenersInvolved) { 1099 // if we're not replacing a package, clean up orphaned bits 1100 if (!queryReplace) { 1101 disableNonexistentListeners(); 1102 } 1103 // make sure we're still bound to any of our 1104 // listeners who may have just upgraded 1105 rebindListenerServices(); 1106 } 1107 } else if (action.equals(Intent.ACTION_SCREEN_ON)) { 1108 // Keep track of screen on/off state, but do not turn off the notification light 1109 // until user passes through the lock screen or views the notification. 1110 mScreenOn = true; 1111 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 1112 mScreenOn = false; 1113 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) { 1114 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK 1115 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE)); 1116 updateNotificationPulse(); 1117 } else if (action.equals(Intent.ACTION_USER_STOPPED)) { 1118 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 1119 if (userHandle >= 0) { 1120 cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle, 1121 REASON_USER_STOPPED, null); 1122 } 1123 } else if (action.equals(Intent.ACTION_USER_PRESENT)) { 1124 // turn off LED when user passes through lock screen 1125 mNotificationLight.turnOff(); 1126 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) { 1127 // reload per-user settings 1128 mSettingsObserver.update(null); 1129 updateCurrentProfilesCache(context); 1130 } else if (action.equals(Intent.ACTION_USER_ADDED)) { 1131 updateCurrentProfilesCache(context); 1132 } 1133 } 1134 }; 1135 1136 class SettingsObserver extends ContentObserver { 1137 private final Uri NOTIFICATION_LIGHT_PULSE_URI 1138 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE); 1139 1140 private final Uri ENABLED_NOTIFICATION_LISTENERS_URI 1141 = Settings.Secure.getUriFor(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS); 1142 1143 private final Uri ZEN_MODE 1144 = Settings.Global.getUriFor(Settings.Global.ZEN_MODE); 1145 1146 SettingsObserver(Handler handler) { 1147 super(handler); 1148 } 1149 1150 void observe() { 1151 ContentResolver resolver = getContext().getContentResolver(); 1152 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI, 1153 false, this, UserHandle.USER_ALL); 1154 resolver.registerContentObserver(ENABLED_NOTIFICATION_LISTENERS_URI, 1155 false, this, UserHandle.USER_ALL); 1156 resolver.registerContentObserver(ZEN_MODE, 1157 false, this); 1158 update(null); 1159 } 1160 1161 @Override public void onChange(boolean selfChange, Uri uri) { 1162 update(uri); 1163 } 1164 1165 public void update(Uri uri) { 1166 ContentResolver resolver = getContext().getContentResolver(); 1167 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) { 1168 boolean pulseEnabled = Settings.System.getInt(resolver, 1169 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0; 1170 if (mNotificationPulseEnabled != pulseEnabled) { 1171 mNotificationPulseEnabled = pulseEnabled; 1172 updateNotificationPulse(); 1173 } 1174 } 1175 if (uri == null || ENABLED_NOTIFICATION_LISTENERS_URI.equals(uri)) { 1176 rebindListenerServices(); 1177 } 1178 if (ZEN_MODE.equals(uri)) { 1179 updateZenMode(); 1180 } 1181 } 1182 } 1183 1184 private SettingsObserver mSettingsObserver; 1185 1186 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) { 1187 int[] ar = r.getIntArray(resid); 1188 if (ar == null) { 1189 return def; 1190 } 1191 final int len = ar.length > maxlen ? maxlen : ar.length; 1192 long[] out = new long[len]; 1193 for (int i=0; i<len; i++) { 1194 out[i] = ar[i]; 1195 } 1196 return out; 1197 } 1198 1199 public NotificationManagerService(Context context) { 1200 super(context); 1201 } 1202 1203 @Override 1204 public void onStart() { 1205 mAm = ActivityManagerNative.getDefault(); 1206 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); 1207 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE); 1208 1209 mHandler = new WorkerHandler(); 1210 1211 importOldBlockDb(); 1212 1213 mStatusBar = getLocalService(StatusBarManagerInternal.class); 1214 mStatusBar.setNotificationDelegate(mNotificationDelegate); 1215 1216 final LightsManager lights = getLocalService(LightsManager.class); 1217 mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS); 1218 mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION); 1219 1220 Resources resources = getContext().getResources(); 1221 mDefaultNotificationColor = resources.getColor( 1222 R.color.config_defaultNotificationColor); 1223 mDefaultNotificationLedOn = resources.getInteger( 1224 R.integer.config_defaultNotificationLedOn); 1225 mDefaultNotificationLedOff = resources.getInteger( 1226 R.integer.config_defaultNotificationLedOff); 1227 1228 mDefaultVibrationPattern = getLongArray(resources, 1229 R.array.config_defaultNotificationVibePattern, 1230 VIBRATE_PATTERN_MAXLEN, 1231 DEFAULT_VIBRATE_PATTERN); 1232 1233 mFallbackVibrationPattern = getLongArray(resources, 1234 R.array.config_notificationFallbackVibePattern, 1235 VIBRATE_PATTERN_MAXLEN, 1236 DEFAULT_VIBRATE_PATTERN); 1237 1238 // Don't start allowing notifications until the setup wizard has run once. 1239 // After that, including subsequent boots, init with notifications turned on. 1240 // This works on the first boot because the setup wizard will toggle this 1241 // flag at least once and we'll go back to 0 after that. 1242 if (0 == Settings.Global.getInt(getContext().getContentResolver(), 1243 Settings.Global.DEVICE_PROVISIONED, 0)) { 1244 mDisableNotificationAlerts = true; 1245 } 1246 updateZenMode(); 1247 1248 // register for various Intents 1249 IntentFilter filter = new IntentFilter(); 1250 filter.addAction(Intent.ACTION_SCREEN_ON); 1251 filter.addAction(Intent.ACTION_SCREEN_OFF); 1252 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); 1253 filter.addAction(Intent.ACTION_USER_PRESENT); 1254 filter.addAction(Intent.ACTION_USER_STOPPED); 1255 filter.addAction(Intent.ACTION_USER_SWITCHED); 1256 filter.addAction(Intent.ACTION_USER_ADDED); 1257 getContext().registerReceiver(mIntentReceiver, filter); 1258 IntentFilter pkgFilter = new IntentFilter(); 1259 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 1260 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 1261 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 1262 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); 1263 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); 1264 pkgFilter.addDataScheme("package"); 1265 getContext().registerReceiver(mIntentReceiver, pkgFilter); 1266 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 1267 getContext().registerReceiver(mIntentReceiver, sdFilter); 1268 1269 mSettingsObserver = new SettingsObserver(mHandler); 1270 1271 // spin up NotificationScorers 1272 String[] notificationScorerNames = resources.getStringArray( 1273 R.array.config_notificationScorers); 1274 for (String scorerName : notificationScorerNames) { 1275 try { 1276 Class<?> scorerClass = getContext().getClassLoader().loadClass(scorerName); 1277 NotificationScorer scorer = (NotificationScorer) scorerClass.newInstance(); 1278 scorer.initialize(getContext()); 1279 mScorers.add(scorer); 1280 } catch (ClassNotFoundException e) { 1281 Slog.w(TAG, "Couldn't find scorer " + scorerName + ".", e); 1282 } catch (InstantiationException e) { 1283 Slog.w(TAG, "Couldn't instantiate scorer " + scorerName + ".", e); 1284 } catch (IllegalAccessException e) { 1285 Slog.w(TAG, "Problem accessing scorer " + scorerName + ".", e); 1286 } 1287 } 1288 1289 publishBinderService(Context.NOTIFICATION_SERVICE, mService); 1290 publishLocalService(NotificationManagerInternal.class, mInternalService); 1291 } 1292 1293 /** 1294 * Read the old XML-based app block database and import those blockages into the AppOps system. 1295 */ 1296 private void importOldBlockDb() { 1297 loadBlockDb(); 1298 1299 PackageManager pm = getContext().getPackageManager(); 1300 for (String pkg : mBlockedPackages) { 1301 PackageInfo info = null; 1302 try { 1303 info = pm.getPackageInfo(pkg, 0); 1304 setNotificationsEnabledForPackageImpl(pkg, info.applicationInfo.uid, false); 1305 } catch (NameNotFoundException e) { 1306 // forget you 1307 } 1308 } 1309 mBlockedPackages.clear(); 1310 if (mPolicyFile != null) { 1311 mPolicyFile.delete(); 1312 } 1313 } 1314 1315 @Override 1316 public void onBootPhase(int phase) { 1317 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 1318 // no beeping until we're basically done booting 1319 mSystemReady = true; 1320 1321 // Grab our optional AudioService 1322 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 1323 1324 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { 1325 // This observer will force an update when observe is called, causing us to 1326 // bind to listener services. 1327 mSettingsObserver.observe(); 1328 } 1329 } 1330 1331 void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) { 1332 Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg); 1333 1334 mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg, 1335 enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED); 1336 1337 // Now, cancel any outstanding notifications that are part of a just-disabled app 1338 if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) { 1339 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid), 1340 REASON_PACKAGE_BANNED, null); 1341 } 1342 } 1343 1344 private final IBinder mService = new INotificationManager.Stub() { 1345 // Toasts 1346 // ============================================================================ 1347 1348 @Override 1349 public void enqueueToast(String pkg, ITransientNotification callback, int duration) 1350 { 1351 if (DBG) { 1352 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback 1353 + " duration=" + duration); 1354 } 1355 1356 if (pkg == null || callback == null) { 1357 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback); 1358 return ; 1359 } 1360 1361 final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg)); 1362 1363 if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) { 1364 if (!isSystemToast) { 1365 Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request."); 1366 return; 1367 } 1368 } 1369 1370 synchronized (mToastQueue) { 1371 int callingPid = Binder.getCallingPid(); 1372 long callingId = Binder.clearCallingIdentity(); 1373 try { 1374 ToastRecord record; 1375 int index = indexOfToastLocked(pkg, callback); 1376 // If it's already in the queue, we update it in place, we don't 1377 // move it to the end of the queue. 1378 if (index >= 0) { 1379 record = mToastQueue.get(index); 1380 record.update(duration); 1381 } else { 1382 // Limit the number of toasts that any given package except the android 1383 // package can enqueue. Prevents DOS attacks and deals with leaks. 1384 if (!isSystemToast) { 1385 int count = 0; 1386 final int N = mToastQueue.size(); 1387 for (int i=0; i<N; i++) { 1388 final ToastRecord r = mToastQueue.get(i); 1389 if (r.pkg.equals(pkg)) { 1390 count++; 1391 if (count >= MAX_PACKAGE_NOTIFICATIONS) { 1392 Slog.e(TAG, "Package has already posted " + count 1393 + " toasts. Not showing more. Package=" + pkg); 1394 return; 1395 } 1396 } 1397 } 1398 } 1399 1400 record = new ToastRecord(callingPid, pkg, callback, duration); 1401 mToastQueue.add(record); 1402 index = mToastQueue.size() - 1; 1403 keepProcessAliveLocked(callingPid); 1404 } 1405 // If it's at index 0, it's the current toast. It doesn't matter if it's 1406 // new or just been updated. Call back and tell it to show itself. 1407 // If the callback fails, this will remove it from the list, so don't 1408 // assume that it's valid after this. 1409 if (index == 0) { 1410 showNextToastLocked(); 1411 } 1412 } finally { 1413 Binder.restoreCallingIdentity(callingId); 1414 } 1415 } 1416 } 1417 1418 @Override 1419 public void cancelToast(String pkg, ITransientNotification callback) { 1420 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback); 1421 1422 if (pkg == null || callback == null) { 1423 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback); 1424 return ; 1425 } 1426 1427 synchronized (mToastQueue) { 1428 long callingId = Binder.clearCallingIdentity(); 1429 try { 1430 int index = indexOfToastLocked(pkg, callback); 1431 if (index >= 0) { 1432 cancelToastLocked(index); 1433 } else { 1434 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg 1435 + " callback=" + callback); 1436 } 1437 } finally { 1438 Binder.restoreCallingIdentity(callingId); 1439 } 1440 } 1441 } 1442 1443 @Override 1444 public void enqueueNotificationWithTag(String pkg, String basePkg, String tag, int id, 1445 Notification notification, int[] idOut, int userId) throws RemoteException { 1446 enqueueNotificationInternal(pkg, basePkg, Binder.getCallingUid(), 1447 Binder.getCallingPid(), tag, id, notification, idOut, userId); 1448 } 1449 1450 @Override 1451 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) { 1452 checkCallerIsSystemOrSameApp(pkg); 1453 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 1454 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg); 1455 // Don't allow client applications to cancel foreground service notis. 1456 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0, 1457 Binder.getCallingUid() == Process.SYSTEM_UID 1458 ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId, REASON_NOMAN_CANCEL, 1459 null); 1460 } 1461 1462 @Override 1463 public void cancelAllNotifications(String pkg, int userId) { 1464 checkCallerIsSystemOrSameApp(pkg); 1465 1466 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 1467 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg); 1468 1469 // Calling from user space, don't allow the canceling of actively 1470 // running foreground services. 1471 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(), 1472 pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId, 1473 REASON_NOMAN_CANCEL_ALL, null); 1474 } 1475 1476 @Override 1477 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) { 1478 checkCallerIsSystem(); 1479 1480 setNotificationsEnabledForPackageImpl(pkg, uid, enabled); 1481 } 1482 1483 /** 1484 * Use this when you just want to know if notifications are OK for this package. 1485 */ 1486 @Override 1487 public boolean areNotificationsEnabledForPackage(String pkg, int uid) { 1488 checkCallerIsSystem(); 1489 return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg) 1490 == AppOpsManager.MODE_ALLOWED); 1491 } 1492 1493 /** 1494 * System-only API for getting a list of current (i.e. not cleared) notifications. 1495 * 1496 * Requires ACCESS_NOTIFICATIONS which is signature|system. 1497 */ 1498 @Override 1499 public StatusBarNotification[] getActiveNotifications(String callingPkg) { 1500 // enforce() will ensure the calling uid has the correct permission 1501 getContext().enforceCallingOrSelfPermission( 1502 android.Manifest.permission.ACCESS_NOTIFICATIONS, 1503 "NotificationManagerService.getActiveNotifications"); 1504 1505 StatusBarNotification[] tmp = null; 1506 int uid = Binder.getCallingUid(); 1507 1508 // noteOp will check to make sure the callingPkg matches the uid 1509 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg) 1510 == AppOpsManager.MODE_ALLOWED) { 1511 synchronized (mNotificationList) { 1512 tmp = new StatusBarNotification[mNotificationList.size()]; 1513 final int N = mNotificationList.size(); 1514 for (int i=0; i<N; i++) { 1515 tmp[i] = mNotificationList.get(i).sbn; 1516 } 1517 } 1518 } 1519 return tmp; 1520 } 1521 1522 /** 1523 * System-only API for getting a list of recent (cleared, no longer shown) notifications. 1524 * 1525 * Requires ACCESS_NOTIFICATIONS which is signature|system. 1526 */ 1527 @Override 1528 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) { 1529 // enforce() will ensure the calling uid has the correct permission 1530 getContext().enforceCallingOrSelfPermission( 1531 android.Manifest.permission.ACCESS_NOTIFICATIONS, 1532 "NotificationManagerService.getHistoricalNotifications"); 1533 1534 StatusBarNotification[] tmp = null; 1535 int uid = Binder.getCallingUid(); 1536 1537 // noteOp will check to make sure the callingPkg matches the uid 1538 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg) 1539 == AppOpsManager.MODE_ALLOWED) { 1540 synchronized (mArchive) { 1541 tmp = mArchive.getArray(count); 1542 } 1543 } 1544 return tmp; 1545 } 1546 1547 /** 1548 * Register a listener binder directly with the notification manager. 1549 * 1550 * Only works with system callers. Apps should extend 1551 * {@link android.service.notification.NotificationListenerService}. 1552 */ 1553 @Override 1554 public void registerListener(final INotificationListener listener, 1555 final ComponentName component, final int userid) { 1556 checkCallerIsSystem(); 1557 checkNullListener(listener); 1558 registerListenerImpl(listener, component, userid); 1559 } 1560 1561 /** 1562 * Remove a listener binder directly 1563 */ 1564 @Override 1565 public void unregisterListener(INotificationListener listener, int userid) { 1566 checkNullListener(listener); 1567 // no need to check permissions; if your listener binder is in the list, 1568 // that's proof that you had permission to add it in the first place 1569 unregisterListenerImpl(listener, userid); 1570 } 1571 1572 /** 1573 * Allow an INotificationListener to simulate a "clear all" operation. 1574 * 1575 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications} 1576 * 1577 * @param token The binder for the listener, to check that the caller is allowed 1578 */ 1579 @Override 1580 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) { 1581 final int callingUid = Binder.getCallingUid(); 1582 final int callingPid = Binder.getCallingPid(); 1583 long identity = Binder.clearCallingIdentity(); 1584 try { 1585 synchronized (mNotificationList) { 1586 final NotificationListenerInfo info = checkListenerTokenLocked(token); 1587 if (keys != null) { 1588 final int N = keys.length; 1589 for (int i = 0; i < N; i++) { 1590 NotificationRecord r = mNotificationsByKey.get(keys[i]); 1591 if (r != null) { 1592 cancelNotificationFromListenerLocked(info, callingUid, callingPid, 1593 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId()); 1594 } 1595 } 1596 } else { 1597 cancelAllLocked(callingUid, callingPid, info.userid, 1598 REASON_LISTENER_CANCEL_ALL, info); 1599 } 1600 } 1601 } finally { 1602 Binder.restoreCallingIdentity(identity); 1603 } 1604 } 1605 1606 private void cancelNotificationFromListenerLocked(NotificationListenerInfo info, 1607 int callingUid, int callingPid, String pkg, String tag, int id) { 1608 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 1609 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE, 1610 true, 1611 info.userid, REASON_LISTENER_CANCEL, info); 1612 } 1613 1614 /** 1615 * Allow an INotificationListener to simulate clearing (dismissing) a single notification. 1616 * 1617 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear} 1618 * 1619 * @param token The binder for the listener, to check that the caller is allowed 1620 */ 1621 @Override 1622 public void cancelNotificationFromListener(INotificationListener token, String pkg, 1623 String tag, int id) { 1624 final int callingUid = Binder.getCallingUid(); 1625 final int callingPid = Binder.getCallingPid(); 1626 long identity = Binder.clearCallingIdentity(); 1627 try { 1628 synchronized (mNotificationList) { 1629 final NotificationListenerInfo info = checkListenerTokenLocked(token); 1630 cancelNotificationFromListenerLocked(info, callingUid, callingPid, 1631 pkg, tag, id); 1632 } 1633 } finally { 1634 Binder.restoreCallingIdentity(identity); 1635 } 1636 } 1637 1638 /** 1639 * Allow an INotificationListener to request the list of outstanding notifications seen by 1640 * the current user. Useful when starting up, after which point the listener callbacks 1641 * should be used. 1642 * 1643 * @param token The binder for the listener, to check that the caller is allowed 1644 */ 1645 @Override 1646 public StatusBarNotification[] getActiveNotificationsFromListener( 1647 INotificationListener token, String[] keys) { 1648 synchronized (mNotificationList) { 1649 final NotificationListenerInfo info = checkListenerTokenLocked(token); 1650 final ArrayList<StatusBarNotification> list 1651 = new ArrayList<StatusBarNotification>(); 1652 if (keys == null) { 1653 final int N = mNotificationList.size(); 1654 for (int i=0; i<N; i++) { 1655 StatusBarNotification sbn = mNotificationList.get(i).sbn; 1656 if (info.enabledAndUserMatches(sbn)) { 1657 list.add(sbn); 1658 } 1659 } 1660 } else { 1661 final int N = keys.length; 1662 for (int i=0; i<N; i++) { 1663 NotificationRecord r = mNotificationsByKey.get(keys[i]); 1664 if (r != null && info.enabledAndUserMatches(r.sbn)) { 1665 list.add(r.sbn); 1666 } 1667 } 1668 } 1669 return list.toArray(new StatusBarNotification[list.size()]); 1670 } 1671 } 1672 1673 @Override 1674 public String[] getActiveNotificationKeysFromListener(INotificationListener token) { 1675 return NotificationManagerService.this.getActiveNotificationKeysFromListener(token); 1676 } 1677 1678 @Override 1679 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1680 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1681 != PackageManager.PERMISSION_GRANTED) { 1682 pw.println("Permission Denial: can't dump NotificationManager from from pid=" 1683 + Binder.getCallingPid() 1684 + ", uid=" + Binder.getCallingUid()); 1685 return; 1686 } 1687 1688 dumpImpl(pw); 1689 } 1690 }; 1691 1692 private String[] getActiveNotificationKeysFromListener(INotificationListener token) { 1693 synchronized (mNotificationList) { 1694 final NotificationListenerInfo info = checkListenerTokenLocked(token); 1695 final ArrayList<String> keys = new ArrayList<String>(); 1696 final int N = mNotificationList.size(); 1697 for (int i=0; i<N; i++) { 1698 final StatusBarNotification sbn = mNotificationList.get(i).sbn; 1699 if (info.enabledAndUserMatches(sbn)) { 1700 keys.add(sbn.getKey()); 1701 } 1702 } 1703 return keys.toArray(new String[keys.size()]); 1704 } 1705 } 1706 1707 void dumpImpl(PrintWriter pw) { 1708 pw.println("Current Notification Manager state:"); 1709 1710 pw.println(" Listeners (" + mEnabledListenersForCurrentUser.size() 1711 + ") enabled for current user:"); 1712 for (ComponentName cmpt : mEnabledListenersForCurrentUser) { 1713 pw.println(" " + cmpt); 1714 } 1715 1716 pw.println(" Live listeners (" + mListeners.size() + "):"); 1717 for (NotificationListenerInfo info : mListeners) { 1718 pw.println(" " + info.component 1719 + " (user " + info.userid + "): " + info.listener 1720 + (info.isSystem?" SYSTEM":"")); 1721 } 1722 1723 int N; 1724 1725 synchronized (mToastQueue) { 1726 N = mToastQueue.size(); 1727 if (N > 0) { 1728 pw.println(" Toast Queue:"); 1729 for (int i=0; i<N; i++) { 1730 mToastQueue.get(i).dump(pw, " "); 1731 } 1732 pw.println(" "); 1733 } 1734 1735 } 1736 1737 synchronized (mNotificationList) { 1738 N = mNotificationList.size(); 1739 if (N > 0) { 1740 pw.println(" Notification List:"); 1741 for (int i=0; i<N; i++) { 1742 mNotificationList.get(i).dump(pw, " ", getContext()); 1743 } 1744 pw.println(" "); 1745 } 1746 1747 N = mLights.size(); 1748 if (N > 0) { 1749 pw.println(" Lights List:"); 1750 for (int i=0; i<N; i++) { 1751 pw.println(" " + mLights.get(i)); 1752 } 1753 pw.println(" "); 1754 } 1755 1756 pw.println(" mSoundNotification=" + mSoundNotification); 1757 pw.println(" mVibrateNotification=" + mVibrateNotification); 1758 pw.println(" mDisableNotificationAlerts=" + mDisableNotificationAlerts); 1759 pw.println(" mZenMode=" + Settings.Global.zenModeToString(mZenMode)); 1760 pw.println(" mSystemReady=" + mSystemReady); 1761 pw.println(" mArchive=" + mArchive.toString()); 1762 Iterator<StatusBarNotification> iter = mArchive.descendingIterator(); 1763 int i=0; 1764 while (iter.hasNext()) { 1765 pw.println(" " + iter.next()); 1766 if (++i >= 5) { 1767 if (iter.hasNext()) pw.println(" ..."); 1768 break; 1769 } 1770 } 1771 1772 pw.println("\n Usage Stats:"); 1773 mUsageStats.dump(pw, " "); 1774 1775 } 1776 } 1777 1778 /** 1779 * The private API only accessible to the system process. 1780 */ 1781 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() { 1782 @Override 1783 public void enqueueNotification(String pkg, String basePkg, int callingUid, int callingPid, 1784 String tag, int id, Notification notification, int[] idReceived, int userId) { 1785 enqueueNotificationInternal(pkg, basePkg, callingUid, callingPid, tag, id, notification, 1786 idReceived, userId); 1787 } 1788 }; 1789 1790 void enqueueNotificationInternal(final String pkg, String basePkg, final int callingUid, 1791 final int callingPid, final String tag, final int id, final Notification notification, 1792 int[] idOut, int incomingUserId) { 1793 if (DBG) { 1794 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id 1795 + " notification=" + notification); 1796 } 1797 checkCallerIsSystemOrSameApp(pkg); 1798 final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg)); 1799 1800 final int userId = ActivityManager.handleIncomingUser(callingPid, 1801 callingUid, incomingUserId, true, false, "enqueueNotification", pkg); 1802 final UserHandle user = new UserHandle(userId); 1803 1804 // Limit the number of notifications that any given package except the android 1805 // package can enqueue. Prevents DOS attacks and deals with leaks. 1806 if (!isSystemNotification) { 1807 synchronized (mNotificationList) { 1808 int count = 0; 1809 final int N = mNotificationList.size(); 1810 for (int i=0; i<N; i++) { 1811 final NotificationRecord r = mNotificationList.get(i); 1812 if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) { 1813 count++; 1814 if (count >= MAX_PACKAGE_NOTIFICATIONS) { 1815 Slog.e(TAG, "Package has already posted " + count 1816 + " notifications. Not showing more. package=" + pkg); 1817 return; 1818 } 1819 } 1820 } 1821 } 1822 } 1823 1824 // This conditional is a dirty hack to limit the logging done on 1825 // behalf of the download manager without affecting other apps. 1826 if (!pkg.equals("com.android.providers.downloads") 1827 || Log.isLoggable("DownloadManager", Log.VERBOSE)) { 1828 EventLogTags.writeNotificationEnqueue(callingUid, callingPid, 1829 pkg, id, tag, userId, notification.toString()); 1830 } 1831 1832 if (pkg == null || notification == null) { 1833 throw new IllegalArgumentException("null not allowed: pkg=" + pkg 1834 + " id=" + id + " notification=" + notification); 1835 } 1836 if (notification.icon != 0) { 1837 if (notification.contentView == null) { 1838 throw new IllegalArgumentException("contentView required: pkg=" + pkg 1839 + " id=" + id + " notification=" + notification); 1840 } 1841 } 1842 1843 mHandler.post(new Runnable() { 1844 @Override 1845 public void run() { 1846 1847 // === Scoring === 1848 1849 // 0. Sanitize inputs 1850 notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN, 1851 Notification.PRIORITY_MAX); 1852 // Migrate notification flags to scores 1853 if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) { 1854 if (notification.priority < Notification.PRIORITY_MAX) { 1855 notification.priority = Notification.PRIORITY_MAX; 1856 } 1857 } else if (SCORE_ONGOING_HIGHER && 1858 0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) { 1859 if (notification.priority < Notification.PRIORITY_HIGH) { 1860 notification.priority = Notification.PRIORITY_HIGH; 1861 } 1862 } 1863 1864 // 1. initial score: buckets of 10, around the app 1865 int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER; //[-20..20] 1866 1867 // 2. Consult external heuristics (TBD) 1868 1869 // 3. Apply local rules 1870 1871 int initialScore = score; 1872 if (!mScorers.isEmpty()) { 1873 if (DBG) Slog.v(TAG, "Initial score is " + score + "."); 1874 for (NotificationScorer scorer : mScorers) { 1875 try { 1876 score = scorer.getScore(notification, score); 1877 } catch (Throwable t) { 1878 Slog.w(TAG, "Scorer threw on .getScore.", t); 1879 } 1880 } 1881 if (DBG) Slog.v(TAG, "Final score is " + score + "."); 1882 } 1883 1884 // add extra to indicate score modified by NotificationScorer 1885 notification.extras.putBoolean(Notification.EXTRA_SCORE_MODIFIED, 1886 score != initialScore); 1887 1888 // blocked apps 1889 if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) { 1890 if (!isSystemNotification) { 1891 score = JUNK_SCORE; 1892 Slog.e(TAG, "Suppressing notification from package " + pkg 1893 + " by user request."); 1894 } 1895 } 1896 1897 if (DBG) { 1898 Slog.v(TAG, "Assigned score=" + score + " to " + notification); 1899 } 1900 1901 if (score < SCORE_DISPLAY_THRESHOLD) { 1902 // Notification will be blocked because the score is too low. 1903 return; 1904 } 1905 1906 // Is this notification intercepted by zen mode? 1907 final boolean intercept = shouldIntercept(pkg, notification); 1908 notification.extras.putBoolean(EXTRA_INTERCEPT, intercept); 1909 1910 // Should this notification make noise, vibe, or use the LED? 1911 final boolean canInterrupt = (score >= SCORE_INTERRUPTION_THRESHOLD) && !intercept; 1912 if (DBG) Slog.v(TAG, "canInterrupt=" + canInterrupt + " intercept=" + intercept); 1913 synchronized (mNotificationList) { 1914 final StatusBarNotification n = new StatusBarNotification( 1915 pkg, id, tag, callingUid, callingPid, score, notification, user); 1916 NotificationRecord r = new NotificationRecord(n); 1917 NotificationRecord old = null; 1918 1919 int index = indexOfNotificationLocked(pkg, tag, id, userId); 1920 if (index < 0) { 1921 mNotificationList.add(r); 1922 mUsageStats.registerPostedByApp(r); 1923 } else { 1924 old = mNotificationList.remove(index); 1925 mNotificationList.add(index, r); 1926 mUsageStats.registerUpdatedByApp(r); 1927 // Make sure we don't lose the foreground service state. 1928 if (old != null) { 1929 notification.flags |= 1930 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE; 1931 } 1932 } 1933 if (old != null) { 1934 mNotificationsByKey.remove(old.sbn.getKey()); 1935 } 1936 mNotificationsByKey.put(n.getKey(), r); 1937 1938 // Ensure if this is a foreground service that the proper additional 1939 // flags are set. 1940 if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) { 1941 notification.flags |= Notification.FLAG_ONGOING_EVENT 1942 | Notification.FLAG_NO_CLEAR; 1943 } 1944 1945 final int currentUser; 1946 final long token = Binder.clearCallingIdentity(); 1947 try { 1948 currentUser = ActivityManager.getCurrentUser(); 1949 } finally { 1950 Binder.restoreCallingIdentity(token); 1951 } 1952 1953 if (notification.icon != 0) { 1954 if (old != null && old.statusBarKey != null) { 1955 r.statusBarKey = old.statusBarKey; 1956 final long identity = Binder.clearCallingIdentity(); 1957 try { 1958 mStatusBar.updateNotification(r.statusBarKey, n); 1959 } finally { 1960 Binder.restoreCallingIdentity(identity); 1961 } 1962 } else { 1963 final long identity = Binder.clearCallingIdentity(); 1964 try { 1965 r.statusBarKey = mStatusBar.addNotification(n); 1966 if ((n.getNotification().flags & Notification.FLAG_SHOW_LIGHTS) != 0 1967 && canInterrupt) { 1968 mAttentionLight.pulse(); 1969 } 1970 } finally { 1971 Binder.restoreCallingIdentity(identity); 1972 } 1973 } 1974 // Send accessibility events only for the current user. 1975 if (currentUser == userId) { 1976 sendAccessibilityEvent(notification, pkg); 1977 } 1978 1979 notifyPostedLocked(r); 1980 } else { 1981 Slog.e(TAG, "Not posting notification with icon==0: " + notification); 1982 if (old != null && old.statusBarKey != null) { 1983 final long identity = Binder.clearCallingIdentity(); 1984 try { 1985 mStatusBar.removeNotification(old.statusBarKey); 1986 } finally { 1987 Binder.restoreCallingIdentity(identity); 1988 } 1989 1990 notifyRemovedLocked(r); 1991 } 1992 // ATTENTION: in a future release we will bail out here 1993 // so that we do not play sounds, show lights, etc. for invalid 1994 // notifications 1995 Slog.e(TAG, "WARNING: In a future release this will crash the app: " 1996 + n.getPackageName()); 1997 } 1998 1999 // If we're not supposed to beep, vibrate, etc. then don't. 2000 if (!mDisableNotificationAlerts 2001 && (!(old != null 2002 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 )) 2003 && (r.getUserId() == UserHandle.USER_ALL || 2004 (r.getUserId() == userId && r.getUserId() == currentUser)) 2005 && canInterrupt 2006 && mSystemReady 2007 && mAudioManager != null) { 2008 if (DBG) Slog.v(TAG, "Interrupting!"); 2009 // sound 2010 2011 // should we use the default notification sound? (indicated either by 2012 // DEFAULT_SOUND or because notification.sound is pointing at 2013 // Settings.System.NOTIFICATION_SOUND) 2014 final boolean useDefaultSound = 2015 (notification.defaults & Notification.DEFAULT_SOUND) != 0 || 2016 Settings.System.DEFAULT_NOTIFICATION_URI 2017 .equals(notification.sound); 2018 2019 Uri soundUri = null; 2020 boolean hasValidSound = false; 2021 2022 if (useDefaultSound) { 2023 soundUri = Settings.System.DEFAULT_NOTIFICATION_URI; 2024 2025 // check to see if the default notification sound is silent 2026 ContentResolver resolver = getContext().getContentResolver(); 2027 hasValidSound = Settings.System.getString(resolver, 2028 Settings.System.NOTIFICATION_SOUND) != null; 2029 } else if (notification.sound != null) { 2030 soundUri = notification.sound; 2031 hasValidSound = (soundUri != null); 2032 } 2033 2034 if (hasValidSound) { 2035 boolean looping = 2036 (notification.flags & Notification.FLAG_INSISTENT) != 0; 2037 int audioStreamType; 2038 if (notification.audioStreamType >= 0) { 2039 audioStreamType = notification.audioStreamType; 2040 } else { 2041 audioStreamType = DEFAULT_STREAM_TYPE; 2042 } 2043 mSoundNotification = r; 2044 // do not play notifications if stream volume is 0 (typically because 2045 // ringer mode is silent) or if there is a user of exclusive audio focus 2046 if ((mAudioManager.getStreamVolume(audioStreamType) != 0) 2047 && !mAudioManager.isAudioFocusExclusive()) { 2048 final long identity = Binder.clearCallingIdentity(); 2049 try { 2050 final IRingtonePlayer player = 2051 mAudioManager.getRingtonePlayer(); 2052 if (player != null) { 2053 if (DBG) Slog.v(TAG, "Playing sound " + soundUri 2054 + " on stream " + audioStreamType); 2055 player.playAsync(soundUri, user, looping, audioStreamType); 2056 } 2057 } catch (RemoteException e) { 2058 } finally { 2059 Binder.restoreCallingIdentity(identity); 2060 } 2061 } 2062 } 2063 2064 // vibrate 2065 // Does the notification want to specify its own vibration? 2066 final boolean hasCustomVibrate = notification.vibrate != null; 2067 2068 // new in 4.2: if there was supposed to be a sound and we're in vibrate 2069 // mode, and no other vibration is specified, we fall back to vibration 2070 final boolean convertSoundToVibration = 2071 !hasCustomVibrate 2072 && hasValidSound 2073 && (mAudioManager.getRingerMode() 2074 == AudioManager.RINGER_MODE_VIBRATE); 2075 2076 // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback. 2077 final boolean useDefaultVibrate = 2078 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0; 2079 2080 if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate) 2081 && !(mAudioManager.getRingerMode() 2082 == AudioManager.RINGER_MODE_SILENT)) { 2083 mVibrateNotification = r; 2084 2085 if (useDefaultVibrate || convertSoundToVibration) { 2086 // Escalate privileges so we can use the vibrator even if the 2087 // notifying app does not have the VIBRATE permission. 2088 long identity = Binder.clearCallingIdentity(); 2089 try { 2090 mVibrator.vibrate(r.sbn.getUid(), r.sbn.getBasePkg(), 2091 useDefaultVibrate ? mDefaultVibrationPattern 2092 : mFallbackVibrationPattern, 2093 ((notification.flags & Notification.FLAG_INSISTENT) != 0) 2094 ? 0: -1, notification.audioStreamType); 2095 } finally { 2096 Binder.restoreCallingIdentity(identity); 2097 } 2098 } else if (notification.vibrate.length > 1) { 2099 // If you want your own vibration pattern, you need the VIBRATE 2100 // permission 2101 mVibrator.vibrate(r.sbn.getUid(), r.sbn.getBasePkg(), 2102 notification.vibrate, 2103 ((notification.flags & Notification.FLAG_INSISTENT) != 0) 2104 ? 0: -1, notification.audioStreamType); 2105 } 2106 } 2107 } 2108 2109 // light 2110 // the most recent thing gets the light 2111 mLights.remove(old); 2112 if (mLedNotification == old) { 2113 mLedNotification = null; 2114 } 2115 //Slog.i(TAG, "notification.lights=" 2116 // + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS) 2117 // != 0)); 2118 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 2119 && canInterrupt) { 2120 mLights.add(r); 2121 updateLightsLocked(); 2122 } else { 2123 if (old != null 2124 && ((old.getFlags() & Notification.FLAG_SHOW_LIGHTS) != 0)) { 2125 updateLightsLocked(); 2126 } 2127 } 2128 } 2129 } 2130 }); 2131 2132 idOut[0] = id; 2133 } 2134 2135 void registerListenerImpl(final INotificationListener listener, 2136 final ComponentName component, final int userid) { 2137 synchronized (mNotificationList) { 2138 try { 2139 NotificationListenerInfo info 2140 = new NotificationListenerInfo(listener, component, userid, true); 2141 listener.asBinder().linkToDeath(info, 0); 2142 mListeners.add(info); 2143 } catch (RemoteException e) { 2144 // already dead 2145 } 2146 } 2147 } 2148 2149 /** 2150 * Removes a listener from the list and unbinds from its service. 2151 */ 2152 void unregisterListenerImpl(final INotificationListener listener, final int userid) { 2153 NotificationListenerInfo info = removeListenerImpl(listener, userid); 2154 if (info != null && info.connection != null) { 2155 getContext().unbindService(info.connection); 2156 } 2157 } 2158 2159 /** 2160 * Removes a listener from the list but does not unbind from the listener's service. 2161 * 2162 * @return the removed listener. 2163 */ 2164 NotificationListenerInfo removeListenerImpl( 2165 final INotificationListener listener, final int userid) { 2166 NotificationListenerInfo listenerInfo = null; 2167 synchronized (mNotificationList) { 2168 final int N = mListeners.size(); 2169 for (int i=N-1; i>=0; i--) { 2170 final NotificationListenerInfo info = mListeners.get(i); 2171 if (info.listener.asBinder() == listener.asBinder() 2172 && info.userid == userid) { 2173 listenerInfo = mListeners.remove(i); 2174 } 2175 } 2176 } 2177 return listenerInfo; 2178 } 2179 2180 void showNextToastLocked() { 2181 ToastRecord record = mToastQueue.get(0); 2182 while (record != null) { 2183 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback); 2184 try { 2185 record.callback.show(); 2186 scheduleTimeoutLocked(record); 2187 return; 2188 } catch (RemoteException e) { 2189 Slog.w(TAG, "Object died trying to show notification " + record.callback 2190 + " in package " + record.pkg); 2191 // remove it from the list and let the process die 2192 int index = mToastQueue.indexOf(record); 2193 if (index >= 0) { 2194 mToastQueue.remove(index); 2195 } 2196 keepProcessAliveLocked(record.pid); 2197 if (mToastQueue.size() > 0) { 2198 record = mToastQueue.get(0); 2199 } else { 2200 record = null; 2201 } 2202 } 2203 } 2204 } 2205 2206 void cancelToastLocked(int index) { 2207 ToastRecord record = mToastQueue.get(index); 2208 try { 2209 record.callback.hide(); 2210 } catch (RemoteException e) { 2211 Slog.w(TAG, "Object died trying to hide notification " + record.callback 2212 + " in package " + record.pkg); 2213 // don't worry about this, we're about to remove it from 2214 // the list anyway 2215 } 2216 mToastQueue.remove(index); 2217 keepProcessAliveLocked(record.pid); 2218 if (mToastQueue.size() > 0) { 2219 // Show the next one. If the callback fails, this will remove 2220 // it from the list, so don't assume that the list hasn't changed 2221 // after this point. 2222 showNextToastLocked(); 2223 } 2224 } 2225 2226 private void scheduleTimeoutLocked(ToastRecord r) 2227 { 2228 mHandler.removeCallbacksAndMessages(r); 2229 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r); 2230 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY; 2231 mHandler.sendMessageDelayed(m, delay); 2232 } 2233 2234 private void handleTimeout(ToastRecord record) 2235 { 2236 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback); 2237 synchronized (mToastQueue) { 2238 int index = indexOfToastLocked(record.pkg, record.callback); 2239 if (index >= 0) { 2240 cancelToastLocked(index); 2241 } 2242 } 2243 } 2244 2245 // lock on mToastQueue 2246 int indexOfToastLocked(String pkg, ITransientNotification callback) 2247 { 2248 IBinder cbak = callback.asBinder(); 2249 ArrayList<ToastRecord> list = mToastQueue; 2250 int len = list.size(); 2251 for (int i=0; i<len; i++) { 2252 ToastRecord r = list.get(i); 2253 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) { 2254 return i; 2255 } 2256 } 2257 return -1; 2258 } 2259 2260 // lock on mToastQueue 2261 void keepProcessAliveLocked(int pid) 2262 { 2263 int toastCount = 0; // toasts from this pid 2264 ArrayList<ToastRecord> list = mToastQueue; 2265 int N = list.size(); 2266 for (int i=0; i<N; i++) { 2267 ToastRecord r = list.get(i); 2268 if (r.pid == pid) { 2269 toastCount++; 2270 } 2271 } 2272 try { 2273 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0); 2274 } catch (RemoteException e) { 2275 // Shouldn't happen. 2276 } 2277 } 2278 2279 private final class WorkerHandler extends Handler 2280 { 2281 @Override 2282 public void handleMessage(Message msg) 2283 { 2284 switch (msg.what) 2285 { 2286 case MESSAGE_TIMEOUT: 2287 handleTimeout((ToastRecord)msg.obj); 2288 break; 2289 } 2290 } 2291 } 2292 2293 2294 // Notifications 2295 // ============================================================================ 2296 static int clamp(int x, int low, int high) { 2297 return (x < low) ? low : ((x > high) ? high : x); 2298 } 2299 2300 void sendAccessibilityEvent(Notification notification, CharSequence packageName) { 2301 AccessibilityManager manager = AccessibilityManager.getInstance(getContext()); 2302 if (!manager.isEnabled()) { 2303 return; 2304 } 2305 2306 AccessibilityEvent event = 2307 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); 2308 event.setPackageName(packageName); 2309 event.setClassName(Notification.class.getName()); 2310 event.setParcelableData(notification); 2311 CharSequence tickerText = notification.tickerText; 2312 if (!TextUtils.isEmpty(tickerText)) { 2313 event.getText().add(tickerText); 2314 } 2315 2316 manager.sendAccessibilityEvent(event); 2317 } 2318 2319 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) { 2320 // tell the app 2321 if (sendDelete) { 2322 if (r.getNotification().deleteIntent != null) { 2323 try { 2324 r.getNotification().deleteIntent.send(); 2325 } catch (PendingIntent.CanceledException ex) { 2326 // do nothing - there's no relevant way to recover, and 2327 // no reason to let this propagate 2328 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex); 2329 } 2330 } 2331 } 2332 2333 // status bar 2334 if (r.getNotification().icon != 0) { 2335 final long identity = Binder.clearCallingIdentity(); 2336 try { 2337 mStatusBar.removeNotification(r.statusBarKey); 2338 } finally { 2339 Binder.restoreCallingIdentity(identity); 2340 } 2341 r.statusBarKey = null; 2342 notifyRemovedLocked(r); 2343 } 2344 2345 // sound 2346 if (mSoundNotification == r) { 2347 mSoundNotification = null; 2348 final long identity = Binder.clearCallingIdentity(); 2349 try { 2350 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 2351 if (player != null) { 2352 player.stopAsync(); 2353 } 2354 } catch (RemoteException e) { 2355 } finally { 2356 Binder.restoreCallingIdentity(identity); 2357 } 2358 } 2359 2360 // vibrate 2361 if (mVibrateNotification == r) { 2362 mVibrateNotification = null; 2363 long identity = Binder.clearCallingIdentity(); 2364 try { 2365 mVibrator.cancel(); 2366 } 2367 finally { 2368 Binder.restoreCallingIdentity(identity); 2369 } 2370 } 2371 2372 // light 2373 mLights.remove(r); 2374 if (mLedNotification == r) { 2375 mLedNotification = null; 2376 } 2377 2378 // Record usage stats 2379 switch (reason) { 2380 case REASON_DELEGATE_CANCEL: 2381 case REASON_DELEGATE_CANCEL_ALL: 2382 case REASON_LISTENER_CANCEL: 2383 case REASON_LISTENER_CANCEL_ALL: 2384 mUsageStats.registerDismissedByUser(r); 2385 break; 2386 case REASON_NOMAN_CANCEL: 2387 case REASON_NOMAN_CANCEL_ALL: 2388 mUsageStats.registerRemovedByApp(r); 2389 break; 2390 case REASON_DELEGATE_CLICK: 2391 mUsageStats.registerCancelDueToClick(r); 2392 break; 2393 default: 2394 mUsageStats.registerCancelUnknown(r); 2395 break; 2396 } 2397 2398 // Save it for users of getHistoricalNotifications() 2399 mArchive.record(r.sbn); 2400 } 2401 2402 /** 2403 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags} 2404 * and none of the {@code mustNotHaveFlags}. 2405 */ 2406 void cancelNotification(final int callingUid, final int callingPid, 2407 final String pkg, final String tag, final int id, 2408 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, 2409 final int userId, final int reason, final NotificationListenerInfo listener) { 2410 // In enqueueNotificationInternal notifications are added by scheduling the 2411 // work on the worker handler. Hence, we also schedule the cancel on this 2412 // handler to avoid a scenario where an add notification call followed by a 2413 // remove notification call ends up in not removing the notification. 2414 mHandler.post(new Runnable() { 2415 @Override 2416 public void run() { 2417 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag, userId, 2418 mustHaveFlags, mustNotHaveFlags, reason, 2419 listener == null ? null : listener.component.toShortString()); 2420 2421 synchronized (mNotificationList) { 2422 int index = indexOfNotificationLocked(pkg, tag, id, userId); 2423 if (index >= 0) { 2424 NotificationRecord r = mNotificationList.get(index); 2425 2426 // Ideally we'd do this in the caller of this method. However, that would 2427 // require the caller to also find the notification. 2428 if (reason == REASON_DELEGATE_CLICK) { 2429 mUsageStats.registerClickedByUser(r); 2430 } 2431 2432 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) { 2433 return; 2434 } 2435 if ((r.getNotification().flags & mustNotHaveFlags) != 0) { 2436 return; 2437 } 2438 2439 mNotificationList.remove(index); 2440 mNotificationsByKey.remove(r.sbn.getKey()); 2441 2442 cancelNotificationLocked(r, sendDelete, reason); 2443 updateLightsLocked(); 2444 } 2445 } 2446 } 2447 }); 2448 } 2449 2450 /** 2451 * Determine whether the userId applies to the notification in question, either because 2452 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard). 2453 */ 2454 private boolean notificationMatchesUserId(NotificationRecord r, int userId) { 2455 return 2456 // looking for USER_ALL notifications? match everything 2457 userId == UserHandle.USER_ALL 2458 // a notification sent to USER_ALL matches any query 2459 || r.getUserId() == UserHandle.USER_ALL 2460 // an exact user match 2461 || r.getUserId() == userId; 2462 } 2463 2464 /** 2465 * Determine whether the userId applies to the notification in question, either because 2466 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or 2467 * because it matches one of the users profiles. 2468 */ 2469 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) { 2470 synchronized (mCurrentProfiles) { 2471 return notificationMatchesUserId(r, userId) 2472 || mCurrentProfiles.get(r.getUserId()) != null; 2473 } 2474 } 2475 2476 /** 2477 * Cancels all notifications from a given package that have all of the 2478 * {@code mustHaveFlags}. 2479 */ 2480 boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags, 2481 int mustNotHaveFlags, boolean doit, int userId, int reason, 2482 NotificationListenerInfo listener) { 2483 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 2484 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason, 2485 listener == null ? null : listener.component.toShortString()); 2486 2487 synchronized (mNotificationList) { 2488 final int N = mNotificationList.size(); 2489 boolean canceledSomething = false; 2490 for (int i = N-1; i >= 0; --i) { 2491 NotificationRecord r = mNotificationList.get(i); 2492 if (!notificationMatchesUserId(r, userId)) { 2493 continue; 2494 } 2495 // Don't remove notifications to all, if there's no package name specified 2496 if (r.getUserId() == UserHandle.USER_ALL && pkg == null) { 2497 continue; 2498 } 2499 if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) { 2500 continue; 2501 } 2502 if ((r.getFlags() & mustNotHaveFlags) != 0) { 2503 continue; 2504 } 2505 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) { 2506 continue; 2507 } 2508 canceledSomething = true; 2509 if (!doit) { 2510 return true; 2511 } 2512 mNotificationList.remove(i); 2513 mNotificationsByKey.remove(r.sbn.getKey()); 2514 cancelNotificationLocked(r, false, reason); 2515 } 2516 if (canceledSomething) { 2517 updateLightsLocked(); 2518 } 2519 return canceledSomething; 2520 } 2521 } 2522 2523 2524 2525 // Return true if the UID is a system or phone UID and therefore should not have 2526 // any notifications or toasts blocked. 2527 boolean isUidSystem(int uid) { 2528 final int appid = UserHandle.getAppId(uid); 2529 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0); 2530 } 2531 2532 // same as isUidSystem(int, int) for the Binder caller's UID. 2533 boolean isCallerSystem() { 2534 return isUidSystem(Binder.getCallingUid()); 2535 } 2536 2537 void checkCallerIsSystem() { 2538 if (isCallerSystem()) { 2539 return; 2540 } 2541 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid()); 2542 } 2543 2544 void checkCallerIsSystemOrSameApp(String pkg) { 2545 if (isCallerSystem()) { 2546 return; 2547 } 2548 final int uid = Binder.getCallingUid(); 2549 try { 2550 ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo( 2551 pkg, 0, UserHandle.getCallingUserId()); 2552 if (!UserHandle.isSameApp(ai.uid, uid)) { 2553 throw new SecurityException("Calling uid " + uid + " gave package" 2554 + pkg + " which is owned by uid " + ai.uid); 2555 } 2556 } catch (RemoteException re) { 2557 throw new SecurityException("Unknown package " + pkg + "\n" + re); 2558 } 2559 } 2560 2561 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason, 2562 NotificationListenerInfo listener) { 2563 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 2564 null, userId, 0, 0, reason, 2565 listener == null ? null : listener.component.toShortString()); 2566 2567 final int N = mNotificationList.size(); 2568 for (int i=N-1; i>=0; i--) { 2569 NotificationRecord r = mNotificationList.get(i); 2570 if (!notificationMatchesCurrentProfiles(r, userId)) { 2571 continue; 2572 } 2573 2574 if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT 2575 | Notification.FLAG_NO_CLEAR)) == 0) { 2576 mNotificationList.remove(i); 2577 mNotificationsByKey.remove(r.sbn.getKey()); 2578 cancelNotificationLocked(r, true, reason); 2579 } 2580 } 2581 updateLightsLocked(); 2582 } 2583 2584 // lock on mNotificationList 2585 void updateLightsLocked() 2586 { 2587 // handle notification lights 2588 if (mLedNotification == null) { 2589 // get next notification, if any 2590 int n = mLights.size(); 2591 if (n > 0) { 2592 mLedNotification = mLights.get(n-1); 2593 } 2594 } 2595 2596 // Don't flash while we are in a call or screen is on 2597 if (mLedNotification == null || mInCall || mScreenOn) { 2598 mNotificationLight.turnOff(); 2599 } else { 2600 final Notification ledno = mLedNotification.sbn.getNotification(); 2601 int ledARGB = ledno.ledARGB; 2602 int ledOnMS = ledno.ledOnMS; 2603 int ledOffMS = ledno.ledOffMS; 2604 if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) { 2605 ledARGB = mDefaultNotificationColor; 2606 ledOnMS = mDefaultNotificationLedOn; 2607 ledOffMS = mDefaultNotificationLedOff; 2608 } 2609 if (mNotificationPulseEnabled) { 2610 // pulse repeatedly 2611 mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED, 2612 ledOnMS, ledOffMS); 2613 } 2614 } 2615 } 2616 2617 // lock on mNotificationList 2618 int indexOfNotificationLocked(String pkg, String tag, int id, int userId) 2619 { 2620 ArrayList<NotificationRecord> list = mNotificationList; 2621 final int len = list.size(); 2622 for (int i=0; i<len; i++) { 2623 NotificationRecord r = list.get(i); 2624 if (!notificationMatchesUserId(r, userId) || r.sbn.getId() != id) { 2625 continue; 2626 } 2627 if (tag == null) { 2628 if (r.sbn.getTag() != null) { 2629 continue; 2630 } 2631 } else { 2632 if (!tag.equals(r.sbn.getTag())) { 2633 continue; 2634 } 2635 } 2636 if (r.sbn.getPackageName().equals(pkg)) { 2637 return i; 2638 } 2639 } 2640 return -1; 2641 } 2642 2643 private void updateNotificationPulse() { 2644 synchronized (mNotificationList) { 2645 updateLightsLocked(); 2646 } 2647 } 2648 2649 private void updateZenMode() { 2650 final int mode = Settings.Global.getInt(getContext().getContentResolver(), 2651 Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF); 2652 if (mode != mZenMode) { 2653 Slog.d(TAG, String.format("updateZenMode: %s -> %s", 2654 Settings.Global.zenModeToString(mZenMode), 2655 Settings.Global.zenModeToString(mode))); 2656 } 2657 mZenMode = mode; 2658 2659 final String[] exceptionPackages = null; // none (for now) 2660 2661 // call restrictions 2662 final boolean muteCalls = mZenMode != Settings.Global.ZEN_MODE_OFF; 2663 mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, AudioManager.STREAM_RING, 2664 muteCalls ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, 2665 exceptionPackages); 2666 mAppOps.setRestriction(AppOpsManager.OP_PLAY_AUDIO, AudioManager.STREAM_RING, 2667 muteCalls ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, 2668 exceptionPackages); 2669 2670 // alarm restrictions 2671 final boolean muteAlarms = false; // TODO until we save user config 2672 mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, AudioManager.STREAM_ALARM, 2673 muteAlarms ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, 2674 exceptionPackages); 2675 mAppOps.setRestriction(AppOpsManager.OP_PLAY_AUDIO, AudioManager.STREAM_ALARM, 2676 muteAlarms ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, 2677 exceptionPackages); 2678 2679 // restrict vibrations with no hints 2680 mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, AudioManager.USE_DEFAULT_STREAM_TYPE, 2681 (muteAlarms || muteCalls) ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, 2682 exceptionPackages); 2683 } 2684 2685 private void updateCurrentProfilesCache(Context context) { 2686 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); 2687 int currentUserId = ActivityManager.getCurrentUser(); 2688 if (userManager != null) { 2689 List<UserInfo> profiles = userManager.getProfiles(currentUserId); 2690 synchronized (mCurrentProfiles) { 2691 mCurrentProfiles.clear(); 2692 for (UserInfo user : profiles) { 2693 mCurrentProfiles.put(user.id, user); 2694 } 2695 } 2696 } 2697 } 2698 2699 private boolean isCall(String pkg, Notification n) { 2700 return CALL_PACKAGES.contains(pkg); 2701 } 2702 2703 private boolean isAlarm(String pkg, Notification n) { 2704 return ALARM_PACKAGES.contains(pkg); 2705 } 2706 2707 private boolean shouldIntercept(String pkg, Notification n) { 2708 if (mZenMode != Settings.Global.ZEN_MODE_OFF) { 2709 return !isAlarm(pkg, n); 2710 } 2711 return false; 2712 } 2713} 2714