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