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