NotificationManagerService.java revision 92d456e9a62d7dadb3e21f481f7453bd82b1aa23
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.NotificationAssistantService.REASON_APP_CANCEL; 20import static android.service.notification.NotificationAssistantService.REASON_APP_CANCEL_ALL; 21import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_CANCEL; 22import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_CANCEL_ALL; 23import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_CLICK; 24import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_ERROR; 25import static android.service.notification.NotificationAssistantService.REASON_GROUP_OPTIMIZATION; 26import static android.service.notification.NotificationAssistantService.REASON_GROUP_SUMMARY_CANCELED; 27import static android.service.notification.NotificationAssistantService.REASON_LISTENER_CANCEL; 28import static android.service.notification.NotificationAssistantService.REASON_LISTENER_CANCEL_ALL; 29import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_BANNED; 30import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_CHANGED; 31import static android.service.notification.NotificationAssistantService.REASON_TOPIC_BANNED; 32import static android.service.notification.NotificationAssistantService.REASON_USER_STOPPED; 33import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS; 34import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH; 35import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_LIGHTS; 36import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_PEEK; 37import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON; 38import static android.service.notification.NotificationListenerService.TRIM_FULL; 39import static android.service.notification.NotificationListenerService.TRIM_LIGHT; 40import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; 41import static org.xmlpull.v1.XmlPullParser.END_TAG; 42import static org.xmlpull.v1.XmlPullParser.START_TAG; 43 44import android.Manifest; 45import android.app.ActivityManager; 46import android.app.ActivityManagerNative; 47import android.app.AppGlobals; 48import android.app.AppOpsManager; 49import android.app.AutomaticZenRule; 50import android.app.IActivityManager; 51import android.app.INotificationManager; 52import android.app.ITransientNotification; 53import android.app.Notification; 54import android.app.NotificationManager; 55import android.app.NotificationManager.Policy; 56import android.app.PendingIntent; 57import android.app.StatusBarManager; 58import android.app.backup.BackupManager; 59import android.app.usage.UsageEvents; 60import android.app.usage.UsageStatsManagerInternal; 61import android.content.BroadcastReceiver; 62import android.content.ComponentName; 63import android.content.ContentResolver; 64import android.content.Context; 65import android.content.Intent; 66import android.content.IntentFilter; 67import android.content.pm.ApplicationInfo; 68import android.content.pm.IPackageManager; 69import android.content.pm.PackageInfo; 70import android.content.pm.PackageManager; 71import android.content.pm.PackageManager.NameNotFoundException; 72import android.content.pm.ParceledListSlice; 73import android.content.pm.UserInfo; 74import android.content.res.Resources; 75import android.database.ContentObserver; 76import android.media.AudioAttributes; 77import android.media.AudioManager; 78import android.media.AudioManagerInternal; 79import android.media.AudioSystem; 80import android.media.IRingtonePlayer; 81import android.net.Uri; 82import android.os.Binder; 83import android.os.Bundle; 84import android.os.Environment; 85import android.os.Handler; 86import android.os.HandlerThread; 87import android.os.IBinder; 88import android.os.IInterface; 89import android.os.Looper; 90import android.os.Message; 91import android.os.Process; 92import android.os.RemoteException; 93import android.os.SystemProperties; 94import android.os.UserHandle; 95import android.os.UserManager; 96import android.os.Vibrator; 97import android.provider.Settings; 98import android.service.notification.Condition; 99import android.service.notification.IConditionProvider; 100import android.service.notification.INotificationListener; 101import android.service.notification.IStatusBarNotificationHolder; 102import android.service.notification.NotificationAssistantService; 103import android.service.notification.NotificationListenerService; 104import android.service.notification.NotificationRankingUpdate; 105import android.service.notification.StatusBarNotification; 106import android.service.notification.ZenModeConfig; 107import android.telephony.PhoneStateListener; 108import android.telephony.TelephonyManager; 109import android.text.TextUtils; 110import android.util.ArrayMap; 111import android.util.ArraySet; 112import android.util.AtomicFile; 113import android.util.Log; 114import android.util.Slog; 115import android.util.Xml; 116import android.view.accessibility.AccessibilityEvent; 117import android.view.accessibility.AccessibilityManager; 118import android.widget.Toast; 119import com.android.internal.R; 120import com.android.internal.statusbar.NotificationVisibility; 121import com.android.internal.util.FastXmlSerializer; 122import com.android.internal.util.Preconditions; 123import com.android.server.EventLogTags; 124import com.android.server.LocalServices; 125import com.android.server.SystemService; 126import com.android.server.lights.Light; 127import com.android.server.lights.LightsManager; 128import com.android.server.notification.ManagedServices.ManagedServiceInfo; 129import com.android.server.notification.ManagedServices.UserProfiles; 130import com.android.server.statusbar.StatusBarManagerInternal; 131import com.android.server.vr.VrManagerInternal; 132import com.android.server.vr.VrStateListener; 133 134import libcore.io.IoUtils; 135import org.json.JSONArray; 136import org.json.JSONException; 137import org.json.JSONObject; 138import org.xmlpull.v1.XmlPullParser; 139import org.xmlpull.v1.XmlPullParserException; 140import org.xmlpull.v1.XmlSerializer; 141 142import java.io.ByteArrayInputStream; 143import java.io.ByteArrayOutputStream; 144import java.io.File; 145import java.io.FileDescriptor; 146import java.io.FileInputStream; 147import java.io.FileNotFoundException; 148import java.io.FileOutputStream; 149import java.io.IOException; 150import java.io.InputStream; 151import java.io.OutputStream; 152import java.io.PrintWriter; 153import java.nio.charset.StandardCharsets; 154import java.util.ArrayDeque; 155import java.util.ArrayList; 156import java.util.HashSet; 157import java.util.Iterator; 158import java.util.List; 159import java.util.Map.Entry; 160import java.util.Objects; 161import java.util.concurrent.TimeUnit; 162 163/** {@hide} */ 164public class NotificationManagerService extends SystemService { 165 static final String TAG = "NotificationService"; 166 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); 167 public static final boolean ENABLE_CHILD_NOTIFICATIONS 168 = SystemProperties.getBoolean("debug.child_notifs", true); 169 170 static final int MAX_PACKAGE_NOTIFICATIONS = 50; 171 172 // message codes 173 static final int MESSAGE_TIMEOUT = 2; 174 static final int MESSAGE_SAVE_POLICY_FILE = 3; 175 static final int MESSAGE_SEND_RANKING_UPDATE = 4; 176 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5; 177 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6; 178 179 // ranking thread messages 180 private static final int MESSAGE_RECONSIDER_RANKING = 1000; 181 private static final int MESSAGE_RANKING_SORT = 1001; 182 183 static final int LONG_DELAY = 3500; // 3.5 seconds 184 static final int SHORT_DELAY = 2000; // 2 seconds 185 186 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250}; 187 188 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps 189 190 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION; 191 192 static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true; 193 static final boolean ENABLE_BLOCKED_TOASTS = true; 194 195 // When #matchesCallFilter is called from the ringer, wait at most 196 // 3s to resolve the contacts. This timeout is required since 197 // ContactsProvider might take a long time to start up. 198 // 199 // Return STARRED_CONTACT when the timeout is hit in order to avoid 200 // missed calls in ZEN mode "Important". 201 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000; 202 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY = 203 ValidateNotificationPeople.STARRED_CONTACT; 204 205 /** notification_enqueue status value for a newly enqueued notification. */ 206 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0; 207 208 /** notification_enqueue status value for an existing notification. */ 209 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1; 210 211 /** notification_enqueue status value for an ignored notification. */ 212 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2; 213 214 private IActivityManager mAm; 215 AudioManager mAudioManager; 216 AudioManagerInternal mAudioManagerInternal; 217 StatusBarManagerInternal mStatusBar; 218 Vibrator mVibrator; 219 private VrManagerInternal mVrManagerInternal; 220 private final NotificationVrListener mVrListener = new NotificationVrListener(); 221 222 final IBinder mForegroundToken = new Binder(); 223 private WorkerHandler mHandler; 224 private final HandlerThread mRankingThread = new HandlerThread("ranker", 225 Process.THREAD_PRIORITY_BACKGROUND); 226 private final HandlerThread mAssistantThread = new HandlerThread("assistant", 227 Process.THREAD_PRIORITY_BACKGROUND); 228 229 private Light mNotificationLight; 230 Light mAttentionLight; 231 private int mDefaultNotificationColor; 232 private int mDefaultNotificationLedOn; 233 234 private int mDefaultNotificationLedOff; 235 private long[] mDefaultVibrationPattern; 236 237 private long[] mFallbackVibrationPattern; 238 private boolean mUseAttentionLight; 239 boolean mSystemReady; 240 241 private boolean mDisableNotificationEffects; 242 private int mCallState; 243 private String mSoundNotificationKey; 244 private String mVibrateNotificationKey; 245 246 private final ArraySet<ManagedServiceInfo> mListenersDisablingEffects = new ArraySet<>(); 247 private ComponentName mEffectsSuppressor; 248 private int mListenerHints; // right now, all hints are global 249 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN; 250 251 // for enabling and disabling notification pulse behavior 252 private boolean mScreenOn = true; 253 private boolean mInCall = false; 254 private boolean mNotificationPulseEnabled; 255 256 // used as a mutex for access to all active notifications & listeners 257 final ArrayList<NotificationRecord> mNotificationList = 258 new ArrayList<NotificationRecord>(); 259 final ArrayMap<String, NotificationRecord> mNotificationsByKey = 260 new ArrayMap<String, NotificationRecord>(); 261 final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>(); 262 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>(); 263 final PolicyAccess mPolicyAccess = new PolicyAccess(); 264 265 // The last key in this list owns the hardware. 266 ArrayList<String> mLights = new ArrayList<>(); 267 268 private AppOpsManager mAppOps; 269 private UsageStatsManagerInternal mAppUsageStats; 270 271 private Archive mArchive; 272 273 // Persistent storage for notification policy 274 private AtomicFile mPolicyFile; 275 276 // Temporary holder for <blocked-packages> config coming from old policy files. 277 private HashSet<String> mBlockedPackages = new HashSet<String>(); 278 279 private static final int DB_VERSION = 1; 280 281 private static final String TAG_NOTIFICATION_POLICY = "notification-policy"; 282 private static final String ATTR_VERSION = "version"; 283 284 // Obsolete: converted if present, but not resaved to disk. 285 private static final String TAG_BLOCKED_PKGS = "blocked-packages"; 286 private static final String TAG_PACKAGE = "package"; 287 private static final String ATTR_NAME = "name"; 288 289 private RankingHelper mRankingHelper; 290 291 private final UserProfiles mUserProfiles = new UserProfiles(); 292 private NotificationListeners mListeners; 293 private NotificationAssistant mAssistant; 294 private ConditionProviders mConditionProviders; 295 private NotificationUsageStats mUsageStats; 296 297 private static final int MY_UID = Process.myUid(); 298 private static final int MY_PID = Process.myPid(); 299 private RankingHandler mRankingHandler; 300 private Handler mAssistantHandler; 301 302 private static class Archive { 303 final int mBufferSize; 304 final ArrayDeque<StatusBarNotification> mBuffer; 305 306 public Archive(int size) { 307 mBufferSize = size; 308 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize); 309 } 310 311 public String toString() { 312 final StringBuilder sb = new StringBuilder(); 313 final int N = mBuffer.size(); 314 sb.append("Archive ("); 315 sb.append(N); 316 sb.append(" notification"); 317 sb.append((N==1)?")":"s)"); 318 return sb.toString(); 319 } 320 321 public void record(StatusBarNotification nr) { 322 if (mBuffer.size() == mBufferSize) { 323 mBuffer.removeFirst(); 324 } 325 326 // We don't want to store the heavy bits of the notification in the archive, 327 // but other clients in the system process might be using the object, so we 328 // store a (lightened) copy. 329 mBuffer.addLast(nr.cloneLight()); 330 } 331 332 public Iterator<StatusBarNotification> descendingIterator() { 333 return mBuffer.descendingIterator(); 334 } 335 336 public StatusBarNotification[] getArray(int count) { 337 if (count == 0) count = mBufferSize; 338 final StatusBarNotification[] a 339 = new StatusBarNotification[Math.min(count, mBuffer.size())]; 340 Iterator<StatusBarNotification> iter = descendingIterator(); 341 int i=0; 342 while (iter.hasNext() && i < count) { 343 a[i++] = iter.next(); 344 } 345 return a; 346 } 347 348 } 349 350 private void readPolicyXml(InputStream stream, boolean forRestore) 351 throws XmlPullParserException, NumberFormatException, IOException { 352 final XmlPullParser parser = Xml.newPullParser(); 353 parser.setInput(stream, StandardCharsets.UTF_8.name()); 354 355 int type; 356 String tag; 357 int version = DB_VERSION; 358 while ((type = parser.next()) != END_DOCUMENT) { 359 tag = parser.getName(); 360 if (type == START_TAG) { 361 if (TAG_NOTIFICATION_POLICY.equals(tag)) { 362 version = Integer.parseInt( 363 parser.getAttributeValue(null, ATTR_VERSION)); 364 } else if (TAG_BLOCKED_PKGS.equals(tag)) { 365 while ((type = parser.next()) != END_DOCUMENT) { 366 tag = parser.getName(); 367 if (TAG_PACKAGE.equals(tag)) { 368 mBlockedPackages.add( 369 parser.getAttributeValue(null, ATTR_NAME)); 370 } else if (TAG_BLOCKED_PKGS.equals(tag) && type == END_TAG) { 371 break; 372 } 373 } 374 } 375 } 376 mZenModeHelper.readXml(parser, forRestore); 377 mRankingHelper.readXml(parser, forRestore); 378 } 379 } 380 381 private void loadPolicyFile() { 382 if (DBG) Slog.d(TAG, "loadPolicyFile"); 383 synchronized(mPolicyFile) { 384 mBlockedPackages.clear(); 385 386 FileInputStream infile = null; 387 try { 388 infile = mPolicyFile.openRead(); 389 readPolicyXml(infile, false /*forRestore*/); 390 } catch (FileNotFoundException e) { 391 // No data yet 392 } catch (IOException e) { 393 Log.wtf(TAG, "Unable to read notification policy", e); 394 } catch (NumberFormatException e) { 395 Log.wtf(TAG, "Unable to parse notification policy", e); 396 } catch (XmlPullParserException e) { 397 Log.wtf(TAG, "Unable to parse notification policy", e); 398 } finally { 399 IoUtils.closeQuietly(infile); 400 } 401 } 402 } 403 404 public void savePolicyFile() { 405 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE); 406 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE); 407 } 408 409 private void handleSavePolicyFile() { 410 if (DBG) Slog.d(TAG, "handleSavePolicyFile"); 411 synchronized (mPolicyFile) { 412 final FileOutputStream stream; 413 try { 414 stream = mPolicyFile.startWrite(); 415 } catch (IOException e) { 416 Slog.w(TAG, "Failed to save policy file", e); 417 return; 418 } 419 420 try { 421 writePolicyXml(stream, false /*forBackup*/); 422 mPolicyFile.finishWrite(stream); 423 } catch (IOException e) { 424 Slog.w(TAG, "Failed to save policy file, restoring backup", e); 425 mPolicyFile.failWrite(stream); 426 } 427 } 428 BackupManager.dataChanged(getContext().getPackageName()); 429 } 430 431 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException { 432 final XmlSerializer out = new FastXmlSerializer(); 433 out.setOutput(stream, StandardCharsets.UTF_8.name()); 434 out.startDocument(null, true); 435 out.startTag(null, TAG_NOTIFICATION_POLICY); 436 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION)); 437 mZenModeHelper.writeXml(out, forBackup); 438 mRankingHelper.writeXml(out, forBackup); 439 out.endTag(null, TAG_NOTIFICATION_POLICY); 440 out.endDocument(); 441 } 442 443 /** Use this when you actually want to post a notification or toast. 444 * 445 * Unchecked. Not exposed via Binder, but can be called in the course of enqueue*(). 446 */ 447 private boolean noteNotificationOp(String pkg, int uid) { 448 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg) 449 != AppOpsManager.MODE_ALLOWED) { 450 Slog.v(TAG, "notifications are disabled by AppOps for " + pkg); 451 return false; 452 } 453 return true; 454 } 455 456 /** Use this to check if a package can post a notification or toast. */ 457 private boolean checkNotificationOp(String pkg, int uid) { 458 return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg) 459 == AppOpsManager.MODE_ALLOWED; 460 } 461 462 private static final class ToastRecord 463 { 464 final int pid; 465 final String pkg; 466 final ITransientNotification callback; 467 int duration; 468 469 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration) 470 { 471 this.pid = pid; 472 this.pkg = pkg; 473 this.callback = callback; 474 this.duration = duration; 475 } 476 477 void update(int duration) { 478 this.duration = duration; 479 } 480 481 void dump(PrintWriter pw, String prefix, DumpFilter filter) { 482 if (filter != null && !filter.matches(pkg)) return; 483 pw.println(prefix + this); 484 } 485 486 @Override 487 public final String toString() 488 { 489 return "ToastRecord{" 490 + Integer.toHexString(System.identityHashCode(this)) 491 + " pkg=" + pkg 492 + " callback=" + callback 493 + " duration=" + duration; 494 } 495 } 496 497 private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() { 498 499 @Override 500 public void onSetDisabled(int status) { 501 synchronized (mNotificationList) { 502 mDisableNotificationEffects = 503 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0; 504 if (disableNotificationEffects(null) != null) { 505 // cancel whatever's going on 506 long identity = Binder.clearCallingIdentity(); 507 try { 508 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 509 if (player != null) { 510 player.stopAsync(); 511 } 512 } catch (RemoteException e) { 513 } finally { 514 Binder.restoreCallingIdentity(identity); 515 } 516 517 identity = Binder.clearCallingIdentity(); 518 try { 519 mVibrator.cancel(); 520 } finally { 521 Binder.restoreCallingIdentity(identity); 522 } 523 } 524 } 525 } 526 527 @Override 528 public void onClearAll(int callingUid, int callingPid, int userId) { 529 synchronized (mNotificationList) { 530 cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null, 531 /*includeCurrentProfiles*/ true); 532 } 533 } 534 535 @Override 536 public void onNotificationClick(int callingUid, int callingPid, String key) { 537 synchronized (mNotificationList) { 538 NotificationRecord r = mNotificationsByKey.get(key); 539 if (r == null) { 540 Log.w(TAG, "No notification with key: " + key); 541 return; 542 } 543 final long now = System.currentTimeMillis(); 544 EventLogTags.writeNotificationClicked(key, 545 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now)); 546 547 StatusBarNotification sbn = r.sbn; 548 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(), 549 sbn.getId(), Notification.FLAG_AUTO_CANCEL, 550 Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(), 551 REASON_DELEGATE_CLICK, null); 552 } 553 } 554 555 @Override 556 public void onNotificationActionClick(int callingUid, int callingPid, String key, 557 int actionIndex) { 558 synchronized (mNotificationList) { 559 NotificationRecord r = mNotificationsByKey.get(key); 560 if (r == null) { 561 Log.w(TAG, "No notification with key: " + key); 562 return; 563 } 564 final long now = System.currentTimeMillis(); 565 EventLogTags.writeNotificationActionClicked(key, actionIndex, 566 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now)); 567 // TODO: Log action click via UsageStats. 568 } 569 } 570 571 @Override 572 public void onNotificationClear(int callingUid, int callingPid, 573 String pkg, String tag, int id, int userId) { 574 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 575 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE, 576 true, userId, REASON_DELEGATE_CANCEL, null); 577 } 578 579 @Override 580 public void onPanelRevealed(boolean clearEffects, int items) { 581 EventLogTags.writeNotificationPanelRevealed(items); 582 if (clearEffects) { 583 clearEffects(); 584 } 585 } 586 587 @Override 588 public void onPanelHidden() { 589 EventLogTags.writeNotificationPanelHidden(); 590 } 591 592 @Override 593 public void clearEffects() { 594 synchronized (mNotificationList) { 595 if (DBG) Slog.d(TAG, "clearEffects"); 596 597 // sound 598 mSoundNotificationKey = null; 599 600 long identity = Binder.clearCallingIdentity(); 601 try { 602 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 603 if (player != null) { 604 player.stopAsync(); 605 } 606 } catch (RemoteException e) { 607 } finally { 608 Binder.restoreCallingIdentity(identity); 609 } 610 611 // vibrate 612 mVibrateNotificationKey = null; 613 identity = Binder.clearCallingIdentity(); 614 try { 615 mVibrator.cancel(); 616 } finally { 617 Binder.restoreCallingIdentity(identity); 618 } 619 620 // light 621 mLights.clear(); 622 updateLightsLocked(); 623 } 624 } 625 626 @Override 627 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id, 628 int uid, int initialPid, String message, int userId) { 629 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id 630 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")"); 631 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId, 632 REASON_DELEGATE_ERROR, null); 633 long ident = Binder.clearCallingIdentity(); 634 try { 635 ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg, 636 "Bad notification posted from package " + pkg 637 + ": " + message); 638 } catch (RemoteException e) { 639 } 640 Binder.restoreCallingIdentity(ident); 641 } 642 643 @Override 644 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys, 645 NotificationVisibility[] noLongerVisibleKeys) { 646 synchronized (mNotificationList) { 647 for (NotificationVisibility nv : newlyVisibleKeys) { 648 NotificationRecord r = mNotificationsByKey.get(nv.key); 649 if (r == null) continue; 650 r.setVisibility(true, nv.rank); 651 nv.recycle(); 652 } 653 // Note that we might receive this event after notifications 654 // have already left the system, e.g. after dismissing from the 655 // shade. Hence not finding notifications in 656 // mNotificationsByKey is not an exceptional condition. 657 for (NotificationVisibility nv : noLongerVisibleKeys) { 658 NotificationRecord r = mNotificationsByKey.get(nv.key); 659 if (r == null) continue; 660 r.setVisibility(false, nv.rank); 661 nv.recycle(); 662 } 663 } 664 } 665 666 @Override 667 public void onNotificationExpansionChanged(String key, 668 boolean userAction, boolean expanded) { 669 synchronized (mNotificationList) { 670 NotificationRecord r = mNotificationsByKey.get(key); 671 if (r != null) { 672 r.stats.onExpansionChanged(userAction, expanded); 673 final long now = System.currentTimeMillis(); 674 EventLogTags.writeNotificationExpansion(key, 675 userAction ? 1 : 0, expanded ? 1 : 0, 676 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now)); 677 } 678 } 679 } 680 }; 681 682 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() { 683 @Override 684 public void onReceive(Context context, Intent intent) { 685 String action = intent.getAction(); 686 if (action == null) { 687 return; 688 } 689 690 boolean queryRestart = false; 691 boolean queryRemove = false; 692 boolean packageChanged = false; 693 boolean cancelNotifications = true; 694 695 if (action.equals(Intent.ACTION_PACKAGE_ADDED) 696 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED)) 697 || action.equals(Intent.ACTION_PACKAGE_RESTARTED) 698 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED)) 699 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART)) 700 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { 701 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 702 UserHandle.USER_ALL); 703 String pkgList[] = null; 704 boolean queryReplace = queryRemove && 705 intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); 706 if (DBG) Slog.i(TAG, "action=" + action + " queryReplace=" + queryReplace); 707 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { 708 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 709 } else if (queryRestart) { 710 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); 711 } else { 712 Uri uri = intent.getData(); 713 if (uri == null) { 714 return; 715 } 716 String pkgName = uri.getSchemeSpecificPart(); 717 if (pkgName == null) { 718 return; 719 } 720 if (packageChanged) { 721 // We cancel notifications for packages which have just been disabled 722 try { 723 final IPackageManager pm = AppGlobals.getPackageManager(); 724 final int enabled = pm.getApplicationEnabledSetting(pkgName, 725 changeUserId != UserHandle.USER_ALL ? changeUserId : 726 UserHandle.USER_SYSTEM); 727 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED 728 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { 729 cancelNotifications = false; 730 } 731 } catch (IllegalArgumentException e) { 732 // Package doesn't exist; probably racing with uninstall. 733 // cancelNotifications is already true, so nothing to do here. 734 if (DBG) { 735 Slog.i(TAG, "Exception trying to look up app enabled setting", e); 736 } 737 } catch (RemoteException e) { 738 // Failed to talk to PackageManagerService Should never happen! 739 } 740 } 741 pkgList = new String[]{pkgName}; 742 } 743 744 if (pkgList != null && (pkgList.length > 0)) { 745 for (String pkgName : pkgList) { 746 if (cancelNotifications) { 747 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart, 748 changeUserId, REASON_PACKAGE_CHANGED, null, null); 749 } 750 } 751 } 752 mListeners.onPackagesChanged(queryReplace, pkgList); 753 mAssistant.onPackagesChanged(queryReplace, pkgList); 754 mConditionProviders.onPackagesChanged(queryReplace, pkgList); 755 mRankingHelper.onPackagesChanged(queryReplace, pkgList); 756 } 757 } 758 }; 759 760 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 761 @Override 762 public void onReceive(Context context, Intent intent) { 763 String action = intent.getAction(); 764 765 if (action.equals(Intent.ACTION_SCREEN_ON)) { 766 // Keep track of screen on/off state, but do not turn off the notification light 767 // until user passes through the lock screen or views the notification. 768 mScreenOn = true; 769 updateNotificationPulse(); 770 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 771 mScreenOn = false; 772 updateNotificationPulse(); 773 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) { 774 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK 775 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE)); 776 updateNotificationPulse(); 777 } else if (action.equals(Intent.ACTION_USER_STOPPED)) { 778 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 779 if (userHandle >= 0) { 780 cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle, 781 REASON_USER_STOPPED, null, null); 782 } 783 } else if (action.equals(Intent.ACTION_USER_PRESENT)) { 784 // turn off LED when user passes through lock screen 785 mNotificationLight.turnOff(); 786 mStatusBar.notificationLightOff(); 787 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) { 788 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); 789 // reload per-user settings 790 mSettingsObserver.update(null); 791 mUserProfiles.updateCache(context); 792 // Refresh managed services 793 mConditionProviders.onUserSwitched(user); 794 mListeners.onUserSwitched(user); 795 mAssistant.onUserSwitched(user); 796 mZenModeHelper.onUserSwitched(user); 797 } else if (action.equals(Intent.ACTION_USER_ADDED)) { 798 mUserProfiles.updateCache(context); 799 } else if (action.equals(Intent.ACTION_USER_REMOVED)) { 800 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); 801 mZenModeHelper.onUserRemoved(user); 802 } 803 } 804 }; 805 806 private final class SettingsObserver extends ContentObserver { 807 private final Uri NOTIFICATION_LIGHT_PULSE_URI 808 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE); 809 810 SettingsObserver(Handler handler) { 811 super(handler); 812 } 813 814 void observe() { 815 ContentResolver resolver = getContext().getContentResolver(); 816 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI, 817 false, this, UserHandle.USER_ALL); 818 update(null); 819 } 820 821 @Override public void onChange(boolean selfChange, Uri uri) { 822 update(uri); 823 } 824 825 public void update(Uri uri) { 826 ContentResolver resolver = getContext().getContentResolver(); 827 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) { 828 boolean pulseEnabled = Settings.System.getInt(resolver, 829 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0; 830 if (mNotificationPulseEnabled != pulseEnabled) { 831 mNotificationPulseEnabled = pulseEnabled; 832 updateNotificationPulse(); 833 } 834 } 835 } 836 } 837 838 private final class NotificationVrListener extends VrStateListener { 839 @Override 840 public void onVrStateChanged(final boolean enabled) { 841 mListeners.setCategoryState(NotificationListenerService.CATEGORY_VR_NOTIFICATIONS, 842 enabled); 843 } 844 } 845 846 private SettingsObserver mSettingsObserver; 847 private ZenModeHelper mZenModeHelper; 848 849 private final Runnable mBuzzBeepBlinked = new Runnable() { 850 @Override 851 public void run() { 852 mStatusBar.buzzBeepBlinked(); 853 } 854 }; 855 856 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) { 857 int[] ar = r.getIntArray(resid); 858 if (ar == null) { 859 return def; 860 } 861 final int len = ar.length > maxlen ? maxlen : ar.length; 862 long[] out = new long[len]; 863 for (int i=0; i<len; i++) { 864 out[i] = ar[i]; 865 } 866 return out; 867 } 868 869 public NotificationManagerService(Context context) { 870 super(context); 871 } 872 873 @Override 874 public void onStart() { 875 Resources resources = getContext().getResources(); 876 877 mAm = ActivityManagerNative.getDefault(); 878 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); 879 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE); 880 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class); 881 882 mHandler = new WorkerHandler(); 883 mRankingThread.start(); 884 mAssistantThread.start(); 885 String[] extractorNames; 886 try { 887 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors); 888 } catch (Resources.NotFoundException e) { 889 extractorNames = new String[0]; 890 } 891 mUsageStats = new NotificationUsageStats(getContext()); 892 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper()); 893 mAssistantHandler = new Handler(mAssistantThread.getLooper()); 894 mRankingHelper = new RankingHelper(getContext(), 895 mRankingHandler, 896 mUsageStats, 897 extractorNames); 898 mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles); 899 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders); 900 mZenModeHelper.addCallback(new ZenModeHelper.Callback() { 901 @Override 902 public void onConfigChanged() { 903 savePolicyFile(); 904 } 905 906 @Override 907 void onZenModeChanged() { 908 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED); 909 getContext().sendBroadcastAsUser( 910 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL) 911 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT), 912 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS); 913 synchronized(mNotificationList) { 914 updateInterruptionFilterLocked(); 915 } 916 } 917 918 @Override 919 void onPolicyChanged() { 920 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED); 921 } 922 }); 923 final File systemDir = new File(Environment.getDataDirectory(), "system"); 924 mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml")); 925 926 importOldBlockDb(); 927 928 mListeners = new NotificationListeners(); 929 mAssistant = new NotificationAssistant(); 930 mStatusBar = getLocalService(StatusBarManagerInternal.class); 931 mStatusBar.setNotificationDelegate(mNotificationDelegate); 932 933 final LightsManager lights = getLocalService(LightsManager.class); 934 mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS); 935 mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION); 936 937 mDefaultNotificationColor = resources.getColor( 938 R.color.config_defaultNotificationColor); 939 mDefaultNotificationLedOn = resources.getInteger( 940 R.integer.config_defaultNotificationLedOn); 941 mDefaultNotificationLedOff = resources.getInteger( 942 R.integer.config_defaultNotificationLedOff); 943 944 mDefaultVibrationPattern = getLongArray(resources, 945 R.array.config_defaultNotificationVibePattern, 946 VIBRATE_PATTERN_MAXLEN, 947 DEFAULT_VIBRATE_PATTERN); 948 949 mFallbackVibrationPattern = getLongArray(resources, 950 R.array.config_notificationFallbackVibePattern, 951 VIBRATE_PATTERN_MAXLEN, 952 DEFAULT_VIBRATE_PATTERN); 953 954 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight); 955 956 // Don't start allowing notifications until the setup wizard has run once. 957 // After that, including subsequent boots, init with notifications turned on. 958 // This works on the first boot because the setup wizard will toggle this 959 // flag at least once and we'll go back to 0 after that. 960 if (0 == Settings.Global.getInt(getContext().getContentResolver(), 961 Settings.Global.DEVICE_PROVISIONED, 0)) { 962 mDisableNotificationEffects = true; 963 } 964 mZenModeHelper.initZenMode(); 965 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter(); 966 967 mUserProfiles.updateCache(getContext()); 968 listenForCallState(); 969 970 // register for various Intents 971 IntentFilter filter = new IntentFilter(); 972 filter.addAction(Intent.ACTION_SCREEN_ON); 973 filter.addAction(Intent.ACTION_SCREEN_OFF); 974 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); 975 filter.addAction(Intent.ACTION_USER_PRESENT); 976 filter.addAction(Intent.ACTION_USER_STOPPED); 977 filter.addAction(Intent.ACTION_USER_SWITCHED); 978 filter.addAction(Intent.ACTION_USER_ADDED); 979 filter.addAction(Intent.ACTION_USER_REMOVED); 980 getContext().registerReceiver(mIntentReceiver, filter); 981 982 IntentFilter pkgFilter = new IntentFilter(); 983 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 984 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 985 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 986 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); 987 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); 988 pkgFilter.addDataScheme("package"); 989 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null, 990 null); 991 992 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 993 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null, 994 null); 995 996 mSettingsObserver = new SettingsObserver(mHandler); 997 998 mArchive = new Archive(resources.getInteger( 999 R.integer.config_notificationServiceArchiveSize)); 1000 1001 publishBinderService(Context.NOTIFICATION_SERVICE, mService); 1002 publishLocalService(NotificationManagerInternal.class, mInternalService); 1003 } 1004 1005 private void sendRegisteredOnlyBroadcast(String action) { 1006 getContext().sendBroadcastAsUser(new Intent(action) 1007 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null); 1008 } 1009 1010 /** 1011 * Read the old XML-based app block database and import those blockages into the AppOps system. 1012 */ 1013 private void importOldBlockDb() { 1014 loadPolicyFile(); 1015 1016 PackageManager pm = getContext().getPackageManager(); 1017 for (String pkg : mBlockedPackages) { 1018 PackageInfo info = null; 1019 try { 1020 info = pm.getPackageInfo(pkg, 0); 1021 setNotificationsEnabledForPackageImpl(pkg, info.applicationInfo.uid, false); 1022 } catch (NameNotFoundException e) { 1023 // forget you 1024 } 1025 } 1026 mBlockedPackages.clear(); 1027 } 1028 1029 @Override 1030 public void onBootPhase(int phase) { 1031 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 1032 // no beeping until we're basically done booting 1033 mSystemReady = true; 1034 1035 // Grab our optional AudioService 1036 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 1037 mAudioManagerInternal = getLocalService(AudioManagerInternal.class); 1038 mVrManagerInternal = getLocalService(VrManagerInternal.class); 1039 mVrManagerInternal.registerListener(mVrListener); 1040 mZenModeHelper.onSystemReady(); 1041 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { 1042 // This observer will force an update when observe is called, causing us to 1043 // bind to listener services. 1044 mSettingsObserver.observe(); 1045 mListeners.onBootPhaseAppsCanStart(); 1046 mAssistant.onBootPhaseAppsCanStart(); 1047 mConditionProviders.onBootPhaseAppsCanStart(); 1048 } 1049 } 1050 1051 void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) { 1052 Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg); 1053 1054 mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg, 1055 enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED); 1056 1057 // Now, cancel any outstanding notifications that are part of a just-disabled app 1058 if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) { 1059 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid), 1060 REASON_PACKAGE_BANNED, null, null); 1061 } 1062 } 1063 1064 private void updateListenerHintsLocked() { 1065 final int hints = mListenersDisablingEffects.isEmpty() ? 0 : HINT_HOST_DISABLE_EFFECTS; 1066 if (hints == mListenerHints) return; 1067 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mListenersDisablingEffects.size()); 1068 mListenerHints = hints; 1069 scheduleListenerHintsChanged(hints); 1070 } 1071 1072 private void updateEffectsSuppressorLocked() { 1073 final ComponentName suppressor = !mListenersDisablingEffects.isEmpty() 1074 ? mListenersDisablingEffects.valueAt(0).component : null; 1075 if (Objects.equals(suppressor, mEffectsSuppressor)) return; 1076 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressor, suppressor); 1077 mEffectsSuppressor = suppressor; 1078 mZenModeHelper.setEffectsSuppressed(suppressor != null); 1079 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED); 1080 } 1081 1082 private void updateInterruptionFilterLocked() { 1083 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter(); 1084 if (interruptionFilter == mInterruptionFilter) return; 1085 mInterruptionFilter = interruptionFilter; 1086 scheduleInterruptionFilterChanged(interruptionFilter); 1087 } 1088 1089 private final IBinder mService = new INotificationManager.Stub() { 1090 // Toasts 1091 // ============================================================================ 1092 1093 @Override 1094 public void enqueueToast(String pkg, ITransientNotification callback, int duration) 1095 { 1096 if (DBG) { 1097 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback 1098 + " duration=" + duration); 1099 } 1100 1101 if (pkg == null || callback == null) { 1102 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback); 1103 return ; 1104 } 1105 1106 final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg)); 1107 1108 if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) { 1109 if (!isSystemToast) { 1110 Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request."); 1111 return; 1112 } 1113 } 1114 1115 synchronized (mToastQueue) { 1116 int callingPid = Binder.getCallingPid(); 1117 long callingId = Binder.clearCallingIdentity(); 1118 try { 1119 ToastRecord record; 1120 int index = indexOfToastLocked(pkg, callback); 1121 // If it's already in the queue, we update it in place, we don't 1122 // move it to the end of the queue. 1123 if (index >= 0) { 1124 record = mToastQueue.get(index); 1125 record.update(duration); 1126 } else { 1127 // Limit the number of toasts that any given package except the android 1128 // package can enqueue. Prevents DOS attacks and deals with leaks. 1129 if (!isSystemToast) { 1130 int count = 0; 1131 final int N = mToastQueue.size(); 1132 for (int i=0; i<N; i++) { 1133 final ToastRecord r = mToastQueue.get(i); 1134 if (r.pkg.equals(pkg)) { 1135 count++; 1136 if (count >= MAX_PACKAGE_NOTIFICATIONS) { 1137 Slog.e(TAG, "Package has already posted " + count 1138 + " toasts. Not showing more. Package=" + pkg); 1139 return; 1140 } 1141 } 1142 } 1143 } 1144 1145 record = new ToastRecord(callingPid, pkg, callback, duration); 1146 mToastQueue.add(record); 1147 index = mToastQueue.size() - 1; 1148 keepProcessAliveLocked(callingPid); 1149 } 1150 // If it's at index 0, it's the current toast. It doesn't matter if it's 1151 // new or just been updated. Call back and tell it to show itself. 1152 // If the callback fails, this will remove it from the list, so don't 1153 // assume that it's valid after this. 1154 if (index == 0) { 1155 showNextToastLocked(); 1156 } 1157 } finally { 1158 Binder.restoreCallingIdentity(callingId); 1159 } 1160 } 1161 } 1162 1163 @Override 1164 public void cancelToast(String pkg, ITransientNotification callback) { 1165 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback); 1166 1167 if (pkg == null || callback == null) { 1168 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback); 1169 return ; 1170 } 1171 1172 synchronized (mToastQueue) { 1173 long callingId = Binder.clearCallingIdentity(); 1174 try { 1175 int index = indexOfToastLocked(pkg, callback); 1176 if (index >= 0) { 1177 cancelToastLocked(index); 1178 } else { 1179 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg 1180 + " callback=" + callback); 1181 } 1182 } finally { 1183 Binder.restoreCallingIdentity(callingId); 1184 } 1185 } 1186 } 1187 1188 @Override 1189 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id, 1190 Notification notification, int[] idOut, int userId) throws RemoteException { 1191 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(), 1192 Binder.getCallingPid(), tag, id, notification, idOut, userId); 1193 } 1194 1195 @Override 1196 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) { 1197 checkCallerIsSystemOrSameApp(pkg); 1198 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 1199 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg); 1200 // Don't allow client applications to cancel foreground service notis. 1201 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0, 1202 Binder.getCallingUid() == Process.SYSTEM_UID 1203 ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId, 1204 REASON_APP_CANCEL, null); 1205 } 1206 1207 @Override 1208 public void cancelAllNotifications(String pkg, int userId) { 1209 checkCallerIsSystemOrSameApp(pkg); 1210 1211 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 1212 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg); 1213 1214 // Calling from user space, don't allow the canceling of actively 1215 // running foreground services. 1216 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(), 1217 pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId, 1218 REASON_APP_CANCEL_ALL, null, null); 1219 } 1220 1221 @Override 1222 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) { 1223 checkCallerIsSystem(); 1224 1225 setNotificationsEnabledForPackageImpl(pkg, uid, enabled); 1226 } 1227 1228 /** 1229 * Use this when you just want to know if notifications are OK for this package. 1230 */ 1231 @Override 1232 public boolean areNotificationsEnabledForPackage(String pkg, int uid) { 1233 checkCallerIsSystem(); 1234 return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg) 1235 == AppOpsManager.MODE_ALLOWED); 1236 } 1237 1238 @Override 1239 public ParceledListSlice<Notification.Topic> getTopics(String pkg, int uid) { 1240 checkCallerIsSystem(); 1241 return new ParceledListSlice<Notification.Topic>(mRankingHelper.getTopics(pkg, uid)); 1242 } 1243 1244 @Override 1245 public void setPriority(String pkg, int uid, Notification.Topic topic, int priority) { 1246 checkCallerIsSystem(); 1247 mRankingHelper.setPriority(pkg, uid, topic, priority); 1248 savePolicyFile(); 1249 } 1250 1251 @Override 1252 public int getPriority(String pkg, int uid, Notification.Topic topic) { 1253 checkCallerIsSystem(); 1254 return mRankingHelper.getPriority(pkg, uid, topic); 1255 } 1256 1257 @Override 1258 public void setVisibilityOverride(String pkg, int uid, Notification.Topic topic, 1259 int visibility) { 1260 checkCallerIsSystem(); 1261 mRankingHelper.setVisibilityOverride(pkg, uid, topic, visibility); 1262 savePolicyFile(); 1263 } 1264 1265 @Override 1266 public int getVisibilityOverride(String pkg, int uid, Notification.Topic topic) { 1267 checkCallerIsSystem(); 1268 return mRankingHelper.getVisibilityOverride(pkg, uid, topic); 1269 } 1270 1271 @Override 1272 public void setImportance(String pkg, int uid, Notification.Topic topic, 1273 int importance) { 1274 enforceSystemOrSystemUI("Caller not system or systemui"); 1275 if (topic == null) { 1276 // App wide, potentially store block in app ops. 1277 setNotificationsEnabledForPackageImpl(pkg, uid, 1278 importance != NotificationListenerService.Ranking.IMPORTANCE_NONE); 1279 } else { 1280 if (NotificationListenerService.Ranking.IMPORTANCE_NONE == importance) { 1281 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, 1282 UserHandle.getUserId(uid), 1283 REASON_TOPIC_BANNED, topic, null); 1284 } 1285 } 1286 mRankingHelper.setImportance(pkg, uid, topic, importance); 1287 savePolicyFile(); 1288 } 1289 1290 @Override 1291 public int getImportance(String pkg, int uid, Notification.Topic topic) { 1292 checkCallerIsSystem(); 1293 return mRankingHelper.getImportance(pkg, uid, topic); 1294 } 1295 1296 @Override 1297 public boolean doesAppUseTopics(String pkg, int uid) { 1298 enforceSystemOrSystemUI("Caller not system or systemui"); 1299 return mRankingHelper.doesAppUseTopics(pkg, uid); 1300 } 1301 1302 /** 1303 * System-only API for getting a list of current (i.e. not cleared) notifications. 1304 * 1305 * Requires ACCESS_NOTIFICATIONS which is signature|system. 1306 * @returns A list of all the notifications, in natural order. 1307 */ 1308 @Override 1309 public StatusBarNotification[] getActiveNotifications(String callingPkg) { 1310 // enforce() will ensure the calling uid has the correct permission 1311 getContext().enforceCallingOrSelfPermission( 1312 android.Manifest.permission.ACCESS_NOTIFICATIONS, 1313 "NotificationManagerService.getActiveNotifications"); 1314 1315 StatusBarNotification[] tmp = null; 1316 int uid = Binder.getCallingUid(); 1317 1318 // noteOp will check to make sure the callingPkg matches the uid 1319 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg) 1320 == AppOpsManager.MODE_ALLOWED) { 1321 synchronized (mNotificationList) { 1322 tmp = new StatusBarNotification[mNotificationList.size()]; 1323 final int N = mNotificationList.size(); 1324 for (int i=0; i<N; i++) { 1325 tmp[i] = mNotificationList.get(i).sbn; 1326 } 1327 } 1328 } 1329 return tmp; 1330 } 1331 1332 /** 1333 * Public API for getting a list of current notifications for the calling package/uid. 1334 * 1335 * @returns A list of all the package's notifications, in natural order. 1336 */ 1337 @Override 1338 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg, 1339 int incomingUserId) { 1340 checkCallerIsSystemOrSameApp(pkg); 1341 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 1342 Binder.getCallingUid(), incomingUserId, true, false, 1343 "getAppActiveNotifications", pkg); 1344 1345 final ArrayList<StatusBarNotification> list 1346 = new ArrayList<StatusBarNotification>(mNotificationList.size()); 1347 1348 synchronized (mNotificationList) { 1349 final int N = mNotificationList.size(); 1350 for (int i = 0; i < N; i++) { 1351 final StatusBarNotification sbn = mNotificationList.get(i).sbn; 1352 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) { 1353 // We could pass back a cloneLight() but clients might get confused and 1354 // try to send this thing back to notify() again, which would not work 1355 // very well. 1356 final StatusBarNotification sbnOut = new StatusBarNotification( 1357 sbn.getPackageName(), 1358 sbn.getOpPkg(), 1359 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(), 1360 0, // hide score from apps 1361 sbn.getNotification().clone(), 1362 sbn.getUser(), sbn.getPostTime()); 1363 list.add(sbnOut); 1364 } 1365 } 1366 } 1367 1368 return new ParceledListSlice<StatusBarNotification>(list); 1369 } 1370 1371 /** 1372 * System-only API for getting a list of recent (cleared, no longer shown) notifications. 1373 * 1374 * Requires ACCESS_NOTIFICATIONS which is signature|system. 1375 */ 1376 @Override 1377 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) { 1378 // enforce() will ensure the calling uid has the correct permission 1379 getContext().enforceCallingOrSelfPermission( 1380 android.Manifest.permission.ACCESS_NOTIFICATIONS, 1381 "NotificationManagerService.getHistoricalNotifications"); 1382 1383 StatusBarNotification[] tmp = null; 1384 int uid = Binder.getCallingUid(); 1385 1386 // noteOp will check to make sure the callingPkg matches the uid 1387 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg) 1388 == AppOpsManager.MODE_ALLOWED) { 1389 synchronized (mArchive) { 1390 tmp = mArchive.getArray(count); 1391 } 1392 } 1393 return tmp; 1394 } 1395 1396 /** 1397 * Register a listener binder directly with the notification manager. 1398 * 1399 * Only works with system callers. Apps should extend 1400 * {@link android.service.notification.NotificationListenerService}. 1401 */ 1402 @Override 1403 public void registerListener(final INotificationListener listener, 1404 final ComponentName component, final int userid) { 1405 enforceSystemOrSystemUI("INotificationManager.registerListener"); 1406 mListeners.registerService(listener, component, userid); 1407 } 1408 1409 /** 1410 * Remove a listener binder directly 1411 */ 1412 @Override 1413 public void unregisterListener(INotificationListener listener, int userid) { 1414 mListeners.unregisterService(listener, userid); 1415 } 1416 1417 /** 1418 * Allow an INotificationListener to simulate a "clear all" operation. 1419 * 1420 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications} 1421 * 1422 * @param token The binder for the listener, to check that the caller is allowed 1423 */ 1424 @Override 1425 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) { 1426 final int callingUid = Binder.getCallingUid(); 1427 final int callingPid = Binder.getCallingPid(); 1428 long identity = Binder.clearCallingIdentity(); 1429 try { 1430 synchronized (mNotificationList) { 1431 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1432 if (keys != null) { 1433 final int N = keys.length; 1434 for (int i = 0; i < N; i++) { 1435 NotificationRecord r = mNotificationsByKey.get(keys[i]); 1436 if (r == null) continue; 1437 final int userId = r.sbn.getUserId(); 1438 if (userId != info.userid && userId != UserHandle.USER_ALL && 1439 !mUserProfiles.isCurrentProfile(userId)) { 1440 throw new SecurityException("Disallowed call from listener: " 1441 + info.service); 1442 } 1443 cancelNotificationFromListenerLocked(info, callingUid, callingPid, 1444 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(), 1445 userId); 1446 } 1447 } else { 1448 cancelAllLocked(callingUid, callingPid, info.userid, 1449 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles()); 1450 } 1451 } 1452 } finally { 1453 Binder.restoreCallingIdentity(identity); 1454 } 1455 } 1456 1457 /** 1458 * Handle request from an approved listener to re-enable itself. 1459 * 1460 * @param component The componenet to be re-enabled, caller must match package. 1461 */ 1462 @Override 1463 public void requestBindListener(ComponentName component) { 1464 checkCallerIsSystemOrSameApp(component.getPackageName()); 1465 long identity = Binder.clearCallingIdentity(); 1466 try { 1467 ManagedServices manager = mAssistant.isComponentEnabledForCurrentProfiles(component) 1468 ? mAssistant 1469 : mListeners; 1470 manager.setComponentState(component, true); 1471 } finally { 1472 Binder.restoreCallingIdentity(identity); 1473 } 1474 } 1475 1476 @Override 1477 public void requestUnbindListener(INotificationListener token) { 1478 long identity = Binder.clearCallingIdentity(); 1479 try { 1480 // allow bound services to disable themselves 1481 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1482 info.getOwner().setComponentState(info.component, false); 1483 } finally { 1484 Binder.restoreCallingIdentity(identity); 1485 } 1486 } 1487 1488 @Override 1489 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) { 1490 long identity = Binder.clearCallingIdentity(); 1491 try { 1492 synchronized (mNotificationList) { 1493 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1494 if (keys != null) { 1495 final int N = keys.length; 1496 for (int i = 0; i < N; i++) { 1497 NotificationRecord r = mNotificationsByKey.get(keys[i]); 1498 if (r == null) continue; 1499 final int userId = r.sbn.getUserId(); 1500 if (userId != info.userid && userId != UserHandle.USER_ALL && 1501 !mUserProfiles.isCurrentProfile(userId)) { 1502 throw new SecurityException("Disallowed call from listener: " 1503 + info.service); 1504 } 1505 if (!r.isSeen()) { 1506 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]); 1507 mAppUsageStats.reportEvent(r.sbn.getPackageName(), 1508 userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM 1509 : userId, 1510 UsageEvents.Event.USER_INTERACTION); 1511 r.setSeen(); 1512 } 1513 } 1514 } 1515 } 1516 } finally { 1517 Binder.restoreCallingIdentity(identity); 1518 } 1519 } 1520 1521 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info, 1522 int callingUid, int callingPid, String pkg, String tag, int id, int userId) { 1523 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 1524 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE, 1525 true, 1526 userId, REASON_LISTENER_CANCEL, info); 1527 } 1528 1529 /** 1530 * Allow an INotificationListener to simulate clearing (dismissing) a single notification. 1531 * 1532 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear} 1533 * 1534 * @param token The binder for the listener, to check that the caller is allowed 1535 */ 1536 @Override 1537 public void cancelNotificationFromListener(INotificationListener token, String pkg, 1538 String tag, int id) { 1539 final int callingUid = Binder.getCallingUid(); 1540 final int callingPid = Binder.getCallingPid(); 1541 long identity = Binder.clearCallingIdentity(); 1542 try { 1543 synchronized (mNotificationList) { 1544 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1545 if (info.supportsProfiles()) { 1546 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) " 1547 + "from " + info.component 1548 + " use cancelNotification(key) instead."); 1549 } else { 1550 cancelNotificationFromListenerLocked(info, callingUid, callingPid, 1551 pkg, tag, id, info.userid); 1552 } 1553 } 1554 } finally { 1555 Binder.restoreCallingIdentity(identity); 1556 } 1557 } 1558 1559 /** 1560 * Allow an INotificationListener to request the list of outstanding notifications seen by 1561 * the current user. Useful when starting up, after which point the listener callbacks 1562 * should be used. 1563 * 1564 * @param token The binder for the listener, to check that the caller is allowed 1565 * @param keys An array of notification keys to fetch, or null to fetch everything 1566 * @returns The return value will contain the notifications specified in keys, in that 1567 * order, or if keys is null, all the notifications, in natural order. 1568 */ 1569 @Override 1570 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener( 1571 INotificationListener token, String[] keys, int trim) { 1572 synchronized (mNotificationList) { 1573 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1574 final boolean getKeys = keys != null; 1575 final int N = getKeys ? keys.length : mNotificationList.size(); 1576 final ArrayList<StatusBarNotification> list 1577 = new ArrayList<StatusBarNotification>(N); 1578 for (int i=0; i<N; i++) { 1579 final NotificationRecord r = getKeys 1580 ? mNotificationsByKey.get(keys[i]) 1581 : mNotificationList.get(i); 1582 if (r == null) continue; 1583 StatusBarNotification sbn = r.sbn; 1584 if (!isVisibleToListener(sbn, info)) continue; 1585 StatusBarNotification sbnToSend = 1586 (trim == TRIM_FULL) ? sbn : sbn.cloneLight(); 1587 list.add(sbnToSend); 1588 } 1589 return new ParceledListSlice<StatusBarNotification>(list); 1590 } 1591 } 1592 1593 @Override 1594 public void requestHintsFromListener(INotificationListener token, int hints) { 1595 final long identity = Binder.clearCallingIdentity(); 1596 try { 1597 synchronized (mNotificationList) { 1598 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1599 final boolean disableEffects = (hints & HINT_HOST_DISABLE_EFFECTS) != 0; 1600 if (disableEffects) { 1601 mListenersDisablingEffects.add(info); 1602 } else { 1603 mListenersDisablingEffects.remove(info); 1604 } 1605 updateListenerHintsLocked(); 1606 updateEffectsSuppressorLocked(); 1607 } 1608 } finally { 1609 Binder.restoreCallingIdentity(identity); 1610 } 1611 } 1612 1613 @Override 1614 public int getHintsFromListener(INotificationListener token) { 1615 synchronized (mNotificationList) { 1616 return mListenerHints; 1617 } 1618 } 1619 1620 @Override 1621 public void requestInterruptionFilterFromListener(INotificationListener token, 1622 int interruptionFilter) throws RemoteException { 1623 final long identity = Binder.clearCallingIdentity(); 1624 try { 1625 synchronized (mNotificationList) { 1626 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1627 mZenModeHelper.requestFromListener(info.component, interruptionFilter); 1628 updateInterruptionFilterLocked(); 1629 } 1630 } finally { 1631 Binder.restoreCallingIdentity(identity); 1632 } 1633 } 1634 1635 @Override 1636 public int getInterruptionFilterFromListener(INotificationListener token) 1637 throws RemoteException { 1638 synchronized (mNotificationLight) { 1639 return mInterruptionFilter; 1640 } 1641 } 1642 1643 @Override 1644 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim) 1645 throws RemoteException { 1646 synchronized (mNotificationList) { 1647 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); 1648 if (info == null) return; 1649 mListeners.setOnNotificationPostedTrimLocked(info, trim); 1650 } 1651 } 1652 1653 @Override 1654 public int getZenMode() { 1655 return mZenModeHelper.getZenMode(); 1656 } 1657 1658 @Override 1659 public ZenModeConfig getZenModeConfig() { 1660 enforceSystemOrSystemUIOrVolume("INotificationManager.getZenModeConfig"); 1661 return mZenModeHelper.getConfig(); 1662 } 1663 1664 @Override 1665 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException { 1666 enforceSystemOrSystemUIOrVolume("INotificationManager.setZenMode"); 1667 final long identity = Binder.clearCallingIdentity(); 1668 try { 1669 mZenModeHelper.setManualZenMode(mode, conditionId, reason); 1670 } finally { 1671 Binder.restoreCallingIdentity(identity); 1672 } 1673 } 1674 1675 @Override 1676 public List<AutomaticZenRule> getAutomaticZenRules() throws RemoteException { 1677 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules"); 1678 return mZenModeHelper.getAutomaticZenRules(); 1679 } 1680 1681 @Override 1682 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException { 1683 Preconditions.checkNotNull(id, "Id is null"); 1684 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule"); 1685 return mZenModeHelper.getAutomaticZenRule(id); 1686 } 1687 1688 @Override 1689 public AutomaticZenRule addAutomaticZenRule(AutomaticZenRule automaticZenRule) 1690 throws RemoteException { 1691 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null"); 1692 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null"); 1693 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null"); 1694 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null"); 1695 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule"); 1696 1697 return mZenModeHelper.addAutomaticZenRule(automaticZenRule, 1698 "addAutomaticZenRule"); 1699 } 1700 1701 @Override 1702 public boolean updateAutomaticZenRule(AutomaticZenRule automaticZenRule) 1703 throws RemoteException { 1704 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null"); 1705 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null"); 1706 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null"); 1707 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null"); 1708 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule"); 1709 1710 return mZenModeHelper.updateAutomaticZenRule(automaticZenRule, 1711 "updateAutomaticZenRule"); 1712 } 1713 1714 @Override 1715 public boolean removeAutomaticZenRule(String id) throws RemoteException { 1716 Preconditions.checkNotNull(id, "Id is null"); 1717 // Verify that they can modify zen rules. 1718 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule"); 1719 1720 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule"); 1721 } 1722 1723 @Override 1724 public boolean removeAutomaticZenRules(String packageName) throws RemoteException { 1725 Preconditions.checkNotNull(packageName, "Package name is null"); 1726 enforceSystemOrSystemUI("removeAutomaticZenRules"); 1727 1728 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules"); 1729 } 1730 1731 @Override 1732 public int getRuleInstanceCount(ComponentName owner) throws RemoteException { 1733 Preconditions.checkNotNull(owner, "Owner is null"); 1734 enforceSystemOrSystemUI("getRuleInstanceCount"); 1735 1736 return mZenModeHelper.getCurrentInstanceCount(owner); 1737 } 1738 1739 @Override 1740 public void setInterruptionFilter(String pkg, int filter) throws RemoteException { 1741 enforcePolicyAccess(pkg, "setInterruptionFilter"); 1742 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1); 1743 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter); 1744 final long identity = Binder.clearCallingIdentity(); 1745 try { 1746 mZenModeHelper.setManualZenMode(zen, null, "setInterruptionFilter"); 1747 } finally { 1748 Binder.restoreCallingIdentity(identity); 1749 } 1750 } 1751 1752 @Override 1753 public void notifyConditions(final String pkg, IConditionProvider provider, 1754 final Condition[] conditions) { 1755 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider); 1756 checkCallerIsSystemOrSameApp(pkg); 1757 mHandler.post(new Runnable() { 1758 @Override 1759 public void run() { 1760 mConditionProviders.notifyConditions(pkg, info, conditions); 1761 } 1762 }); 1763 } 1764 1765 private void enforceSystemOrSystemUIOrVolume(String message) { 1766 if (mAudioManagerInternal != null) { 1767 final int vcuid = mAudioManagerInternal.getVolumeControllerUid(); 1768 if (vcuid > 0 && Binder.getCallingUid() == vcuid) { 1769 return; 1770 } 1771 } 1772 enforceSystemOrSystemUI(message); 1773 } 1774 1775 private void enforceSystemOrSystemUI(String message) { 1776 if (isCallerSystem()) return; 1777 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE, 1778 message); 1779 } 1780 1781 private void enforcePolicyAccess(int uid, String method) { 1782 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission( 1783 android.Manifest.permission.MANAGE_NOTIFICATIONS)) { 1784 return; 1785 } 1786 boolean accessAllowed = false; 1787 String[] packages = getContext().getPackageManager().getPackagesForUid(uid); 1788 final int packageCount = packages.length; 1789 for (int i = 0; i < packageCount; i++) { 1790 if (checkPolicyAccess(packages[i])) { 1791 accessAllowed = true; 1792 } 1793 } 1794 if (!accessAllowed) { 1795 Slog.w(TAG, "Notification policy access denied calling " + method); 1796 throw new SecurityException("Notification policy access denied"); 1797 } 1798 } 1799 1800 private void enforcePolicyAccess(String pkg, String method) { 1801 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission( 1802 android.Manifest.permission.MANAGE_NOTIFICATIONS)) { 1803 return; 1804 } 1805 if (!checkPolicyAccess(pkg)) { 1806 Slog.w(TAG, "Notification policy access denied calling " + method); 1807 throw new SecurityException("Notification policy access denied"); 1808 } 1809 } 1810 1811 private boolean checkPackagePolicyAccess(String pkg) { 1812 return mPolicyAccess.isPackageGranted(pkg); 1813 } 1814 1815 private boolean checkPolicyAccess(String pkg) { 1816 return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg); 1817 } 1818 1819 @Override 1820 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1821 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1822 != PackageManager.PERMISSION_GRANTED) { 1823 pw.println("Permission Denial: can't dump NotificationManager from pid=" 1824 + Binder.getCallingPid() 1825 + ", uid=" + Binder.getCallingUid()); 1826 return; 1827 } 1828 1829 final DumpFilter filter = DumpFilter.parseFromArguments(args); 1830 if (filter != null && filter.stats) { 1831 dumpJson(pw, filter); 1832 } else { 1833 dumpImpl(pw, filter); 1834 } 1835 } 1836 1837 @Override 1838 public ComponentName getEffectsSuppressor() { 1839 enforceSystemOrSystemUIOrVolume("INotificationManager.getEffectsSuppressor"); 1840 return mEffectsSuppressor; 1841 } 1842 1843 @Override 1844 public boolean matchesCallFilter(Bundle extras) { 1845 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter"); 1846 return mZenModeHelper.matchesCallFilter( 1847 Binder.getCallingUserHandle(), 1848 extras, 1849 mRankingHelper.findExtractor(ValidateNotificationPeople.class), 1850 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS, 1851 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY); 1852 } 1853 1854 @Override 1855 public boolean isSystemConditionProviderEnabled(String path) { 1856 enforceSystemOrSystemUIOrVolume("INotificationManager.isSystemConditionProviderEnabled"); 1857 return mConditionProviders.isSystemProviderEnabled(path); 1858 } 1859 1860 // Backup/restore interface 1861 @Override 1862 public byte[] getBackupPayload(int user) { 1863 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user); 1864 //TODO: http://b/22388012 1865 if (user != UserHandle.USER_SYSTEM) { 1866 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user); 1867 return null; 1868 } 1869 final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 1870 try { 1871 writePolicyXml(baos, true /*forBackup*/); 1872 return baos.toByteArray(); 1873 } catch (IOException e) { 1874 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e); 1875 } 1876 return null; 1877 } 1878 1879 @Override 1880 public void applyRestore(byte[] payload, int user) { 1881 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload=" 1882 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null)); 1883 if (payload == null) { 1884 Slog.w(TAG, "applyRestore: no payload to restore for user " + user); 1885 return; 1886 } 1887 //TODO: http://b/22388012 1888 if (user != UserHandle.USER_SYSTEM) { 1889 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user); 1890 return; 1891 } 1892 final ByteArrayInputStream bais = new ByteArrayInputStream(payload); 1893 try { 1894 readPolicyXml(bais, true /*forRestore*/); 1895 savePolicyFile(); 1896 } catch (NumberFormatException | XmlPullParserException | IOException e) { 1897 Slog.w(TAG, "applyRestore: error reading payload", e); 1898 } 1899 } 1900 1901 @Override 1902 public boolean isNotificationPolicyAccessGranted(String pkg) { 1903 return checkPolicyAccess(pkg); 1904 } 1905 1906 @Override 1907 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) { 1908 enforceSystemOrSystemUI("request policy access status for another package"); 1909 return checkPackagePolicyAccess(pkg); 1910 } 1911 1912 @Override 1913 public String[] getPackagesRequestingNotificationPolicyAccess() 1914 throws RemoteException { 1915 enforceSystemOrSystemUI("request policy access packages"); 1916 final long identity = Binder.clearCallingIdentity(); 1917 try { 1918 return mPolicyAccess.getRequestingPackages(); 1919 } finally { 1920 Binder.restoreCallingIdentity(identity); 1921 } 1922 } 1923 1924 @Override 1925 public void setNotificationPolicyAccessGranted(String pkg, boolean granted) 1926 throws RemoteException { 1927 enforceSystemOrSystemUI("grant notification policy access"); 1928 final long identity = Binder.clearCallingIdentity(); 1929 try { 1930 synchronized (mNotificationList) { 1931 mPolicyAccess.put(pkg, granted); 1932 } 1933 } finally { 1934 Binder.restoreCallingIdentity(identity); 1935 } 1936 } 1937 1938 @Override 1939 public Policy getNotificationPolicy(String pkg) { 1940 enforcePolicyAccess(pkg, "getNotificationPolicy"); 1941 final long identity = Binder.clearCallingIdentity(); 1942 try { 1943 return mZenModeHelper.getNotificationPolicy(); 1944 } finally { 1945 Binder.restoreCallingIdentity(identity); 1946 } 1947 } 1948 1949 @Override 1950 public void setNotificationPolicy(String pkg, Policy policy) { 1951 enforcePolicyAccess(pkg, "setNotificationPolicy"); 1952 final long identity = Binder.clearCallingIdentity(); 1953 try { 1954 mZenModeHelper.setNotificationPolicy(policy); 1955 } finally { 1956 Binder.restoreCallingIdentity(identity); 1957 } 1958 } 1959 1960 @Override 1961 public void setImportanceFromAssistant(INotificationListener token, String key, 1962 int importance, CharSequence explanation) throws RemoteException { 1963 final long identity = Binder.clearCallingIdentity(); 1964 try { 1965 synchronized (mNotificationList) { 1966 mAssistant.checkServiceTokenLocked(token); 1967 NotificationRecord n = mNotificationsByKey.get(key); 1968 n.setImportance(importance, explanation); 1969 mRankingHandler.requestSort(); 1970 } 1971 } finally { 1972 Binder.restoreCallingIdentity(identity); 1973 } 1974 } 1975 }; 1976 1977 private String disableNotificationEffects(NotificationRecord record) { 1978 if (mDisableNotificationEffects) { 1979 return "booleanState"; 1980 } 1981 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) { 1982 return "listenerHints"; 1983 } 1984 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) { 1985 return "callState"; 1986 } 1987 return null; 1988 }; 1989 1990 private void dumpJson(PrintWriter pw, DumpFilter filter) { 1991 JSONObject dump = new JSONObject(); 1992 try { 1993 dump.put("service", "Notification Manager"); 1994 JSONArray bans = new JSONArray(); 1995 try { 1996 ArrayMap<Integer, ArrayList<String>> packageBans = getPackageBans(filter); 1997 for (Integer userId : packageBans.keySet()) { 1998 for (String packageName : packageBans.get(userId)) { 1999 JSONObject ban = new JSONObject(); 2000 ban.put("userId", userId); 2001 ban.put("packageName", packageName); 2002 bans.put(ban); 2003 } 2004 } 2005 } catch (NameNotFoundException e) { 2006 // pass 2007 } 2008 dump.put("bans", bans); 2009 dump.put("stats", mUsageStats.dumpJson(filter)); 2010 } catch (JSONException e) { 2011 e.printStackTrace(); 2012 } 2013 pw.println(dump); 2014 } 2015 2016 void dumpImpl(PrintWriter pw, DumpFilter filter) { 2017 pw.print("Current Notification Manager state"); 2018 if (filter.filtered) { 2019 pw.print(" (filtered to "); pw.print(filter); pw.print(")"); 2020 } 2021 pw.println(':'); 2022 int N; 2023 final boolean zenOnly = filter.filtered && filter.zen; 2024 2025 if (!zenOnly) { 2026 synchronized (mToastQueue) { 2027 N = mToastQueue.size(); 2028 if (N > 0) { 2029 pw.println(" Toast Queue:"); 2030 for (int i=0; i<N; i++) { 2031 mToastQueue.get(i).dump(pw, " ", filter); 2032 } 2033 pw.println(" "); 2034 } 2035 } 2036 } 2037 2038 synchronized (mNotificationList) { 2039 if (!zenOnly) { 2040 N = mNotificationList.size(); 2041 if (N > 0) { 2042 pw.println(" Notification List:"); 2043 for (int i=0; i<N; i++) { 2044 final NotificationRecord nr = mNotificationList.get(i); 2045 if (filter.filtered && !filter.matches(nr.sbn)) continue; 2046 nr.dump(pw, " ", getContext(), filter.redact); 2047 } 2048 pw.println(" "); 2049 } 2050 2051 if (!filter.filtered) { 2052 N = mLights.size(); 2053 if (N > 0) { 2054 pw.println(" Lights List:"); 2055 for (int i=0; i<N; i++) { 2056 if (i == N - 1) { 2057 pw.print(" > "); 2058 } else { 2059 pw.print(" "); 2060 } 2061 pw.println(mLights.get(i)); 2062 } 2063 pw.println(" "); 2064 } 2065 pw.println(" mUseAttentionLight=" + mUseAttentionLight); 2066 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled); 2067 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey); 2068 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey); 2069 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects); 2070 pw.println(" mCallState=" + callStateToString(mCallState)); 2071 pw.println(" mSystemReady=" + mSystemReady); 2072 } 2073 pw.println(" mArchive=" + mArchive.toString()); 2074 Iterator<StatusBarNotification> iter = mArchive.descendingIterator(); 2075 int i=0; 2076 while (iter.hasNext()) { 2077 final StatusBarNotification sbn = iter.next(); 2078 if (filter != null && !filter.matches(sbn)) continue; 2079 pw.println(" " + sbn); 2080 if (++i >= 5) { 2081 if (iter.hasNext()) pw.println(" ..."); 2082 break; 2083 } 2084 } 2085 } 2086 2087 if (!zenOnly) { 2088 pw.println("\n Usage Stats:"); 2089 mUsageStats.dump(pw, " ", filter); 2090 } 2091 2092 if (!filter.filtered || zenOnly) { 2093 pw.println("\n Zen Mode:"); 2094 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter); 2095 mZenModeHelper.dump(pw, " "); 2096 2097 pw.println("\n Zen Log:"); 2098 ZenLog.dump(pw, " "); 2099 } 2100 2101 if (!zenOnly) { 2102 pw.println("\n Ranking Config:"); 2103 mRankingHelper.dump(pw, " ", filter); 2104 2105 pw.println("\n Notification listeners:"); 2106 mListeners.dump(pw, filter); 2107 pw.print(" mListenerHints: "); pw.println(mListenerHints); 2108 pw.print(" mListenersDisablingEffects: ("); 2109 N = mListenersDisablingEffects.size(); 2110 for (int i = 0; i < N; i++) { 2111 final ManagedServiceInfo listener = mListenersDisablingEffects.valueAt(i); 2112 if (i > 0) pw.print(','); 2113 pw.print(listener.component); 2114 } 2115 pw.println(')'); 2116 pw.println("\n Notification assistant:"); 2117 mAssistant.dump(pw, filter); 2118 } 2119 pw.println("\n Policy access:"); 2120 pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess); 2121 2122 pw.println("\n Condition providers:"); 2123 mConditionProviders.dump(pw, filter); 2124 2125 pw.println("\n Group summaries:"); 2126 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) { 2127 NotificationRecord r = entry.getValue(); 2128 pw.println(" " + entry.getKey() + " -> " + r.getKey()); 2129 if (mNotificationsByKey.get(r.getKey()) != r) { 2130 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey."); 2131 r.dump(pw, " ", getContext(), filter.redact); 2132 } 2133 } 2134 2135 try { 2136 pw.println("\n Banned Packages:"); 2137 ArrayMap<Integer, ArrayList<String>> packageBans = getPackageBans(filter); 2138 for (Integer userId : packageBans.keySet()) { 2139 for (String packageName : packageBans.get(userId)) { 2140 pw.println(" " + userId + ": " + packageName); 2141 } 2142 } 2143 } catch (NameNotFoundException e) { 2144 // pass 2145 } 2146 } 2147 } 2148 2149 private ArrayMap<Integer, ArrayList<String>> getPackageBans(DumpFilter filter) 2150 throws NameNotFoundException { 2151 ArrayMap<Integer, ArrayList<String>> packageBans = new ArrayMap<>(); 2152 ArrayList<String> packageNames = new ArrayList<>(); 2153 for (UserInfo user : UserManager.get(getContext()).getUsers()) { 2154 final int userId = user.getUserHandle().getIdentifier(); 2155 final PackageManager packageManager = getContext().getPackageManager(); 2156 List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId); 2157 final int packageCount = packages.size(); 2158 for (int p = 0; p < packageCount; p++) { 2159 final String packageName = packages.get(p).packageName; 2160 if (filter == null || filter.matches(packageName)) { 2161 final int uid = packageManager.getPackageUidAsUser(packageName, userId); 2162 if (!checkNotificationOp(packageName, uid)) { 2163 packageNames.add(packageName); 2164 } 2165 } 2166 } 2167 if (!packageNames.isEmpty()) { 2168 packageBans.put(userId, packageNames); 2169 packageNames = new ArrayList<>(); 2170 } 2171 } 2172 return packageBans; 2173 } 2174 2175 /** 2176 * The private API only accessible to the system process. 2177 */ 2178 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() { 2179 @Override 2180 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid, 2181 String tag, int id, Notification notification, int[] idReceived, int userId) { 2182 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification, 2183 idReceived, userId); 2184 } 2185 2186 @Override 2187 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId, 2188 int userId) { 2189 checkCallerIsSystem(); 2190 synchronized (mNotificationList) { 2191 int i = indexOfNotificationLocked(pkg, null, notificationId, userId); 2192 if (i < 0) { 2193 Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with " 2194 + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId); 2195 return; 2196 } 2197 NotificationRecord r = mNotificationList.get(i); 2198 StatusBarNotification sbn = r.sbn; 2199 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees 2200 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE, 2201 // we have to revert to the flags we received initially *and* force remove 2202 // FLAG_FOREGROUND_SERVICE. 2203 sbn.getNotification().flags = 2204 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE); 2205 mRankingHelper.sort(mNotificationList); 2206 mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */); 2207 } 2208 } 2209 }; 2210 2211 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, 2212 final int callingPid, final String tag, final int id, final Notification notification, 2213 int[] idOut, int incomingUserId) { 2214 if (DBG) { 2215 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id 2216 + " notification=" + notification); 2217 } 2218 checkCallerIsSystemOrSameApp(pkg); 2219 final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg)); 2220 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg); 2221 2222 final int userId = ActivityManager.handleIncomingUser(callingPid, 2223 callingUid, incomingUserId, true, false, "enqueueNotification", pkg); 2224 final UserHandle user = new UserHandle(userId); 2225 2226 // Limit the number of notifications that any given package except the android 2227 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks. 2228 if (!isSystemNotification && !isNotificationFromListener) { 2229 synchronized (mNotificationList) { 2230 int count = 0; 2231 final int N = mNotificationList.size(); 2232 for (int i=0; i<N; i++) { 2233 final NotificationRecord r = mNotificationList.get(i); 2234 if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) { 2235 if (r.sbn.getId() == id && TextUtils.equals(r.sbn.getTag(), tag)) { 2236 break; // Allow updating existing notification 2237 } 2238 count++; 2239 if (count >= MAX_PACKAGE_NOTIFICATIONS) { 2240 Slog.e(TAG, "Package has already posted " + count 2241 + " notifications. Not showing more. package=" + pkg); 2242 return; 2243 } 2244 } 2245 } 2246 } 2247 } 2248 2249 if (pkg == null || notification == null) { 2250 throw new IllegalArgumentException("null not allowed: pkg=" + pkg 2251 + " id=" + id + " notification=" + notification); 2252 } 2253 2254 // Sanitize inputs 2255 notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN, 2256 Notification.PRIORITY_MAX); 2257 2258 // setup local book-keeping 2259 final StatusBarNotification n = new StatusBarNotification( 2260 pkg, opPkg, id, tag, callingUid, callingPid, 0, notification, 2261 user); 2262 final NotificationRecord r = new NotificationRecord(getContext(), n); 2263 mHandler.post(new EnqueueNotificationRunnable(userId, r)); 2264 2265 idOut[0] = id; 2266 } 2267 2268 private class EnqueueNotificationRunnable implements Runnable { 2269 private final NotificationRecord r; 2270 private final int userId; 2271 2272 EnqueueNotificationRunnable(int userId, NotificationRecord r) { 2273 this.userId = userId; 2274 this.r = r; 2275 }; 2276 2277 @Override 2278 public void run() { 2279 2280 synchronized (mNotificationList) { 2281 final StatusBarNotification n = r.sbn; 2282 Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey()); 2283 NotificationRecord old = mNotificationsByKey.get(n.getKey()); 2284 if (old != null) { 2285 // Retain ranking information from previous record 2286 r.copyRankingInformation(old); 2287 } 2288 2289 final int callingUid = n.getUid(); 2290 final int callingPid = n.getInitialPid(); 2291 final Notification notification = n.getNotification(); 2292 final String pkg = n.getPackageName(); 2293 final int id = n.getId(); 2294 final String tag = n.getTag(); 2295 final boolean isSystemNotification = isUidSystem(callingUid) || 2296 ("android".equals(pkg)); 2297 2298 // Handle grouped notifications and bail out early if we 2299 // can to avoid extracting signals. 2300 handleGroupedNotificationLocked(r, old, callingUid, callingPid); 2301 boolean ignoreNotification = 2302 removeUnusedGroupedNotificationLocked(r, old, callingUid, callingPid); 2303 Slog.d(TAG, "ignoreNotification is " + ignoreNotification); 2304 2305 // This conditional is a dirty hack to limit the logging done on 2306 // behalf of the download manager without affecting other apps. 2307 if (!pkg.equals("com.android.providers.downloads") 2308 || Log.isLoggable("DownloadManager", Log.VERBOSE)) { 2309 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW; 2310 if (ignoreNotification) { 2311 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_IGNORED; 2312 } else if (old != null) { 2313 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE; 2314 } 2315 EventLogTags.writeNotificationEnqueue(callingUid, callingPid, 2316 pkg, id, tag, userId, notification.toString(), 2317 enqueueStatus); 2318 } 2319 2320 if (ignoreNotification) { 2321 return; 2322 } 2323 2324 mRankingHelper.extractSignals(r); 2325 2326 // why is this here? 2327 savePolicyFile(); 2328 2329 // blocked apps/topics 2330 if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE 2331 || !noteNotificationOp(pkg, callingUid)) { 2332 if (!isSystemNotification) { 2333 Slog.e(TAG, "Suppressing notification from package " + pkg 2334 + " by user request."); 2335 mUsageStats.registerBlocked(r); 2336 return; 2337 } 2338 } 2339 2340 // tell the assistant about the notification 2341 if (mAssistant.isEnabled()) { 2342 mAssistant.onNotificationEnqueued(r); 2343 // TODO delay the code below here for 100ms or until there is an answer 2344 } 2345 2346 2347 int index = indexOfNotificationLocked(n.getKey()); 2348 if (index < 0) { 2349 mNotificationList.add(r); 2350 mUsageStats.registerPostedByApp(r); 2351 } else { 2352 old = mNotificationList.get(index); 2353 mNotificationList.set(index, r); 2354 mUsageStats.registerUpdatedByApp(r, old); 2355 // Make sure we don't lose the foreground service state. 2356 notification.flags |= 2357 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE; 2358 r.isUpdate = true; 2359 } 2360 2361 mNotificationsByKey.put(n.getKey(), r); 2362 2363 // Ensure if this is a foreground service that the proper additional 2364 // flags are set. 2365 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) { 2366 notification.flags |= Notification.FLAG_ONGOING_EVENT 2367 | Notification.FLAG_NO_CLEAR; 2368 } 2369 2370 applyZenModeLocked(r); 2371 mRankingHelper.sort(mNotificationList); 2372 2373 if (notification.getSmallIcon() != null) { 2374 StatusBarNotification oldSbn = (old != null) ? old.sbn : null; 2375 mListeners.notifyPostedLocked(n, oldSbn); 2376 } else { 2377 Slog.e(TAG, "Not posting notification without small icon: " + notification); 2378 if (old != null && !old.isCanceled) { 2379 mListeners.notifyRemovedLocked(n); 2380 } 2381 // ATTENTION: in a future release we will bail out here 2382 // so that we do not play sounds, show lights, etc. for invalid 2383 // notifications 2384 Slog.e(TAG, "WARNING: In a future release this will crash the app: " 2385 + n.getPackageName()); 2386 } 2387 2388 buzzBeepBlinkLocked(r); 2389 } 2390 } 2391 } 2392 2393 /** 2394 * Ensures that grouped notification receive their special treatment. 2395 * 2396 * <p>Cancels group children if the new notification causes a group to lose 2397 * its summary.</p> 2398 * 2399 * <p>Updates mSummaryByGroupKey.</p> 2400 */ 2401 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old, 2402 int callingUid, int callingPid) { 2403 StatusBarNotification sbn = r.sbn; 2404 Notification n = sbn.getNotification(); 2405 String group = sbn.getGroupKey(); 2406 boolean isSummary = n.isGroupSummary(); 2407 2408 Notification oldN = old != null ? old.sbn.getNotification() : null; 2409 String oldGroup = old != null ? old.sbn.getGroupKey() : null; 2410 boolean oldIsSummary = old != null && oldN.isGroupSummary(); 2411 2412 if (oldIsSummary) { 2413 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup); 2414 if (removedSummary != old) { 2415 String removedKey = 2416 removedSummary != null ? removedSummary.getKey() : "<null>"; 2417 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() + 2418 ", removed=" + removedKey); 2419 } 2420 } 2421 if (isSummary) { 2422 mSummaryByGroupKey.put(group, r); 2423 } 2424 2425 // Clear out group children of the old notification if the update 2426 // causes the group summary to go away. This happens when the old 2427 // notification was a summary and the new one isn't, or when the old 2428 // notification was a summary and its group key changed. 2429 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) { 2430 cancelGroupChildrenLocked(old, callingUid, callingPid, null, 2431 REASON_GROUP_SUMMARY_CANCELED); 2432 } 2433 } 2434 2435 /** 2436 * Performs group notification optimizations if SysUI is the only active 2437 * notification listener and returns whether the given notification should 2438 * be ignored. 2439 * 2440 * <p>Returns true if the given notification is a child of a group with a 2441 * summary, which means that SysUI will never show it, and hence the new 2442 * notification can be safely ignored. Also cancels any previous instance 2443 * of the ignored notification.</p> 2444 * 2445 * <p>For summaries, cancels all children of that group, as SysUI will 2446 * never show them anymore.</p> 2447 * 2448 * @return true if the given notification can be ignored as an optimization 2449 */ 2450 private boolean removeUnusedGroupedNotificationLocked(NotificationRecord r, 2451 NotificationRecord old, int callingUid, int callingPid) { 2452 if (!ENABLE_CHILD_NOTIFICATIONS) { 2453 // No optimizations are possible if listeners want groups. 2454 if (mListeners.notificationGroupsDesired()) { 2455 return false; 2456 } 2457 2458 StatusBarNotification sbn = r.sbn; 2459 String group = sbn.getGroupKey(); 2460 boolean isSummary = sbn.getNotification().isGroupSummary(); 2461 boolean isChild = sbn.getNotification().isGroupChild(); 2462 2463 NotificationRecord summary = mSummaryByGroupKey.get(group); 2464 if (isChild && summary != null) { 2465 // Child with an active summary -> ignore 2466 if (DBG) { 2467 Slog.d(TAG, "Ignoring group child " + sbn.getKey() + " due to existing summary " 2468 + summary.getKey()); 2469 } 2470 // Make sure we don't leave an old version of the notification around. 2471 if (old != null) { 2472 if (DBG) { 2473 Slog.d(TAG, "Canceling old version of ignored group child " + sbn.getKey()); 2474 } 2475 cancelNotificationLocked(old, false, REASON_GROUP_OPTIMIZATION); 2476 } 2477 return true; 2478 } else if (isSummary) { 2479 // Summary -> cancel children 2480 cancelGroupChildrenLocked(r, callingUid, callingPid, null, 2481 REASON_GROUP_OPTIMIZATION); 2482 } 2483 } 2484 return false; 2485 } 2486 2487 private void buzzBeepBlinkLocked(NotificationRecord record) { 2488 boolean buzz = false; 2489 boolean beep = false; 2490 boolean blink = false; 2491 2492 final Notification notification = record.sbn.getNotification(); 2493 2494 // Should this notification make noise, vibe, or use the LED? 2495 final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_HIGH; 2496 final boolean canInterrupt = aboveThreshold && !record.isIntercepted(); 2497 if (DBG || record.isIntercepted()) 2498 Slog.v(TAG, 2499 "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt + 2500 " intercept=" + record.isIntercepted() 2501 ); 2502 2503 final int currentUser; 2504 final long token = Binder.clearCallingIdentity(); 2505 try { 2506 currentUser = ActivityManager.getCurrentUser(); 2507 } finally { 2508 Binder.restoreCallingIdentity(token); 2509 } 2510 2511 // If we're not supposed to beep, vibrate, etc. then don't. 2512 final String disableEffects = disableNotificationEffects(record); 2513 if (disableEffects != null) { 2514 ZenLog.traceDisableEffects(record, disableEffects); 2515 } 2516 if (disableEffects == null 2517 && (!(record.isUpdate 2518 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 )) 2519 && (record.getUserId() == UserHandle.USER_ALL || 2520 record.getUserId() == currentUser || 2521 mUserProfiles.isCurrentProfile(record.getUserId())) 2522 && canInterrupt 2523 && mSystemReady 2524 && mAudioManager != null) { 2525 if (DBG) Slog.v(TAG, "Interrupting!"); 2526 2527 sendAccessibilityEvent(notification, record.sbn.getPackageName()); 2528 2529 // sound 2530 2531 // should we use the default notification sound? (indicated either by 2532 // DEFAULT_SOUND or because notification.sound is pointing at 2533 // Settings.System.NOTIFICATION_SOUND) 2534 final boolean useDefaultSound = 2535 (notification.defaults & Notification.DEFAULT_SOUND) != 0 || 2536 Settings.System.DEFAULT_NOTIFICATION_URI 2537 .equals(notification.sound); 2538 2539 Uri soundUri = null; 2540 boolean hasValidSound = false; 2541 2542 if (useDefaultSound) { 2543 soundUri = Settings.System.DEFAULT_NOTIFICATION_URI; 2544 2545 // check to see if the default notification sound is silent 2546 ContentResolver resolver = getContext().getContentResolver(); 2547 hasValidSound = Settings.System.getString(resolver, 2548 Settings.System.NOTIFICATION_SOUND) != null; 2549 } else if (notification.sound != null) { 2550 soundUri = notification.sound; 2551 hasValidSound = (soundUri != null); 2552 } 2553 2554 if (hasValidSound) { 2555 boolean looping = 2556 (notification.flags & Notification.FLAG_INSISTENT) != 0; 2557 AudioAttributes audioAttributes = audioAttributesForNotification(notification); 2558 mSoundNotificationKey = record.getKey(); 2559 // do not play notifications if stream volume is 0 (typically because 2560 // ringer mode is silent) or if there is a user of exclusive audio focus 2561 if ((mAudioManager.getStreamVolume( 2562 AudioAttributes.toLegacyStreamType(audioAttributes)) != 0) 2563 && !mAudioManager.isAudioFocusExclusive()) { 2564 final long identity = Binder.clearCallingIdentity(); 2565 try { 2566 final IRingtonePlayer player = 2567 mAudioManager.getRingtonePlayer(); 2568 if (player != null) { 2569 if (DBG) Slog.v(TAG, "Playing sound " + soundUri 2570 + " with attributes " + audioAttributes); 2571 player.playAsync(soundUri, record.sbn.getUser(), looping, 2572 audioAttributes); 2573 beep = true; 2574 } 2575 } catch (RemoteException e) { 2576 } finally { 2577 Binder.restoreCallingIdentity(identity); 2578 } 2579 } 2580 } 2581 2582 // vibrate 2583 // Does the notification want to specify its own vibration? 2584 final boolean hasCustomVibrate = notification.vibrate != null; 2585 2586 // new in 4.2: if there was supposed to be a sound and we're in vibrate 2587 // mode, and no other vibration is specified, we fall back to vibration 2588 final boolean convertSoundToVibration = 2589 !hasCustomVibrate 2590 && hasValidSound 2591 && (mAudioManager.getRingerModeInternal() 2592 == AudioManager.RINGER_MODE_VIBRATE); 2593 2594 // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback. 2595 final boolean useDefaultVibrate = 2596 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0; 2597 2598 if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate) 2599 && !(mAudioManager.getRingerModeInternal() 2600 == AudioManager.RINGER_MODE_SILENT)) { 2601 mVibrateNotificationKey = record.getKey(); 2602 2603 if (useDefaultVibrate || convertSoundToVibration) { 2604 // Escalate privileges so we can use the vibrator even if the 2605 // notifying app does not have the VIBRATE permission. 2606 long identity = Binder.clearCallingIdentity(); 2607 try { 2608 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(), 2609 useDefaultVibrate ? mDefaultVibrationPattern 2610 : mFallbackVibrationPattern, 2611 ((notification.flags & Notification.FLAG_INSISTENT) != 0) 2612 ? 0: -1, audioAttributesForNotification(notification)); 2613 buzz = true; 2614 } finally { 2615 Binder.restoreCallingIdentity(identity); 2616 } 2617 } else if (notification.vibrate.length > 1) { 2618 // If you want your own vibration pattern, you need the VIBRATE 2619 // permission 2620 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(), 2621 notification.vibrate, 2622 ((notification.flags & Notification.FLAG_INSISTENT) != 0) 2623 ? 0: -1, audioAttributesForNotification(notification)); 2624 buzz = true; 2625 } 2626 } 2627 } 2628 2629 // light 2630 // release the light 2631 boolean wasShowLights = mLights.remove(record.getKey()); 2632 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold 2633 && ((record.getSuppressedVisualEffects() 2634 & NotificationListenerService.SUPPRESSED_EFFECT_LIGHTS) == 0)) { 2635 mLights.add(record.getKey()); 2636 updateLightsLocked(); 2637 if (mUseAttentionLight) { 2638 mAttentionLight.pulse(); 2639 } 2640 blink = true; 2641 } else if (wasShowLights) { 2642 updateLightsLocked(); 2643 } 2644 if (buzz || beep || blink) { 2645 if (((record.getSuppressedVisualEffects() 2646 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON) != 0)) { 2647 if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on"); 2648 } else { 2649 EventLogTags.writeNotificationAlert(record.getKey(), 2650 buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0); 2651 mHandler.post(mBuzzBeepBlinked); 2652 } 2653 } 2654 } 2655 2656 private static AudioAttributes audioAttributesForNotification(Notification n) { 2657 if (n.audioAttributes != null 2658 && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) { 2659 // the audio attributes are set and different from the default, use them 2660 return n.audioAttributes; 2661 } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) { 2662 // the stream type is valid, use it 2663 return new AudioAttributes.Builder() 2664 .setInternalLegacyStreamType(n.audioStreamType) 2665 .build(); 2666 } else if (n.audioStreamType == AudioSystem.STREAM_DEFAULT) { 2667 return Notification.AUDIO_ATTRIBUTES_DEFAULT; 2668 } else { 2669 Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType)); 2670 return Notification.AUDIO_ATTRIBUTES_DEFAULT; 2671 } 2672 } 2673 2674 void showNextToastLocked() { 2675 ToastRecord record = mToastQueue.get(0); 2676 while (record != null) { 2677 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback); 2678 try { 2679 record.callback.show(); 2680 scheduleTimeoutLocked(record); 2681 return; 2682 } catch (RemoteException e) { 2683 Slog.w(TAG, "Object died trying to show notification " + record.callback 2684 + " in package " + record.pkg); 2685 // remove it from the list and let the process die 2686 int index = mToastQueue.indexOf(record); 2687 if (index >= 0) { 2688 mToastQueue.remove(index); 2689 } 2690 keepProcessAliveLocked(record.pid); 2691 if (mToastQueue.size() > 0) { 2692 record = mToastQueue.get(0); 2693 } else { 2694 record = null; 2695 } 2696 } 2697 } 2698 } 2699 2700 void cancelToastLocked(int index) { 2701 ToastRecord record = mToastQueue.get(index); 2702 try { 2703 record.callback.hide(); 2704 } catch (RemoteException e) { 2705 Slog.w(TAG, "Object died trying to hide notification " + record.callback 2706 + " in package " + record.pkg); 2707 // don't worry about this, we're about to remove it from 2708 // the list anyway 2709 } 2710 mToastQueue.remove(index); 2711 keepProcessAliveLocked(record.pid); 2712 if (mToastQueue.size() > 0) { 2713 // Show the next one. If the callback fails, this will remove 2714 // it from the list, so don't assume that the list hasn't changed 2715 // after this point. 2716 showNextToastLocked(); 2717 } 2718 } 2719 2720 private void scheduleTimeoutLocked(ToastRecord r) 2721 { 2722 mHandler.removeCallbacksAndMessages(r); 2723 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r); 2724 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY; 2725 mHandler.sendMessageDelayed(m, delay); 2726 } 2727 2728 private void handleTimeout(ToastRecord record) 2729 { 2730 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback); 2731 synchronized (mToastQueue) { 2732 int index = indexOfToastLocked(record.pkg, record.callback); 2733 if (index >= 0) { 2734 cancelToastLocked(index); 2735 } 2736 } 2737 } 2738 2739 // lock on mToastQueue 2740 int indexOfToastLocked(String pkg, ITransientNotification callback) 2741 { 2742 IBinder cbak = callback.asBinder(); 2743 ArrayList<ToastRecord> list = mToastQueue; 2744 int len = list.size(); 2745 for (int i=0; i<len; i++) { 2746 ToastRecord r = list.get(i); 2747 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) { 2748 return i; 2749 } 2750 } 2751 return -1; 2752 } 2753 2754 // lock on mToastQueue 2755 void keepProcessAliveLocked(int pid) 2756 { 2757 int toastCount = 0; // toasts from this pid 2758 ArrayList<ToastRecord> list = mToastQueue; 2759 int N = list.size(); 2760 for (int i=0; i<N; i++) { 2761 ToastRecord r = list.get(i); 2762 if (r.pid == pid) { 2763 toastCount++; 2764 } 2765 } 2766 try { 2767 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0); 2768 } catch (RemoteException e) { 2769 // Shouldn't happen. 2770 } 2771 } 2772 2773 private void handleRankingReconsideration(Message message) { 2774 if (!(message.obj instanceof RankingReconsideration)) return; 2775 RankingReconsideration recon = (RankingReconsideration) message.obj; 2776 recon.run(); 2777 boolean changed; 2778 synchronized (mNotificationList) { 2779 final NotificationRecord record = mNotificationsByKey.get(recon.getKey()); 2780 if (record == null) { 2781 return; 2782 } 2783 int indexBefore = findNotificationRecordIndexLocked(record); 2784 boolean interceptBefore = record.isIntercepted(); 2785 int visibilityBefore = record.getPackageVisibilityOverride(); 2786 recon.applyChangesLocked(record); 2787 applyZenModeLocked(record); 2788 mRankingHelper.sort(mNotificationList); 2789 int indexAfter = findNotificationRecordIndexLocked(record); 2790 boolean interceptAfter = record.isIntercepted(); 2791 int visibilityAfter = record.getPackageVisibilityOverride(); 2792 changed = indexBefore != indexAfter || interceptBefore != interceptAfter 2793 || visibilityBefore != visibilityAfter; 2794 if (interceptBefore && !interceptAfter) { 2795 buzzBeepBlinkLocked(record); 2796 } 2797 } 2798 if (changed) { 2799 scheduleSendRankingUpdate(); 2800 } 2801 } 2802 2803 private void handleRankingSort() { 2804 synchronized (mNotificationList) { 2805 final int N = mNotificationList.size(); 2806 ArrayList<String> orderBefore = new ArrayList<String>(N); 2807 int[] visibilities = new int[N]; 2808 for (int i = 0; i < N; i++) { 2809 final NotificationRecord r = mNotificationList.get(i); 2810 orderBefore.add(r.getKey()); 2811 visibilities[i] = r.getPackageVisibilityOverride(); 2812 mRankingHelper.extractSignals(r); 2813 } 2814 mRankingHelper.sort(mNotificationList); 2815 for (int i = 0; i < N; i++) { 2816 final NotificationRecord r = mNotificationList.get(i); 2817 if (!orderBefore.get(i).equals(r.getKey()) 2818 || visibilities[i] != r.getPackageVisibilityOverride()) { 2819 scheduleSendRankingUpdate(); 2820 return; 2821 } 2822 } 2823 } 2824 } 2825 2826 // let zen mode evaluate this record 2827 private void applyZenModeLocked(NotificationRecord record) { 2828 record.setIntercepted(mZenModeHelper.shouldIntercept(record)); 2829 if (record.isIntercepted()) { 2830 int suppressed = (mZenModeHelper.shouldSuppressLight() ? SUPPRESSED_EFFECT_LIGHTS : 0) 2831 | (mZenModeHelper.shouldSuppressPeek() ? SUPPRESSED_EFFECT_PEEK : 0) 2832 | (mZenModeHelper.shouldSuppressScreenOn() ? SUPPRESSED_EFFECT_SCREEN_ON : 0); 2833 record.setSuppressedVisualEffects(suppressed); 2834 } 2835 } 2836 2837 // lock on mNotificationList 2838 private int findNotificationRecordIndexLocked(NotificationRecord target) { 2839 return mRankingHelper.indexOf(mNotificationList, target); 2840 } 2841 2842 private void scheduleSendRankingUpdate() { 2843 mHandler.removeMessages(MESSAGE_SEND_RANKING_UPDATE); 2844 Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE); 2845 mHandler.sendMessage(m); 2846 } 2847 2848 private void handleSendRankingUpdate() { 2849 synchronized (mNotificationList) { 2850 mListeners.notifyRankingUpdateLocked(); 2851 } 2852 } 2853 2854 private void scheduleListenerHintsChanged(int state) { 2855 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED); 2856 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget(); 2857 } 2858 2859 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) { 2860 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED); 2861 mHandler.obtainMessage( 2862 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED, 2863 listenerInterruptionFilter, 2864 0).sendToTarget(); 2865 } 2866 2867 private void handleListenerHintsChanged(int hints) { 2868 synchronized (mNotificationList) { 2869 mListeners.notifyListenerHintsChangedLocked(hints); 2870 } 2871 } 2872 2873 private void handleListenerInterruptionFilterChanged(int interruptionFilter) { 2874 synchronized (mNotificationList) { 2875 mListeners.notifyInterruptionFilterChanged(interruptionFilter); 2876 } 2877 } 2878 2879 private final class WorkerHandler extends Handler 2880 { 2881 @Override 2882 public void handleMessage(Message msg) 2883 { 2884 switch (msg.what) 2885 { 2886 case MESSAGE_TIMEOUT: 2887 handleTimeout((ToastRecord)msg.obj); 2888 break; 2889 case MESSAGE_SAVE_POLICY_FILE: 2890 handleSavePolicyFile(); 2891 break; 2892 case MESSAGE_SEND_RANKING_UPDATE: 2893 handleSendRankingUpdate(); 2894 break; 2895 case MESSAGE_LISTENER_HINTS_CHANGED: 2896 handleListenerHintsChanged(msg.arg1); 2897 break; 2898 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED: 2899 handleListenerInterruptionFilterChanged(msg.arg1); 2900 break; 2901 } 2902 } 2903 2904 } 2905 2906 private final class RankingHandlerWorker extends Handler implements RankingHandler 2907 { 2908 public RankingHandlerWorker(Looper looper) { 2909 super(looper); 2910 } 2911 2912 @Override 2913 public void handleMessage(Message msg) { 2914 switch (msg.what) { 2915 case MESSAGE_RECONSIDER_RANKING: 2916 handleRankingReconsideration(msg); 2917 break; 2918 case MESSAGE_RANKING_SORT: 2919 handleRankingSort(); 2920 break; 2921 } 2922 } 2923 2924 public void requestSort() { 2925 removeMessages(MESSAGE_RANKING_SORT); 2926 sendEmptyMessage(MESSAGE_RANKING_SORT); 2927 } 2928 2929 public void requestReconsideration(RankingReconsideration recon) { 2930 Message m = Message.obtain(this, 2931 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon); 2932 long delay = recon.getDelay(TimeUnit.MILLISECONDS); 2933 sendMessageDelayed(m, delay); 2934 } 2935 } 2936 2937 // Notifications 2938 // ============================================================================ 2939 static int clamp(int x, int low, int high) { 2940 return (x < low) ? low : ((x > high) ? high : x); 2941 } 2942 2943 void sendAccessibilityEvent(Notification notification, CharSequence packageName) { 2944 AccessibilityManager manager = AccessibilityManager.getInstance(getContext()); 2945 if (!manager.isEnabled()) { 2946 return; 2947 } 2948 2949 AccessibilityEvent event = 2950 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); 2951 event.setPackageName(packageName); 2952 event.setClassName(Notification.class.getName()); 2953 event.setParcelableData(notification); 2954 CharSequence tickerText = notification.tickerText; 2955 if (!TextUtils.isEmpty(tickerText)) { 2956 event.getText().add(tickerText); 2957 } 2958 2959 manager.sendAccessibilityEvent(event); 2960 } 2961 2962 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) { 2963 // tell the app 2964 if (sendDelete) { 2965 if (r.getNotification().deleteIntent != null) { 2966 try { 2967 r.getNotification().deleteIntent.send(); 2968 } catch (PendingIntent.CanceledException ex) { 2969 // do nothing - there's no relevant way to recover, and 2970 // no reason to let this propagate 2971 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex); 2972 } 2973 } 2974 } 2975 2976 // status bar 2977 if (r.getNotification().getSmallIcon() != null) { 2978 r.isCanceled = true; 2979 mListeners.notifyRemovedLocked(r.sbn); 2980 } 2981 2982 final String canceledKey = r.getKey(); 2983 2984 // sound 2985 if (canceledKey.equals(mSoundNotificationKey)) { 2986 mSoundNotificationKey = null; 2987 final long identity = Binder.clearCallingIdentity(); 2988 try { 2989 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 2990 if (player != null) { 2991 player.stopAsync(); 2992 } 2993 } catch (RemoteException e) { 2994 } finally { 2995 Binder.restoreCallingIdentity(identity); 2996 } 2997 } 2998 2999 // vibrate 3000 if (canceledKey.equals(mVibrateNotificationKey)) { 3001 mVibrateNotificationKey = null; 3002 long identity = Binder.clearCallingIdentity(); 3003 try { 3004 mVibrator.cancel(); 3005 } 3006 finally { 3007 Binder.restoreCallingIdentity(identity); 3008 } 3009 } 3010 3011 // light 3012 mLights.remove(canceledKey); 3013 3014 // Record usage stats 3015 switch (reason) { 3016 case REASON_DELEGATE_CANCEL: 3017 case REASON_DELEGATE_CANCEL_ALL: 3018 case REASON_LISTENER_CANCEL: 3019 case REASON_LISTENER_CANCEL_ALL: 3020 mUsageStats.registerDismissedByUser(r); 3021 break; 3022 case REASON_APP_CANCEL: 3023 case REASON_APP_CANCEL_ALL: 3024 mUsageStats.registerRemovedByApp(r); 3025 break; 3026 } 3027 3028 mNotificationsByKey.remove(r.sbn.getKey()); 3029 String groupKey = r.getGroupKey(); 3030 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey); 3031 if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) { 3032 mSummaryByGroupKey.remove(groupKey); 3033 } 3034 3035 // Save it for users of getHistoricalNotifications() 3036 mArchive.record(r.sbn); 3037 3038 final long now = System.currentTimeMillis(); 3039 EventLogTags.writeNotificationCanceled(canceledKey, reason, 3040 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now)); 3041 } 3042 3043 /** 3044 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags} 3045 * and none of the {@code mustNotHaveFlags}. 3046 */ 3047 void cancelNotification(final int callingUid, final int callingPid, 3048 final String pkg, final String tag, final int id, 3049 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, 3050 final int userId, final int reason, final ManagedServiceInfo listener) { 3051 // In enqueueNotificationInternal notifications are added by scheduling the 3052 // work on the worker handler. Hence, we also schedule the cancel on this 3053 // handler to avoid a scenario where an add notification call followed by a 3054 // remove notification call ends up in not removing the notification. 3055 mHandler.post(new Runnable() { 3056 @Override 3057 public void run() { 3058 String listenerName = listener == null ? null : listener.component.toShortString(); 3059 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag, 3060 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName); 3061 3062 synchronized (mNotificationList) { 3063 int index = indexOfNotificationLocked(pkg, tag, id, userId); 3064 if (index >= 0) { 3065 NotificationRecord r = mNotificationList.get(index); 3066 3067 // Ideally we'd do this in the caller of this method. However, that would 3068 // require the caller to also find the notification. 3069 if (reason == REASON_DELEGATE_CLICK) { 3070 mUsageStats.registerClickedByUser(r); 3071 } 3072 3073 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) { 3074 return; 3075 } 3076 if ((r.getNotification().flags & mustNotHaveFlags) != 0) { 3077 return; 3078 } 3079 3080 mNotificationList.remove(index); 3081 3082 cancelNotificationLocked(r, sendDelete, reason); 3083 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName, 3084 REASON_GROUP_SUMMARY_CANCELED); 3085 updateLightsLocked(); 3086 } 3087 } 3088 } 3089 }); 3090 } 3091 3092 /** 3093 * Determine whether the userId applies to the notification in question, either because 3094 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard). 3095 */ 3096 private boolean notificationMatchesUserId(NotificationRecord r, int userId) { 3097 return 3098 // looking for USER_ALL notifications? match everything 3099 userId == UserHandle.USER_ALL 3100 // a notification sent to USER_ALL matches any query 3101 || r.getUserId() == UserHandle.USER_ALL 3102 // an exact user match 3103 || r.getUserId() == userId; 3104 } 3105 3106 /** 3107 * Determine whether the userId applies to the notification in question, either because 3108 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or 3109 * because it matches one of the users profiles. 3110 */ 3111 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) { 3112 return notificationMatchesUserId(r, userId) 3113 || mUserProfiles.isCurrentProfile(r.getUserId()); 3114 } 3115 3116 /** 3117 * Cancels all notifications from a given package or topic that have all of the 3118 * {@code mustHaveFlags}. 3119 */ 3120 boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags, 3121 int mustNotHaveFlags, boolean doit, int userId, int reason, Notification.Topic topic, 3122 ManagedServiceInfo listener) { 3123 String listenerName = listener == null ? null : listener.component.toShortString(); 3124 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 3125 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason, 3126 listenerName); 3127 3128 synchronized (mNotificationList) { 3129 final int N = mNotificationList.size(); 3130 ArrayList<NotificationRecord> canceledNotifications = null; 3131 for (int i = N-1; i >= 0; --i) { 3132 NotificationRecord r = mNotificationList.get(i); 3133 if (!notificationMatchesUserId(r, userId)) { 3134 continue; 3135 } 3136 // Don't remove notifications to all, if there's no package name specified 3137 if (r.getUserId() == UserHandle.USER_ALL && pkg == null) { 3138 continue; 3139 } 3140 if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) { 3141 continue; 3142 } 3143 if ((r.getFlags() & mustNotHaveFlags) != 0) { 3144 continue; 3145 } 3146 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) { 3147 continue; 3148 } 3149 if (topic != null 3150 && !topic.getId().equals(r.getNotification().getTopic().getId())) { 3151 continue; 3152 } 3153 if (canceledNotifications == null) { 3154 canceledNotifications = new ArrayList<>(); 3155 } 3156 canceledNotifications.add(r); 3157 if (!doit) { 3158 return true; 3159 } 3160 mNotificationList.remove(i); 3161 cancelNotificationLocked(r, false, reason); 3162 } 3163 if (doit && canceledNotifications != null) { 3164 final int M = canceledNotifications.size(); 3165 for (int i = 0; i < M; i++) { 3166 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid, 3167 listenerName, REASON_GROUP_SUMMARY_CANCELED); 3168 } 3169 } 3170 if (canceledNotifications != null) { 3171 updateLightsLocked(); 3172 } 3173 return canceledNotifications != null; 3174 } 3175 } 3176 3177 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason, 3178 ManagedServiceInfo listener, boolean includeCurrentProfiles) { 3179 String listenerName = listener == null ? null : listener.component.toShortString(); 3180 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 3181 null, userId, 0, 0, reason, listenerName); 3182 3183 ArrayList<NotificationRecord> canceledNotifications = null; 3184 final int N = mNotificationList.size(); 3185 for (int i=N-1; i>=0; i--) { 3186 NotificationRecord r = mNotificationList.get(i); 3187 if (includeCurrentProfiles) { 3188 if (!notificationMatchesCurrentProfiles(r, userId)) { 3189 continue; 3190 } 3191 } else { 3192 if (!notificationMatchesUserId(r, userId)) { 3193 continue; 3194 } 3195 } 3196 3197 if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT 3198 | Notification.FLAG_NO_CLEAR)) == 0) { 3199 mNotificationList.remove(i); 3200 cancelNotificationLocked(r, true, reason); 3201 // Make a note so we can cancel children later. 3202 if (canceledNotifications == null) { 3203 canceledNotifications = new ArrayList<>(); 3204 } 3205 canceledNotifications.add(r); 3206 } 3207 } 3208 int M = canceledNotifications != null ? canceledNotifications.size() : 0; 3209 for (int i = 0; i < M; i++) { 3210 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid, 3211 listenerName, REASON_GROUP_SUMMARY_CANCELED); 3212 } 3213 updateLightsLocked(); 3214 } 3215 3216 // Warning: The caller is responsible for invoking updateLightsLocked(). 3217 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid, 3218 String listenerName, int reason) { 3219 Notification n = r.getNotification(); 3220 if (!n.isGroupSummary()) { 3221 return; 3222 } 3223 3224 String pkg = r.sbn.getPackageName(); 3225 int userId = r.getUserId(); 3226 3227 if (pkg == null) { 3228 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey()); 3229 return; 3230 } 3231 3232 final int N = mNotificationList.size(); 3233 for (int i = N - 1; i >= 0; i--) { 3234 NotificationRecord childR = mNotificationList.get(i); 3235 StatusBarNotification childSbn = childR.sbn; 3236 if (childR.getNotification().isGroupChild() && 3237 childR.getGroupKey().equals(r.getGroupKey())) { 3238 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(), 3239 childSbn.getTag(), userId, 0, 0, reason, listenerName); 3240 mNotificationList.remove(i); 3241 cancelNotificationLocked(childR, false, reason); 3242 } 3243 } 3244 } 3245 3246 // lock on mNotificationList 3247 void updateLightsLocked() 3248 { 3249 // handle notification lights 3250 NotificationRecord ledNotification = null; 3251 while (ledNotification == null && !mLights.isEmpty()) { 3252 final String owner = mLights.get(mLights.size() - 1); 3253 ledNotification = mNotificationsByKey.get(owner); 3254 if (ledNotification == null) { 3255 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner); 3256 mLights.remove(owner); 3257 } 3258 } 3259 3260 // Don't flash while we are in a call or screen is on 3261 if (ledNotification == null || mInCall || mScreenOn) { 3262 mNotificationLight.turnOff(); 3263 mStatusBar.notificationLightOff(); 3264 } else { 3265 final Notification ledno = ledNotification.sbn.getNotification(); 3266 int ledARGB = ledno.ledARGB; 3267 int ledOnMS = ledno.ledOnMS; 3268 int ledOffMS = ledno.ledOffMS; 3269 if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) { 3270 ledARGB = mDefaultNotificationColor; 3271 ledOnMS = mDefaultNotificationLedOn; 3272 ledOffMS = mDefaultNotificationLedOff; 3273 } 3274 if (mNotificationPulseEnabled) { 3275 // pulse repeatedly 3276 mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED, 3277 ledOnMS, ledOffMS); 3278 } 3279 // let SystemUI make an independent decision 3280 mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS); 3281 } 3282 } 3283 3284 // lock on mNotificationList 3285 int indexOfNotificationLocked(String pkg, String tag, int id, int userId) 3286 { 3287 ArrayList<NotificationRecord> list = mNotificationList; 3288 final int len = list.size(); 3289 for (int i=0; i<len; i++) { 3290 NotificationRecord r = list.get(i); 3291 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id && 3292 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) { 3293 return i; 3294 } 3295 } 3296 return -1; 3297 } 3298 3299 // lock on mNotificationList 3300 int indexOfNotificationLocked(String key) { 3301 final int N = mNotificationList.size(); 3302 for (int i = 0; i < N; i++) { 3303 if (key.equals(mNotificationList.get(i).getKey())) { 3304 return i; 3305 } 3306 } 3307 return -1; 3308 } 3309 3310 private void updateNotificationPulse() { 3311 synchronized (mNotificationList) { 3312 updateLightsLocked(); 3313 } 3314 } 3315 3316 private static boolean isUidSystem(int uid) { 3317 final int appid = UserHandle.getAppId(uid); 3318 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0); 3319 } 3320 3321 private static boolean isCallerSystem() { 3322 return isUidSystem(Binder.getCallingUid()); 3323 } 3324 3325 private static void checkCallerIsSystem() { 3326 if (isCallerSystem()) { 3327 return; 3328 } 3329 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid()); 3330 } 3331 3332 private static void checkCallerIsSystemOrSameApp(String pkg) { 3333 if (isCallerSystem()) { 3334 return; 3335 } 3336 final int uid = Binder.getCallingUid(); 3337 try { 3338 ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo( 3339 pkg, 0, UserHandle.getCallingUserId()); 3340 if (ai == null) { 3341 throw new SecurityException("Unknown package " + pkg); 3342 } 3343 if (!UserHandle.isSameApp(ai.uid, uid)) { 3344 throw new SecurityException("Calling uid " + uid + " gave package" 3345 + pkg + " which is owned by uid " + ai.uid); 3346 } 3347 } catch (RemoteException re) { 3348 throw new SecurityException("Unknown package " + pkg + "\n" + re); 3349 } 3350 } 3351 3352 private static String callStateToString(int state) { 3353 switch (state) { 3354 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE"; 3355 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING"; 3356 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK"; 3357 default: return "CALL_STATE_UNKNOWN_" + state; 3358 } 3359 } 3360 3361 private void listenForCallState() { 3362 TelephonyManager.from(getContext()).listen(new PhoneStateListener() { 3363 @Override 3364 public void onCallStateChanged(int state, String incomingNumber) { 3365 if (mCallState == state) return; 3366 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state)); 3367 mCallState = state; 3368 } 3369 }, PhoneStateListener.LISTEN_CALL_STATE); 3370 } 3371 3372 /** 3373 * Generates a NotificationRankingUpdate from 'sbns', considering only 3374 * notifications visible to the given listener. 3375 * 3376 * <p>Caller must hold a lock on mNotificationList.</p> 3377 */ 3378 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) { 3379 final int N = mNotificationList.size(); 3380 ArrayList<String> keys = new ArrayList<String>(N); 3381 ArrayList<String> interceptedKeys = new ArrayList<String>(N); 3382 ArrayList<Integer> importance = new ArrayList<>(N); 3383 Bundle visibilityOverrides = new Bundle(); 3384 Bundle suppressedVisualEffects = new Bundle(); 3385 Bundle explanation = new Bundle(); 3386 for (int i = 0; i < N; i++) { 3387 NotificationRecord record = mNotificationList.get(i); 3388 if (!isVisibleToListener(record.sbn, info)) { 3389 continue; 3390 } 3391 final String key = record.sbn.getKey(); 3392 keys.add(key); 3393 importance.add(record.getImportance()); 3394 if (record.getImportanceExplanation() != null) { 3395 explanation.putCharSequence(key, record.getImportanceExplanation()); 3396 } 3397 if (record.isIntercepted()) { 3398 interceptedKeys.add(key); 3399 3400 } 3401 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects()); 3402 if (record.getPackageVisibilityOverride() 3403 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) { 3404 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride()); 3405 } 3406 } 3407 final int M = keys.size(); 3408 String[] keysAr = keys.toArray(new String[M]); 3409 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]); 3410 int[] importanceAr = new int[M]; 3411 for (int i = 0; i < M; i++) { 3412 importanceAr[i] = importance.get(i); 3413 } 3414 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides, 3415 suppressedVisualEffects, importanceAr, explanation); 3416 } 3417 3418 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) { 3419 if (!listener.enabledAndUserMatches(sbn.getUserId())) { 3420 return false; 3421 } 3422 // TODO: remove this for older listeners. 3423 return true; 3424 } 3425 3426 private class TrimCache { 3427 StatusBarNotification heavy; 3428 StatusBarNotification sbnClone; 3429 StatusBarNotification sbnCloneLight; 3430 3431 TrimCache(StatusBarNotification sbn) { 3432 heavy = sbn; 3433 } 3434 3435 StatusBarNotification ForListener(ManagedServiceInfo info) { 3436 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) { 3437 if (sbnCloneLight == null) { 3438 sbnCloneLight = heavy.cloneLight(); 3439 } 3440 return sbnCloneLight; 3441 } else { 3442 if (sbnClone == null) { 3443 sbnClone = heavy.clone(); 3444 } 3445 return sbnClone; 3446 } 3447 } 3448 } 3449 3450 public class NotificationAssistant extends ManagedServices { 3451 3452 public NotificationAssistant() { 3453 super(getContext(), mHandler, mNotificationList, mUserProfiles); 3454 } 3455 3456 @Override 3457 protected Config getConfig() { 3458 Config c = new Config(); 3459 c.caption = "notification assistant"; 3460 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE; 3461 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT; 3462 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE; 3463 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS; 3464 c.clientLabel = R.string.notification_assistant_binding_label; 3465 return c; 3466 } 3467 3468 @Override 3469 protected IInterface asInterface(IBinder binder) { 3470 return INotificationListener.Stub.asInterface(binder); 3471 } 3472 3473 @Override 3474 protected boolean checkType(IInterface service) { 3475 return service instanceof INotificationListener; 3476 } 3477 3478 @Override 3479 protected void onServiceAdded(ManagedServiceInfo info) { 3480 mListeners.registerGuestService(info); 3481 } 3482 3483 @Override 3484 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { 3485 mListeners.unregisterService(removed.service, removed.userid); 3486 } 3487 3488 public void onNotificationEnqueued(final NotificationRecord r) { 3489 final StatusBarNotification sbn = r.sbn; 3490 TrimCache trimCache = new TrimCache(sbn); 3491 3492 // mServices is the list inside ManagedServices of all the assistants, 3493 // There should be only one, but it's a list, so while we enforce 3494 // singularity elsewhere, we keep it general here, to avoid surprises. 3495 for (final ManagedServiceInfo info : NotificationAssistant.this.mServices) { 3496 boolean sbnVisible = isVisibleToListener(sbn, info); 3497 if (!sbnVisible) { 3498 continue; 3499 } 3500 3501 final int importance = r.getImportance(); 3502 final boolean fromUser = r.isImportanceFromUser(); 3503 final StatusBarNotification sbnToPost = trimCache.ForListener(info); 3504 mAssistantHandler.post(new Runnable() { 3505 @Override 3506 public void run() { 3507 notifyEnqueued(info, sbnToPost, importance, fromUser); 3508 } 3509 }); 3510 } 3511 } 3512 3513 private void notifyEnqueued(final ManagedServiceInfo info, 3514 final StatusBarNotification sbn, int importance, boolean fromUser) { 3515 final INotificationListener assistant = (INotificationListener) info.service; 3516 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 3517 try { 3518 assistant.onNotificationEnqueued(sbnHolder, importance, fromUser); 3519 } catch (RemoteException ex) { 3520 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex); 3521 } 3522 } 3523 3524 public boolean isEnabled() { 3525 return !mServices.isEmpty(); 3526 } 3527 } 3528 3529 public class NotificationListeners extends ManagedServices { 3530 3531 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>(); 3532 private boolean mNotificationGroupsDesired; 3533 3534 public NotificationListeners() { 3535 super(getContext(), mHandler, mNotificationList, mUserProfiles); 3536 } 3537 3538 @Override 3539 protected Config getConfig() { 3540 Config c = new Config(); 3541 c.caption = "notification listener"; 3542 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE; 3543 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS; 3544 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE; 3545 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS; 3546 c.clientLabel = R.string.notification_listener_binding_label; 3547 return c; 3548 } 3549 3550 @Override 3551 protected IInterface asInterface(IBinder binder) { 3552 return INotificationListener.Stub.asInterface(binder); 3553 } 3554 3555 @Override 3556 protected boolean checkType(IInterface service) { 3557 return service instanceof INotificationListener; 3558 } 3559 3560 @Override 3561 public void onServiceAdded(ManagedServiceInfo info) { 3562 final INotificationListener listener = (INotificationListener) info.service; 3563 final NotificationRankingUpdate update; 3564 synchronized (mNotificationList) { 3565 updateNotificationGroupsDesiredLocked(); 3566 update = makeRankingUpdateLocked(info); 3567 } 3568 try { 3569 listener.onListenerConnected(update); 3570 } catch (RemoteException e) { 3571 // we tried 3572 } 3573 } 3574 3575 @Override 3576 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { 3577 if (mListenersDisablingEffects.remove(removed)) { 3578 updateListenerHintsLocked(); 3579 updateEffectsSuppressorLocked(); 3580 } 3581 mLightTrimListeners.remove(removed); 3582 updateNotificationGroupsDesiredLocked(); 3583 } 3584 3585 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) { 3586 if (trim == TRIM_LIGHT) { 3587 mLightTrimListeners.add(info); 3588 } else { 3589 mLightTrimListeners.remove(info); 3590 } 3591 } 3592 3593 public int getOnNotificationPostedTrim(ManagedServiceInfo info) { 3594 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL; 3595 } 3596 3597 /** 3598 * asynchronously notify all listeners about a new notification 3599 * 3600 * <p> 3601 * Also takes care of removing a notification that has been visible to a listener before, 3602 * but isn't anymore. 3603 */ 3604 public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) { 3605 // Lazily initialized snapshots of the notification. 3606 TrimCache trimCache = new TrimCache(sbn); 3607 3608 for (final ManagedServiceInfo info : mServices) { 3609 boolean sbnVisible = isVisibleToListener(sbn, info); 3610 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false; 3611 // This notification hasn't been and still isn't visible -> ignore. 3612 if (!oldSbnVisible && !sbnVisible) { 3613 continue; 3614 } 3615 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 3616 3617 // This notification became invisible -> remove the old one. 3618 if (oldSbnVisible && !sbnVisible) { 3619 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight(); 3620 mHandler.post(new Runnable() { 3621 @Override 3622 public void run() { 3623 notifyRemoved(info, oldSbnLightClone, update); 3624 } 3625 }); 3626 continue; 3627 } 3628 3629 final StatusBarNotification sbnToPost = trimCache.ForListener(info); 3630 mHandler.post(new Runnable() { 3631 @Override 3632 public void run() { 3633 notifyPosted(info, sbnToPost, update); 3634 } 3635 }); 3636 } 3637 } 3638 3639 /** 3640 * asynchronously notify all listeners about a removed notification 3641 */ 3642 public void notifyRemovedLocked(StatusBarNotification sbn) { 3643 // make a copy in case changes are made to the underlying Notification object 3644 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the 3645 // notification 3646 final StatusBarNotification sbnLight = sbn.cloneLight(); 3647 for (final ManagedServiceInfo info : mServices) { 3648 if (!isVisibleToListener(sbn, info)) { 3649 continue; 3650 } 3651 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 3652 mHandler.post(new Runnable() { 3653 @Override 3654 public void run() { 3655 notifyRemoved(info, sbnLight, update); 3656 } 3657 }); 3658 } 3659 } 3660 3661 /** 3662 * asynchronously notify all listeners about a reordering of notifications 3663 */ 3664 public void notifyRankingUpdateLocked() { 3665 for (final ManagedServiceInfo serviceInfo : mServices) { 3666 if (!serviceInfo.isEnabledForCurrentProfiles()) { 3667 continue; 3668 } 3669 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo); 3670 mHandler.post(new Runnable() { 3671 @Override 3672 public void run() { 3673 notifyRankingUpdate(serviceInfo, update); 3674 } 3675 }); 3676 } 3677 } 3678 3679 public void notifyListenerHintsChangedLocked(final int hints) { 3680 for (final ManagedServiceInfo serviceInfo : mServices) { 3681 if (!serviceInfo.isEnabledForCurrentProfiles()) { 3682 continue; 3683 } 3684 mHandler.post(new Runnable() { 3685 @Override 3686 public void run() { 3687 notifyListenerHintsChanged(serviceInfo, hints); 3688 } 3689 }); 3690 } 3691 } 3692 3693 public void notifyInterruptionFilterChanged(final int interruptionFilter) { 3694 for (final ManagedServiceInfo serviceInfo : mServices) { 3695 if (!serviceInfo.isEnabledForCurrentProfiles()) { 3696 continue; 3697 } 3698 mHandler.post(new Runnable() { 3699 @Override 3700 public void run() { 3701 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter); 3702 } 3703 }); 3704 } 3705 } 3706 3707 private void notifyPosted(final ManagedServiceInfo info, 3708 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) { 3709 final INotificationListener listener = (INotificationListener)info.service; 3710 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 3711 try { 3712 listener.onNotificationPosted(sbnHolder, rankingUpdate); 3713 } catch (RemoteException ex) { 3714 Log.e(TAG, "unable to notify listener (posted): " + listener, ex); 3715 } 3716 } 3717 3718 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn, 3719 NotificationRankingUpdate rankingUpdate) { 3720 if (!info.enabledAndUserMatches(sbn.getUserId())) { 3721 return; 3722 } 3723 final INotificationListener listener = (INotificationListener) info.service; 3724 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 3725 try { 3726 listener.onNotificationRemoved(sbnHolder, rankingUpdate); 3727 } catch (RemoteException ex) { 3728 Log.e(TAG, "unable to notify listener (removed): " + listener, ex); 3729 } 3730 } 3731 3732 private void notifyRankingUpdate(ManagedServiceInfo info, 3733 NotificationRankingUpdate rankingUpdate) { 3734 final INotificationListener listener = (INotificationListener) info.service; 3735 try { 3736 listener.onNotificationRankingUpdate(rankingUpdate); 3737 } catch (RemoteException ex) { 3738 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex); 3739 } 3740 } 3741 3742 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) { 3743 final INotificationListener listener = (INotificationListener) info.service; 3744 try { 3745 listener.onListenerHintsChanged(hints); 3746 } catch (RemoteException ex) { 3747 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex); 3748 } 3749 } 3750 3751 private void notifyInterruptionFilterChanged(ManagedServiceInfo info, 3752 int interruptionFilter) { 3753 final INotificationListener listener = (INotificationListener) info.service; 3754 try { 3755 listener.onInterruptionFilterChanged(interruptionFilter); 3756 } catch (RemoteException ex) { 3757 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex); 3758 } 3759 } 3760 3761 private boolean isListenerPackage(String packageName) { 3762 if (packageName == null) { 3763 return false; 3764 } 3765 // TODO: clean up locking object later 3766 synchronized (mNotificationList) { 3767 for (final ManagedServiceInfo serviceInfo : mServices) { 3768 if (packageName.equals(serviceInfo.component.getPackageName())) { 3769 return true; 3770 } 3771 } 3772 } 3773 return false; 3774 } 3775 3776 /** 3777 * Returns whether any of the currently registered listeners wants to receive notification 3778 * groups. 3779 * 3780 * <p>Currently we assume groups are desired by non-SystemUI listeners.</p> 3781 */ 3782 public boolean notificationGroupsDesired() { 3783 return mNotificationGroupsDesired; 3784 } 3785 3786 private void updateNotificationGroupsDesiredLocked() { 3787 mNotificationGroupsDesired = true; 3788 // No listeners, no groups. 3789 if (mServices.isEmpty()) { 3790 mNotificationGroupsDesired = false; 3791 return; 3792 } 3793 // One listener: Check whether it's SysUI. 3794 if (mServices.size() == 1 && 3795 mServices.get(0).component.getPackageName().equals("com.android.systemui")) { 3796 mNotificationGroupsDesired = false; 3797 return; 3798 } 3799 } 3800 } 3801 3802 public static final class DumpFilter { 3803 public boolean filtered = false; 3804 public String pkgFilter; 3805 public boolean zen; 3806 public long since; 3807 public boolean stats; 3808 public boolean redact = true; 3809 3810 public static DumpFilter parseFromArguments(String[] args) { 3811 final DumpFilter filter = new DumpFilter(); 3812 for (int ai = 0; ai < args.length; ai++) { 3813 final String a = args[ai]; 3814 if ("--noredact".equals(a) || "--reveal".equals(a)) { 3815 filter.redact = false; 3816 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) { 3817 if (ai < args.length-1) { 3818 ai++; 3819 filter.pkgFilter = args[ai].trim().toLowerCase(); 3820 if (filter.pkgFilter.isEmpty()) { 3821 filter.pkgFilter = null; 3822 } else { 3823 filter.filtered = true; 3824 } 3825 } 3826 } else if ("--zen".equals(a) || "zen".equals(a)) { 3827 filter.filtered = true; 3828 filter.zen = true; 3829 } else if ("--stats".equals(a)) { 3830 filter.stats = true; 3831 if (ai < args.length-1) { 3832 ai++; 3833 filter.since = Long.valueOf(args[ai]); 3834 } else { 3835 filter.since = 0; 3836 } 3837 } 3838 } 3839 return filter; 3840 } 3841 3842 public boolean matches(StatusBarNotification sbn) { 3843 if (!filtered) return true; 3844 return zen ? true : sbn != null 3845 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg())); 3846 } 3847 3848 public boolean matches(ComponentName component) { 3849 if (!filtered) return true; 3850 return zen ? true : component != null && matches(component.getPackageName()); 3851 } 3852 3853 public boolean matches(String pkg) { 3854 if (!filtered) return true; 3855 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter); 3856 } 3857 3858 @Override 3859 public String toString() { 3860 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\''); 3861 } 3862 } 3863 3864 /** 3865 * Wrapper for a StatusBarNotification object that allows transfer across a oneway 3866 * binder without sending large amounts of data over a oneway transaction. 3867 */ 3868 private static final class StatusBarNotificationHolder 3869 extends IStatusBarNotificationHolder.Stub { 3870 private StatusBarNotification mValue; 3871 3872 public StatusBarNotificationHolder(StatusBarNotification value) { 3873 mValue = value; 3874 } 3875 3876 /** Get the held value and clear it. This function should only be called once per holder */ 3877 @Override 3878 public StatusBarNotification get() { 3879 StatusBarNotification value = mValue; 3880 mValue = null; 3881 return value; 3882 } 3883 } 3884 3885 private final class PolicyAccess { 3886 private static final String SEPARATOR = ":"; 3887 private final String[] PERM = { 3888 android.Manifest.permission.ACCESS_NOTIFICATION_POLICY 3889 }; 3890 3891 public boolean isPackageGranted(String pkg) { 3892 return pkg != null && getGrantedPackages().contains(pkg); 3893 } 3894 3895 public void put(String pkg, boolean granted) { 3896 if (pkg == null) return; 3897 final ArraySet<String> pkgs = getGrantedPackages(); 3898 boolean changed; 3899 if (granted) { 3900 changed = pkgs.add(pkg); 3901 } else { 3902 changed = pkgs.remove(pkg); 3903 } 3904 if (!changed) return; 3905 final String setting = TextUtils.join(SEPARATOR, pkgs); 3906 final int currentUser = ActivityManager.getCurrentUser(); 3907 Settings.Secure.putStringForUser(getContext().getContentResolver(), 3908 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES, 3909 setting, 3910 currentUser); 3911 getContext().sendBroadcastAsUser(new Intent(NotificationManager 3912 .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED) 3913 .setPackage(pkg) 3914 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null); 3915 } 3916 3917 public ArraySet<String> getGrantedPackages() { 3918 final ArraySet<String> pkgs = new ArraySet<>(); 3919 3920 long identity = Binder.clearCallingIdentity(); 3921 try { 3922 final String setting = Settings.Secure.getStringForUser( 3923 getContext().getContentResolver(), 3924 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES, 3925 ActivityManager.getCurrentUser()); 3926 if (setting != null) { 3927 final String[] tokens = setting.split(SEPARATOR); 3928 for (int i = 0; i < tokens.length; i++) { 3929 String token = tokens[i]; 3930 if (token != null) { 3931 token = token.trim(); 3932 } 3933 if (TextUtils.isEmpty(token)) { 3934 continue; 3935 } 3936 pkgs.add(token); 3937 } 3938 } 3939 } finally { 3940 Binder.restoreCallingIdentity(identity); 3941 } 3942 return pkgs; 3943 } 3944 3945 public String[] getRequestingPackages() throws RemoteException { 3946 final ParceledListSlice list = AppGlobals.getPackageManager() 3947 .getPackagesHoldingPermissions(PERM, 0 /*flags*/, 3948 ActivityManager.getCurrentUser()); 3949 final List<PackageInfo> pkgs = list.getList(); 3950 if (pkgs == null || pkgs.isEmpty()) return new String[0]; 3951 final int N = pkgs.size(); 3952 final String[] rt = new String[N]; 3953 for (int i = 0; i < N; i++) { 3954 rt[i] = pkgs.get(i).packageName; 3955 } 3956 return rt; 3957 } 3958 } 3959} 3960