Loading core/java/android/app/INotificationManager.aidl +0 −1 Original line number Diff line number Diff line Loading @@ -115,7 +115,6 @@ interface INotificationManager ParceledListSlice getNotificationChannelGroups(String pkg); boolean onlyHasDefaultChannel(String pkg, int uid); boolean areChannelsBypassingDnd(); int getAppsBypassingDndCount(int uid); ParceledListSlice getNotificationChannelsBypassingDnd(String pkg, int userId); boolean isPackagePaused(String pkg); void deleteNotificationHistoryItem(String pkg, int uid, long postedTime); Loading services/core/java/com/android/server/notification/NotificationManagerService.java +9 −8 Original line number Diff line number Diff line Loading @@ -479,6 +479,7 @@ public class NotificationManagerService extends SystemService { private ActivityManagerInternal mAmi; private IPackageManager mPackageManager; private PackageManager mPackageManagerClient; private PackageManagerInternal mPackageManagerInternal; AudioManager mAudioManager; AudioManagerInternal mAudioManagerInternal; // Can be null for wear Loading Loading @@ -2212,6 +2213,7 @@ public class NotificationManagerService extends SystemService { mUgmInternal = ugmInternal; mPackageManager = packageManager; mPackageManagerClient = packageManagerClient; mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); mAppOps = appOps; mAppOpsService = iAppOps; try { Loading Loading @@ -2292,10 +2294,12 @@ public class NotificationManagerService extends SystemService { }); } }); mPermissionHelper = permissionHelper; mPreferencesHelper = new PreferencesHelper(getContext(), mPackageManagerClient, mRankingHandler, mZenModeHelper, mPermissionHelper, new NotificationChannelLoggerImpl(), mAppOps, new SysUiStatsEvent.BuilderFactory()); Loading @@ -2309,7 +2313,6 @@ public class NotificationManagerService extends SystemService { mGroupHelper = groupHelper; mVibratorHelper = new VibratorHelper(getContext()); mHistoryManager = historyManager; mPermissionHelper = permissionHelper; // This is a ManagedServices object that keeps track of the listeners. mListeners = notificationListeners; Loading Loading @@ -3481,7 +3484,7 @@ public class NotificationManagerService extends SystemService { mPreferencesHelper.setEnabled(pkg, uid, enabled); // TODO (b/194833441): this is being ignored by app ops now that the permission // exists // exists, so send the broadcast manually mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg, enabled ? MODE_ALLOWED : AppOpsManager.MODE_IGNORED); Loading Loading @@ -4081,16 +4084,14 @@ public class NotificationManagerService extends SystemService { + " cannot read channels for " + targetPkg + " in " + userId); } @Override public int getAppsBypassingDndCount(int userId) { checkCallerIsSystem(); return mPreferencesHelper.getAppsBypassingDndCount(userId); } @Override public ParceledListSlice<NotificationChannel> getNotificationChannelsBypassingDnd( String pkg, int userId) { checkCallerIsSystem(); if (!areNotificationsEnabledForPackage(pkg, mPackageManagerInternal.getPackageUid(pkg, 0, userId))) { return ParceledListSlice.emptyList(); } return mPreferencesHelper.getNotificationChannelsBypassingDnd(pkg, userId); } Loading services/core/java/com/android/server/notification/PermissionHelper.java +4 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,10 @@ public final class PermissionHelper { mMigrationEnabled = migrationEnabled; } public boolean isMigrationEnabled() { return mMigrationEnabled; } /** * Returns whether the given uid holds the notification permission. Must not be called * with a lock held. Loading services/core/java/com/android/server/notification/PreferencesHelper.java +116 −106 Original line number Diff line number Diff line Loading @@ -169,6 +169,7 @@ public class PreferencesHelper implements RankingConfig { private final PackageManager mPm; private final RankingHandler mRankingHandler; private final ZenModeHelper mZenModeHelper; private final PermissionHelper mPermissionHelper; private final NotificationChannelLogger mNotificationChannelLogger; private final AppOpsManager mAppOps; Loading @@ -187,12 +188,14 @@ public class PreferencesHelper implements RankingConfig { private int mCurrentUserId = UserHandle.USER_NULL; public PreferencesHelper(Context context, PackageManager pm, RankingHandler rankingHandler, ZenModeHelper zenHelper, NotificationChannelLogger notificationChannelLogger, ZenModeHelper zenHelper, PermissionHelper permHelper, NotificationChannelLogger notificationChannelLogger, AppOpsManager appOpsManager, SysUiStatsEvent.BuilderFactory statsEventBuilderFactory) { mContext = context; mZenModeHelper = zenHelper; mRankingHandler = rankingHandler; mPermissionHelper = permHelper; mPm = pm; mNotificationChannelLogger = notificationChannelLogger; mAppOps = appOpsManager; Loading Loading @@ -791,6 +794,7 @@ public class PreferencesHelper implements RankingConfig { Objects.requireNonNull(group); Objects.requireNonNull(group.getId()); Objects.requireNonNull(!TextUtils.isEmpty(group.getName())); boolean needsDndChange = false; synchronized (mPackagePreferences) { PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid); if (r == null) { Loading @@ -809,7 +813,7 @@ public class PreferencesHelper implements RankingConfig { // but the system can if (group.isBlocked() != oldGroup.isBlocked()) { group.lockFields(NotificationChannelGroup.USER_LOCKED_BLOCKED_STATE); updateChannelsBypassingDnd(); needsDndChange = true; } } } Loading @@ -822,6 +826,9 @@ public class PreferencesHelper implements RankingConfig { } r.groups.put(group.getId(), group); } if (needsDndChange) { updateChannelsBypassingDnd(); } } @Override Loading @@ -831,7 +838,7 @@ public class PreferencesHelper implements RankingConfig { Objects.requireNonNull(channel); Objects.requireNonNull(channel.getId()); Preconditions.checkArgument(!TextUtils.isEmpty(channel.getName())); boolean needsPolicyFileChange = false, wasUndeleted = false; boolean needsPolicyFileChange = false, wasUndeleted = false, needsDndChange = false; synchronized (mPackagePreferences) { PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid); if (r == null) { Loading Loading @@ -897,7 +904,7 @@ public class PreferencesHelper implements RankingConfig { if (bypassDnd != mAreChannelsBypassingDnd || previousExistingImportance != existing.getImportance()) { updateChannelsBypassingDnd(); needsDndChange = true; } } } Loading @@ -912,9 +919,7 @@ public class PreferencesHelper implements RankingConfig { mNotificationChannelLogger.logNotificationChannelModified(existing, uid, pkg, previousLoggingImportance, false); } return needsPolicyFileChange; } } else { if (r.channels.size() >= NOTIFICATION_CHANNEL_COUNT_LIMIT) { throw new IllegalStateException("Limit exceed; cannot create more channels"); } Loading Loading @@ -955,18 +960,24 @@ public class PreferencesHelper implements RankingConfig { // validate parent if (channel.getParentChannelId() != null) { Preconditions.checkArgument(r.channels.containsKey(channel.getParentChannelId()), Preconditions.checkArgument( r.channels.containsKey(channel.getParentChannelId()), "Tried to create a conversation channel without a preexisting parent"); } r.channels.put(channel.getId(), channel); if (channel.canBypassDnd() != mAreChannelsBypassingDnd) { updateChannelsBypassingDnd(); needsDndChange = true; } MetricsLogger.action(getChannelLog(channel, pkg).setType( com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_OPEN)); mNotificationChannelLogger.logNotificationChannelCreated(channel, uid, pkg); } } if (needsDndChange) { updateChannelsBypassingDnd(); } return needsPolicyFileChange; } Loading Loading @@ -997,6 +1008,7 @@ public class PreferencesHelper implements RankingConfig { boolean fromUser) { Objects.requireNonNull(updatedChannel); Objects.requireNonNull(updatedChannel.getId()); boolean needsDndChange = false; synchronized (mPackagePreferences) { PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid); if (r == null) { Loading Loading @@ -1050,9 +1062,12 @@ public class PreferencesHelper implements RankingConfig { if (updatedChannel.canBypassDnd() != mAreChannelsBypassingDnd || channel.getImportance() != updatedChannel.getImportance()) { updateChannelsBypassingDnd(); needsDndChange = true; } } if (needsDndChange) { updateChannelsBypassingDnd(); } updateConfig(); } Loading Loading @@ -1126,6 +1141,8 @@ public class PreferencesHelper implements RankingConfig { @Override public boolean deleteNotificationChannel(String pkg, int uid, String channelId) { boolean deletedChannel = false; boolean channelBypassedDnd = false; synchronized (mPackagePreferences) { PackagePreferences r = getPackagePreferencesLocked(pkg, uid); if (r == null) { Loading @@ -1133,13 +1150,18 @@ public class PreferencesHelper implements RankingConfig { } NotificationChannel channel = r.channels.get(channelId); if (channel != null) { return deleteNotificationChannelLocked(channel, pkg, uid); channelBypassedDnd = channel.canBypassDnd(); deletedChannel = deleteNotificationChannelLocked(channel, pkg, uid); } return false; } if (channelBypassedDnd) { updateChannelsBypassingDnd(); } return deletedChannel; } private boolean deleteNotificationChannelLocked(NotificationChannel channel, String pkg, int uid) { private boolean deleteNotificationChannelLocked(NotificationChannel channel, String pkg, int uid) { if (!channel.isDeleted()) { channel.setDeleted(true); channel.setDeletedTimeMs(System.currentTimeMillis()); Loading @@ -1147,10 +1169,6 @@ public class PreferencesHelper implements RankingConfig { lm.setType(com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_CLOSE); MetricsLogger.action(lm); mNotificationChannelLogger.logNotificationChannelDeleted(channel, uid, pkg); if (mAreChannelsBypassingDnd && channel.canBypassDnd()) { updateChannelsBypassingDnd(); } return true; } return false; Loading Loading @@ -1352,6 +1370,7 @@ public class PreferencesHelper implements RankingConfig { public List<NotificationChannel> deleteNotificationChannelGroup(String pkg, int uid, String groupId) { List<NotificationChannel> deletedChannels = new ArrayList<>(); boolean groupBypassedDnd = false; synchronized (mPackagePreferences) { PackagePreferences r = getPackagePreferencesLocked(pkg, uid); if (r == null || TextUtils.isEmpty(groupId)) { Loading @@ -1368,11 +1387,15 @@ public class PreferencesHelper implements RankingConfig { for (int i = 0; i < N; i++) { final NotificationChannel nc = r.channels.valueAt(i); if (groupId.equals(nc.getGroup())) { groupBypassedDnd |= nc.canBypassDnd(); deleteNotificationChannelLocked(nc, pkg, uid); deletedChannels.add(nc); } } } if (groupBypassedDnd) { updateChannelsBypassingDnd(); } return deletedChannels; } Loading Loading @@ -1495,8 +1518,8 @@ public class PreferencesHelper implements RankingConfig { public @NonNull List<String> deleteConversations(String pkg, int uid, Set<String> conversationIds) { synchronized (mPackagePreferences) { List<String> deletedChannelIds = new ArrayList<>(); synchronized (mPackagePreferences) { PackagePreferences r = getPackagePreferencesLocked(pkg, uid); if (r == null) { return deletedChannelIds; Loading @@ -1517,12 +1540,12 @@ public class PreferencesHelper implements RankingConfig { deletedChannelIds.add(nc.getId()); } } } if (!deletedChannelIds.isEmpty() && mAreChannelsBypassingDnd) { updateChannelsBypassingDnd(); } return deletedChannelIds; } } @Override public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid, Loading Loading @@ -1554,8 +1577,7 @@ public class PreferencesHelper implements RankingConfig { synchronized (mPackagePreferences) { final PackagePreferences r = mPackagePreferences.get( packagePreferencesKey(pkg, userId)); // notifications from this package aren't blocked if (r != null && r.importance != IMPORTANCE_NONE) { if (r != null) { for (NotificationChannel channel : r.channels.values()) { if (channelIsLiveLocked(r, channel) && channel.canBypassDnd()) { channels.add(channel); Loading Loading @@ -1621,33 +1643,6 @@ public class PreferencesHelper implements RankingConfig { } } /** * Returns the number of apps that have at least one notification channel that can bypass DND * for given particular user */ public int getAppsBypassingDndCount(int userId) { int count = 0; synchronized (mPackagePreferences) { final int numPackagePreferences = mPackagePreferences.size(); for (int i = 0; i < numPackagePreferences; i++) { final PackagePreferences r = mPackagePreferences.valueAt(i); // Package isn't associated with this userId or notifications from this package are // blocked if (userId != UserHandle.getUserId(r.uid) || r.importance == IMPORTANCE_NONE) { continue; } for (NotificationChannel channel : r.channels.values()) { if (channelIsLiveLocked(r, channel) && channel.canBypassDnd()) { count++; break; } } } } return count; } /** * Syncs {@link #mAreChannelsBypassingDnd} with the current user's notification policy before * updating Loading @@ -1655,41 +1650,56 @@ public class PreferencesHelper implements RankingConfig { private void syncChannelsBypassingDnd() { mAreChannelsBypassingDnd = (mZenModeHelper.getNotificationPolicy().state & NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND) == 1; updateChannelsBypassingDnd(); } /** * Updates the user's NotificationPolicy based on whether the current userId * has channels bypassing DND * @param userId */ private void updateChannelsBypassingDnd() { ArraySet<Pair<String, Integer>> candidatePkgs = new ArraySet<>(); synchronized (mPackagePreferences) { final int numPackagePreferences = mPackagePreferences.size(); for (int i = 0; i < numPackagePreferences; i++) { final PackagePreferences r = mPackagePreferences.valueAt(i); // Package isn't associated with the current userId or notifications from this // package are blocked if (mCurrentUserId != UserHandle.getUserId(r.uid) || r.importance == IMPORTANCE_NONE) { // Package isn't associated with the current userId if (mCurrentUserId != UserHandle.getUserId(r.uid)) { continue; } for (NotificationChannel channel : r.channels.values()) { if (channelIsLiveLocked(r, channel) && channel.canBypassDnd()) { if (!mAreChannelsBypassingDnd) { mAreChannelsBypassingDnd = true; updateZenPolicy(true); candidatePkgs.add(new Pair(r.pkg, r.uid)); break; } return; } } } for (int i = candidatePkgs.size() - 1; i >= 0; i--) { Pair<String, Integer> app = candidatePkgs.valueAt(i); if (mPermissionHelper.isMigrationEnabled()) { if (!mPermissionHelper.hasPermission(app.second)) { candidatePkgs.removeAt(i); } } else { synchronized (mPackagePreferences) { PackagePreferences r = getPackagePreferencesLocked(app.first, app.second); if (r == null) { continue; } if (r.importance == IMPORTANCE_NONE) { candidatePkgs.removeAt(i); } } } } // If no channels bypass DND, update the zen policy once to disable DND bypass. if (mAreChannelsBypassingDnd) { mAreChannelsBypassingDnd = false; updateZenPolicy(false); boolean haveBypassingApps = candidatePkgs.size() > 0; if (mAreChannelsBypassingDnd != haveBypassingApps) { mAreChannelsBypassingDnd = haveBypassingApps; updateZenPolicy(mAreChannelsBypassingDnd); } } Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +16 −0 Original line number Diff line number Diff line Loading @@ -132,6 +132,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutServiceInternal; Loading Loading @@ -248,6 +249,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Mock private PackageManager mPackageManagerClient; @Mock private PackageManagerInternal mPackageManagerInternal; @Mock private WindowManagerInternal mWindowManagerInternal; @Mock private PermissionHelper mPermissionHelper; Loading Loading @@ -375,6 +378,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { LocalServices.addService(DeviceIdleInternal.class, deviceIdleInternal); LocalServices.removeServiceForTest(ActivityManagerInternal.class); LocalServices.addService(ActivityManagerInternal.class, mAmi); LocalServices.removeServiceForTest(PackageManagerInternal.class); LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal); mContext.addMockSystemService(Context.ALARM_SERVICE, mAlarmManager); doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any()); Loading Loading @@ -8307,4 +8312,15 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testMigrationDisabledByDefault() { assertThat(mService.mEnableAppSettingMigration).isFalse(); } @Test public void testGetNotificationChannelsBypassingDnd_blocked() throws RemoteException { mService.setPreferencesHelper(mPreferencesHelper); when(mPreferencesHelper.getImportance(PKG, mUid)).thenReturn(IMPORTANCE_NONE); assertThat(mBinderService.getNotificationChannelsBypassingDnd(PKG, mUid).getList()) .isEmpty(); verify(mPermissionHelper, never()).hasPermission(anyInt()); verify(mPreferencesHelper, never()).getNotificationChannelsBypassingDnd(PKG, mUid); } } Loading
core/java/android/app/INotificationManager.aidl +0 −1 Original line number Diff line number Diff line Loading @@ -115,7 +115,6 @@ interface INotificationManager ParceledListSlice getNotificationChannelGroups(String pkg); boolean onlyHasDefaultChannel(String pkg, int uid); boolean areChannelsBypassingDnd(); int getAppsBypassingDndCount(int uid); ParceledListSlice getNotificationChannelsBypassingDnd(String pkg, int userId); boolean isPackagePaused(String pkg); void deleteNotificationHistoryItem(String pkg, int uid, long postedTime); Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +9 −8 Original line number Diff line number Diff line Loading @@ -479,6 +479,7 @@ public class NotificationManagerService extends SystemService { private ActivityManagerInternal mAmi; private IPackageManager mPackageManager; private PackageManager mPackageManagerClient; private PackageManagerInternal mPackageManagerInternal; AudioManager mAudioManager; AudioManagerInternal mAudioManagerInternal; // Can be null for wear Loading Loading @@ -2212,6 +2213,7 @@ public class NotificationManagerService extends SystemService { mUgmInternal = ugmInternal; mPackageManager = packageManager; mPackageManagerClient = packageManagerClient; mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); mAppOps = appOps; mAppOpsService = iAppOps; try { Loading Loading @@ -2292,10 +2294,12 @@ public class NotificationManagerService extends SystemService { }); } }); mPermissionHelper = permissionHelper; mPreferencesHelper = new PreferencesHelper(getContext(), mPackageManagerClient, mRankingHandler, mZenModeHelper, mPermissionHelper, new NotificationChannelLoggerImpl(), mAppOps, new SysUiStatsEvent.BuilderFactory()); Loading @@ -2309,7 +2313,6 @@ public class NotificationManagerService extends SystemService { mGroupHelper = groupHelper; mVibratorHelper = new VibratorHelper(getContext()); mHistoryManager = historyManager; mPermissionHelper = permissionHelper; // This is a ManagedServices object that keeps track of the listeners. mListeners = notificationListeners; Loading Loading @@ -3481,7 +3484,7 @@ public class NotificationManagerService extends SystemService { mPreferencesHelper.setEnabled(pkg, uid, enabled); // TODO (b/194833441): this is being ignored by app ops now that the permission // exists // exists, so send the broadcast manually mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg, enabled ? MODE_ALLOWED : AppOpsManager.MODE_IGNORED); Loading Loading @@ -4081,16 +4084,14 @@ public class NotificationManagerService extends SystemService { + " cannot read channels for " + targetPkg + " in " + userId); } @Override public int getAppsBypassingDndCount(int userId) { checkCallerIsSystem(); return mPreferencesHelper.getAppsBypassingDndCount(userId); } @Override public ParceledListSlice<NotificationChannel> getNotificationChannelsBypassingDnd( String pkg, int userId) { checkCallerIsSystem(); if (!areNotificationsEnabledForPackage(pkg, mPackageManagerInternal.getPackageUid(pkg, 0, userId))) { return ParceledListSlice.emptyList(); } return mPreferencesHelper.getNotificationChannelsBypassingDnd(pkg, userId); } Loading
services/core/java/com/android/server/notification/PermissionHelper.java +4 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,10 @@ public final class PermissionHelper { mMigrationEnabled = migrationEnabled; } public boolean isMigrationEnabled() { return mMigrationEnabled; } /** * Returns whether the given uid holds the notification permission. Must not be called * with a lock held. Loading
services/core/java/com/android/server/notification/PreferencesHelper.java +116 −106 Original line number Diff line number Diff line Loading @@ -169,6 +169,7 @@ public class PreferencesHelper implements RankingConfig { private final PackageManager mPm; private final RankingHandler mRankingHandler; private final ZenModeHelper mZenModeHelper; private final PermissionHelper mPermissionHelper; private final NotificationChannelLogger mNotificationChannelLogger; private final AppOpsManager mAppOps; Loading @@ -187,12 +188,14 @@ public class PreferencesHelper implements RankingConfig { private int mCurrentUserId = UserHandle.USER_NULL; public PreferencesHelper(Context context, PackageManager pm, RankingHandler rankingHandler, ZenModeHelper zenHelper, NotificationChannelLogger notificationChannelLogger, ZenModeHelper zenHelper, PermissionHelper permHelper, NotificationChannelLogger notificationChannelLogger, AppOpsManager appOpsManager, SysUiStatsEvent.BuilderFactory statsEventBuilderFactory) { mContext = context; mZenModeHelper = zenHelper; mRankingHandler = rankingHandler; mPermissionHelper = permHelper; mPm = pm; mNotificationChannelLogger = notificationChannelLogger; mAppOps = appOpsManager; Loading Loading @@ -791,6 +794,7 @@ public class PreferencesHelper implements RankingConfig { Objects.requireNonNull(group); Objects.requireNonNull(group.getId()); Objects.requireNonNull(!TextUtils.isEmpty(group.getName())); boolean needsDndChange = false; synchronized (mPackagePreferences) { PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid); if (r == null) { Loading @@ -809,7 +813,7 @@ public class PreferencesHelper implements RankingConfig { // but the system can if (group.isBlocked() != oldGroup.isBlocked()) { group.lockFields(NotificationChannelGroup.USER_LOCKED_BLOCKED_STATE); updateChannelsBypassingDnd(); needsDndChange = true; } } } Loading @@ -822,6 +826,9 @@ public class PreferencesHelper implements RankingConfig { } r.groups.put(group.getId(), group); } if (needsDndChange) { updateChannelsBypassingDnd(); } } @Override Loading @@ -831,7 +838,7 @@ public class PreferencesHelper implements RankingConfig { Objects.requireNonNull(channel); Objects.requireNonNull(channel.getId()); Preconditions.checkArgument(!TextUtils.isEmpty(channel.getName())); boolean needsPolicyFileChange = false, wasUndeleted = false; boolean needsPolicyFileChange = false, wasUndeleted = false, needsDndChange = false; synchronized (mPackagePreferences) { PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid); if (r == null) { Loading Loading @@ -897,7 +904,7 @@ public class PreferencesHelper implements RankingConfig { if (bypassDnd != mAreChannelsBypassingDnd || previousExistingImportance != existing.getImportance()) { updateChannelsBypassingDnd(); needsDndChange = true; } } } Loading @@ -912,9 +919,7 @@ public class PreferencesHelper implements RankingConfig { mNotificationChannelLogger.logNotificationChannelModified(existing, uid, pkg, previousLoggingImportance, false); } return needsPolicyFileChange; } } else { if (r.channels.size() >= NOTIFICATION_CHANNEL_COUNT_LIMIT) { throw new IllegalStateException("Limit exceed; cannot create more channels"); } Loading Loading @@ -955,18 +960,24 @@ public class PreferencesHelper implements RankingConfig { // validate parent if (channel.getParentChannelId() != null) { Preconditions.checkArgument(r.channels.containsKey(channel.getParentChannelId()), Preconditions.checkArgument( r.channels.containsKey(channel.getParentChannelId()), "Tried to create a conversation channel without a preexisting parent"); } r.channels.put(channel.getId(), channel); if (channel.canBypassDnd() != mAreChannelsBypassingDnd) { updateChannelsBypassingDnd(); needsDndChange = true; } MetricsLogger.action(getChannelLog(channel, pkg).setType( com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_OPEN)); mNotificationChannelLogger.logNotificationChannelCreated(channel, uid, pkg); } } if (needsDndChange) { updateChannelsBypassingDnd(); } return needsPolicyFileChange; } Loading Loading @@ -997,6 +1008,7 @@ public class PreferencesHelper implements RankingConfig { boolean fromUser) { Objects.requireNonNull(updatedChannel); Objects.requireNonNull(updatedChannel.getId()); boolean needsDndChange = false; synchronized (mPackagePreferences) { PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid); if (r == null) { Loading Loading @@ -1050,9 +1062,12 @@ public class PreferencesHelper implements RankingConfig { if (updatedChannel.canBypassDnd() != mAreChannelsBypassingDnd || channel.getImportance() != updatedChannel.getImportance()) { updateChannelsBypassingDnd(); needsDndChange = true; } } if (needsDndChange) { updateChannelsBypassingDnd(); } updateConfig(); } Loading Loading @@ -1126,6 +1141,8 @@ public class PreferencesHelper implements RankingConfig { @Override public boolean deleteNotificationChannel(String pkg, int uid, String channelId) { boolean deletedChannel = false; boolean channelBypassedDnd = false; synchronized (mPackagePreferences) { PackagePreferences r = getPackagePreferencesLocked(pkg, uid); if (r == null) { Loading @@ -1133,13 +1150,18 @@ public class PreferencesHelper implements RankingConfig { } NotificationChannel channel = r.channels.get(channelId); if (channel != null) { return deleteNotificationChannelLocked(channel, pkg, uid); channelBypassedDnd = channel.canBypassDnd(); deletedChannel = deleteNotificationChannelLocked(channel, pkg, uid); } return false; } if (channelBypassedDnd) { updateChannelsBypassingDnd(); } return deletedChannel; } private boolean deleteNotificationChannelLocked(NotificationChannel channel, String pkg, int uid) { private boolean deleteNotificationChannelLocked(NotificationChannel channel, String pkg, int uid) { if (!channel.isDeleted()) { channel.setDeleted(true); channel.setDeletedTimeMs(System.currentTimeMillis()); Loading @@ -1147,10 +1169,6 @@ public class PreferencesHelper implements RankingConfig { lm.setType(com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_CLOSE); MetricsLogger.action(lm); mNotificationChannelLogger.logNotificationChannelDeleted(channel, uid, pkg); if (mAreChannelsBypassingDnd && channel.canBypassDnd()) { updateChannelsBypassingDnd(); } return true; } return false; Loading Loading @@ -1352,6 +1370,7 @@ public class PreferencesHelper implements RankingConfig { public List<NotificationChannel> deleteNotificationChannelGroup(String pkg, int uid, String groupId) { List<NotificationChannel> deletedChannels = new ArrayList<>(); boolean groupBypassedDnd = false; synchronized (mPackagePreferences) { PackagePreferences r = getPackagePreferencesLocked(pkg, uid); if (r == null || TextUtils.isEmpty(groupId)) { Loading @@ -1368,11 +1387,15 @@ public class PreferencesHelper implements RankingConfig { for (int i = 0; i < N; i++) { final NotificationChannel nc = r.channels.valueAt(i); if (groupId.equals(nc.getGroup())) { groupBypassedDnd |= nc.canBypassDnd(); deleteNotificationChannelLocked(nc, pkg, uid); deletedChannels.add(nc); } } } if (groupBypassedDnd) { updateChannelsBypassingDnd(); } return deletedChannels; } Loading Loading @@ -1495,8 +1518,8 @@ public class PreferencesHelper implements RankingConfig { public @NonNull List<String> deleteConversations(String pkg, int uid, Set<String> conversationIds) { synchronized (mPackagePreferences) { List<String> deletedChannelIds = new ArrayList<>(); synchronized (mPackagePreferences) { PackagePreferences r = getPackagePreferencesLocked(pkg, uid); if (r == null) { return deletedChannelIds; Loading @@ -1517,12 +1540,12 @@ public class PreferencesHelper implements RankingConfig { deletedChannelIds.add(nc.getId()); } } } if (!deletedChannelIds.isEmpty() && mAreChannelsBypassingDnd) { updateChannelsBypassingDnd(); } return deletedChannelIds; } } @Override public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid, Loading Loading @@ -1554,8 +1577,7 @@ public class PreferencesHelper implements RankingConfig { synchronized (mPackagePreferences) { final PackagePreferences r = mPackagePreferences.get( packagePreferencesKey(pkg, userId)); // notifications from this package aren't blocked if (r != null && r.importance != IMPORTANCE_NONE) { if (r != null) { for (NotificationChannel channel : r.channels.values()) { if (channelIsLiveLocked(r, channel) && channel.canBypassDnd()) { channels.add(channel); Loading Loading @@ -1621,33 +1643,6 @@ public class PreferencesHelper implements RankingConfig { } } /** * Returns the number of apps that have at least one notification channel that can bypass DND * for given particular user */ public int getAppsBypassingDndCount(int userId) { int count = 0; synchronized (mPackagePreferences) { final int numPackagePreferences = mPackagePreferences.size(); for (int i = 0; i < numPackagePreferences; i++) { final PackagePreferences r = mPackagePreferences.valueAt(i); // Package isn't associated with this userId or notifications from this package are // blocked if (userId != UserHandle.getUserId(r.uid) || r.importance == IMPORTANCE_NONE) { continue; } for (NotificationChannel channel : r.channels.values()) { if (channelIsLiveLocked(r, channel) && channel.canBypassDnd()) { count++; break; } } } } return count; } /** * Syncs {@link #mAreChannelsBypassingDnd} with the current user's notification policy before * updating Loading @@ -1655,41 +1650,56 @@ public class PreferencesHelper implements RankingConfig { private void syncChannelsBypassingDnd() { mAreChannelsBypassingDnd = (mZenModeHelper.getNotificationPolicy().state & NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND) == 1; updateChannelsBypassingDnd(); } /** * Updates the user's NotificationPolicy based on whether the current userId * has channels bypassing DND * @param userId */ private void updateChannelsBypassingDnd() { ArraySet<Pair<String, Integer>> candidatePkgs = new ArraySet<>(); synchronized (mPackagePreferences) { final int numPackagePreferences = mPackagePreferences.size(); for (int i = 0; i < numPackagePreferences; i++) { final PackagePreferences r = mPackagePreferences.valueAt(i); // Package isn't associated with the current userId or notifications from this // package are blocked if (mCurrentUserId != UserHandle.getUserId(r.uid) || r.importance == IMPORTANCE_NONE) { // Package isn't associated with the current userId if (mCurrentUserId != UserHandle.getUserId(r.uid)) { continue; } for (NotificationChannel channel : r.channels.values()) { if (channelIsLiveLocked(r, channel) && channel.canBypassDnd()) { if (!mAreChannelsBypassingDnd) { mAreChannelsBypassingDnd = true; updateZenPolicy(true); candidatePkgs.add(new Pair(r.pkg, r.uid)); break; } return; } } } for (int i = candidatePkgs.size() - 1; i >= 0; i--) { Pair<String, Integer> app = candidatePkgs.valueAt(i); if (mPermissionHelper.isMigrationEnabled()) { if (!mPermissionHelper.hasPermission(app.second)) { candidatePkgs.removeAt(i); } } else { synchronized (mPackagePreferences) { PackagePreferences r = getPackagePreferencesLocked(app.first, app.second); if (r == null) { continue; } if (r.importance == IMPORTANCE_NONE) { candidatePkgs.removeAt(i); } } } } // If no channels bypass DND, update the zen policy once to disable DND bypass. if (mAreChannelsBypassingDnd) { mAreChannelsBypassingDnd = false; updateZenPolicy(false); boolean haveBypassingApps = candidatePkgs.size() > 0; if (mAreChannelsBypassingDnd != haveBypassingApps) { mAreChannelsBypassingDnd = haveBypassingApps; updateZenPolicy(mAreChannelsBypassingDnd); } } Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +16 −0 Original line number Diff line number Diff line Loading @@ -132,6 +132,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutServiceInternal; Loading Loading @@ -248,6 +249,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Mock private PackageManager mPackageManagerClient; @Mock private PackageManagerInternal mPackageManagerInternal; @Mock private WindowManagerInternal mWindowManagerInternal; @Mock private PermissionHelper mPermissionHelper; Loading Loading @@ -375,6 +378,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { LocalServices.addService(DeviceIdleInternal.class, deviceIdleInternal); LocalServices.removeServiceForTest(ActivityManagerInternal.class); LocalServices.addService(ActivityManagerInternal.class, mAmi); LocalServices.removeServiceForTest(PackageManagerInternal.class); LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal); mContext.addMockSystemService(Context.ALARM_SERVICE, mAlarmManager); doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any()); Loading Loading @@ -8307,4 +8312,15 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testMigrationDisabledByDefault() { assertThat(mService.mEnableAppSettingMigration).isFalse(); } @Test public void testGetNotificationChannelsBypassingDnd_blocked() throws RemoteException { mService.setPreferencesHelper(mPreferencesHelper); when(mPreferencesHelper.getImportance(PKG, mUid)).thenReturn(IMPORTANCE_NONE); assertThat(mBinderService.getNotificationChannelsBypassingDnd(PKG, mUid).getList()) .isEmpty(); verify(mPermissionHelper, never()).hasPermission(anyInt()); verify(mPreferencesHelper, never()).getNotificationChannelsBypassingDnd(PKG, mUid); } }