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