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