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