Loading core/java/android/app/INotificationManager.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.app.ITransientNotification; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; import android.app.NotificationHistory; import android.app.NotificationManager; import android.content.ComponentName; import android.content.Intent; Loading Loading @@ -119,6 +120,8 @@ interface INotificationManager @UnsupportedAppUsage StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count); NotificationHistory getNotificationHistory(String callingPkg); void registerListener(in INotificationListener listener, in ComponentName component, int userid); void unregisterListener(in INotificationListener listener, int userid); Loading services/core/java/com/android/server/notification/NotificationHistoryDatabase.java +1 −0 Original line number Diff line number Diff line Loading @@ -183,6 +183,7 @@ public class NotificationHistoryDatabase { public NotificationHistory readNotificationHistory() { synchronized (mLock) { NotificationHistory notifications = new NotificationHistory(); notifications.addNotificationsToWrite(mBuffer); for (AtomicFile file : mHistoryFiles) { try { Loading services/core/java/com/android/server/notification/NotificationHistoryManager.java +5 −4 Original line number Diff line number Diff line Loading @@ -112,7 +112,7 @@ public class NotificationHistoryManager { } } void onUserRemoved(@UserIdInt int userId) { public void onUserRemoved(@UserIdInt int userId) { synchronized (mLock) { // Actual data deletion is handled by other parts of the system (the entire directory is // removed) - we just need clean up our internal state for GC Loading @@ -122,7 +122,7 @@ public class NotificationHistoryManager { } } void onPackageRemoved(int userId, String packageName) { public void onPackageRemoved(int userId, String packageName) { synchronized (mLock) { if (!mUserUnlockedStates.get(userId, false)) { if (mHistoryEnabled.get(userId, false)) { Loading @@ -142,7 +142,8 @@ public class NotificationHistoryManager { } } void triggerWriteToDisk() { // TODO: wire this up to AMS when power button is long pressed public void triggerWriteToDisk() { synchronized (mLock) { final int userCount = mUserState.size(); for (int i = 0; i < userCount; i++) { Loading Loading @@ -204,7 +205,7 @@ public class NotificationHistoryManager { } } public boolean isHistoryEnabled(@UserIdInt int userId) { boolean isHistoryEnabled(@UserIdInt int userId) { synchronized (mLock) { return mHistoryEnabled.get(userId); } Loading services/core/java/com/android/server/notification/NotificationManagerService.java +126 −20 Original line number Diff line number Diff line Loading @@ -103,6 +103,8 @@ import android.Manifest.permission; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.WorkerThread; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AlarmManager; Loading @@ -116,6 +118,8 @@ import android.app.IUriGrantsManager; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; import android.app.NotificationHistory; import android.app.NotificationHistory.HistoricalNotification; import android.app.NotificationManager; import android.app.NotificationManager.Policy; import android.app.PendingIntent; Loading Loading @@ -160,6 +164,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.HandlerExecutor; import android.os.HandlerThread; import android.os.IBinder; import android.os.IDeviceIdleController; Loading Loading @@ -477,12 +482,14 @@ public class NotificationManagerService extends SystemService { private long mLastOverRateLogTime; private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE; private NotificationHistoryManager mHistoryManager; private SnoozeHelper mSnoozeHelper; private GroupHelper mGroupHelper; private int mAutoGroupAtCount; private boolean mIsTelevision; private boolean mIsAutomotive; private boolean mNotificationEffectsEnabledForAutomotive; private DeviceConfig.OnPropertiesChangedListener mDeviceConfigChangedListener; private int mWarnRemoteViewsSizeBytes; private int mStripRemoteViewsSizeBytes; Loading Loading @@ -1547,6 +1554,7 @@ public class NotificationManagerService extends SystemService { mListeners.onUserRemoved(userId); mConditionProviders.onUserRemoved(userId); mAssistants.onUserRemoved(userId); mHistoryManager.onUserRemoved(userId); handleSavePolicyFile(); } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) { final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL); Loading Loading @@ -1775,8 +1783,8 @@ public class NotificationManagerService extends SystemService { // TODO: All tests should use this init instead of the one-off setters above. @VisibleForTesting void init(Looper looper, RankingHandler rankingHandler, IPackageManager packageManager, PackageManager packageManagerClient, void init(WorkerHandler handler, RankingHandler rankingHandler, IPackageManager packageManager, PackageManager packageManagerClient, LightsManager lightsManager, NotificationListeners notificationListeners, NotificationAssistants notificationAssistants, ConditionProviders conditionProviders, ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper, Loading @@ -1784,7 +1792,8 @@ public class NotificationManagerService extends SystemService { ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am, UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm, IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, UserManager userManager) { UserManager userManager, NotificationHistoryManager historyManager) { mHandler = handler; Resources resources = getContext().getResources(); mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(), Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, Loading @@ -1810,7 +1819,6 @@ public class NotificationManagerService extends SystemService { mPlatformCompat = IPlatformCompat.Stub.asInterface( ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); mHandler = new WorkerHandler(looper); mUiHandler = new Handler(UiThread.get().getLooper()); String[] extractorNames; try { Loading Loading @@ -1869,6 +1877,7 @@ public class NotificationManagerService extends SystemService { extractorNames); mSnoozeHelper = snoozeHelper; mGroupHelper = groupHelper; mHistoryManager = historyManager; // This is a ManagedServices object that keeps track of the listeners. mListeners = notificationListeners; Loading Loading @@ -1966,7 +1975,9 @@ public class NotificationManagerService extends SystemService { final File systemDir = new File(Environment.getDataDirectory(), "system"); mRankingThread.start(); init(Looper.myLooper(), new RankingHandlerWorker(mRankingThread.getLooper()), WorkerHandler handler = new WorkerHandler(Looper.myLooper()); init(handler, new RankingHandlerWorker(mRankingThread.getLooper()), AppGlobals.getPackageManager(), getContext().getPackageManager(), getLocalService(LightsManager.class), new NotificationListeners(AppGlobals.getPackageManager()), Loading @@ -1983,7 +1994,8 @@ public class NotificationManagerService extends SystemService { UriGrantsManager.getService(), LocalServices.getService(UriGrantsManagerInternal.class), (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE), getContext().getSystemService(UserManager.class)); getContext().getSystemService(UserManager.class), new NotificationHistoryManager(getContext(), handler)); // register for various Intents IntentFilter filter = new IntentFilter(); Loading Loading @@ -2036,10 +2048,7 @@ public class NotificationManagerService extends SystemService { } private void registerDeviceConfigChange() { DeviceConfig.addOnPropertiesChangedListener( DeviceConfig.NAMESPACE_SYSTEMUI, getContext().getMainExecutor(), (properties) -> { mDeviceConfigChangedListener = properties -> { if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(properties.getNamespace())) { return; } Loading @@ -2048,7 +2057,17 @@ public class NotificationManagerService extends SystemService { mAssistants.allowAdjustmentType(Adjustment.KEY_IMPORTANCE); mAssistants.resetDefaultAssistantsIfNecessary(); } }); }; DeviceConfig.addOnPropertiesChangedListener( DeviceConfig.NAMESPACE_SYSTEMUI, new HandlerExecutor(mHandler), mDeviceConfigChangedListener); } void unregisterDeviceConfigChange() { if (mDeviceConfigChangedListener != null) { DeviceConfig.removeOnPropertiesChangedListener(mDeviceConfigChangedListener); } } private GroupHelper getGroupHelper() { Loading Loading @@ -2134,10 +2153,21 @@ public class NotificationManagerService extends SystemService { mListeners.onBootPhaseAppsCanStart(); mAssistants.onBootPhaseAppsCanStart(); mConditionProviders.onBootPhaseAppsCanStart(); mHistoryManager.onBootPhaseAppsCanStart(); registerDeviceConfigChange(); } } @Override public void onUnlockUser(@NonNull UserInfo userInfo) { mHandler.post(() -> mHistoryManager.onUserUnlocked(userInfo.id)); } @Override public void onStopUser(@NonNull UserInfo userInfo) { mHandler.post(() -> mHistoryManager.onUserStopped(userInfo.id)); } @GuardedBy("mNotificationLock") private void updateListenerHintsLocked() { final int hints = calculateHints(); Loading Loading @@ -2449,10 +2479,56 @@ public class NotificationManagerService extends SystemService { mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(), r.getChannel().getId(), getRealUserId(r.sbn.getUserId())); mHistoryManager.addNotification(new HistoricalNotification.Builder() .setPackage(r.sbn.getPackageName()) .setUid(r.sbn.getUid()) .setChannelId(r.getChannel().getId()) .setChannelName(r.getChannel().getName().toString()) .setPostedTimeMs(r.sbn.getPostTime()) .setTitle(getHistoryTitle(r.getNotification())) .setText(getHistoryText( r.sbn.getPackageContext(getContext()), r.getNotification())) .setIcon(r.getNotification().getSmallIcon()) .build()); r.setRecordedInterruption(true); } } private String getHistoryTitle(Notification n) { CharSequence title = null; if (n.extras != null) { title = n.extras.getCharSequence(Notification.EXTRA_TITLE); } return title == null? null : String.valueOf(title); } /** * Returns the appropriate substring for this notification based on the style of notification. */ private String getHistoryText(Context appContext, Notification n) { CharSequence text = null; if (n.extras != null) { text = n.extras.getCharSequence(Notification.EXTRA_TEXT); Notification.Builder nb = Notification.Builder.recoverBuilder(appContext, n); if (nb.getStyle() instanceof Notification.BigTextStyle) { text = ((Notification.BigTextStyle) nb.getStyle()).getBigText(); } else if (nb.getStyle() instanceof Notification.MessagingStyle) { Notification.MessagingStyle ms = (Notification.MessagingStyle) nb.getStyle(); final List<Notification.MessagingStyle.Message> messages = ms.getMessages(); if (messages != null && messages.size() > 0) { text = messages.get(messages.size() - 1).getText(); } } if (TextUtils.isEmpty(text)) { text = n.extras.getCharSequence(Notification.EXTRA_TEXT); } } return text == null ? null : String.valueOf(text); } /** * Report to usage stats that the user interacted with the notification. * @param r notification record Loading Loading @@ -3343,10 +3419,9 @@ public class NotificationManagerService extends SystemService { /** * System-only API for getting a list of recent (cleared, no longer shown) notifications. * * Requires ACCESS_NOTIFICATIONS which is signature|system. */ @Override @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS) public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) { // enforce() will ensure the calling uid has the correct permission getContext().enforceCallingOrSelfPermission( Loading @@ -3366,6 +3441,29 @@ public class NotificationManagerService extends SystemService { return tmp; } /** * System-only API for getting a list of historical notifications. May contain multiple days * of notifications. */ @Override @WorkerThread @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS) public NotificationHistory getNotificationHistory(String callingPkg) { // enforce() will ensure the calling uid has the correct permission getContext().enforceCallingOrSelfPermission( android.Manifest.permission.ACCESS_NOTIFICATIONS, "NotificationManagerService.getNotificationHistory"); int uid = Binder.getCallingUid(); // noteOp will check to make sure the callingPkg matches the uid if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg) == AppOpsManager.MODE_ALLOWED) { IntArray currentUserIds = mUserProfiles.getCurrentProfileIds(); return mHistoryManager.readNotificationHistory(currentUserIds.toArray()); } return new NotificationHistory(); } /** * Register a listener binder directly with the notification manager. * Loading Loading @@ -6831,7 +6929,7 @@ public class NotificationManagerService extends SystemService { } } private void handleOnPackageChanged(boolean removingPackage, int changeUserId, void handleOnPackageChanged(boolean removingPackage, int changeUserId, String[] pkgList, int[] uidList) { boolean preferencesChanged = removingPackage; mListeners.onPackagesChanged(removingPackage, pkgList, uidList); Loading @@ -6839,6 +6937,14 @@ public class NotificationManagerService extends SystemService { mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList); preferencesChanged |= mPreferencesHelper.onPackagesChanged( removingPackage, changeUserId, pkgList, uidList); if (removingPackage) { int size = Math.min(pkgList.length, uidList.length); for (int i = 0; i < size; i++) { final String pkg = pkgList[i]; final int uid = uidList[i]; mHistoryManager.onPackageRemoved(UserHandle.getUserId(uid), pkg); } } if (preferencesChanged) { handleSavePolicyFile(); } Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java +11 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.AlarmManager; import android.app.NotificationHistory; import android.app.NotificationHistory.HistoricalNotification; import android.content.Context; import android.graphics.drawable.Icon; Loading Loading @@ -198,6 +199,16 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase { } } @Test public void testReadNotificationHistory_readsBuffer() throws Exception { HistoricalNotification hn = getHistoricalNotification(1); mDataBase.addNotification(hn); NotificationHistory nh = mDataBase.readNotificationHistory(); assertThat(nh.getNotificationsToWrite()).contains(hn); } @Test public void testReadNotificationHistory_withNumFilterDoesNotReadExtraFiles() throws Exception { AtomicFile af = mock(AtomicFile.class); Loading Loading
core/java/android/app/INotificationManager.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.app.ITransientNotification; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; import android.app.NotificationHistory; import android.app.NotificationManager; import android.content.ComponentName; import android.content.Intent; Loading Loading @@ -119,6 +120,8 @@ interface INotificationManager @UnsupportedAppUsage StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count); NotificationHistory getNotificationHistory(String callingPkg); void registerListener(in INotificationListener listener, in ComponentName component, int userid); void unregisterListener(in INotificationListener listener, int userid); Loading
services/core/java/com/android/server/notification/NotificationHistoryDatabase.java +1 −0 Original line number Diff line number Diff line Loading @@ -183,6 +183,7 @@ public class NotificationHistoryDatabase { public NotificationHistory readNotificationHistory() { synchronized (mLock) { NotificationHistory notifications = new NotificationHistory(); notifications.addNotificationsToWrite(mBuffer); for (AtomicFile file : mHistoryFiles) { try { Loading
services/core/java/com/android/server/notification/NotificationHistoryManager.java +5 −4 Original line number Diff line number Diff line Loading @@ -112,7 +112,7 @@ public class NotificationHistoryManager { } } void onUserRemoved(@UserIdInt int userId) { public void onUserRemoved(@UserIdInt int userId) { synchronized (mLock) { // Actual data deletion is handled by other parts of the system (the entire directory is // removed) - we just need clean up our internal state for GC Loading @@ -122,7 +122,7 @@ public class NotificationHistoryManager { } } void onPackageRemoved(int userId, String packageName) { public void onPackageRemoved(int userId, String packageName) { synchronized (mLock) { if (!mUserUnlockedStates.get(userId, false)) { if (mHistoryEnabled.get(userId, false)) { Loading @@ -142,7 +142,8 @@ public class NotificationHistoryManager { } } void triggerWriteToDisk() { // TODO: wire this up to AMS when power button is long pressed public void triggerWriteToDisk() { synchronized (mLock) { final int userCount = mUserState.size(); for (int i = 0; i < userCount; i++) { Loading Loading @@ -204,7 +205,7 @@ public class NotificationHistoryManager { } } public boolean isHistoryEnabled(@UserIdInt int userId) { boolean isHistoryEnabled(@UserIdInt int userId) { synchronized (mLock) { return mHistoryEnabled.get(userId); } Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +126 −20 Original line number Diff line number Diff line Loading @@ -103,6 +103,8 @@ import android.Manifest.permission; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.WorkerThread; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AlarmManager; Loading @@ -116,6 +118,8 @@ import android.app.IUriGrantsManager; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; import android.app.NotificationHistory; import android.app.NotificationHistory.HistoricalNotification; import android.app.NotificationManager; import android.app.NotificationManager.Policy; import android.app.PendingIntent; Loading Loading @@ -160,6 +164,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.HandlerExecutor; import android.os.HandlerThread; import android.os.IBinder; import android.os.IDeviceIdleController; Loading Loading @@ -477,12 +482,14 @@ public class NotificationManagerService extends SystemService { private long mLastOverRateLogTime; private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE; private NotificationHistoryManager mHistoryManager; private SnoozeHelper mSnoozeHelper; private GroupHelper mGroupHelper; private int mAutoGroupAtCount; private boolean mIsTelevision; private boolean mIsAutomotive; private boolean mNotificationEffectsEnabledForAutomotive; private DeviceConfig.OnPropertiesChangedListener mDeviceConfigChangedListener; private int mWarnRemoteViewsSizeBytes; private int mStripRemoteViewsSizeBytes; Loading Loading @@ -1547,6 +1554,7 @@ public class NotificationManagerService extends SystemService { mListeners.onUserRemoved(userId); mConditionProviders.onUserRemoved(userId); mAssistants.onUserRemoved(userId); mHistoryManager.onUserRemoved(userId); handleSavePolicyFile(); } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) { final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL); Loading Loading @@ -1775,8 +1783,8 @@ public class NotificationManagerService extends SystemService { // TODO: All tests should use this init instead of the one-off setters above. @VisibleForTesting void init(Looper looper, RankingHandler rankingHandler, IPackageManager packageManager, PackageManager packageManagerClient, void init(WorkerHandler handler, RankingHandler rankingHandler, IPackageManager packageManager, PackageManager packageManagerClient, LightsManager lightsManager, NotificationListeners notificationListeners, NotificationAssistants notificationAssistants, ConditionProviders conditionProviders, ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper, Loading @@ -1784,7 +1792,8 @@ public class NotificationManagerService extends SystemService { ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am, UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm, IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, UserManager userManager) { UserManager userManager, NotificationHistoryManager historyManager) { mHandler = handler; Resources resources = getContext().getResources(); mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(), Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, Loading @@ -1810,7 +1819,6 @@ public class NotificationManagerService extends SystemService { mPlatformCompat = IPlatformCompat.Stub.asInterface( ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); mHandler = new WorkerHandler(looper); mUiHandler = new Handler(UiThread.get().getLooper()); String[] extractorNames; try { Loading Loading @@ -1869,6 +1877,7 @@ public class NotificationManagerService extends SystemService { extractorNames); mSnoozeHelper = snoozeHelper; mGroupHelper = groupHelper; mHistoryManager = historyManager; // This is a ManagedServices object that keeps track of the listeners. mListeners = notificationListeners; Loading Loading @@ -1966,7 +1975,9 @@ public class NotificationManagerService extends SystemService { final File systemDir = new File(Environment.getDataDirectory(), "system"); mRankingThread.start(); init(Looper.myLooper(), new RankingHandlerWorker(mRankingThread.getLooper()), WorkerHandler handler = new WorkerHandler(Looper.myLooper()); init(handler, new RankingHandlerWorker(mRankingThread.getLooper()), AppGlobals.getPackageManager(), getContext().getPackageManager(), getLocalService(LightsManager.class), new NotificationListeners(AppGlobals.getPackageManager()), Loading @@ -1983,7 +1994,8 @@ public class NotificationManagerService extends SystemService { UriGrantsManager.getService(), LocalServices.getService(UriGrantsManagerInternal.class), (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE), getContext().getSystemService(UserManager.class)); getContext().getSystemService(UserManager.class), new NotificationHistoryManager(getContext(), handler)); // register for various Intents IntentFilter filter = new IntentFilter(); Loading Loading @@ -2036,10 +2048,7 @@ public class NotificationManagerService extends SystemService { } private void registerDeviceConfigChange() { DeviceConfig.addOnPropertiesChangedListener( DeviceConfig.NAMESPACE_SYSTEMUI, getContext().getMainExecutor(), (properties) -> { mDeviceConfigChangedListener = properties -> { if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(properties.getNamespace())) { return; } Loading @@ -2048,7 +2057,17 @@ public class NotificationManagerService extends SystemService { mAssistants.allowAdjustmentType(Adjustment.KEY_IMPORTANCE); mAssistants.resetDefaultAssistantsIfNecessary(); } }); }; DeviceConfig.addOnPropertiesChangedListener( DeviceConfig.NAMESPACE_SYSTEMUI, new HandlerExecutor(mHandler), mDeviceConfigChangedListener); } void unregisterDeviceConfigChange() { if (mDeviceConfigChangedListener != null) { DeviceConfig.removeOnPropertiesChangedListener(mDeviceConfigChangedListener); } } private GroupHelper getGroupHelper() { Loading Loading @@ -2134,10 +2153,21 @@ public class NotificationManagerService extends SystemService { mListeners.onBootPhaseAppsCanStart(); mAssistants.onBootPhaseAppsCanStart(); mConditionProviders.onBootPhaseAppsCanStart(); mHistoryManager.onBootPhaseAppsCanStart(); registerDeviceConfigChange(); } } @Override public void onUnlockUser(@NonNull UserInfo userInfo) { mHandler.post(() -> mHistoryManager.onUserUnlocked(userInfo.id)); } @Override public void onStopUser(@NonNull UserInfo userInfo) { mHandler.post(() -> mHistoryManager.onUserStopped(userInfo.id)); } @GuardedBy("mNotificationLock") private void updateListenerHintsLocked() { final int hints = calculateHints(); Loading Loading @@ -2449,10 +2479,56 @@ public class NotificationManagerService extends SystemService { mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(), r.getChannel().getId(), getRealUserId(r.sbn.getUserId())); mHistoryManager.addNotification(new HistoricalNotification.Builder() .setPackage(r.sbn.getPackageName()) .setUid(r.sbn.getUid()) .setChannelId(r.getChannel().getId()) .setChannelName(r.getChannel().getName().toString()) .setPostedTimeMs(r.sbn.getPostTime()) .setTitle(getHistoryTitle(r.getNotification())) .setText(getHistoryText( r.sbn.getPackageContext(getContext()), r.getNotification())) .setIcon(r.getNotification().getSmallIcon()) .build()); r.setRecordedInterruption(true); } } private String getHistoryTitle(Notification n) { CharSequence title = null; if (n.extras != null) { title = n.extras.getCharSequence(Notification.EXTRA_TITLE); } return title == null? null : String.valueOf(title); } /** * Returns the appropriate substring for this notification based on the style of notification. */ private String getHistoryText(Context appContext, Notification n) { CharSequence text = null; if (n.extras != null) { text = n.extras.getCharSequence(Notification.EXTRA_TEXT); Notification.Builder nb = Notification.Builder.recoverBuilder(appContext, n); if (nb.getStyle() instanceof Notification.BigTextStyle) { text = ((Notification.BigTextStyle) nb.getStyle()).getBigText(); } else if (nb.getStyle() instanceof Notification.MessagingStyle) { Notification.MessagingStyle ms = (Notification.MessagingStyle) nb.getStyle(); final List<Notification.MessagingStyle.Message> messages = ms.getMessages(); if (messages != null && messages.size() > 0) { text = messages.get(messages.size() - 1).getText(); } } if (TextUtils.isEmpty(text)) { text = n.extras.getCharSequence(Notification.EXTRA_TEXT); } } return text == null ? null : String.valueOf(text); } /** * Report to usage stats that the user interacted with the notification. * @param r notification record Loading Loading @@ -3343,10 +3419,9 @@ public class NotificationManagerService extends SystemService { /** * System-only API for getting a list of recent (cleared, no longer shown) notifications. * * Requires ACCESS_NOTIFICATIONS which is signature|system. */ @Override @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS) public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) { // enforce() will ensure the calling uid has the correct permission getContext().enforceCallingOrSelfPermission( Loading @@ -3366,6 +3441,29 @@ public class NotificationManagerService extends SystemService { return tmp; } /** * System-only API for getting a list of historical notifications. May contain multiple days * of notifications. */ @Override @WorkerThread @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS) public NotificationHistory getNotificationHistory(String callingPkg) { // enforce() will ensure the calling uid has the correct permission getContext().enforceCallingOrSelfPermission( android.Manifest.permission.ACCESS_NOTIFICATIONS, "NotificationManagerService.getNotificationHistory"); int uid = Binder.getCallingUid(); // noteOp will check to make sure the callingPkg matches the uid if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg) == AppOpsManager.MODE_ALLOWED) { IntArray currentUserIds = mUserProfiles.getCurrentProfileIds(); return mHistoryManager.readNotificationHistory(currentUserIds.toArray()); } return new NotificationHistory(); } /** * Register a listener binder directly with the notification manager. * Loading Loading @@ -6831,7 +6929,7 @@ public class NotificationManagerService extends SystemService { } } private void handleOnPackageChanged(boolean removingPackage, int changeUserId, void handleOnPackageChanged(boolean removingPackage, int changeUserId, String[] pkgList, int[] uidList) { boolean preferencesChanged = removingPackage; mListeners.onPackagesChanged(removingPackage, pkgList, uidList); Loading @@ -6839,6 +6937,14 @@ public class NotificationManagerService extends SystemService { mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList); preferencesChanged |= mPreferencesHelper.onPackagesChanged( removingPackage, changeUserId, pkgList, uidList); if (removingPackage) { int size = Math.min(pkgList.length, uidList.length); for (int i = 0; i < size; i++) { final String pkg = pkgList[i]; final int uid = uidList[i]; mHistoryManager.onPackageRemoved(UserHandle.getUserId(uid), pkg); } } if (preferencesChanged) { handleSavePolicyFile(); } Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java +11 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.AlarmManager; import android.app.NotificationHistory; import android.app.NotificationHistory.HistoricalNotification; import android.content.Context; import android.graphics.drawable.Icon; Loading Loading @@ -198,6 +199,16 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase { } } @Test public void testReadNotificationHistory_readsBuffer() throws Exception { HistoricalNotification hn = getHistoricalNotification(1); mDataBase.addNotification(hn); NotificationHistory nh = mDataBase.readNotificationHistory(); assertThat(nh.getNotificationsToWrite()).contains(hn); } @Test public void testReadNotificationHistory_withNumFilterDoesNotReadExtraFiles() throws Exception { AtomicFile af = mock(AtomicFile.class); Loading