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