/** Called when a notification has been updated. */ public void registerUpdatedByApp(NotificationRecord notification, NotificationRecord old) { notification.stats = old.stats; AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification); for (AggregatedStats stats : aggregatedStatsArray) { stats.numUpdatedByApp++; stats.countApiUse(notification); } releaseAggregatedStatsLocked(aggregatedStatsArray); }
/** Called when the user clicked the notification in the UI. */ public synchronized void registerClickedByUser(NotificationRecord notification) { MetricsLogger.histogram( mContext, "note_click_longevity", (int) (System.currentTimeMillis() - notification.getRankingTimeMs()) / (60 * 1000)); notification.stats.onClick(); if (ENABLE_SQLITE_LOG) { mSQLiteLog.logClicked(notification); } }
private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete) { // tell the app if (sendDelete) { if (r.notification.deleteIntent != null) { try { r.notification.deleteIntent.send(); } catch (PendingIntent.CanceledException ex) { // do nothing - there's no relevant way to recover, and // no reason to let this propagate Slog.w(TAG, "canceled PendingIntent for " + r.pkg, ex); } } } // status bar if (r.notification.icon != 0) { long identity = Binder.clearCallingIdentity(); try { mStatusBar.removeNotification(r.statusBarKey); } finally { Binder.restoreCallingIdentity(identity); } r.statusBarKey = null; } // sound if (mSoundNotification == r) { mSoundNotification = null; long identity = Binder.clearCallingIdentity(); try { mSound.stop(); } finally { Binder.restoreCallingIdentity(identity); } } // vibrate if (mVibrateNotification == r) { mVibrateNotification = null; long identity = Binder.clearCallingIdentity(); try { mVibrator.cancel(); } finally { Binder.restoreCallingIdentity(identity); } } // light mLights.remove(r); if (mLedNotification == r) { mLedNotification = null; } }
/** Called when a notification has been posted. */ public synchronized void registerPostedByApp(NotificationRecord notification) { notification.stats = new SingleNotificationStats(); notification.stats.posttimeElapsedMs = SystemClock.elapsedRealtime(); AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification); for (AggregatedStats stats : aggregatedStatsArray) { stats.numPostedByApp++; stats.countApiUse(notification); } releaseAggregatedStatsLocked(aggregatedStatsArray); if (ENABLE_SQLITE_LOG) { mSQLiteLog.logPosted(notification); } }
private static void putNotificationDetails(NotificationRecord r, ContentValues outCv) { outCv.put(COL_NOTIFICATION_ID, r.sbn.getId()); if (r.sbn.getTag() != null) { outCv.put(COL_TAG, r.sbn.getTag()); } outCv.put(COL_WHEN_MS, r.sbn.getPostTime()); outCv.put(COL_FLAGS, r.getNotification().flags); outCv.put(COL_PRIORITY, r.getNotification().priority); if (r.getNotification().category != null) { outCv.put(COL_CATEGORY, r.getNotification().category); } outCv.put( COL_ACTION_COUNT, r.getNotification().actions != null ? r.getNotification().actions.length : 0); }
public void enqueueNotificationInternal( String pkg, int callingUid, int callingPid, String tag, int id, int priority, Notification notification, int[] idOut) { checkIncomingCall(pkg); // Limit the number of notifications that any given package except the android // package can enqueue. Prevents DOS attacks and deals with leaks. if (!"android".equals(pkg)) { synchronized (mNotificationList) { int count = 0; final int N = mNotificationList.size(); for (int i = 0; i < N; i++) { final NotificationRecord r = mNotificationList.get(i); if (r.pkg.equals(pkg)) { count++; if (count >= MAX_PACKAGE_NOTIFICATIONS) { Slog.e( TAG, "Package has already posted " + count + " notifications. Not showing more. package=" + pkg); return; } } } } } // This conditional is a dirty hack to limit the logging done on // behalf of the download manager without affecting other apps. if (!pkg.equals("com.android.providers.downloads") || Log.isLoggable("DownloadManager", Log.VERBOSE)) { EventLog.writeEvent(EventLogTags.NOTIFICATION_ENQUEUE, pkg, id, notification.toString()); } if (pkg == null || notification == null) { throw new IllegalArgumentException( "null not allowed: pkg=" + pkg + " id=" + id + " notification=" + notification); } if (notification.icon != 0) { if (notification.contentView == null) { throw new IllegalArgumentException( "contentView required: pkg=" + pkg + " id=" + id + " notification=" + notification); } } synchronized (mNotificationList) { NotificationRecord r = new NotificationRecord(pkg, tag, id, callingUid, callingPid, priority, notification); NotificationRecord old = null; int index = indexOfNotificationLocked(pkg, tag, id); if (index < 0) { mNotificationList.add(r); } else { old = mNotificationList.remove(index); mNotificationList.add(index, r); // Make sure we don't lose the foreground service state. if (old != null) { notification.flags |= old.notification.flags & Notification.FLAG_FOREGROUND_SERVICE; } } // Ensure if this is a foreground service that the proper additional // flags are set. if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) { notification.flags |= Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR; } if (notification.icon != 0) { StatusBarNotification n = new StatusBarNotification(pkg, id, tag, r.uid, r.initialPid, notification); n.priority = r.priority; if (old != null && old.statusBarKey != null) { r.statusBarKey = old.statusBarKey; long identity = Binder.clearCallingIdentity(); try { mStatusBar.updateNotification(r.statusBarKey, n); } finally { Binder.restoreCallingIdentity(identity); } } else { long identity = Binder.clearCallingIdentity(); try { r.statusBarKey = mStatusBar.addNotification(n); mAttentionLight.pulse(); } finally { Binder.restoreCallingIdentity(identity); } } sendAccessibilityEvent(notification, pkg); } else { Slog.e(TAG, "Ignoring notification with icon==0: " + notification); if (old != null && old.statusBarKey != null) { long identity = Binder.clearCallingIdentity(); try { mStatusBar.removeNotification(old.statusBarKey); } finally { Binder.restoreCallingIdentity(identity); } } } // If we're not supposed to beep, vibrate, etc. then don't. if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0) && (!(old != null && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) && mSystemReady) { final AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); // sound final boolean useDefaultSound = (notification.defaults & Notification.DEFAULT_SOUND) != 0; if (useDefaultSound || notification.sound != null) { Uri uri; if (useDefaultSound) { uri = Settings.System.DEFAULT_NOTIFICATION_URI; } else { uri = notification.sound; } boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0; int audioStreamType; if (notification.audioStreamType >= 0) { audioStreamType = notification.audioStreamType; } else { audioStreamType = DEFAULT_STREAM_TYPE; } mSoundNotification = r; // do not play notifications if stream volume is 0 // (typically because ringer mode is silent). if (audioManager.getStreamVolume(audioStreamType) != 0) { long identity = Binder.clearCallingIdentity(); try { mSound.play(mContext, uri, looping, audioStreamType); } finally { Binder.restoreCallingIdentity(identity); } } } // vibrate final boolean useDefaultVibrate = (notification.defaults & Notification.DEFAULT_VIBRATE) != 0; if ((useDefaultVibrate || notification.vibrate != null) && audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_NOTIFICATION)) { mVibrateNotification = r; mVibrator.vibrate( useDefaultVibrate ? DEFAULT_VIBRATE_PATTERN : notification.vibrate, ((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0 : -1); } } // this option doesn't shut off the lights // light // the most recent thing gets the light mLights.remove(old); if (mLedNotification == old) { mLedNotification = null; } // Slog.i(TAG, "notification.lights=" // + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS) != 0)); if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) { mLights.add(r); updateLightsLocked(); } else { if (old != null && ((old.notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0)) { updateLightsLocked(); } } } idOut[0] = id; }
public void countApiUse(NotificationRecord record) { final Notification n = record.getNotification(); if (n.actions != null) { numWithActions++; } if ((n.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) { numForegroundService++; } if ((n.flags & Notification.FLAG_ONGOING_EVENT) != 0) { numOngoing++; } if ((n.flags & Notification.FLAG_AUTO_CANCEL) != 0) { numAutoCancel++; } if ((n.defaults & Notification.DEFAULT_SOUND) != 0 || (n.defaults & Notification.DEFAULT_VIBRATE) != 0 || n.sound != null || n.vibrate != null) { numInterrupt++; } switch (n.visibility) { case Notification.VISIBILITY_PRIVATE: numPrivate++; break; case Notification.VISIBILITY_SECRET: numSecret++; break; } switch (n.priority) { case Notification.PRIORITY_MAX: numPriorityMax++; break; case Notification.PRIORITY_HIGH: numPriorityHigh++; break; case Notification.PRIORITY_LOW: numPriorityLow++; break; case Notification.PRIORITY_MIN: numPriorityMin++; break; } for (String Key : n.extras.keySet()) { if (Notification.EXTRA_BIG_TEXT.equals(key)) { numWithBigText++; } else if (Notification.EXTRA_PICTURE.equals(key)) { numWithBigPicture++; } else if (Notification.EXTRA_LARGE_ICON.equals(key)) { numWithLargeIcon++; } else if (Notification.EXTRA_TEXT_LINES.equals(key)) { numWithInbox++; } else if (Notification.EXTRA_MEDIA_SESSION.equals(key)) { numWithMediaSession++; } else if (Notification.EXTRA_TITLE.equals(key)) { numWithTitle++; } else if (Notification.EXTRA_TEXT.equals(key)) { numWithText++; } else if (Notification.EXTRA_SUB_TEXT.equals(key)) { numWithSubText++; } else if (Notification.EXTRA_INFO_TEXT.equals(key)) { numWithInfoText++; } } }