NotificationManagerService.java revision a263e4e438746f91fb78857bd569ba4f796a346d
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 synchronized (mNotificationList) { 1014 // sound 1015 mSoundNotification = null; 1016 1017 long identity = Binder.clearCallingIdentity(); 1018 try { 1019 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 1020 if (player != null) { 1021 player.stopAsync(); 1022 } 1023 } catch (RemoteException e) { 1024 } finally { 1025 Binder.restoreCallingIdentity(identity); 1026 } 1027 1028 // vibrate 1029 mVibrateNotification = null; 1030 identity = Binder.clearCallingIdentity(); 1031 try { 1032 mVibrator.cancel(); 1033 } finally { 1034 Binder.restoreCallingIdentity(identity); 1035 } 1036 1037 // light 1038 mLights.clear(); 1039 mLedNotification = null; 1040 updateLightsLocked(); 1041 } 1042 } 1043 1044 @Override 1045 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id, 1046 int uid, int initialPid, String message, int userId) { 1047 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id 1048 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")"); 1049 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId, 1050 REASON_DELEGATE_ERROR, null); 1051 long ident = Binder.clearCallingIdentity(); 1052 try { 1053 ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg, 1054 "Bad notification posted from package " + pkg 1055 + ": " + message); 1056 } catch (RemoteException e) { 1057 } 1058 Binder.restoreCallingIdentity(ident); 1059 } 1060 1061 @Override 1062 public boolean allowDisable(int what, IBinder token, String pkg) { 1063 if (isCall(pkg, null)) { 1064 return mZenMode == Settings.Global.ZEN_MODE_OFF; 1065 } 1066 return true; 1067 } 1068 }; 1069 1070 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 1071 @Override 1072 public void onReceive(Context context, Intent intent) { 1073 String action = intent.getAction(); 1074 1075 boolean queryRestart = false; 1076 boolean queryRemove = false; 1077 boolean packageChanged = false; 1078 boolean cancelNotifications = true; 1079 1080 if (action.equals(Intent.ACTION_PACKAGE_ADDED) 1081 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED)) 1082 || action.equals(Intent.ACTION_PACKAGE_RESTARTED) 1083 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED)) 1084 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART)) 1085 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { 1086 String pkgList[] = null; 1087 boolean queryReplace = queryRemove && 1088 intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); 1089 if (DBG) Slog.i(TAG, "queryReplace=" + queryReplace); 1090 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { 1091 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1092 } else if (queryRestart) { 1093 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); 1094 } else { 1095 Uri uri = intent.getData(); 1096 if (uri == null) { 1097 return; 1098 } 1099 String pkgName = uri.getSchemeSpecificPart(); 1100 if (pkgName == null) { 1101 return; 1102 } 1103 if (packageChanged) { 1104 // We cancel notifications for packages which have just been disabled 1105 try { 1106 final int enabled = getContext().getPackageManager() 1107 .getApplicationEnabledSetting(pkgName); 1108 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED 1109 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { 1110 cancelNotifications = false; 1111 } 1112 } catch (IllegalArgumentException e) { 1113 // Package doesn't exist; probably racing with uninstall. 1114 // cancelNotifications is already true, so nothing to do here. 1115 if (DBG) { 1116 Slog.i(TAG, "Exception trying to look up app enabled setting", e); 1117 } 1118 } 1119 } 1120 pkgList = new String[]{pkgName}; 1121 } 1122 1123 boolean anyListenersInvolved = false; 1124 if (pkgList != null && (pkgList.length > 0)) { 1125 for (String pkgName : pkgList) { 1126 if (cancelNotifications) { 1127 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart, 1128 UserHandle.USER_ALL, REASON_PACKAGE_CHANGED, null); 1129 } 1130 if (mEnabledListenerPackageNames.contains(pkgName)) { 1131 anyListenersInvolved = true; 1132 } 1133 } 1134 } 1135 1136 if (anyListenersInvolved) { 1137 // if we're not replacing a package, clean up orphaned bits 1138 if (!queryReplace) { 1139 disableNonexistentListeners(); 1140 } 1141 // make sure we're still bound to any of our 1142 // listeners who may have just upgraded 1143 rebindListenerServices(); 1144 } 1145 } else if (action.equals(Intent.ACTION_SCREEN_ON)) { 1146 // Keep track of screen on/off state, but do not turn off the notification light 1147 // until user passes through the lock screen or views the notification. 1148 mScreenOn = true; 1149 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 1150 mScreenOn = false; 1151 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) { 1152 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK 1153 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE)); 1154 updateNotificationPulse(); 1155 } else if (action.equals(Intent.ACTION_USER_STOPPED)) { 1156 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 1157 if (userHandle >= 0) { 1158 cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle, 1159 REASON_USER_STOPPED, null); 1160 } 1161 } else if (action.equals(Intent.ACTION_USER_PRESENT)) { 1162 // turn off LED when user passes through lock screen 1163 mNotificationLight.turnOff(); 1164 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) { 1165 // reload per-user settings 1166 mSettingsObserver.update(null); 1167 updateCurrentProfilesCache(context); 1168 } else if (action.equals(Intent.ACTION_USER_ADDED)) { 1169 updateCurrentProfilesCache(context); 1170 } 1171 } 1172 }; 1173 1174 class SettingsObserver extends ContentObserver { 1175 private final Uri NOTIFICATION_LIGHT_PULSE_URI 1176 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE); 1177 1178 private final Uri ENABLED_NOTIFICATION_LISTENERS_URI 1179 = Settings.Secure.getUriFor(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS); 1180 1181 private final Uri ZEN_MODE 1182 = Settings.Global.getUriFor(Settings.Global.ZEN_MODE); 1183 1184 SettingsObserver(Handler handler) { 1185 super(handler); 1186 } 1187 1188 void observe() { 1189 ContentResolver resolver = getContext().getContentResolver(); 1190 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI, 1191 false, this, UserHandle.USER_ALL); 1192 resolver.registerContentObserver(ENABLED_NOTIFICATION_LISTENERS_URI, 1193 false, this, UserHandle.USER_ALL); 1194 resolver.registerContentObserver(ZEN_MODE, 1195 false, this); 1196 update(null); 1197 } 1198 1199 @Override public void onChange(boolean selfChange, Uri uri) { 1200 update(uri); 1201 } 1202 1203 public void update(Uri uri) { 1204 ContentResolver resolver = getContext().getContentResolver(); 1205 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) { 1206 boolean pulseEnabled = Settings.System.getInt(resolver, 1207 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0; 1208 if (mNotificationPulseEnabled != pulseEnabled) { 1209 mNotificationPulseEnabled = pulseEnabled; 1210 updateNotificationPulse(); 1211 } 1212 } 1213 if (uri == null || ENABLED_NOTIFICATION_LISTENERS_URI.equals(uri)) { 1214 rebindListenerServices(); 1215 } 1216 if (ZEN_MODE.equals(uri)) { 1217 updateZenMode(); 1218 } 1219 } 1220 } 1221 1222 private SettingsObserver mSettingsObserver; 1223 1224 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) { 1225 int[] ar = r.getIntArray(resid); 1226 if (ar == null) { 1227 return def; 1228 } 1229 final int len = ar.length > maxlen ? maxlen : ar.length; 1230 long[] out = new long[len]; 1231 for (int i=0; i<len; i++) { 1232 out[i] = ar[i]; 1233 } 1234 return out; 1235 } 1236 1237 public NotificationManagerService(Context context) { 1238 super(context); 1239 } 1240 1241 @Override 1242 public void onStart() { 1243 mAm = ActivityManagerNative.getDefault(); 1244 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); 1245 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE); 1246 1247 mHandler = new WorkerHandler(); 1248 1249 importOldBlockDb(); 1250 1251 mStatusBar = getLocalService(StatusBarManagerInternal.class); 1252 mStatusBar.setNotificationDelegate(mNotificationDelegate); 1253 1254 final LightsManager lights = getLocalService(LightsManager.class); 1255 mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS); 1256 mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION); 1257 1258 Resources resources = getContext().getResources(); 1259 mDefaultNotificationColor = resources.getColor( 1260 R.color.config_defaultNotificationColor); 1261 mDefaultNotificationLedOn = resources.getInteger( 1262 R.integer.config_defaultNotificationLedOn); 1263 mDefaultNotificationLedOff = resources.getInteger( 1264 R.integer.config_defaultNotificationLedOff); 1265 1266 mDefaultVibrationPattern = getLongArray(resources, 1267 R.array.config_defaultNotificationVibePattern, 1268 VIBRATE_PATTERN_MAXLEN, 1269 DEFAULT_VIBRATE_PATTERN); 1270 1271 mFallbackVibrationPattern = getLongArray(resources, 1272 R.array.config_notificationFallbackVibePattern, 1273 VIBRATE_PATTERN_MAXLEN, 1274 DEFAULT_VIBRATE_PATTERN); 1275 1276 // Don't start allowing notifications until the setup wizard has run once. 1277 // After that, including subsequent boots, init with notifications turned on. 1278 // This works on the first boot because the setup wizard will toggle this 1279 // flag at least once and we'll go back to 0 after that. 1280 if (0 == Settings.Global.getInt(getContext().getContentResolver(), 1281 Settings.Global.DEVICE_PROVISIONED, 0)) { 1282 mDisableNotificationAlerts = true; 1283 } 1284 updateZenMode(); 1285 1286 updateCurrentProfilesCache(getContext()); 1287 1288 // register for various Intents 1289 IntentFilter filter = new IntentFilter(); 1290 filter.addAction(Intent.ACTION_SCREEN_ON); 1291 filter.addAction(Intent.ACTION_SCREEN_OFF); 1292 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); 1293 filter.addAction(Intent.ACTION_USER_PRESENT); 1294 filter.addAction(Intent.ACTION_USER_STOPPED); 1295 filter.addAction(Intent.ACTION_USER_SWITCHED); 1296 filter.addAction(Intent.ACTION_USER_ADDED); 1297 getContext().registerReceiver(mIntentReceiver, filter); 1298 IntentFilter pkgFilter = new IntentFilter(); 1299 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 1300 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 1301 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 1302 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); 1303 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); 1304 pkgFilter.addDataScheme("package"); 1305 getContext().registerReceiver(mIntentReceiver, pkgFilter); 1306 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 1307 getContext().registerReceiver(mIntentReceiver, sdFilter); 1308 1309 mSettingsObserver = new SettingsObserver(mHandler); 1310 1311 // spin up NotificationScorers 1312 String[] notificationScorerNames = resources.getStringArray( 1313 R.array.config_notificationScorers); 1314 for (String scorerName : notificationScorerNames) { 1315 try { 1316 Class<?> scorerClass = getContext().getClassLoader().loadClass(scorerName); 1317 NotificationScorer scorer = (NotificationScorer) scorerClass.newInstance(); 1318 scorer.initialize(getContext()); 1319 mScorers.add(scorer); 1320 } catch (ClassNotFoundException e) { 1321 Slog.w(TAG, "Couldn't find scorer " + scorerName + ".", e); 1322 } catch (InstantiationException e) { 1323 Slog.w(TAG, "Couldn't instantiate scorer " + scorerName + ".", e); 1324 } catch (IllegalAccessException e) { 1325 Slog.w(TAG, "Problem accessing scorer " + scorerName + ".", e); 1326 } 1327 } 1328 1329 publishBinderService(Context.NOTIFICATION_SERVICE, mService); 1330 publishLocalService(NotificationManagerInternal.class, mInternalService); 1331 } 1332 1333 /** 1334 * Read the old XML-based app block database and import those blockages into the AppOps system. 1335 */ 1336 private void importOldBlockDb() { 1337 loadBlockDb(); 1338 1339 PackageManager pm = getContext().getPackageManager(); 1340 for (String pkg : mBlockedPackages) { 1341 PackageInfo info = null; 1342 try { 1343 info = pm.getPackageInfo(pkg, 0); 1344 setNotificationsEnabledForPackageImpl(pkg, info.applicationInfo.uid, false); 1345 } catch (NameNotFoundException e) { 1346 // forget you 1347 } 1348 } 1349 mBlockedPackages.clear(); 1350 if (mPolicyFile != null) { 1351 mPolicyFile.delete(); 1352 } 1353 } 1354 1355 @Override 1356 public void onBootPhase(int phase) { 1357 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 1358 // no beeping until we're basically done booting 1359 mSystemReady = true; 1360 1361 // Grab our optional AudioService 1362 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 1363 1364 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { 1365 // This observer will force an update when observe is called, causing us to 1366 // bind to listener services. 1367 mSettingsObserver.observe(); 1368 } 1369 } 1370 1371 void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) { 1372 Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg); 1373 1374 mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg, 1375 enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED); 1376 1377 // Now, cancel any outstanding notifications that are part of a just-disabled app 1378 if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) { 1379 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid), 1380 REASON_PACKAGE_BANNED, null); 1381 } 1382 } 1383 1384 private final IBinder mService = new INotificationManager.Stub() { 1385 // Toasts 1386 // ============================================================================ 1387 1388 @Override 1389 public void enqueueToast(String pkg, ITransientNotification callback, int duration) 1390 { 1391 if (DBG) { 1392 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback 1393 + " duration=" + duration); 1394 } 1395 1396 if (pkg == null || callback == null) { 1397 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback); 1398 return ; 1399 } 1400 1401 final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg)); 1402 1403 if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) { 1404 if (!isSystemToast) { 1405 Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request."); 1406 return; 1407 } 1408 } 1409 1410 synchronized (mToastQueue) { 1411 int callingPid = Binder.getCallingPid(); 1412 long callingId = Binder.clearCallingIdentity(); 1413 try { 1414 ToastRecord record; 1415 int index = indexOfToastLocked(pkg, callback); 1416 // If it's already in the queue, we update it in place, we don't 1417 // move it to the end of the queue. 1418 if (index >= 0) { 1419 record = mToastQueue.get(index); 1420 record.update(duration); 1421 } else { 1422 // Limit the number of toasts that any given package except the android 1423 // package can enqueue. Prevents DOS attacks and deals with leaks. 1424 if (!isSystemToast) { 1425 int count = 0; 1426 final int N = mToastQueue.size(); 1427 for (int i=0; i<N; i++) { 1428 final ToastRecord r = mToastQueue.get(i); 1429 if (r.pkg.equals(pkg)) { 1430 count++; 1431 if (count >= MAX_PACKAGE_NOTIFICATIONS) { 1432 Slog.e(TAG, "Package has already posted " + count 1433 + " toasts. Not showing more. Package=" + pkg); 1434 return; 1435 } 1436 } 1437 } 1438 } 1439 1440 record = new ToastRecord(callingPid, pkg, callback, duration); 1441 mToastQueue.add(record); 1442 index = mToastQueue.size() - 1; 1443 keepProcessAliveLocked(callingPid); 1444 } 1445 // If it's at index 0, it's the current toast. It doesn't matter if it's 1446 // new or just been updated. Call back and tell it to show itself. 1447 // If the callback fails, this will remove it from the list, so don't 1448 // assume that it's valid after this. 1449 if (index == 0) { 1450 showNextToastLocked(); 1451 } 1452 } finally { 1453 Binder.restoreCallingIdentity(callingId); 1454 } 1455 } 1456 } 1457 1458 @Override 1459 public void cancelToast(String pkg, ITransientNotification callback) { 1460 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback); 1461 1462 if (pkg == null || callback == null) { 1463 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback); 1464 return ; 1465 } 1466 1467 synchronized (mToastQueue) { 1468 long callingId = Binder.clearCallingIdentity(); 1469 try { 1470 int index = indexOfToastLocked(pkg, callback); 1471 if (index >= 0) { 1472 cancelToastLocked(index); 1473 } else { 1474 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg 1475 + " callback=" + callback); 1476 } 1477 } finally { 1478 Binder.restoreCallingIdentity(callingId); 1479 } 1480 } 1481 } 1482 1483 @Override 1484 public void enqueueNotificationWithTag(String pkg, String basePkg, String tag, int id, 1485 Notification notification, int[] idOut, int userId) throws RemoteException { 1486 enqueueNotificationInternal(pkg, basePkg, Binder.getCallingUid(), 1487 Binder.getCallingPid(), tag, id, notification, idOut, userId); 1488 } 1489 1490 @Override 1491 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) { 1492 checkCallerIsSystemOrSameApp(pkg); 1493 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 1494 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg); 1495 // Don't allow client applications to cancel foreground service notis. 1496 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0, 1497 Binder.getCallingUid() == Process.SYSTEM_UID 1498 ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId, REASON_NOMAN_CANCEL, 1499 null); 1500 } 1501 1502 @Override 1503 public void cancelAllNotifications(String pkg, int userId) { 1504 checkCallerIsSystemOrSameApp(pkg); 1505 1506 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 1507 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg); 1508 1509 // Calling from user space, don't allow the canceling of actively 1510 // running foreground services. 1511 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(), 1512 pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId, 1513 REASON_NOMAN_CANCEL_ALL, null); 1514 } 1515 1516 @Override 1517 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) { 1518 checkCallerIsSystem(); 1519 1520 setNotificationsEnabledForPackageImpl(pkg, uid, enabled); 1521 } 1522 1523 /** 1524 * Use this when you just want to know if notifications are OK for this package. 1525 */ 1526 @Override 1527 public boolean areNotificationsEnabledForPackage(String pkg, int uid) { 1528 checkCallerIsSystem(); 1529 return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg) 1530 == AppOpsManager.MODE_ALLOWED); 1531 } 1532 1533 /** 1534 * System-only API for getting a list of current (i.e. not cleared) notifications. 1535 * 1536 * Requires ACCESS_NOTIFICATIONS which is signature|system. 1537 */ 1538 @Override 1539 public StatusBarNotification[] getActiveNotifications(String callingPkg) { 1540 // enforce() will ensure the calling uid has the correct permission 1541 getContext().enforceCallingOrSelfPermission( 1542 android.Manifest.permission.ACCESS_NOTIFICATIONS, 1543 "NotificationManagerService.getActiveNotifications"); 1544 1545 StatusBarNotification[] tmp = null; 1546 int uid = Binder.getCallingUid(); 1547 1548 // noteOp will check to make sure the callingPkg matches the uid 1549 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg) 1550 == AppOpsManager.MODE_ALLOWED) { 1551 synchronized (mNotificationList) { 1552 tmp = new StatusBarNotification[mNotificationList.size()]; 1553 final int N = mNotificationList.size(); 1554 for (int i=0; i<N; i++) { 1555 tmp[i] = mNotificationList.get(i).sbn; 1556 } 1557 } 1558 } 1559 return tmp; 1560 } 1561 1562 /** 1563 * System-only API for getting a list of recent (cleared, no longer shown) notifications. 1564 * 1565 * Requires ACCESS_NOTIFICATIONS which is signature|system. 1566 */ 1567 @Override 1568 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) { 1569 // enforce() will ensure the calling uid has the correct permission 1570 getContext().enforceCallingOrSelfPermission( 1571 android.Manifest.permission.ACCESS_NOTIFICATIONS, 1572 "NotificationManagerService.getHistoricalNotifications"); 1573 1574 StatusBarNotification[] tmp = null; 1575 int uid = Binder.getCallingUid(); 1576 1577 // noteOp will check to make sure the callingPkg matches the uid 1578 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg) 1579 == AppOpsManager.MODE_ALLOWED) { 1580 synchronized (mArchive) { 1581 tmp = mArchive.getArray(count); 1582 } 1583 } 1584 return tmp; 1585 } 1586 1587 /** 1588 * Register a listener binder directly with the notification manager. 1589 * 1590 * Only works with system callers. Apps should extend 1591 * {@link android.service.notification.NotificationListenerService}. 1592 */ 1593 @Override 1594 public void registerListener(final INotificationListener listener, 1595 final ComponentName component, final int userid) { 1596 checkCallerIsSystem(); 1597 checkNullListener(listener); 1598 registerListenerImpl(listener, component, userid); 1599 } 1600 1601 /** 1602 * Remove a listener binder directly 1603 */ 1604 @Override 1605 public void unregisterListener(INotificationListener listener, int userid) { 1606 checkNullListener(listener); 1607 // no need to check permissions; if your listener binder is in the list, 1608 // that's proof that you had permission to add it in the first place 1609 unregisterListenerImpl(listener, userid); 1610 } 1611 1612 /** 1613 * Allow an INotificationListener to simulate a "clear all" operation. 1614 * 1615 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications} 1616 * 1617 * @param token The binder for the listener, to check that the caller is allowed 1618 */ 1619 @Override 1620 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) { 1621 final int callingUid = Binder.getCallingUid(); 1622 final int callingPid = Binder.getCallingPid(); 1623 long identity = Binder.clearCallingIdentity(); 1624 try { 1625 synchronized (mNotificationList) { 1626 final NotificationListenerInfo info = checkListenerTokenLocked(token); 1627 if (keys != null) { 1628 final int N = keys.length; 1629 for (int i = 0; i < N; i++) { 1630 NotificationRecord r = mNotificationsByKey.get(keys[i]); 1631 final int userId = r.sbn.getUserId(); 1632 if (userId != info.userid && userId != UserHandle.USER_ALL && 1633 !isCurrentProfile(userId)) { 1634 throw new SecurityException("Disallowed call from listener: " 1635 + info.listener); 1636 } 1637 if (r != null) { 1638 cancelNotificationFromListenerLocked(info, callingUid, callingPid, 1639 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(), 1640 userId); 1641 } 1642 } 1643 } else { 1644 cancelAllLocked(callingUid, callingPid, info.userid, 1645 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles()); 1646 } 1647 } 1648 } finally { 1649 Binder.restoreCallingIdentity(identity); 1650 } 1651 } 1652 1653 private void cancelNotificationFromListenerLocked(NotificationListenerInfo info, 1654 int callingUid, int callingPid, String pkg, String tag, int id, int userId) { 1655 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 1656 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE, 1657 true, 1658 userId, REASON_LISTENER_CANCEL, info); 1659 } 1660 1661 /** 1662 * Allow an INotificationListener to simulate clearing (dismissing) a single notification. 1663 * 1664 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear} 1665 * 1666 * @param token The binder for the listener, to check that the caller is allowed 1667 */ 1668 @Override 1669 public void cancelNotificationFromListener(INotificationListener token, String pkg, 1670 String tag, int id) { 1671 final int callingUid = Binder.getCallingUid(); 1672 final int callingPid = Binder.getCallingPid(); 1673 long identity = Binder.clearCallingIdentity(); 1674 try { 1675 synchronized (mNotificationList) { 1676 final NotificationListenerInfo info = checkListenerTokenLocked(token); 1677 if (info.supportsProfiles()) { 1678 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) " 1679 + "from " + info.component 1680 + " use cancelNotification(key) instead."); 1681 } else { 1682 cancelNotificationFromListenerLocked(info, callingUid, callingPid, 1683 pkg, tag, id, info.userid); 1684 } 1685 } 1686 } finally { 1687 Binder.restoreCallingIdentity(identity); 1688 } 1689 } 1690 1691 /** 1692 * Allow an INotificationListener to request the list of outstanding notifications seen by 1693 * the current user. Useful when starting up, after which point the listener callbacks 1694 * should be used. 1695 * 1696 * @param token The binder for the listener, to check that the caller is allowed 1697 */ 1698 @Override 1699 public StatusBarNotification[] getActiveNotificationsFromListener( 1700 INotificationListener token, String[] keys) { 1701 synchronized (mNotificationList) { 1702 final NotificationListenerInfo info = checkListenerTokenLocked(token); 1703 final ArrayList<StatusBarNotification> list 1704 = new ArrayList<StatusBarNotification>(); 1705 if (keys == null) { 1706 final int N = mNotificationList.size(); 1707 for (int i=0; i<N; i++) { 1708 StatusBarNotification sbn = mNotificationList.get(i).sbn; 1709 if (info.enabledAndUserMatches(sbn)) { 1710 list.add(sbn); 1711 } 1712 } 1713 } else { 1714 final int N = keys.length; 1715 for (int i=0; i<N; i++) { 1716 NotificationRecord r = mNotificationsByKey.get(keys[i]); 1717 if (r != null && info.enabledAndUserMatches(r.sbn)) { 1718 list.add(r.sbn); 1719 } 1720 } 1721 } 1722 return list.toArray(new StatusBarNotification[list.size()]); 1723 } 1724 } 1725 1726 @Override 1727 public String[] getActiveNotificationKeysFromListener(INotificationListener token) { 1728 return NotificationManagerService.this.getActiveNotificationKeysFromListener(token); 1729 } 1730 1731 @Override 1732 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1733 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1734 != PackageManager.PERMISSION_GRANTED) { 1735 pw.println("Permission Denial: can't dump NotificationManager from from pid=" 1736 + Binder.getCallingPid() 1737 + ", uid=" + Binder.getCallingUid()); 1738 return; 1739 } 1740 1741 dumpImpl(pw); 1742 } 1743 }; 1744 1745 private String[] getActiveNotificationKeysFromListener(INotificationListener token) { 1746 synchronized (mNotificationList) { 1747 final NotificationListenerInfo info = checkListenerTokenLocked(token); 1748 final ArrayList<String> keys = new ArrayList<String>(); 1749 final int N = mNotificationList.size(); 1750 for (int i=0; i<N; i++) { 1751 final StatusBarNotification sbn = mNotificationList.get(i).sbn; 1752 if (info.enabledAndUserMatches(sbn)) { 1753 keys.add(sbn.getKey()); 1754 } 1755 } 1756 return keys.toArray(new String[keys.size()]); 1757 } 1758 } 1759 1760 void dumpImpl(PrintWriter pw) { 1761 pw.println("Current Notification Manager state:"); 1762 1763 pw.println(" Listeners (" + mEnabledListenersForCurrentProfiles.size() 1764 + ") enabled for current profiles:"); 1765 for (ComponentName cmpt : mEnabledListenersForCurrentProfiles) { 1766 pw.println(" " + cmpt); 1767 } 1768 1769 pw.println(" Live listeners (" + mListeners.size() + "):"); 1770 for (NotificationListenerInfo info : mListeners) { 1771 pw.println(" " + info.component 1772 + " (user " + info.userid + "): " + info.listener 1773 + (info.isSystem?" SYSTEM":"")); 1774 } 1775 1776 int N; 1777 1778 synchronized (mToastQueue) { 1779 N = mToastQueue.size(); 1780 if (N > 0) { 1781 pw.println(" Toast Queue:"); 1782 for (int i=0; i<N; i++) { 1783 mToastQueue.get(i).dump(pw, " "); 1784 } 1785 pw.println(" "); 1786 } 1787 1788 } 1789 1790 synchronized (mNotificationList) { 1791 N = mNotificationList.size(); 1792 if (N > 0) { 1793 pw.println(" Notification List:"); 1794 for (int i=0; i<N; i++) { 1795 mNotificationList.get(i).dump(pw, " ", getContext()); 1796 } 1797 pw.println(" "); 1798 } 1799 1800 N = mLights.size(); 1801 if (N > 0) { 1802 pw.println(" Lights List:"); 1803 for (int i=0; i<N; i++) { 1804 pw.println(" " + mLights.get(i)); 1805 } 1806 pw.println(" "); 1807 } 1808 1809 pw.println(" mSoundNotification=" + mSoundNotification); 1810 pw.println(" mVibrateNotification=" + mVibrateNotification); 1811 pw.println(" mDisableNotificationAlerts=" + mDisableNotificationAlerts); 1812 pw.println(" mZenMode=" + Settings.Global.zenModeToString(mZenMode)); 1813 pw.println(" mSystemReady=" + mSystemReady); 1814 pw.println(" mArchive=" + mArchive.toString()); 1815 Iterator<StatusBarNotification> iter = mArchive.descendingIterator(); 1816 int i=0; 1817 while (iter.hasNext()) { 1818 pw.println(" " + iter.next()); 1819 if (++i >= 5) { 1820 if (iter.hasNext()) pw.println(" ..."); 1821 break; 1822 } 1823 } 1824 1825 pw.println("\n Usage Stats:"); 1826 mUsageStats.dump(pw, " "); 1827 1828 } 1829 } 1830 1831 /** 1832 * The private API only accessible to the system process. 1833 */ 1834 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() { 1835 @Override 1836 public void enqueueNotification(String pkg, String basePkg, int callingUid, int callingPid, 1837 String tag, int id, Notification notification, int[] idReceived, int userId) { 1838 enqueueNotificationInternal(pkg, basePkg, callingUid, callingPid, tag, id, notification, 1839 idReceived, userId); 1840 } 1841 }; 1842 1843 void enqueueNotificationInternal(final String pkg, String basePkg, final int callingUid, 1844 final int callingPid, final String tag, final int id, final Notification notification, 1845 int[] idOut, int incomingUserId) { 1846 if (DBG) { 1847 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id 1848 + " notification=" + notification); 1849 } 1850 checkCallerIsSystemOrSameApp(pkg); 1851 final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg)); 1852 1853 final int userId = ActivityManager.handleIncomingUser(callingPid, 1854 callingUid, incomingUserId, true, false, "enqueueNotification", pkg); 1855 final UserHandle user = new UserHandle(userId); 1856 1857 // Limit the number of notifications that any given package except the android 1858 // package can enqueue. Prevents DOS attacks and deals with leaks. 1859 if (!isSystemNotification) { 1860 synchronized (mNotificationList) { 1861 int count = 0; 1862 final int N = mNotificationList.size(); 1863 for (int i=0; i<N; i++) { 1864 final NotificationRecord r = mNotificationList.get(i); 1865 if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) { 1866 count++; 1867 if (count >= MAX_PACKAGE_NOTIFICATIONS) { 1868 Slog.e(TAG, "Package has already posted " + count 1869 + " notifications. Not showing more. package=" + pkg); 1870 return; 1871 } 1872 } 1873 } 1874 } 1875 } 1876 1877 // This conditional is a dirty hack to limit the logging done on 1878 // behalf of the download manager without affecting other apps. 1879 if (!pkg.equals("com.android.providers.downloads") 1880 || Log.isLoggable("DownloadManager", Log.VERBOSE)) { 1881 EventLogTags.writeNotificationEnqueue(callingUid, callingPid, 1882 pkg, id, tag, userId, notification.toString()); 1883 } 1884 1885 if (pkg == null || notification == null) { 1886 throw new IllegalArgumentException("null not allowed: pkg=" + pkg 1887 + " id=" + id + " notification=" + notification); 1888 } 1889 if (notification.icon != 0) { 1890 if (notification.contentView == null) { 1891 throw new IllegalArgumentException("contentView required: pkg=" + pkg 1892 + " id=" + id + " notification=" + notification); 1893 } 1894 } 1895 1896 mHandler.post(new Runnable() { 1897 @Override 1898 public void run() { 1899 1900 // === Scoring === 1901 1902 // 0. Sanitize inputs 1903 notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN, 1904 Notification.PRIORITY_MAX); 1905 // Migrate notification flags to scores 1906 if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) { 1907 if (notification.priority < Notification.PRIORITY_MAX) { 1908 notification.priority = Notification.PRIORITY_MAX; 1909 } 1910 } else if (SCORE_ONGOING_HIGHER && 1911 0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) { 1912 if (notification.priority < Notification.PRIORITY_HIGH) { 1913 notification.priority = Notification.PRIORITY_HIGH; 1914 } 1915 } 1916 1917 // 1. initial score: buckets of 10, around the app 1918 int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER; //[-20..20] 1919 1920 // 2. Consult external heuristics (TBD) 1921 1922 // 3. Apply local rules 1923 1924 int initialScore = score; 1925 if (!mScorers.isEmpty()) { 1926 if (DBG) Slog.v(TAG, "Initial score is " + score + "."); 1927 for (NotificationScorer scorer : mScorers) { 1928 try { 1929 score = scorer.getScore(notification, score); 1930 } catch (Throwable t) { 1931 Slog.w(TAG, "Scorer threw on .getScore.", t); 1932 } 1933 } 1934 if (DBG) Slog.v(TAG, "Final score is " + score + "."); 1935 } 1936 1937 // add extra to indicate score modified by NotificationScorer 1938 notification.extras.putBoolean(Notification.EXTRA_SCORE_MODIFIED, 1939 score != initialScore); 1940 1941 // blocked apps 1942 if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) { 1943 if (!isSystemNotification) { 1944 score = JUNK_SCORE; 1945 Slog.e(TAG, "Suppressing notification from package " + pkg 1946 + " by user request."); 1947 } 1948 } 1949 1950 if (DBG) { 1951 Slog.v(TAG, "Assigned score=" + score + " to " + notification); 1952 } 1953 1954 if (score < SCORE_DISPLAY_THRESHOLD) { 1955 // Notification will be blocked because the score is too low. 1956 return; 1957 } 1958 1959 // Is this notification intercepted by zen mode? 1960 final boolean intercept = shouldIntercept(pkg, notification); 1961 notification.extras.putBoolean(EXTRA_INTERCEPT, intercept); 1962 1963 // Should this notification make noise, vibe, or use the LED? 1964 final boolean canInterrupt = (score >= SCORE_INTERRUPTION_THRESHOLD) && !intercept; 1965 if (DBG) Slog.v(TAG, "canInterrupt=" + canInterrupt + " intercept=" + intercept); 1966 synchronized (mNotificationList) { 1967 final StatusBarNotification n = new StatusBarNotification( 1968 pkg, id, tag, callingUid, callingPid, score, notification, user); 1969 NotificationRecord r = new NotificationRecord(n); 1970 NotificationRecord old = null; 1971 1972 int index = indexOfNotificationLocked(pkg, tag, id, userId); 1973 if (index < 0) { 1974 mNotificationList.add(r); 1975 mUsageStats.registerPostedByApp(r); 1976 } else { 1977 old = mNotificationList.remove(index); 1978 mNotificationList.add(index, r); 1979 mUsageStats.registerUpdatedByApp(r); 1980 // Make sure we don't lose the foreground service state. 1981 if (old != null) { 1982 notification.flags |= 1983 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE; 1984 } 1985 } 1986 if (old != null) { 1987 mNotificationsByKey.remove(old.sbn.getKey()); 1988 } 1989 mNotificationsByKey.put(n.getKey(), r); 1990 1991 // Ensure if this is a foreground service that the proper additional 1992 // flags are set. 1993 if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) { 1994 notification.flags |= Notification.FLAG_ONGOING_EVENT 1995 | Notification.FLAG_NO_CLEAR; 1996 } 1997 1998 final int currentUser; 1999 final long token = Binder.clearCallingIdentity(); 2000 try { 2001 currentUser = ActivityManager.getCurrentUser(); 2002 } finally { 2003 Binder.restoreCallingIdentity(token); 2004 } 2005 2006 if (notification.icon != 0) { 2007 if (old != null && old.statusBarKey != null) { 2008 r.statusBarKey = old.statusBarKey; 2009 final long identity = Binder.clearCallingIdentity(); 2010 try { 2011 mStatusBar.updateNotification(r.statusBarKey, n); 2012 } finally { 2013 Binder.restoreCallingIdentity(identity); 2014 } 2015 } else { 2016 final long identity = Binder.clearCallingIdentity(); 2017 try { 2018 r.statusBarKey = mStatusBar.addNotification(n); 2019 if ((n.getNotification().flags & Notification.FLAG_SHOW_LIGHTS) != 0 2020 && canInterrupt) { 2021 mAttentionLight.pulse(); 2022 } 2023 } finally { 2024 Binder.restoreCallingIdentity(identity); 2025 } 2026 } 2027 // Send accessibility events only for the current user. 2028 if (currentUser == userId) { 2029 sendAccessibilityEvent(notification, pkg); 2030 } 2031 2032 notifyPostedLocked(r); 2033 } else { 2034 Slog.e(TAG, "Not posting notification with icon==0: " + notification); 2035 if (old != null && old.statusBarKey != null) { 2036 final long identity = Binder.clearCallingIdentity(); 2037 try { 2038 mStatusBar.removeNotification(old.statusBarKey); 2039 } finally { 2040 Binder.restoreCallingIdentity(identity); 2041 } 2042 2043 notifyRemovedLocked(r); 2044 } 2045 // ATTENTION: in a future release we will bail out here 2046 // so that we do not play sounds, show lights, etc. for invalid 2047 // notifications 2048 Slog.e(TAG, "WARNING: In a future release this will crash the app: " 2049 + n.getPackageName()); 2050 } 2051 2052 // If we're not supposed to beep, vibrate, etc. then don't. 2053 if (!mDisableNotificationAlerts 2054 && (!(old != null 2055 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 )) 2056 && (r.getUserId() == UserHandle.USER_ALL || 2057 (r.getUserId() == userId && r.getUserId() == currentUser) || 2058 isCurrentProfile(r.getUserId())) 2059 && canInterrupt 2060 && mSystemReady 2061 && mAudioManager != null) { 2062 if (DBG) Slog.v(TAG, "Interrupting!"); 2063 // sound 2064 2065 // should we use the default notification sound? (indicated either by 2066 // DEFAULT_SOUND or because notification.sound is pointing at 2067 // Settings.System.NOTIFICATION_SOUND) 2068 final boolean useDefaultSound = 2069 (notification.defaults & Notification.DEFAULT_SOUND) != 0 || 2070 Settings.System.DEFAULT_NOTIFICATION_URI 2071 .equals(notification.sound); 2072 2073 Uri soundUri = null; 2074 boolean hasValidSound = false; 2075 2076 if (useDefaultSound) { 2077 soundUri = Settings.System.DEFAULT_NOTIFICATION_URI; 2078 2079 // check to see if the default notification sound is silent 2080 ContentResolver resolver = getContext().getContentResolver(); 2081 hasValidSound = Settings.System.getString(resolver, 2082 Settings.System.NOTIFICATION_SOUND) != null; 2083 } else if (notification.sound != null) { 2084 soundUri = notification.sound; 2085 hasValidSound = (soundUri != null); 2086 } 2087 2088 if (hasValidSound) { 2089 boolean looping = 2090 (notification.flags & Notification.FLAG_INSISTENT) != 0; 2091 int audioStreamType; 2092 if (notification.audioStreamType >= 0) { 2093 audioStreamType = notification.audioStreamType; 2094 } else { 2095 audioStreamType = DEFAULT_STREAM_TYPE; 2096 } 2097 mSoundNotification = r; 2098 // do not play notifications if stream volume is 0 (typically because 2099 // ringer mode is silent) or if there is a user of exclusive audio focus 2100 if ((mAudioManager.getStreamVolume(audioStreamType) != 0) 2101 && !mAudioManager.isAudioFocusExclusive()) { 2102 final long identity = Binder.clearCallingIdentity(); 2103 try { 2104 final IRingtonePlayer player = 2105 mAudioManager.getRingtonePlayer(); 2106 if (player != null) { 2107 if (DBG) Slog.v(TAG, "Playing sound " + soundUri 2108 + " on stream " + audioStreamType); 2109 player.playAsync(soundUri, user, looping, audioStreamType); 2110 } 2111 } catch (RemoteException e) { 2112 } finally { 2113 Binder.restoreCallingIdentity(identity); 2114 } 2115 } 2116 } 2117 2118 // vibrate 2119 // Does the notification want to specify its own vibration? 2120 final boolean hasCustomVibrate = notification.vibrate != null; 2121 2122 // new in 4.2: if there was supposed to be a sound and we're in vibrate 2123 // mode, and no other vibration is specified, we fall back to vibration 2124 final boolean convertSoundToVibration = 2125 !hasCustomVibrate 2126 && hasValidSound 2127 && (mAudioManager.getRingerMode() 2128 == AudioManager.RINGER_MODE_VIBRATE); 2129 2130 // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback. 2131 final boolean useDefaultVibrate = 2132 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0; 2133 2134 if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate) 2135 && !(mAudioManager.getRingerMode() 2136 == AudioManager.RINGER_MODE_SILENT)) { 2137 mVibrateNotification = r; 2138 2139 if (useDefaultVibrate || convertSoundToVibration) { 2140 // Escalate privileges so we can use the vibrator even if the 2141 // notifying app does not have the VIBRATE permission. 2142 long identity = Binder.clearCallingIdentity(); 2143 try { 2144 mVibrator.vibrate(r.sbn.getUid(), r.sbn.getBasePkg(), 2145 useDefaultVibrate ? mDefaultVibrationPattern 2146 : mFallbackVibrationPattern, 2147 ((notification.flags & Notification.FLAG_INSISTENT) != 0) 2148 ? 0: -1, notification.audioStreamType); 2149 } finally { 2150 Binder.restoreCallingIdentity(identity); 2151 } 2152 } else if (notification.vibrate.length > 1) { 2153 // If you want your own vibration pattern, you need the VIBRATE 2154 // permission 2155 mVibrator.vibrate(r.sbn.getUid(), r.sbn.getBasePkg(), 2156 notification.vibrate, 2157 ((notification.flags & Notification.FLAG_INSISTENT) != 0) 2158 ? 0: -1, notification.audioStreamType); 2159 } 2160 } 2161 } 2162 2163 // light 2164 // the most recent thing gets the light 2165 mLights.remove(old); 2166 if (mLedNotification == old) { 2167 mLedNotification = null; 2168 } 2169 //Slog.i(TAG, "notification.lights=" 2170 // + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS) 2171 // != 0)); 2172 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 2173 && canInterrupt) { 2174 mLights.add(r); 2175 updateLightsLocked(); 2176 } else { 2177 if (old != null 2178 && ((old.getFlags() & Notification.FLAG_SHOW_LIGHTS) != 0)) { 2179 updateLightsLocked(); 2180 } 2181 } 2182 } 2183 } 2184 }); 2185 2186 idOut[0] = id; 2187 } 2188 2189 void registerListenerImpl(final INotificationListener listener, 2190 final ComponentName component, final int userid) { 2191 synchronized (mNotificationList) { 2192 try { 2193 NotificationListenerInfo info 2194 = new NotificationListenerInfo(listener, component, userid, 2195 /*isSystem*/ true, Build.VERSION_CODES.L); 2196 listener.asBinder().linkToDeath(info, 0); 2197 mListeners.add(info); 2198 } catch (RemoteException e) { 2199 // already dead 2200 } 2201 } 2202 } 2203 2204 /** 2205 * Removes a listener from the list and unbinds from its service. 2206 */ 2207 void unregisterListenerImpl(final INotificationListener listener, final int userid) { 2208 NotificationListenerInfo info = removeListenerImpl(listener, userid); 2209 if (info != null && info.connection != null) { 2210 getContext().unbindService(info.connection); 2211 } 2212 } 2213 2214 /** 2215 * Removes a listener from the list but does not unbind from the listener's service. 2216 * 2217 * @return the removed listener. 2218 */ 2219 NotificationListenerInfo removeListenerImpl( 2220 final INotificationListener listener, final int userid) { 2221 NotificationListenerInfo listenerInfo = null; 2222 synchronized (mNotificationList) { 2223 final int N = mListeners.size(); 2224 for (int i=N-1; i>=0; i--) { 2225 final NotificationListenerInfo info = mListeners.get(i); 2226 if (info.listener.asBinder() == listener.asBinder() 2227 && info.userid == userid) { 2228 listenerInfo = mListeners.remove(i); 2229 } 2230 } 2231 } 2232 return listenerInfo; 2233 } 2234 2235 void showNextToastLocked() { 2236 ToastRecord record = mToastQueue.get(0); 2237 while (record != null) { 2238 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback); 2239 try { 2240 record.callback.show(); 2241 scheduleTimeoutLocked(record); 2242 return; 2243 } catch (RemoteException e) { 2244 Slog.w(TAG, "Object died trying to show notification " + record.callback 2245 + " in package " + record.pkg); 2246 // remove it from the list and let the process die 2247 int index = mToastQueue.indexOf(record); 2248 if (index >= 0) { 2249 mToastQueue.remove(index); 2250 } 2251 keepProcessAliveLocked(record.pid); 2252 if (mToastQueue.size() > 0) { 2253 record = mToastQueue.get(0); 2254 } else { 2255 record = null; 2256 } 2257 } 2258 } 2259 } 2260 2261 void cancelToastLocked(int index) { 2262 ToastRecord record = mToastQueue.get(index); 2263 try { 2264 record.callback.hide(); 2265 } catch (RemoteException e) { 2266 Slog.w(TAG, "Object died trying to hide notification " + record.callback 2267 + " in package " + record.pkg); 2268 // don't worry about this, we're about to remove it from 2269 // the list anyway 2270 } 2271 mToastQueue.remove(index); 2272 keepProcessAliveLocked(record.pid); 2273 if (mToastQueue.size() > 0) { 2274 // Show the next one. If the callback fails, this will remove 2275 // it from the list, so don't assume that the list hasn't changed 2276 // after this point. 2277 showNextToastLocked(); 2278 } 2279 } 2280 2281 private void scheduleTimeoutLocked(ToastRecord r) 2282 { 2283 mHandler.removeCallbacksAndMessages(r); 2284 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r); 2285 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY; 2286 mHandler.sendMessageDelayed(m, delay); 2287 } 2288 2289 private void handleTimeout(ToastRecord record) 2290 { 2291 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback); 2292 synchronized (mToastQueue) { 2293 int index = indexOfToastLocked(record.pkg, record.callback); 2294 if (index >= 0) { 2295 cancelToastLocked(index); 2296 } 2297 } 2298 } 2299 2300 // lock on mToastQueue 2301 int indexOfToastLocked(String pkg, ITransientNotification callback) 2302 { 2303 IBinder cbak = callback.asBinder(); 2304 ArrayList<ToastRecord> list = mToastQueue; 2305 int len = list.size(); 2306 for (int i=0; i<len; i++) { 2307 ToastRecord r = list.get(i); 2308 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) { 2309 return i; 2310 } 2311 } 2312 return -1; 2313 } 2314 2315 // lock on mToastQueue 2316 void keepProcessAliveLocked(int pid) 2317 { 2318 int toastCount = 0; // toasts from this pid 2319 ArrayList<ToastRecord> list = mToastQueue; 2320 int N = list.size(); 2321 for (int i=0; i<N; i++) { 2322 ToastRecord r = list.get(i); 2323 if (r.pid == pid) { 2324 toastCount++; 2325 } 2326 } 2327 try { 2328 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0); 2329 } catch (RemoteException e) { 2330 // Shouldn't happen. 2331 } 2332 } 2333 2334 private final class WorkerHandler extends Handler 2335 { 2336 @Override 2337 public void handleMessage(Message msg) 2338 { 2339 switch (msg.what) 2340 { 2341 case MESSAGE_TIMEOUT: 2342 handleTimeout((ToastRecord)msg.obj); 2343 break; 2344 } 2345 } 2346 } 2347 2348 2349 // Notifications 2350 // ============================================================================ 2351 static int clamp(int x, int low, int high) { 2352 return (x < low) ? low : ((x > high) ? high : x); 2353 } 2354 2355 void sendAccessibilityEvent(Notification notification, CharSequence packageName) { 2356 AccessibilityManager manager = AccessibilityManager.getInstance(getContext()); 2357 if (!manager.isEnabled()) { 2358 return; 2359 } 2360 2361 AccessibilityEvent event = 2362 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); 2363 event.setPackageName(packageName); 2364 event.setClassName(Notification.class.getName()); 2365 event.setParcelableData(notification); 2366 CharSequence tickerText = notification.tickerText; 2367 if (!TextUtils.isEmpty(tickerText)) { 2368 event.getText().add(tickerText); 2369 } 2370 2371 manager.sendAccessibilityEvent(event); 2372 } 2373 2374 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) { 2375 // tell the app 2376 if (sendDelete) { 2377 if (r.getNotification().deleteIntent != null) { 2378 try { 2379 r.getNotification().deleteIntent.send(); 2380 } catch (PendingIntent.CanceledException ex) { 2381 // do nothing - there's no relevant way to recover, and 2382 // no reason to let this propagate 2383 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex); 2384 } 2385 } 2386 } 2387 2388 // status bar 2389 if (r.getNotification().icon != 0) { 2390 final long identity = Binder.clearCallingIdentity(); 2391 try { 2392 mStatusBar.removeNotification(r.statusBarKey); 2393 } finally { 2394 Binder.restoreCallingIdentity(identity); 2395 } 2396 r.statusBarKey = null; 2397 notifyRemovedLocked(r); 2398 } 2399 2400 // sound 2401 if (mSoundNotification == r) { 2402 mSoundNotification = null; 2403 final long identity = Binder.clearCallingIdentity(); 2404 try { 2405 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 2406 if (player != null) { 2407 player.stopAsync(); 2408 } 2409 } catch (RemoteException e) { 2410 } finally { 2411 Binder.restoreCallingIdentity(identity); 2412 } 2413 } 2414 2415 // vibrate 2416 if (mVibrateNotification == r) { 2417 mVibrateNotification = null; 2418 long identity = Binder.clearCallingIdentity(); 2419 try { 2420 mVibrator.cancel(); 2421 } 2422 finally { 2423 Binder.restoreCallingIdentity(identity); 2424 } 2425 } 2426 2427 // light 2428 mLights.remove(r); 2429 if (mLedNotification == r) { 2430 mLedNotification = null; 2431 } 2432 2433 // Record usage stats 2434 switch (reason) { 2435 case REASON_DELEGATE_CANCEL: 2436 case REASON_DELEGATE_CANCEL_ALL: 2437 case REASON_LISTENER_CANCEL: 2438 case REASON_LISTENER_CANCEL_ALL: 2439 mUsageStats.registerDismissedByUser(r); 2440 break; 2441 case REASON_NOMAN_CANCEL: 2442 case REASON_NOMAN_CANCEL_ALL: 2443 mUsageStats.registerRemovedByApp(r); 2444 break; 2445 case REASON_DELEGATE_CLICK: 2446 mUsageStats.registerCancelDueToClick(r); 2447 break; 2448 default: 2449 mUsageStats.registerCancelUnknown(r); 2450 break; 2451 } 2452 2453 // Save it for users of getHistoricalNotifications() 2454 mArchive.record(r.sbn); 2455 } 2456 2457 /** 2458 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags} 2459 * and none of the {@code mustNotHaveFlags}. 2460 */ 2461 void cancelNotification(final int callingUid, final int callingPid, 2462 final String pkg, final String tag, final int id, 2463 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, 2464 final int userId, final int reason, final NotificationListenerInfo listener) { 2465 // In enqueueNotificationInternal notifications are added by scheduling the 2466 // work on the worker handler. Hence, we also schedule the cancel on this 2467 // handler to avoid a scenario where an add notification call followed by a 2468 // remove notification call ends up in not removing the notification. 2469 mHandler.post(new Runnable() { 2470 @Override 2471 public void run() { 2472 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag, userId, 2473 mustHaveFlags, mustNotHaveFlags, reason, 2474 listener == null ? null : listener.component.toShortString()); 2475 2476 synchronized (mNotificationList) { 2477 int index = indexOfNotificationLocked(pkg, tag, id, userId); 2478 if (index >= 0) { 2479 NotificationRecord r = mNotificationList.get(index); 2480 2481 // Ideally we'd do this in the caller of this method. However, that would 2482 // require the caller to also find the notification. 2483 if (reason == REASON_DELEGATE_CLICK) { 2484 mUsageStats.registerClickedByUser(r); 2485 } 2486 2487 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) { 2488 return; 2489 } 2490 if ((r.getNotification().flags & mustNotHaveFlags) != 0) { 2491 return; 2492 } 2493 2494 mNotificationList.remove(index); 2495 mNotificationsByKey.remove(r.sbn.getKey()); 2496 2497 cancelNotificationLocked(r, sendDelete, reason); 2498 updateLightsLocked(); 2499 } 2500 } 2501 } 2502 }); 2503 } 2504 2505 /** 2506 * Determine whether the userId applies to the notification in question, either because 2507 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard). 2508 */ 2509 private boolean notificationMatchesUserId(NotificationRecord r, int userId) { 2510 return 2511 // looking for USER_ALL notifications? match everything 2512 userId == UserHandle.USER_ALL 2513 // a notification sent to USER_ALL matches any query 2514 || r.getUserId() == UserHandle.USER_ALL 2515 // an exact user match 2516 || r.getUserId() == userId; 2517 } 2518 2519 /** 2520 * Determine whether the userId applies to the notification in question, either because 2521 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or 2522 * because it matches one of the users profiles. 2523 */ 2524 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) { 2525 return notificationMatchesUserId(r, userId) 2526 || isCurrentProfile(r.getUserId()); 2527 } 2528 2529 /** 2530 * Cancels all notifications from a given package that have all of the 2531 * {@code mustHaveFlags}. 2532 */ 2533 boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags, 2534 int mustNotHaveFlags, boolean doit, int userId, int reason, 2535 NotificationListenerInfo listener) { 2536 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 2537 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason, 2538 listener == null ? null : listener.component.toShortString()); 2539 2540 synchronized (mNotificationList) { 2541 final int N = mNotificationList.size(); 2542 boolean canceledSomething = false; 2543 for (int i = N-1; i >= 0; --i) { 2544 NotificationRecord r = mNotificationList.get(i); 2545 if (!notificationMatchesUserId(r, userId)) { 2546 continue; 2547 } 2548 // Don't remove notifications to all, if there's no package name specified 2549 if (r.getUserId() == UserHandle.USER_ALL && pkg == null) { 2550 continue; 2551 } 2552 if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) { 2553 continue; 2554 } 2555 if ((r.getFlags() & mustNotHaveFlags) != 0) { 2556 continue; 2557 } 2558 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) { 2559 continue; 2560 } 2561 canceledSomething = true; 2562 if (!doit) { 2563 return true; 2564 } 2565 mNotificationList.remove(i); 2566 mNotificationsByKey.remove(r.sbn.getKey()); 2567 cancelNotificationLocked(r, false, reason); 2568 } 2569 if (canceledSomething) { 2570 updateLightsLocked(); 2571 } 2572 return canceledSomething; 2573 } 2574 } 2575 2576 2577 2578 // Return true if the UID is a system or phone UID and therefore should not have 2579 // any notifications or toasts blocked. 2580 boolean isUidSystem(int uid) { 2581 final int appid = UserHandle.getAppId(uid); 2582 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0); 2583 } 2584 2585 // same as isUidSystem(int, int) for the Binder caller's UID. 2586 boolean isCallerSystem() { 2587 return isUidSystem(Binder.getCallingUid()); 2588 } 2589 2590 void checkCallerIsSystem() { 2591 if (isCallerSystem()) { 2592 return; 2593 } 2594 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid()); 2595 } 2596 2597 void checkCallerIsSystemOrSameApp(String pkg) { 2598 if (isCallerSystem()) { 2599 return; 2600 } 2601 final int uid = Binder.getCallingUid(); 2602 try { 2603 ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo( 2604 pkg, 0, UserHandle.getCallingUserId()); 2605 if (!UserHandle.isSameApp(ai.uid, uid)) { 2606 throw new SecurityException("Calling uid " + uid + " gave package" 2607 + pkg + " which is owned by uid " + ai.uid); 2608 } 2609 } catch (RemoteException re) { 2610 throw new SecurityException("Unknown package " + pkg + "\n" + re); 2611 } 2612 } 2613 2614 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason, 2615 NotificationListenerInfo listener, boolean includeCurrentProfiles) { 2616 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 2617 null, userId, 0, 0, reason, 2618 listener == null ? null : listener.component.toShortString()); 2619 2620 final int N = mNotificationList.size(); 2621 for (int i=N-1; i>=0; i--) { 2622 NotificationRecord r = mNotificationList.get(i); 2623 if (includeCurrentProfiles) { 2624 if (!notificationMatchesCurrentProfiles(r, userId)) { 2625 continue; 2626 } 2627 } else { 2628 if (!notificationMatchesUserId(r, userId)) { 2629 continue; 2630 } 2631 } 2632 2633 if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT 2634 | Notification.FLAG_NO_CLEAR)) == 0) { 2635 mNotificationList.remove(i); 2636 mNotificationsByKey.remove(r.sbn.getKey()); 2637 cancelNotificationLocked(r, true, reason); 2638 } 2639 } 2640 updateLightsLocked(); 2641 } 2642 2643 // lock on mNotificationList 2644 void updateLightsLocked() 2645 { 2646 // handle notification lights 2647 if (mLedNotification == null) { 2648 // get next notification, if any 2649 int n = mLights.size(); 2650 if (n > 0) { 2651 mLedNotification = mLights.get(n-1); 2652 } 2653 } 2654 2655 // Don't flash while we are in a call or screen is on 2656 if (mLedNotification == null || mInCall || mScreenOn) { 2657 mNotificationLight.turnOff(); 2658 } else { 2659 final Notification ledno = mLedNotification.sbn.getNotification(); 2660 int ledARGB = ledno.ledARGB; 2661 int ledOnMS = ledno.ledOnMS; 2662 int ledOffMS = ledno.ledOffMS; 2663 if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) { 2664 ledARGB = mDefaultNotificationColor; 2665 ledOnMS = mDefaultNotificationLedOn; 2666 ledOffMS = mDefaultNotificationLedOff; 2667 } 2668 if (mNotificationPulseEnabled) { 2669 // pulse repeatedly 2670 mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED, 2671 ledOnMS, ledOffMS); 2672 } 2673 } 2674 } 2675 2676 // lock on mNotificationList 2677 int indexOfNotificationLocked(String pkg, String tag, int id, int userId) 2678 { 2679 ArrayList<NotificationRecord> list = mNotificationList; 2680 final int len = list.size(); 2681 for (int i=0; i<len; i++) { 2682 NotificationRecord r = list.get(i); 2683 if (!notificationMatchesUserId(r, userId) || r.sbn.getId() != id) { 2684 continue; 2685 } 2686 if (tag == null) { 2687 if (r.sbn.getTag() != null) { 2688 continue; 2689 } 2690 } else { 2691 if (!tag.equals(r.sbn.getTag())) { 2692 continue; 2693 } 2694 } 2695 if (r.sbn.getPackageName().equals(pkg)) { 2696 return i; 2697 } 2698 } 2699 return -1; 2700 } 2701 2702 private void updateNotificationPulse() { 2703 synchronized (mNotificationList) { 2704 updateLightsLocked(); 2705 } 2706 } 2707 2708 private void updateZenMode() { 2709 final int mode = Settings.Global.getInt(getContext().getContentResolver(), 2710 Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF); 2711 if (mode != mZenMode) { 2712 Slog.d(TAG, String.format("updateZenMode: %s -> %s", 2713 Settings.Global.zenModeToString(mZenMode), 2714 Settings.Global.zenModeToString(mode))); 2715 } 2716 mZenMode = mode; 2717 2718 final String[] exceptionPackages = null; // none (for now) 2719 2720 // call restrictions 2721 final boolean muteCalls = mZenMode != Settings.Global.ZEN_MODE_OFF; 2722 mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, AudioManager.STREAM_RING, 2723 muteCalls ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, 2724 exceptionPackages); 2725 mAppOps.setRestriction(AppOpsManager.OP_PLAY_AUDIO, AudioManager.STREAM_RING, 2726 muteCalls ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, 2727 exceptionPackages); 2728 2729 // alarm restrictions 2730 final boolean muteAlarms = false; // TODO until we save user config 2731 mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, AudioManager.STREAM_ALARM, 2732 muteAlarms ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, 2733 exceptionPackages); 2734 mAppOps.setRestriction(AppOpsManager.OP_PLAY_AUDIO, AudioManager.STREAM_ALARM, 2735 muteAlarms ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, 2736 exceptionPackages); 2737 2738 // restrict vibrations with no hints 2739 mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, AudioManager.USE_DEFAULT_STREAM_TYPE, 2740 (muteAlarms || muteCalls) ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, 2741 exceptionPackages); 2742 } 2743 2744 private void updateCurrentProfilesCache(Context context) { 2745 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); 2746 if (userManager != null) { 2747 int currentUserId = ActivityManager.getCurrentUser(); 2748 List<UserInfo> profiles = userManager.getProfiles(currentUserId); 2749 synchronized (mCurrentProfiles) { 2750 mCurrentProfiles.clear(); 2751 for (UserInfo user : profiles) { 2752 mCurrentProfiles.put(user.id, user); 2753 } 2754 } 2755 } 2756 } 2757 2758 private int[] getCurrentProfileIds() { 2759 synchronized (mCurrentProfiles) { 2760 int[] users = new int[mCurrentProfiles.size()]; 2761 final int N = mCurrentProfiles.size(); 2762 for (int i = 0; i < N; ++i) { 2763 users[i] = mCurrentProfiles.keyAt(i); 2764 } 2765 return users; 2766 } 2767 } 2768 2769 private boolean isCurrentProfile(int userId) { 2770 synchronized (mCurrentProfiles) { 2771 return mCurrentProfiles.get(userId) != null; 2772 } 2773 } 2774 2775 private boolean isCall(String pkg, Notification n) { 2776 return CALL_PACKAGES.contains(pkg); 2777 } 2778 2779 private boolean isAlarm(String pkg, Notification n) { 2780 return ALARM_PACKAGES.contains(pkg); 2781 } 2782 2783 private boolean shouldIntercept(String pkg, Notification n) { 2784 if (mZenMode != Settings.Global.ZEN_MODE_OFF) { 2785 return !isAlarm(pkg, n); 2786 } 2787 return false; 2788 } 2789} 2790