NotificationManagerService.java revision b1ebc3b7a013a647dd4a3c6f006e00a017886b20
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<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 if (mAutobundledSummaries.containsKey(adjustment.getPackage())) { 2200 // Clear summary. 2201 final NotificationRecord removed = mNotificationsByKey.get( 2202 mAutobundledSummaries.remove(adjustment.getPackage())); 2203 if (removed != null) { 2204 mNotificationList.remove(removed); 2205 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED); 2206 } 2207 } 2208 } 2209 } 2210 } 2211 2212 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit. 2213 private void maybeAddAutobundleSummary(Adjustment adjustment) { 2214 if (adjustment.getSignals() != null) { 2215 Bundle.setDefusable(adjustment.getSignals(), true); 2216 if (adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) { 2217 final String newAutoBundleKey = 2218 adjustment.getSignals().getString(Adjustment.GROUP_KEY_OVERRIDE_KEY, null); 2219 int userId = -1; 2220 NotificationRecord summaryRecord = null; 2221 synchronized (mNotificationList) { 2222 if (!mAutobundledSummaries.containsKey(adjustment.getPackage()) 2223 && newAutoBundleKey != null) { 2224 // Add summary 2225 final StatusBarNotification adjustedSbn 2226 = mNotificationsByKey.get(adjustment.getKey()).sbn; 2227 2228 final ApplicationInfo appInfo = 2229 adjustedSbn.getNotification().extras.getParcelable( 2230 Notification.EXTRA_BUILDER_APPLICATION_INFO); 2231 final Bundle extras = new Bundle(); 2232 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo); 2233 final Notification summaryNotification = 2234 new Notification.Builder(getContext()).setSmallIcon( 2235 adjustedSbn.getNotification().getSmallIcon()) 2236 .setGroupSummary(true) 2237 .setGroup(newAutoBundleKey) 2238 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true) 2239 .setFlag(Notification.FLAG_GROUP_SUMMARY, true) 2240 .build(); 2241 summaryNotification.extras.putAll(extras); 2242 final StatusBarNotification summarySbn = 2243 new StatusBarNotification(adjustedSbn.getPackageName(), 2244 adjustedSbn.getOpPkg(), 2245 Integer.MAX_VALUE, Adjustment.GROUP_KEY_OVERRIDE_KEY, 2246 adjustedSbn.getUid(), adjustedSbn.getInitialPid(), 2247 summaryNotification, adjustedSbn.getUser(), 2248 newAutoBundleKey, 2249 System.currentTimeMillis()); 2250 summaryRecord = new NotificationRecord(getContext(), summarySbn); 2251 mAutobundledSummaries.put(adjustment.getPackage(), summarySbn.getKey()); 2252 userId = adjustedSbn.getUser().getIdentifier(); 2253 } 2254 } 2255 if (summaryRecord != null) { 2256 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord)); 2257 } 2258 } 2259 } 2260 } 2261 2262 private String disableNotificationEffects(NotificationRecord record) { 2263 if (mDisableNotificationEffects) { 2264 return "booleanState"; 2265 } 2266 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) { 2267 return "listenerHints"; 2268 } 2269 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) { 2270 return "callState"; 2271 } 2272 return null; 2273 }; 2274 2275 private void dumpJson(PrintWriter pw, DumpFilter filter) { 2276 JSONObject dump = new JSONObject(); 2277 try { 2278 dump.put("service", "Notification Manager"); 2279 dump.put("bans", mRankingHelper.dumpBansJson(filter)); 2280 dump.put("ranking", mRankingHelper.dumpJson(filter)); 2281 dump.put("stats", mUsageStats.dumpJson(filter)); 2282 } catch (JSONException e) { 2283 e.printStackTrace(); 2284 } 2285 pw.println(dump); 2286 } 2287 2288 void dumpImpl(PrintWriter pw, DumpFilter filter) { 2289 pw.print("Current Notification Manager state"); 2290 if (filter.filtered) { 2291 pw.print(" (filtered to "); pw.print(filter); pw.print(")"); 2292 } 2293 pw.println(':'); 2294 int N; 2295 final boolean zenOnly = filter.filtered && filter.zen; 2296 2297 if (!zenOnly) { 2298 synchronized (mToastQueue) { 2299 N = mToastQueue.size(); 2300 if (N > 0) { 2301 pw.println(" Toast Queue:"); 2302 for (int i=0; i<N; i++) { 2303 mToastQueue.get(i).dump(pw, " ", filter); 2304 } 2305 pw.println(" "); 2306 } 2307 } 2308 } 2309 2310 synchronized (mNotificationList) { 2311 if (!zenOnly) { 2312 N = mNotificationList.size(); 2313 if (N > 0) { 2314 pw.println(" Notification List:"); 2315 for (int i=0; i<N; i++) { 2316 final NotificationRecord nr = mNotificationList.get(i); 2317 if (filter.filtered && !filter.matches(nr.sbn)) continue; 2318 nr.dump(pw, " ", getContext(), filter.redact); 2319 } 2320 pw.println(" "); 2321 } 2322 2323 if (!filter.filtered) { 2324 N = mLights.size(); 2325 if (N > 0) { 2326 pw.println(" Lights List:"); 2327 for (int i=0; i<N; i++) { 2328 if (i == N - 1) { 2329 pw.print(" > "); 2330 } else { 2331 pw.print(" "); 2332 } 2333 pw.println(mLights.get(i)); 2334 } 2335 pw.println(" "); 2336 } 2337 pw.println(" mUseAttentionLight=" + mUseAttentionLight); 2338 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled); 2339 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey); 2340 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey); 2341 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects); 2342 pw.println(" mCallState=" + callStateToString(mCallState)); 2343 pw.println(" mSystemReady=" + mSystemReady); 2344 } 2345 pw.println(" mArchive=" + mArchive.toString()); 2346 Iterator<StatusBarNotification> iter = mArchive.descendingIterator(); 2347 int i=0; 2348 while (iter.hasNext()) { 2349 final StatusBarNotification sbn = iter.next(); 2350 if (filter != null && !filter.matches(sbn)) continue; 2351 pw.println(" " + sbn); 2352 if (++i >= 5) { 2353 if (iter.hasNext()) pw.println(" ..."); 2354 break; 2355 } 2356 } 2357 } 2358 2359 if (!zenOnly) { 2360 pw.println("\n Usage Stats:"); 2361 mUsageStats.dump(pw, " ", filter); 2362 } 2363 2364 if (!filter.filtered || zenOnly) { 2365 pw.println("\n Zen Mode:"); 2366 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter); 2367 mZenModeHelper.dump(pw, " "); 2368 2369 pw.println("\n Zen Log:"); 2370 ZenLog.dump(pw, " "); 2371 } 2372 2373 if (!zenOnly) { 2374 pw.println("\n Ranking Config:"); 2375 mRankingHelper.dump(pw, " ", filter); 2376 2377 pw.println("\n Notification listeners:"); 2378 mListeners.dump(pw, filter); 2379 pw.print(" mListenerHints: "); pw.println(mListenerHints); 2380 pw.print(" mListenersDisablingEffects: ("); 2381 N = mListenersDisablingEffects.size(); 2382 for (int i = 0; i < N; i++) { 2383 final int hint = mListenersDisablingEffects.keyAt(i); 2384 if (i > 0) pw.print(';'); 2385 pw.print("hint[" + hint + "]:"); 2386 2387 final ArraySet<ManagedServiceInfo> listeners = 2388 mListenersDisablingEffects.valueAt(i); 2389 final int listenerSize = listeners.size(); 2390 2391 for (int j = 0; j < listenerSize; j++) { 2392 if (i > 0) pw.print(','); 2393 final ManagedServiceInfo listener = listeners.valueAt(i); 2394 pw.print(listener.component); 2395 } 2396 } 2397 pw.println(')'); 2398 pw.println("\n mRankerServicePackageName: " + mRankerServicePackageName); 2399 pw.println("\n Notification ranker services:"); 2400 mRankerServices.dump(pw, filter); 2401 } 2402 pw.println("\n Policy access:"); 2403 pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess); 2404 2405 pw.println("\n Condition providers:"); 2406 mConditionProviders.dump(pw, filter); 2407 2408 pw.println("\n Group summaries:"); 2409 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) { 2410 NotificationRecord r = entry.getValue(); 2411 pw.println(" " + entry.getKey() + " -> " + r.getKey()); 2412 if (mNotificationsByKey.get(r.getKey()) != r) { 2413 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey."); 2414 r.dump(pw, " ", getContext(), filter.redact); 2415 } 2416 } 2417 } 2418 } 2419 2420 /** 2421 * The private API only accessible to the system process. 2422 */ 2423 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() { 2424 @Override 2425 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid, 2426 String tag, int id, Notification notification, int[] idReceived, int userId) { 2427 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification, 2428 idReceived, userId); 2429 } 2430 2431 @Override 2432 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId, 2433 int userId) { 2434 checkCallerIsSystem(); 2435 synchronized (mNotificationList) { 2436 int i = indexOfNotificationLocked(pkg, null, notificationId, userId); 2437 if (i < 0) { 2438 Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with " 2439 + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId); 2440 return; 2441 } 2442 NotificationRecord r = mNotificationList.get(i); 2443 StatusBarNotification sbn = r.sbn; 2444 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees 2445 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE, 2446 // we have to revert to the flags we received initially *and* force remove 2447 // FLAG_FOREGROUND_SERVICE. 2448 sbn.getNotification().flags = 2449 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE); 2450 mRankingHelper.sort(mNotificationList); 2451 mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */); 2452 } 2453 } 2454 }; 2455 2456 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, 2457 final int callingPid, final String tag, final int id, final Notification notification, 2458 int[] idOut, int incomingUserId) { 2459 if (DBG) { 2460 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id 2461 + " notification=" + notification); 2462 } 2463 checkCallerIsSystemOrSameApp(pkg); 2464 final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg)); 2465 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg); 2466 2467 final int userId = ActivityManager.handleIncomingUser(callingPid, 2468 callingUid, incomingUserId, true, false, "enqueueNotification", pkg); 2469 final UserHandle user = new UserHandle(userId); 2470 2471 // Fix the notification as best we can. 2472 try { 2473 final ApplicationInfo ai = getContext().getPackageManager().getApplicationInfoAsUser( 2474 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, 2475 (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId); 2476 Notification.addFieldsFromContext(ai, userId, notification); 2477 } catch (NameNotFoundException e) { 2478 Slog.e(TAG, "Cannot create a context for sending app", e); 2479 return; 2480 } 2481 2482 // Limit the number of notifications that any given package except the android 2483 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks. 2484 if (!isSystemNotification && !isNotificationFromListener) { 2485 synchronized (mNotificationList) { 2486 int count = 0; 2487 final int N = mNotificationList.size(); 2488 for (int i=0; i<N; i++) { 2489 final NotificationRecord r = mNotificationList.get(i); 2490 if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) { 2491 if (r.sbn.getId() == id && TextUtils.equals(r.sbn.getTag(), tag)) { 2492 break; // Allow updating existing notification 2493 } 2494 count++; 2495 if (count >= MAX_PACKAGE_NOTIFICATIONS) { 2496 Slog.e(TAG, "Package has already posted " + count 2497 + " notifications. Not showing more. package=" + pkg); 2498 return; 2499 } 2500 } 2501 } 2502 } 2503 } 2504 2505 if (pkg == null || notification == null) { 2506 throw new IllegalArgumentException("null not allowed: pkg=" + pkg 2507 + " id=" + id + " notification=" + notification); 2508 } 2509 2510 // Sanitize inputs 2511 notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN, 2512 Notification.PRIORITY_MAX); 2513 2514 // setup local book-keeping 2515 final StatusBarNotification n = new StatusBarNotification( 2516 pkg, opPkg, id, tag, callingUid, callingPid, 0, notification, 2517 user); 2518 final NotificationRecord r = new NotificationRecord(getContext(), n); 2519 mHandler.post(new EnqueueNotificationRunnable(userId, r)); 2520 2521 idOut[0] = id; 2522 } 2523 2524 private class EnqueueNotificationRunnable implements Runnable { 2525 private final NotificationRecord r; 2526 private final int userId; 2527 2528 EnqueueNotificationRunnable(int userId, NotificationRecord r) { 2529 this.userId = userId; 2530 this.r = r; 2531 }; 2532 2533 @Override 2534 public void run() { 2535 2536 synchronized (mNotificationList) { 2537 final StatusBarNotification n = r.sbn; 2538 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey()); 2539 NotificationRecord old = mNotificationsByKey.get(n.getKey()); 2540 if (old != null) { 2541 // Retain ranking information from previous record 2542 r.copyRankingInformation(old); 2543 } 2544 2545 final int callingUid = n.getUid(); 2546 final int callingPid = n.getInitialPid(); 2547 final Notification notification = n.getNotification(); 2548 final String pkg = n.getPackageName(); 2549 final int id = n.getId(); 2550 final String tag = n.getTag(); 2551 final boolean isSystemNotification = isUidSystem(callingUid) || 2552 ("android".equals(pkg)); 2553 2554 // Handle grouped notifications and bail out early if we 2555 // can to avoid extracting signals. 2556 handleGroupedNotificationLocked(r, old, callingUid, callingPid); 2557 2558 // This conditional is a dirty hack to limit the logging done on 2559 // behalf of the download manager without affecting other apps. 2560 if (!pkg.equals("com.android.providers.downloads") 2561 || Log.isLoggable("DownloadManager", Log.VERBOSE)) { 2562 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW; 2563 if (old != null) { 2564 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE; 2565 } 2566 EventLogTags.writeNotificationEnqueue(callingUid, callingPid, 2567 pkg, id, tag, userId, notification.toString(), 2568 enqueueStatus); 2569 } 2570 2571 mRankingHelper.extractSignals(r); 2572 2573 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid); 2574 2575 // blocked apps 2576 if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE 2577 || !noteNotificationOp(pkg, callingUid) || isPackageSuspended) { 2578 if (!isSystemNotification) { 2579 if (isPackageSuspended) { 2580 Slog.e(TAG, "Suppressing notification from package due to package " 2581 + "suspended by administrator."); 2582 mUsageStats.registerSuspendedByAdmin(r); 2583 } else { 2584 Slog.e(TAG, "Suppressing notification from package by user request."); 2585 mUsageStats.registerBlocked(r); 2586 } 2587 return; 2588 } 2589 } 2590 2591 // tell the ranker service about the notification 2592 if (mRankerServices.isEnabled()) { 2593 mRankerServices.onNotificationEnqueued(r); 2594 // TODO delay the code below here for 100ms or until there is an answer 2595 } 2596 2597 2598 int index = indexOfNotificationLocked(n.getKey()); 2599 if (index < 0) { 2600 mNotificationList.add(r); 2601 mUsageStats.registerPostedByApp(r); 2602 } else { 2603 old = mNotificationList.get(index); 2604 mNotificationList.set(index, r); 2605 mUsageStats.registerUpdatedByApp(r, old); 2606 // Make sure we don't lose the foreground service state. 2607 notification.flags |= 2608 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE; 2609 r.isUpdate = true; 2610 } 2611 2612 mNotificationsByKey.put(n.getKey(), r); 2613 2614 // Ensure if this is a foreground service that the proper additional 2615 // flags are set. 2616 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) { 2617 notification.flags |= Notification.FLAG_ONGOING_EVENT 2618 | Notification.FLAG_NO_CLEAR; 2619 } 2620 2621 applyZenModeLocked(r); 2622 mRankingHelper.sort(mNotificationList); 2623 2624 if (notification.getSmallIcon() != null) { 2625 StatusBarNotification oldSbn = (old != null) ? old.sbn : null; 2626 mListeners.notifyPostedLocked(n, oldSbn); 2627 } else { 2628 Slog.e(TAG, "Not posting notification without small icon: " + notification); 2629 if (old != null && !old.isCanceled) { 2630 mListeners.notifyRemovedLocked(n); 2631 } 2632 // ATTENTION: in a future release we will bail out here 2633 // so that we do not play sounds, show lights, etc. for invalid 2634 // notifications 2635 Slog.e(TAG, "WARNING: In a future release this will crash the app: " 2636 + n.getPackageName()); 2637 } 2638 2639 buzzBeepBlinkLocked(r); 2640 } 2641 } 2642 } 2643 2644 /** 2645 * Ensures that grouped notification receive their special treatment. 2646 * 2647 * <p>Cancels group children if the new notification causes a group to lose 2648 * its summary.</p> 2649 * 2650 * <p>Updates mSummaryByGroupKey.</p> 2651 */ 2652 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old, 2653 int callingUid, int callingPid) { 2654 StatusBarNotification sbn = r.sbn; 2655 Notification n = sbn.getNotification(); 2656 String group = sbn.getGroupKey(); 2657 boolean isSummary = n.isGroupSummary(); 2658 2659 Notification oldN = old != null ? old.sbn.getNotification() : null; 2660 String oldGroup = old != null ? old.sbn.getGroupKey() : null; 2661 boolean oldIsSummary = old != null && oldN.isGroupSummary(); 2662 2663 if (oldIsSummary) { 2664 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup); 2665 if (removedSummary != old) { 2666 String removedKey = 2667 removedSummary != null ? removedSummary.getKey() : "<null>"; 2668 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() + 2669 ", removed=" + removedKey); 2670 } 2671 } 2672 if (isSummary) { 2673 mSummaryByGroupKey.put(group, r); 2674 } 2675 2676 // Clear out group children of the old notification if the update 2677 // causes the group summary to go away. This happens when the old 2678 // notification was a summary and the new one isn't, or when the old 2679 // notification was a summary and its group key changed. 2680 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) { 2681 cancelGroupChildrenLocked(old, callingUid, callingPid, null, 2682 REASON_GROUP_SUMMARY_CANCELED); 2683 } 2684 } 2685 2686 @VisibleForTesting 2687 void buzzBeepBlinkLocked(NotificationRecord record) { 2688 boolean buzz = false; 2689 boolean beep = false; 2690 boolean blink = false; 2691 2692 final Notification notification = record.sbn.getNotification(); 2693 final String key = record.getKey(); 2694 2695 // Should this notification make noise, vibe, or use the LED? 2696 final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_DEFAULT; 2697 final boolean canInterrupt = aboveThreshold && !record.isIntercepted(); 2698 if (DBG || record.isIntercepted()) 2699 Slog.v(TAG, 2700 "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt + 2701 " intercept=" + record.isIntercepted() 2702 ); 2703 2704 final int currentUser; 2705 final long token = Binder.clearCallingIdentity(); 2706 try { 2707 currentUser = ActivityManager.getCurrentUser(); 2708 } finally { 2709 Binder.restoreCallingIdentity(token); 2710 } 2711 2712 // If we're not supposed to beep, vibrate, etc. then don't. 2713 final String disableEffects = disableNotificationEffects(record); 2714 if (disableEffects != null) { 2715 ZenLog.traceDisableEffects(record, disableEffects); 2716 } 2717 2718 // Remember if this notification already owns the notification channels. 2719 boolean wasBeep = key != null && key.equals(mSoundNotificationKey); 2720 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey); 2721 2722 // These are set inside the conditional if the notification is allowed to make noise. 2723 boolean hasValidVibrate = false; 2724 boolean hasValidSound = false; 2725 if (disableEffects == null 2726 && (record.getUserId() == UserHandle.USER_ALL || 2727 record.getUserId() == currentUser || 2728 mUserProfiles.isCurrentProfile(record.getUserId())) 2729 && canInterrupt 2730 && mSystemReady 2731 && mAudioManager != null) { 2732 if (DBG) Slog.v(TAG, "Interrupting!"); 2733 2734 // should we use the default notification sound? (indicated either by 2735 // DEFAULT_SOUND or because notification.sound is pointing at 2736 // Settings.System.NOTIFICATION_SOUND) 2737 final boolean useDefaultSound = 2738 (notification.defaults & Notification.DEFAULT_SOUND) != 0 || 2739 Settings.System.DEFAULT_NOTIFICATION_URI 2740 .equals(notification.sound); 2741 2742 Uri soundUri = null; 2743 if (useDefaultSound) { 2744 soundUri = Settings.System.DEFAULT_NOTIFICATION_URI; 2745 2746 // check to see if the default notification sound is silent 2747 ContentResolver resolver = getContext().getContentResolver(); 2748 hasValidSound = Settings.System.getString(resolver, 2749 Settings.System.NOTIFICATION_SOUND) != null; 2750 } else if (notification.sound != null) { 2751 soundUri = notification.sound; 2752 hasValidSound = (soundUri != null); 2753 } 2754 2755 // Does the notification want to specify its own vibration? 2756 final boolean hasCustomVibrate = notification.vibrate != null; 2757 2758 // new in 4.2: if there was supposed to be a sound and we're in vibrate 2759 // mode, and no other vibration is specified, we fall back to vibration 2760 final boolean convertSoundToVibration = 2761 !hasCustomVibrate 2762 && hasValidSound 2763 && (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE); 2764 2765 // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback. 2766 final boolean useDefaultVibrate = 2767 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0; 2768 2769 hasValidVibrate = useDefaultVibrate || convertSoundToVibration || 2770 hasCustomVibrate; 2771 2772 // We can alert, and we're allowed to alert, but if the developer asked us to only do 2773 // it once, and we already have, then don't. 2774 if (!(record.isUpdate 2775 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) { 2776 2777 sendAccessibilityEvent(notification, record.sbn.getPackageName()); 2778 2779 if (hasValidSound) { 2780 boolean looping = 2781 (notification.flags & Notification.FLAG_INSISTENT) != 0; 2782 AudioAttributes audioAttributes = audioAttributesForNotification(notification); 2783 mSoundNotificationKey = key; 2784 // do not play notifications if stream volume is 0 (typically because 2785 // ringer mode is silent) or if there is a user of exclusive audio focus 2786 if ((mAudioManager.getStreamVolume( 2787 AudioAttributes.toLegacyStreamType(audioAttributes)) != 0) 2788 && !mAudioManager.isAudioFocusExclusive()) { 2789 final long identity = Binder.clearCallingIdentity(); 2790 try { 2791 final IRingtonePlayer player = 2792 mAudioManager.getRingtonePlayer(); 2793 if (player != null) { 2794 if (DBG) Slog.v(TAG, "Playing sound " + soundUri 2795 + " with attributes " + audioAttributes); 2796 player.playAsync(soundUri, record.sbn.getUser(), looping, 2797 audioAttributes); 2798 beep = true; 2799 } 2800 } catch (RemoteException e) { 2801 } finally { 2802 Binder.restoreCallingIdentity(identity); 2803 } 2804 } 2805 } 2806 2807 if (hasValidVibrate && !(mAudioManager.getRingerModeInternal() 2808 == AudioManager.RINGER_MODE_SILENT)) { 2809 mVibrateNotificationKey = key; 2810 2811 if (useDefaultVibrate || convertSoundToVibration) { 2812 // Escalate privileges so we can use the vibrator even if the 2813 // notifying app does not have the VIBRATE permission. 2814 long identity = Binder.clearCallingIdentity(); 2815 try { 2816 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(), 2817 useDefaultVibrate ? mDefaultVibrationPattern 2818 : mFallbackVibrationPattern, 2819 ((notification.flags & Notification.FLAG_INSISTENT) != 0) 2820 ? 0: -1, audioAttributesForNotification(notification)); 2821 buzz = true; 2822 } finally { 2823 Binder.restoreCallingIdentity(identity); 2824 } 2825 } else if (notification.vibrate.length > 1) { 2826 // If you want your own vibration pattern, you need the VIBRATE 2827 // permission 2828 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(), 2829 notification.vibrate, 2830 ((notification.flags & Notification.FLAG_INSISTENT) != 0) 2831 ? 0: -1, audioAttributesForNotification(notification)); 2832 buzz = true; 2833 } 2834 } 2835 } 2836 2837 } 2838 // If a notification is updated to remove the actively playing sound or vibrate, 2839 // cancel that feedback now 2840 if (wasBeep && !hasValidSound) { 2841 clearSoundLocked(); 2842 } 2843 if (wasBuzz && !hasValidVibrate) { 2844 clearVibrateLocked(); 2845 } 2846 2847 // light 2848 // release the light 2849 boolean wasShowLights = mLights.remove(key); 2850 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold 2851 && ((record.getSuppressedVisualEffects() 2852 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) { 2853 mLights.add(key); 2854 updateLightsLocked(); 2855 if (mUseAttentionLight) { 2856 mAttentionLight.pulse(); 2857 } 2858 blink = true; 2859 } else if (wasShowLights) { 2860 updateLightsLocked(); 2861 } 2862 if (buzz || beep || blink) { 2863 if (((record.getSuppressedVisualEffects() 2864 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) { 2865 if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on"); 2866 } else { 2867 EventLogTags.writeNotificationAlert(key, 2868 buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0); 2869 mHandler.post(mBuzzBeepBlinked); 2870 } 2871 } 2872 } 2873 2874 private static AudioAttributes audioAttributesForNotification(Notification n) { 2875 if (n.audioAttributes != null 2876 && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) { 2877 // the audio attributes are set and different from the default, use them 2878 return n.audioAttributes; 2879 } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) { 2880 // the stream type is valid, use it 2881 return new AudioAttributes.Builder() 2882 .setInternalLegacyStreamType(n.audioStreamType) 2883 .build(); 2884 } else if (n.audioStreamType == AudioSystem.STREAM_DEFAULT) { 2885 return Notification.AUDIO_ATTRIBUTES_DEFAULT; 2886 } else { 2887 Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType)); 2888 return Notification.AUDIO_ATTRIBUTES_DEFAULT; 2889 } 2890 } 2891 2892 void showNextToastLocked() { 2893 ToastRecord record = mToastQueue.get(0); 2894 while (record != null) { 2895 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback); 2896 try { 2897 record.callback.show(); 2898 scheduleTimeoutLocked(record); 2899 return; 2900 } catch (RemoteException e) { 2901 Slog.w(TAG, "Object died trying to show notification " + record.callback 2902 + " in package " + record.pkg); 2903 // remove it from the list and let the process die 2904 int index = mToastQueue.indexOf(record); 2905 if (index >= 0) { 2906 mToastQueue.remove(index); 2907 } 2908 keepProcessAliveLocked(record.pid); 2909 if (mToastQueue.size() > 0) { 2910 record = mToastQueue.get(0); 2911 } else { 2912 record = null; 2913 } 2914 } 2915 } 2916 } 2917 2918 void cancelToastLocked(int index) { 2919 ToastRecord record = mToastQueue.get(index); 2920 try { 2921 record.callback.hide(); 2922 } catch (RemoteException e) { 2923 Slog.w(TAG, "Object died trying to hide notification " + record.callback 2924 + " in package " + record.pkg); 2925 // don't worry about this, we're about to remove it from 2926 // the list anyway 2927 } 2928 mToastQueue.remove(index); 2929 keepProcessAliveLocked(record.pid); 2930 if (mToastQueue.size() > 0) { 2931 // Show the next one. If the callback fails, this will remove 2932 // it from the list, so don't assume that the list hasn't changed 2933 // after this point. 2934 showNextToastLocked(); 2935 } 2936 } 2937 2938 private void scheduleTimeoutLocked(ToastRecord r) 2939 { 2940 mHandler.removeCallbacksAndMessages(r); 2941 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r); 2942 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY; 2943 mHandler.sendMessageDelayed(m, delay); 2944 } 2945 2946 private void handleTimeout(ToastRecord record) 2947 { 2948 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback); 2949 synchronized (mToastQueue) { 2950 int index = indexOfToastLocked(record.pkg, record.callback); 2951 if (index >= 0) { 2952 cancelToastLocked(index); 2953 } 2954 } 2955 } 2956 2957 // lock on mToastQueue 2958 int indexOfToastLocked(String pkg, ITransientNotification callback) 2959 { 2960 IBinder cbak = callback.asBinder(); 2961 ArrayList<ToastRecord> list = mToastQueue; 2962 int len = list.size(); 2963 for (int i=0; i<len; i++) { 2964 ToastRecord r = list.get(i); 2965 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) { 2966 return i; 2967 } 2968 } 2969 return -1; 2970 } 2971 2972 // lock on mToastQueue 2973 void keepProcessAliveLocked(int pid) 2974 { 2975 int toastCount = 0; // toasts from this pid 2976 ArrayList<ToastRecord> list = mToastQueue; 2977 int N = list.size(); 2978 for (int i=0; i<N; i++) { 2979 ToastRecord r = list.get(i); 2980 if (r.pid == pid) { 2981 toastCount++; 2982 } 2983 } 2984 try { 2985 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0); 2986 } catch (RemoteException e) { 2987 // Shouldn't happen. 2988 } 2989 } 2990 2991 private void handleRankingReconsideration(Message message) { 2992 if (!(message.obj instanceof RankingReconsideration)) return; 2993 RankingReconsideration recon = (RankingReconsideration) message.obj; 2994 recon.run(); 2995 boolean changed; 2996 synchronized (mNotificationList) { 2997 final NotificationRecord record = mNotificationsByKey.get(recon.getKey()); 2998 if (record == null) { 2999 return; 3000 } 3001 int indexBefore = findNotificationRecordIndexLocked(record); 3002 boolean interceptBefore = record.isIntercepted(); 3003 int visibilityBefore = record.getPackageVisibilityOverride(); 3004 recon.applyChangesLocked(record); 3005 applyZenModeLocked(record); 3006 mRankingHelper.sort(mNotificationList); 3007 int indexAfter = findNotificationRecordIndexLocked(record); 3008 boolean interceptAfter = record.isIntercepted(); 3009 int visibilityAfter = record.getPackageVisibilityOverride(); 3010 changed = indexBefore != indexAfter || interceptBefore != interceptAfter 3011 || visibilityBefore != visibilityAfter; 3012 if (interceptBefore && !interceptAfter) { 3013 buzzBeepBlinkLocked(record); 3014 } 3015 } 3016 if (changed) { 3017 scheduleSendRankingUpdate(); 3018 } 3019 } 3020 3021 private void handleRankingSort() { 3022 synchronized (mNotificationList) { 3023 final int N = mNotificationList.size(); 3024 ArrayList<String> orderBefore = new ArrayList<String>(N); 3025 ArrayList<String> groupOverrideBefore = new ArrayList<>(N); 3026 int[] visibilities = new int[N]; 3027 int[] importances = new int[N]; 3028 for (int i = 0; i < N; i++) { 3029 final NotificationRecord r = mNotificationList.get(i); 3030 orderBefore.add(r.getKey()); 3031 groupOverrideBefore.add(r.sbn.getGroupKey()); 3032 visibilities[i] = r.getPackageVisibilityOverride(); 3033 importances[i] = r.getImportance(); 3034 mRankingHelper.extractSignals(r); 3035 } 3036 mRankingHelper.sort(mNotificationList); 3037 for (int i = 0; i < N; i++) { 3038 final NotificationRecord r = mNotificationList.get(i); 3039 if (!orderBefore.get(i).equals(r.getKey()) 3040 || visibilities[i] != r.getPackageVisibilityOverride() 3041 || importances[i] != r.getImportance() 3042 || !groupOverrideBefore.get(i).equals(r.sbn.getGroupKey())) { 3043 scheduleSendRankingUpdate(); 3044 return; 3045 } 3046 } 3047 } 3048 } 3049 3050 // let zen mode evaluate this record 3051 private void applyZenModeLocked(NotificationRecord record) { 3052 record.setIntercepted(mZenModeHelper.shouldIntercept(record)); 3053 if (record.isIntercepted()) { 3054 int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff() 3055 ? SUPPRESSED_EFFECT_SCREEN_OFF : 0) 3056 | (mZenModeHelper.shouldSuppressWhenScreenOn() 3057 ? SUPPRESSED_EFFECT_SCREEN_ON : 0); 3058 record.setSuppressedVisualEffects(suppressed); 3059 } 3060 } 3061 3062 // lock on mNotificationList 3063 private int findNotificationRecordIndexLocked(NotificationRecord target) { 3064 return mRankingHelper.indexOf(mNotificationList, target); 3065 } 3066 3067 private void scheduleSendRankingUpdate() { 3068 if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) { 3069 Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE); 3070 mHandler.sendMessage(m); 3071 } 3072 } 3073 3074 private void handleSendRankingUpdate() { 3075 synchronized (mNotificationList) { 3076 mListeners.notifyRankingUpdateLocked(); 3077 } 3078 } 3079 3080 private void scheduleListenerHintsChanged(int state) { 3081 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED); 3082 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget(); 3083 } 3084 3085 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) { 3086 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED); 3087 mHandler.obtainMessage( 3088 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED, 3089 listenerInterruptionFilter, 3090 0).sendToTarget(); 3091 } 3092 3093 private void handleListenerHintsChanged(int hints) { 3094 synchronized (mNotificationList) { 3095 mListeners.notifyListenerHintsChangedLocked(hints); 3096 } 3097 } 3098 3099 private void handleListenerInterruptionFilterChanged(int interruptionFilter) { 3100 synchronized (mNotificationList) { 3101 mListeners.notifyInterruptionFilterChanged(interruptionFilter); 3102 } 3103 } 3104 3105 private final class WorkerHandler extends Handler 3106 { 3107 @Override 3108 public void handleMessage(Message msg) 3109 { 3110 switch (msg.what) 3111 { 3112 case MESSAGE_TIMEOUT: 3113 handleTimeout((ToastRecord)msg.obj); 3114 break; 3115 case MESSAGE_SAVE_POLICY_FILE: 3116 handleSavePolicyFile(); 3117 break; 3118 case MESSAGE_SEND_RANKING_UPDATE: 3119 handleSendRankingUpdate(); 3120 break; 3121 case MESSAGE_LISTENER_HINTS_CHANGED: 3122 handleListenerHintsChanged(msg.arg1); 3123 break; 3124 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED: 3125 handleListenerInterruptionFilterChanged(msg.arg1); 3126 break; 3127 } 3128 } 3129 3130 } 3131 3132 private final class RankingHandlerWorker extends Handler implements RankingHandler 3133 { 3134 public RankingHandlerWorker(Looper looper) { 3135 super(looper); 3136 } 3137 3138 @Override 3139 public void handleMessage(Message msg) { 3140 switch (msg.what) { 3141 case MESSAGE_RECONSIDER_RANKING: 3142 handleRankingReconsideration(msg); 3143 break; 3144 case MESSAGE_RANKING_SORT: 3145 handleRankingSort(); 3146 break; 3147 } 3148 } 3149 3150 public void requestSort() { 3151 removeMessages(MESSAGE_RANKING_SORT); 3152 sendEmptyMessage(MESSAGE_RANKING_SORT); 3153 } 3154 3155 public void requestReconsideration(RankingReconsideration recon) { 3156 Message m = Message.obtain(this, 3157 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon); 3158 long delay = recon.getDelay(TimeUnit.MILLISECONDS); 3159 sendMessageDelayed(m, delay); 3160 } 3161 } 3162 3163 // Notifications 3164 // ============================================================================ 3165 static int clamp(int x, int low, int high) { 3166 return (x < low) ? low : ((x > high) ? high : x); 3167 } 3168 3169 void sendAccessibilityEvent(Notification notification, CharSequence packageName) { 3170 AccessibilityManager manager = AccessibilityManager.getInstance(getContext()); 3171 if (!manager.isEnabled()) { 3172 return; 3173 } 3174 3175 AccessibilityEvent event = 3176 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); 3177 event.setPackageName(packageName); 3178 event.setClassName(Notification.class.getName()); 3179 event.setParcelableData(notification); 3180 CharSequence tickerText = notification.tickerText; 3181 if (!TextUtils.isEmpty(tickerText)) { 3182 event.getText().add(tickerText); 3183 } 3184 3185 manager.sendAccessibilityEvent(event); 3186 } 3187 3188 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) { 3189 // tell the app 3190 if (sendDelete) { 3191 if (r.getNotification().deleteIntent != null) { 3192 try { 3193 r.getNotification().deleteIntent.send(); 3194 } catch (PendingIntent.CanceledException ex) { 3195 // do nothing - there's no relevant way to recover, and 3196 // no reason to let this propagate 3197 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex); 3198 } 3199 } 3200 } 3201 3202 // status bar 3203 if (r.getNotification().getSmallIcon() != null) { 3204 r.isCanceled = true; 3205 mListeners.notifyRemovedLocked(r.sbn); 3206 } 3207 3208 final String canceledKey = r.getKey(); 3209 3210 // sound 3211 if (canceledKey.equals(mSoundNotificationKey)) { 3212 mSoundNotificationKey = null; 3213 final long identity = Binder.clearCallingIdentity(); 3214 try { 3215 final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); 3216 if (player != null) { 3217 player.stopAsync(); 3218 } 3219 } catch (RemoteException e) { 3220 } finally { 3221 Binder.restoreCallingIdentity(identity); 3222 } 3223 } 3224 3225 // vibrate 3226 if (canceledKey.equals(mVibrateNotificationKey)) { 3227 mVibrateNotificationKey = null; 3228 long identity = Binder.clearCallingIdentity(); 3229 try { 3230 mVibrator.cancel(); 3231 } 3232 finally { 3233 Binder.restoreCallingIdentity(identity); 3234 } 3235 } 3236 3237 // light 3238 mLights.remove(canceledKey); 3239 3240 // Record usage stats 3241 // TODO: add unbundling stats? 3242 switch (reason) { 3243 case REASON_DELEGATE_CANCEL: 3244 case REASON_DELEGATE_CANCEL_ALL: 3245 case REASON_LISTENER_CANCEL: 3246 case REASON_LISTENER_CANCEL_ALL: 3247 mUsageStats.registerDismissedByUser(r); 3248 break; 3249 case REASON_APP_CANCEL: 3250 case REASON_APP_CANCEL_ALL: 3251 mUsageStats.registerRemovedByApp(r); 3252 break; 3253 } 3254 3255 mNotificationsByKey.remove(r.sbn.getKey()); 3256 String groupKey = r.getGroupKey(); 3257 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey); 3258 if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) { 3259 mSummaryByGroupKey.remove(groupKey); 3260 } 3261 if (r.sbn.getKey().equals(mAutobundledSummaries.get(r.sbn.getPackageName()))) { 3262 mAutobundledSummaries.remove(r.sbn.getPackageName()); 3263 } 3264 3265 // Save it for users of getHistoricalNotifications() 3266 mArchive.record(r.sbn); 3267 3268 final long now = System.currentTimeMillis(); 3269 EventLogTags.writeNotificationCanceled(canceledKey, reason, 3270 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now)); 3271 } 3272 3273 /** 3274 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags} 3275 * and none of the {@code mustNotHaveFlags}. 3276 */ 3277 void cancelNotification(final int callingUid, final int callingPid, 3278 final String pkg, final String tag, final int id, 3279 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, 3280 final int userId, final int reason, final ManagedServiceInfo listener) { 3281 // In enqueueNotificationInternal notifications are added by scheduling the 3282 // work on the worker handler. Hence, we also schedule the cancel on this 3283 // handler to avoid a scenario where an add notification call followed by a 3284 // remove notification call ends up in not removing the notification. 3285 mHandler.post(new Runnable() { 3286 @Override 3287 public void run() { 3288 String listenerName = listener == null ? null : listener.component.toShortString(); 3289 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag, 3290 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName); 3291 3292 synchronized (mNotificationList) { 3293 int index = indexOfNotificationLocked(pkg, tag, id, userId); 3294 if (index >= 0) { 3295 NotificationRecord r = mNotificationList.get(index); 3296 3297 // Ideally we'd do this in the caller of this method. However, that would 3298 // require the caller to also find the notification. 3299 if (reason == REASON_DELEGATE_CLICK) { 3300 mUsageStats.registerClickedByUser(r); 3301 } 3302 3303 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) { 3304 return; 3305 } 3306 if ((r.getNotification().flags & mustNotHaveFlags) != 0) { 3307 return; 3308 } 3309 3310 mNotificationList.remove(index); 3311 3312 cancelNotificationLocked(r, sendDelete, reason); 3313 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName, 3314 REASON_GROUP_SUMMARY_CANCELED); 3315 updateLightsLocked(); 3316 } 3317 } 3318 } 3319 }); 3320 } 3321 3322 /** 3323 * Determine whether the userId applies to the notification in question, either because 3324 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard). 3325 */ 3326 private boolean notificationMatchesUserId(NotificationRecord r, int userId) { 3327 return 3328 // looking for USER_ALL notifications? match everything 3329 userId == UserHandle.USER_ALL 3330 // a notification sent to USER_ALL matches any query 3331 || r.getUserId() == UserHandle.USER_ALL 3332 // an exact user match 3333 || r.getUserId() == userId; 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) or 3339 * because it matches one of the users profiles. 3340 */ 3341 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) { 3342 return notificationMatchesUserId(r, userId) 3343 || mUserProfiles.isCurrentProfile(r.getUserId()); 3344 } 3345 3346 /** 3347 * Cancels all notifications from a given package that have all of the 3348 * {@code mustHaveFlags}. 3349 */ 3350 boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags, 3351 int mustNotHaveFlags, boolean doit, int userId, int reason, 3352 ManagedServiceInfo listener) { 3353 String listenerName = listener == null ? null : listener.component.toShortString(); 3354 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 3355 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason, 3356 listenerName); 3357 3358 synchronized (mNotificationList) { 3359 final int N = mNotificationList.size(); 3360 ArrayList<NotificationRecord> canceledNotifications = null; 3361 for (int i = N-1; i >= 0; --i) { 3362 NotificationRecord r = mNotificationList.get(i); 3363 if (!notificationMatchesUserId(r, userId)) { 3364 continue; 3365 } 3366 // Don't remove notifications to all, if there's no package name specified 3367 if (r.getUserId() == UserHandle.USER_ALL && pkg == null) { 3368 continue; 3369 } 3370 if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) { 3371 continue; 3372 } 3373 if ((r.getFlags() & mustNotHaveFlags) != 0) { 3374 continue; 3375 } 3376 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) { 3377 continue; 3378 } 3379 if (canceledNotifications == null) { 3380 canceledNotifications = new ArrayList<>(); 3381 } 3382 canceledNotifications.add(r); 3383 if (!doit) { 3384 return true; 3385 } 3386 mNotificationList.remove(i); 3387 cancelNotificationLocked(r, false, reason); 3388 } 3389 if (doit && canceledNotifications != null) { 3390 final int M = canceledNotifications.size(); 3391 for (int i = 0; i < M; i++) { 3392 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid, 3393 listenerName, REASON_GROUP_SUMMARY_CANCELED); 3394 } 3395 } 3396 if (canceledNotifications != null) { 3397 updateLightsLocked(); 3398 } 3399 return canceledNotifications != null; 3400 } 3401 } 3402 3403 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason, 3404 ManagedServiceInfo listener, boolean includeCurrentProfiles) { 3405 String listenerName = listener == null ? null : listener.component.toShortString(); 3406 EventLogTags.writeNotificationCancelAll(callingUid, callingPid, 3407 null, userId, 0, 0, reason, listenerName); 3408 3409 ArrayList<NotificationRecord> canceledNotifications = null; 3410 final int N = mNotificationList.size(); 3411 for (int i=N-1; i>=0; i--) { 3412 NotificationRecord r = mNotificationList.get(i); 3413 if (includeCurrentProfiles) { 3414 if (!notificationMatchesCurrentProfiles(r, userId)) { 3415 continue; 3416 } 3417 } else { 3418 if (!notificationMatchesUserId(r, userId)) { 3419 continue; 3420 } 3421 } 3422 3423 if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT 3424 | Notification.FLAG_NO_CLEAR)) == 0) { 3425 mNotificationList.remove(i); 3426 cancelNotificationLocked(r, true, reason); 3427 // Make a note so we can cancel children later. 3428 if (canceledNotifications == null) { 3429 canceledNotifications = new ArrayList<>(); 3430 } 3431 canceledNotifications.add(r); 3432 } 3433 } 3434 int M = canceledNotifications != null ? canceledNotifications.size() : 0; 3435 for (int i = 0; i < M; i++) { 3436 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid, 3437 listenerName, REASON_GROUP_SUMMARY_CANCELED); 3438 } 3439 updateLightsLocked(); 3440 } 3441 3442 // Warning: The caller is responsible for invoking updateLightsLocked(). 3443 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid, 3444 String listenerName, int reason) { 3445 Notification n = r.getNotification(); 3446 if (!n.isGroupSummary()) { 3447 return; 3448 } 3449 3450 String pkg = r.sbn.getPackageName(); 3451 int userId = r.getUserId(); 3452 3453 if (pkg == null) { 3454 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey()); 3455 return; 3456 } 3457 3458 final int N = mNotificationList.size(); 3459 for (int i = N - 1; i >= 0; i--) { 3460 NotificationRecord childR = mNotificationList.get(i); 3461 StatusBarNotification childSbn = childR.sbn; 3462 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) && 3463 childR.getGroupKey().equals(r.getGroupKey())) { 3464 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(), 3465 childSbn.getTag(), userId, 0, 0, reason, listenerName); 3466 mNotificationList.remove(i); 3467 cancelNotificationLocked(childR, false, reason); 3468 } 3469 } 3470 } 3471 3472 // lock on mNotificationList 3473 void updateLightsLocked() 3474 { 3475 // handle notification lights 3476 NotificationRecord ledNotification = null; 3477 while (ledNotification == null && !mLights.isEmpty()) { 3478 final String owner = mLights.get(mLights.size() - 1); 3479 ledNotification = mNotificationsByKey.get(owner); 3480 if (ledNotification == null) { 3481 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner); 3482 mLights.remove(owner); 3483 } 3484 } 3485 3486 // Don't flash while we are in a call or screen is on 3487 if (ledNotification == null || mInCall || mScreenOn) { 3488 mNotificationLight.turnOff(); 3489 if (mStatusBar != null) { 3490 mStatusBar.notificationLightOff(); 3491 } 3492 } else { 3493 final Notification ledno = ledNotification.sbn.getNotification(); 3494 int ledARGB = ledno.ledARGB; 3495 int ledOnMS = ledno.ledOnMS; 3496 int ledOffMS = ledno.ledOffMS; 3497 if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) { 3498 ledARGB = mDefaultNotificationColor; 3499 ledOnMS = mDefaultNotificationLedOn; 3500 ledOffMS = mDefaultNotificationLedOff; 3501 } 3502 if (mNotificationPulseEnabled) { 3503 // pulse repeatedly 3504 mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED, 3505 ledOnMS, ledOffMS); 3506 } 3507 if (mStatusBar != null) { 3508 // let SystemUI make an independent decision 3509 mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS); 3510 } 3511 } 3512 } 3513 3514 // lock on mNotificationList 3515 int indexOfNotificationLocked(String pkg, String tag, int id, int userId) 3516 { 3517 ArrayList<NotificationRecord> list = mNotificationList; 3518 final int len = list.size(); 3519 for (int i=0; i<len; i++) { 3520 NotificationRecord r = list.get(i); 3521 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id && 3522 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) { 3523 return i; 3524 } 3525 } 3526 return -1; 3527 } 3528 3529 // lock on mNotificationList 3530 int indexOfNotificationLocked(String key) { 3531 final int N = mNotificationList.size(); 3532 for (int i = 0; i < N; i++) { 3533 if (key.equals(mNotificationList.get(i).getKey())) { 3534 return i; 3535 } 3536 } 3537 return -1; 3538 } 3539 3540 private void updateNotificationPulse() { 3541 synchronized (mNotificationList) { 3542 updateLightsLocked(); 3543 } 3544 } 3545 3546 private static boolean isUidSystem(int uid) { 3547 final int appid = UserHandle.getAppId(uid); 3548 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0); 3549 } 3550 3551 private static boolean isCallerSystem() { 3552 return isUidSystem(Binder.getCallingUid()); 3553 } 3554 3555 private static void checkCallerIsSystem() { 3556 if (isCallerSystem()) { 3557 return; 3558 } 3559 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid()); 3560 } 3561 3562 private static void checkCallerIsSystemOrSameApp(String pkg) { 3563 if (isCallerSystem()) { 3564 return; 3565 } 3566 final int uid = Binder.getCallingUid(); 3567 try { 3568 ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo( 3569 pkg, 0, UserHandle.getCallingUserId()); 3570 if (ai == null) { 3571 throw new SecurityException("Unknown package " + pkg); 3572 } 3573 if (!UserHandle.isSameApp(ai.uid, uid)) { 3574 throw new SecurityException("Calling uid " + uid + " gave package" 3575 + pkg + " which is owned by uid " + ai.uid); 3576 } 3577 } catch (RemoteException re) { 3578 throw new SecurityException("Unknown package " + pkg + "\n" + re); 3579 } 3580 } 3581 3582 private static String callStateToString(int state) { 3583 switch (state) { 3584 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE"; 3585 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING"; 3586 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK"; 3587 default: return "CALL_STATE_UNKNOWN_" + state; 3588 } 3589 } 3590 3591 private void listenForCallState() { 3592 TelephonyManager.from(getContext()).listen(new PhoneStateListener() { 3593 @Override 3594 public void onCallStateChanged(int state, String incomingNumber) { 3595 if (mCallState == state) return; 3596 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state)); 3597 mCallState = state; 3598 } 3599 }, PhoneStateListener.LISTEN_CALL_STATE); 3600 } 3601 3602 /** 3603 * Generates a NotificationRankingUpdate from 'sbns', considering only 3604 * notifications visible to the given listener. 3605 * 3606 * <p>Caller must hold a lock on mNotificationList.</p> 3607 */ 3608 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) { 3609 final int N = mNotificationList.size(); 3610 ArrayList<String> keys = new ArrayList<String>(N); 3611 ArrayList<String> interceptedKeys = new ArrayList<String>(N); 3612 ArrayList<Integer> importance = new ArrayList<>(N); 3613 Bundle overrideGroupKeys = new Bundle(); 3614 Bundle visibilityOverrides = new Bundle(); 3615 Bundle suppressedVisualEffects = new Bundle(); 3616 Bundle explanation = new Bundle(); 3617 for (int i = 0; i < N; i++) { 3618 NotificationRecord record = mNotificationList.get(i); 3619 if (!isVisibleToListener(record.sbn, info)) { 3620 continue; 3621 } 3622 final String key = record.sbn.getKey(); 3623 keys.add(key); 3624 importance.add(record.getImportance()); 3625 if (record.getImportanceExplanation() != null) { 3626 explanation.putCharSequence(key, record.getImportanceExplanation()); 3627 } 3628 if (record.isIntercepted()) { 3629 interceptedKeys.add(key); 3630 3631 } 3632 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects()); 3633 if (record.getPackageVisibilityOverride() 3634 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) { 3635 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride()); 3636 } 3637 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey()); 3638 } 3639 final int M = keys.size(); 3640 String[] keysAr = keys.toArray(new String[M]); 3641 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]); 3642 int[] importanceAr = new int[M]; 3643 for (int i = 0; i < M; i++) { 3644 importanceAr[i] = importance.get(i); 3645 } 3646 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides, 3647 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys); 3648 } 3649 3650 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) { 3651 if (!listener.enabledAndUserMatches(sbn.getUserId())) { 3652 return false; 3653 } 3654 // TODO: remove this for older listeners. 3655 return true; 3656 } 3657 3658 private boolean isPackageSuspendedForUser(String pkg, int uid) { 3659 int userId = UserHandle.getUserId(uid); 3660 try { 3661 return AppGlobals.getPackageManager().isPackageSuspendedForUser(pkg, userId); 3662 } catch (RemoteException re) { 3663 throw new SecurityException("Could not talk to package manager service"); 3664 } catch (IllegalArgumentException ex) { 3665 // Package not found. 3666 return false; 3667 } 3668 } 3669 3670 private class TrimCache { 3671 StatusBarNotification heavy; 3672 StatusBarNotification sbnClone; 3673 StatusBarNotification sbnCloneLight; 3674 3675 TrimCache(StatusBarNotification sbn) { 3676 heavy = sbn; 3677 } 3678 3679 StatusBarNotification ForListener(ManagedServiceInfo info) { 3680 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) { 3681 if (sbnCloneLight == null) { 3682 sbnCloneLight = heavy.cloneLight(); 3683 } 3684 return sbnCloneLight; 3685 } else { 3686 if (sbnClone == null) { 3687 sbnClone = heavy.clone(); 3688 } 3689 return sbnClone; 3690 } 3691 } 3692 } 3693 3694 public class NotificationRankers extends ManagedServices { 3695 3696 public NotificationRankers() { 3697 super(getContext(), mHandler, mNotificationList, mUserProfiles); 3698 } 3699 3700 @Override 3701 protected Config getConfig() { 3702 Config c = new Config(); 3703 c.caption = "notification ranker service"; 3704 c.serviceInterface = NotificationRankerService.SERVICE_INTERFACE; 3705 c.secureSettingName = null; 3706 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_RANKER_SERVICE; 3707 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS; 3708 c.clientLabel = R.string.notification_ranker_binding_label; 3709 return c; 3710 } 3711 3712 @Override 3713 protected IInterface asInterface(IBinder binder) { 3714 return INotificationListener.Stub.asInterface(binder); 3715 } 3716 3717 @Override 3718 protected boolean checkType(IInterface service) { 3719 return service instanceof INotificationListener; 3720 } 3721 3722 @Override 3723 protected void onServiceAdded(ManagedServiceInfo info) { 3724 mListeners.registerGuestService(info); 3725 } 3726 3727 @Override 3728 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { 3729 mListeners.unregisterService(removed.service, removed.userid); 3730 } 3731 3732 public void onNotificationEnqueued(final NotificationRecord r) { 3733 final StatusBarNotification sbn = r.sbn; 3734 TrimCache trimCache = new TrimCache(sbn); 3735 3736 // mServices is the list inside ManagedServices of all the rankers, 3737 // There should be only one, but it's a list, so while we enforce 3738 // singularity elsewhere, we keep it general here, to avoid surprises. 3739 for (final ManagedServiceInfo info : NotificationRankers.this.mServices) { 3740 boolean sbnVisible = isVisibleToListener(sbn, info); 3741 if (!sbnVisible) { 3742 continue; 3743 } 3744 3745 final int importance = r.getImportance(); 3746 final boolean fromUser = r.isImportanceFromUser(); 3747 final StatusBarNotification sbnToPost = trimCache.ForListener(info); 3748 mHandler.post(new Runnable() { 3749 @Override 3750 public void run() { 3751 notifyEnqueued(info, sbnToPost, importance, fromUser); 3752 } 3753 }); 3754 } 3755 } 3756 3757 private void notifyEnqueued(final ManagedServiceInfo info, 3758 final StatusBarNotification sbn, int importance, boolean fromUser) { 3759 final INotificationListener ranker = (INotificationListener) info.service; 3760 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 3761 try { 3762 ranker.onNotificationEnqueued(sbnHolder, importance, fromUser); 3763 } catch (RemoteException ex) { 3764 Log.e(TAG, "unable to notify ranker (enqueued): " + ranker, ex); 3765 } 3766 } 3767 3768 public boolean isEnabled() { 3769 return !mServices.isEmpty(); 3770 } 3771 3772 @Override 3773 public void onUserSwitched(int user) { 3774 for (ManagedServiceInfo info : mServices) { 3775 unregisterService(info.service, info.userid); 3776 } 3777 registerRanker(); 3778 } 3779 3780 @Override 3781 public void onPackagesChanged(boolean queryReplace, String[] pkgList) { 3782 if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace 3783 + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))); 3784 if (mRankerServicePackageName == null) { 3785 return; 3786 } 3787 3788 if (pkgList != null && (pkgList.length > 0)) { 3789 for (String pkgName : pkgList) { 3790 if (mRankerServicePackageName.equals(pkgName)) { 3791 registerRanker(); 3792 } 3793 } 3794 } 3795 } 3796 3797 protected void registerRanker() { 3798 // Find the updatable ranker and register it. 3799 if (mRankerServicePackageName == null) { 3800 Slog.w(TAG, "could not start ranker service: no package specified!"); 3801 return; 3802 } 3803 Set<ComponentName> rankerComponents = queryPackageForServices( 3804 mRankerServicePackageName, UserHandle.USER_SYSTEM); 3805 Iterator<ComponentName> iterator = rankerComponents.iterator(); 3806 if (iterator.hasNext()) { 3807 ComponentName rankerComponent = iterator.next(); 3808 if (iterator.hasNext()) { 3809 Slog.e(TAG, "found multiple ranker services:" + rankerComponents); 3810 } else { 3811 registerSystemService(rankerComponent, UserHandle.USER_SYSTEM); 3812 } 3813 } else { 3814 Slog.w(TAG, "could not start ranker service: none found"); 3815 } 3816 } 3817 } 3818 3819 public class NotificationListeners extends ManagedServices { 3820 3821 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>(); 3822 3823 public NotificationListeners() { 3824 super(getContext(), mHandler, mNotificationList, mUserProfiles); 3825 } 3826 3827 @Override 3828 protected Config getConfig() { 3829 Config c = new Config(); 3830 c.caption = "notification listener"; 3831 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE; 3832 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS; 3833 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE; 3834 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS; 3835 c.clientLabel = R.string.notification_listener_binding_label; 3836 return c; 3837 } 3838 3839 @Override 3840 protected IInterface asInterface(IBinder binder) { 3841 return INotificationListener.Stub.asInterface(binder); 3842 } 3843 3844 @Override 3845 protected boolean checkType(IInterface service) { 3846 return service instanceof INotificationListener; 3847 } 3848 3849 @Override 3850 public void onServiceAdded(ManagedServiceInfo info) { 3851 final INotificationListener listener = (INotificationListener) info.service; 3852 final NotificationRankingUpdate update; 3853 synchronized (mNotificationList) { 3854 update = makeRankingUpdateLocked(info); 3855 } 3856 try { 3857 listener.onListenerConnected(update); 3858 } catch (RemoteException e) { 3859 // we tried 3860 } 3861 } 3862 3863 @Override 3864 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { 3865 if (removeDisabledHints(removed)) { 3866 updateListenerHintsLocked(); 3867 updateEffectsSuppressorLocked(); 3868 } 3869 mLightTrimListeners.remove(removed); 3870 } 3871 3872 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) { 3873 if (trim == TRIM_LIGHT) { 3874 mLightTrimListeners.add(info); 3875 } else { 3876 mLightTrimListeners.remove(info); 3877 } 3878 } 3879 3880 public int getOnNotificationPostedTrim(ManagedServiceInfo info) { 3881 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL; 3882 } 3883 3884 /** 3885 * asynchronously notify all listeners about a new notification 3886 * 3887 * <p> 3888 * Also takes care of removing a notification that has been visible to a listener before, 3889 * but isn't anymore. 3890 */ 3891 public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) { 3892 // Lazily initialized snapshots of the notification. 3893 TrimCache trimCache = new TrimCache(sbn); 3894 3895 for (final ManagedServiceInfo info : mServices) { 3896 boolean sbnVisible = isVisibleToListener(sbn, info); 3897 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false; 3898 // This notification hasn't been and still isn't visible -> ignore. 3899 if (!oldSbnVisible && !sbnVisible) { 3900 continue; 3901 } 3902 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 3903 3904 // This notification became invisible -> remove the old one. 3905 if (oldSbnVisible && !sbnVisible) { 3906 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight(); 3907 mHandler.post(new Runnable() { 3908 @Override 3909 public void run() { 3910 notifyRemoved(info, oldSbnLightClone, update); 3911 } 3912 }); 3913 continue; 3914 } 3915 3916 final StatusBarNotification sbnToPost = trimCache.ForListener(info); 3917 mHandler.post(new Runnable() { 3918 @Override 3919 public void run() { 3920 notifyPosted(info, sbnToPost, update); 3921 } 3922 }); 3923 } 3924 } 3925 3926 /** 3927 * asynchronously notify all listeners about a removed notification 3928 */ 3929 public void notifyRemovedLocked(StatusBarNotification sbn) { 3930 // make a copy in case changes are made to the underlying Notification object 3931 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the 3932 // notification 3933 final StatusBarNotification sbnLight = sbn.cloneLight(); 3934 for (final ManagedServiceInfo info : mServices) { 3935 if (!isVisibleToListener(sbn, info)) { 3936 continue; 3937 } 3938 final NotificationRankingUpdate update = makeRankingUpdateLocked(info); 3939 mHandler.post(new Runnable() { 3940 @Override 3941 public void run() { 3942 notifyRemoved(info, sbnLight, update); 3943 } 3944 }); 3945 } 3946 } 3947 3948 /** 3949 * asynchronously notify all listeners about a reordering of notifications 3950 */ 3951 public void notifyRankingUpdateLocked() { 3952 for (final ManagedServiceInfo serviceInfo : mServices) { 3953 if (!serviceInfo.isEnabledForCurrentProfiles()) { 3954 continue; 3955 } 3956 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo); 3957 mHandler.post(new Runnable() { 3958 @Override 3959 public void run() { 3960 notifyRankingUpdate(serviceInfo, update); 3961 } 3962 }); 3963 } 3964 } 3965 3966 public void notifyListenerHintsChangedLocked(final int hints) { 3967 for (final ManagedServiceInfo serviceInfo : mServices) { 3968 if (!serviceInfo.isEnabledForCurrentProfiles()) { 3969 continue; 3970 } 3971 mHandler.post(new Runnable() { 3972 @Override 3973 public void run() { 3974 notifyListenerHintsChanged(serviceInfo, hints); 3975 } 3976 }); 3977 } 3978 } 3979 3980 public void notifyInterruptionFilterChanged(final int interruptionFilter) { 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 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter); 3989 } 3990 }); 3991 } 3992 } 3993 3994 private void notifyPosted(final ManagedServiceInfo info, 3995 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) { 3996 final INotificationListener listener = (INotificationListener)info.service; 3997 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 3998 try { 3999 listener.onNotificationPosted(sbnHolder, rankingUpdate); 4000 } catch (RemoteException ex) { 4001 Log.e(TAG, "unable to notify listener (posted): " + listener, ex); 4002 } 4003 } 4004 4005 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn, 4006 NotificationRankingUpdate rankingUpdate) { 4007 if (!info.enabledAndUserMatches(sbn.getUserId())) { 4008 return; 4009 } 4010 final INotificationListener listener = (INotificationListener) info.service; 4011 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); 4012 try { 4013 listener.onNotificationRemoved(sbnHolder, rankingUpdate); 4014 } catch (RemoteException ex) { 4015 Log.e(TAG, "unable to notify listener (removed): " + listener, ex); 4016 } 4017 } 4018 4019 private void notifyRankingUpdate(ManagedServiceInfo info, 4020 NotificationRankingUpdate rankingUpdate) { 4021 final INotificationListener listener = (INotificationListener) info.service; 4022 try { 4023 listener.onNotificationRankingUpdate(rankingUpdate); 4024 } catch (RemoteException ex) { 4025 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex); 4026 } 4027 } 4028 4029 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) { 4030 final INotificationListener listener = (INotificationListener) info.service; 4031 try { 4032 listener.onListenerHintsChanged(hints); 4033 } catch (RemoteException ex) { 4034 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex); 4035 } 4036 } 4037 4038 private void notifyInterruptionFilterChanged(ManagedServiceInfo info, 4039 int interruptionFilter) { 4040 final INotificationListener listener = (INotificationListener) info.service; 4041 try { 4042 listener.onInterruptionFilterChanged(interruptionFilter); 4043 } catch (RemoteException ex) { 4044 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex); 4045 } 4046 } 4047 4048 private boolean isListenerPackage(String packageName) { 4049 if (packageName == null) { 4050 return false; 4051 } 4052 // TODO: clean up locking object later 4053 synchronized (mNotificationList) { 4054 for (final ManagedServiceInfo serviceInfo : mServices) { 4055 if (packageName.equals(serviceInfo.component.getPackageName())) { 4056 return true; 4057 } 4058 } 4059 } 4060 return false; 4061 } 4062 } 4063 4064 public static final class DumpFilter { 4065 public boolean filtered = false; 4066 public String pkgFilter; 4067 public boolean zen; 4068 public long since; 4069 public boolean stats; 4070 public boolean redact = true; 4071 4072 public static DumpFilter parseFromArguments(String[] args) { 4073 final DumpFilter filter = new DumpFilter(); 4074 for (int ai = 0; ai < args.length; ai++) { 4075 final String a = args[ai]; 4076 if ("--noredact".equals(a) || "--reveal".equals(a)) { 4077 filter.redact = false; 4078 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) { 4079 if (ai < args.length-1) { 4080 ai++; 4081 filter.pkgFilter = args[ai].trim().toLowerCase(); 4082 if (filter.pkgFilter.isEmpty()) { 4083 filter.pkgFilter = null; 4084 } else { 4085 filter.filtered = true; 4086 } 4087 } 4088 } else if ("--zen".equals(a) || "zen".equals(a)) { 4089 filter.filtered = true; 4090 filter.zen = true; 4091 } else if ("--stats".equals(a)) { 4092 filter.stats = true; 4093 if (ai < args.length-1) { 4094 ai++; 4095 filter.since = Long.valueOf(args[ai]); 4096 } else { 4097 filter.since = 0; 4098 } 4099 } 4100 } 4101 return filter; 4102 } 4103 4104 public boolean matches(StatusBarNotification sbn) { 4105 if (!filtered) return true; 4106 return zen ? true : sbn != null 4107 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg())); 4108 } 4109 4110 public boolean matches(ComponentName component) { 4111 if (!filtered) return true; 4112 return zen ? true : component != null && matches(component.getPackageName()); 4113 } 4114 4115 public boolean matches(String pkg) { 4116 if (!filtered) return true; 4117 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter); 4118 } 4119 4120 @Override 4121 public String toString() { 4122 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\''); 4123 } 4124 } 4125 4126 /** 4127 * Wrapper for a StatusBarNotification object that allows transfer across a oneway 4128 * binder without sending large amounts of data over a oneway transaction. 4129 */ 4130 private static final class StatusBarNotificationHolder 4131 extends IStatusBarNotificationHolder.Stub { 4132 private StatusBarNotification mValue; 4133 4134 public StatusBarNotificationHolder(StatusBarNotification value) { 4135 mValue = value; 4136 } 4137 4138 /** Get the held value and clear it. This function should only be called once per holder */ 4139 @Override 4140 public StatusBarNotification get() { 4141 StatusBarNotification value = mValue; 4142 mValue = null; 4143 return value; 4144 } 4145 } 4146 4147 private final class PolicyAccess { 4148 private static final String SEPARATOR = ":"; 4149 private final String[] PERM = { 4150 android.Manifest.permission.ACCESS_NOTIFICATION_POLICY 4151 }; 4152 4153 public boolean isPackageGranted(String pkg) { 4154 return pkg != null && getGrantedPackages().contains(pkg); 4155 } 4156 4157 public void put(String pkg, boolean granted) { 4158 if (pkg == null) return; 4159 final ArraySet<String> pkgs = getGrantedPackages(); 4160 boolean changed; 4161 if (granted) { 4162 changed = pkgs.add(pkg); 4163 } else { 4164 changed = pkgs.remove(pkg); 4165 } 4166 if (!changed) return; 4167 final String setting = TextUtils.join(SEPARATOR, pkgs); 4168 final int currentUser = ActivityManager.getCurrentUser(); 4169 Settings.Secure.putStringForUser(getContext().getContentResolver(), 4170 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES, 4171 setting, 4172 currentUser); 4173 getContext().sendBroadcastAsUser(new Intent(NotificationManager 4174 .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED) 4175 .setPackage(pkg) 4176 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null); 4177 } 4178 4179 public ArraySet<String> getGrantedPackages() { 4180 final ArraySet<String> pkgs = new ArraySet<>(); 4181 4182 long identity = Binder.clearCallingIdentity(); 4183 try { 4184 final String setting = Settings.Secure.getStringForUser( 4185 getContext().getContentResolver(), 4186 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES, 4187 ActivityManager.getCurrentUser()); 4188 if (setting != null) { 4189 final String[] tokens = setting.split(SEPARATOR); 4190 for (int i = 0; i < tokens.length; i++) { 4191 String token = tokens[i]; 4192 if (token != null) { 4193 token = token.trim(); 4194 } 4195 if (TextUtils.isEmpty(token)) { 4196 continue; 4197 } 4198 pkgs.add(token); 4199 } 4200 } 4201 } finally { 4202 Binder.restoreCallingIdentity(identity); 4203 } 4204 return pkgs; 4205 } 4206 4207 public String[] getRequestingPackages() throws RemoteException { 4208 final ParceledListSlice list = AppGlobals.getPackageManager() 4209 .getPackagesHoldingPermissions(PERM, 0 /*flags*/, 4210 ActivityManager.getCurrentUser()); 4211 final List<PackageInfo> pkgs = list.getList(); 4212 if (pkgs == null || pkgs.isEmpty()) return new String[0]; 4213 final int N = pkgs.size(); 4214 final String[] rt = new String[N]; 4215 for (int i = 0; i < N; i++) { 4216 rt[i] = pkgs.get(i).packageName; 4217 } 4218 return rt; 4219 } 4220 } 4221} 4222