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