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