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