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