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