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