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