diff options
13 files changed, 2253 insertions, 528 deletions
diff --git a/core/java/android/service/notification/ZenModeDiff.java b/core/java/android/service/notification/ZenModeDiff.java index c7b89eb284b6..a4f129ec247e 100644 --- a/core/java/android/service/notification/ZenModeDiff.java +++ b/core/java/android/service/notification/ZenModeDiff.java @@ -205,12 +205,24 @@ public class ZenModeDiff { private final ArrayMap<String, RuleDiff> mAutomaticRulesDiff = new ArrayMap<>(); private RuleDiff mManualRuleDiff; - // Helpers for string generation - private static final String ALLOW_CALLS_FROM_FIELD = "allowCallsFrom"; - private static final String ALLOW_MESSAGES_FROM_FIELD = "allowMessagesFrom"; - private static final String ALLOW_CONVERSATIONS_FROM_FIELD = "allowConversationsFrom"; + // Field name constants + public static final String FIELD_USER = "user"; + public static final String FIELD_ALLOW_ALARMS = "allowAlarms"; + public static final String FIELD_ALLOW_MEDIA = "allowMedia"; + public static final String FIELD_ALLOW_SYSTEM = "allowSystem"; + public static final String FIELD_ALLOW_CALLS = "allowCalls"; + public static final String FIELD_ALLOW_REMINDERS = "allowReminders"; + public static final String FIELD_ALLOW_EVENTS = "allowEvents"; + public static final String FIELD_ALLOW_REPEAT_CALLERS = "allowRepeatCallers"; + public static final String FIELD_ALLOW_MESSAGES = "allowMessages"; + public static final String FIELD_ALLOW_CONVERSATIONS = "allowConversations"; + public static final String FIELD_ALLOW_CALLS_FROM = "allowCallsFrom"; + public static final String FIELD_ALLOW_MESSAGES_FROM = "allowMessagesFrom"; + public static final String FIELD_ALLOW_CONVERSATIONS_FROM = "allowConversationsFrom"; + public static final String FIELD_SUPPRESSED_VISUAL_EFFECTS = "suppressedVisualEffects"; + public static final String FIELD_ARE_CHANNELS_BYPASSING_DND = "areChannelsBypassingDnd"; private static final Set<String> PEOPLE_TYPE_FIELDS = - Set.of(ALLOW_CALLS_FROM_FIELD, ALLOW_MESSAGES_FROM_FIELD); + Set.of(FIELD_ALLOW_CALLS_FROM, FIELD_ALLOW_MESSAGES_FROM); /** * Create a diff that contains diffs between the "from" and "to" ZenModeConfigs. @@ -232,57 +244,57 @@ public class ZenModeDiff { // Now we compare all the fields, knowing there's a diff and that neither is null if (from.user != to.user) { - addField("user", new FieldDiff<>(from.user, to.user)); + addField(FIELD_USER, new FieldDiff<>(from.user, to.user)); } if (from.allowAlarms != to.allowAlarms) { - addField("allowAlarms", new FieldDiff<>(from.allowAlarms, to.allowAlarms)); + addField(FIELD_ALLOW_ALARMS, new FieldDiff<>(from.allowAlarms, to.allowAlarms)); } if (from.allowMedia != to.allowMedia) { - addField("allowMedia", new FieldDiff<>(from.allowMedia, to.allowMedia)); + addField(FIELD_ALLOW_MEDIA, new FieldDiff<>(from.allowMedia, to.allowMedia)); } if (from.allowSystem != to.allowSystem) { - addField("allowSystem", new FieldDiff<>(from.allowSystem, to.allowSystem)); + addField(FIELD_ALLOW_SYSTEM, new FieldDiff<>(from.allowSystem, to.allowSystem)); } if (from.allowCalls != to.allowCalls) { - addField("allowCalls", new FieldDiff<>(from.allowCalls, to.allowCalls)); + addField(FIELD_ALLOW_CALLS, new FieldDiff<>(from.allowCalls, to.allowCalls)); } if (from.allowReminders != to.allowReminders) { - addField("allowReminders", + addField(FIELD_ALLOW_REMINDERS, new FieldDiff<>(from.allowReminders, to.allowReminders)); } if (from.allowEvents != to.allowEvents) { - addField("allowEvents", new FieldDiff<>(from.allowEvents, to.allowEvents)); + addField(FIELD_ALLOW_EVENTS, new FieldDiff<>(from.allowEvents, to.allowEvents)); } if (from.allowRepeatCallers != to.allowRepeatCallers) { - addField("allowRepeatCallers", + addField(FIELD_ALLOW_REPEAT_CALLERS, new FieldDiff<>(from.allowRepeatCallers, to.allowRepeatCallers)); } if (from.allowMessages != to.allowMessages) { - addField("allowMessages", + addField(FIELD_ALLOW_MESSAGES, new FieldDiff<>(from.allowMessages, to.allowMessages)); } if (from.allowConversations != to.allowConversations) { - addField("allowConversations", + addField(FIELD_ALLOW_CONVERSATIONS, new FieldDiff<>(from.allowConversations, to.allowConversations)); } if (from.allowCallsFrom != to.allowCallsFrom) { - addField("allowCallsFrom", + addField(FIELD_ALLOW_CALLS_FROM, new FieldDiff<>(from.allowCallsFrom, to.allowCallsFrom)); } if (from.allowMessagesFrom != to.allowMessagesFrom) { - addField("allowMessagesFrom", + addField(FIELD_ALLOW_MESSAGES_FROM, new FieldDiff<>(from.allowMessagesFrom, to.allowMessagesFrom)); } if (from.allowConversationsFrom != to.allowConversationsFrom) { - addField("allowConversationsFrom", + addField(FIELD_ALLOW_CONVERSATIONS_FROM, new FieldDiff<>(from.allowConversationsFrom, to.allowConversationsFrom)); } if (from.suppressedVisualEffects != to.suppressedVisualEffects) { - addField("suppressedVisualEffects", + addField(FIELD_SUPPRESSED_VISUAL_EFFECTS, new FieldDiff<>(from.suppressedVisualEffects, to.suppressedVisualEffects)); } if (from.areChannelsBypassingDnd != to.areChannelsBypassingDnd) { - addField("areChannelsBypassingDnd", + addField(FIELD_ARE_CHANNELS_BYPASSING_DND, new FieldDiff<>(from.areChannelsBypassingDnd, to.areChannelsBypassingDnd)); } @@ -366,7 +378,7 @@ public class ZenModeDiff { sb.append(ZenModeConfig.sourceToString((int) diff.from())); sb.append("->"); sb.append(ZenModeConfig.sourceToString((int) diff.to())); - } else if (key.equals(ALLOW_CONVERSATIONS_FROM_FIELD)) { + } else if (key.equals(FIELD_ALLOW_CONVERSATIONS_FROM)) { sb.append(key); sb.append(":"); sb.append(ZenPolicy.conversationTypeToString((int) diff.from())); @@ -428,6 +440,24 @@ public class ZenModeDiff { * Diff class representing a change between two ZenRules. */ public static class RuleDiff extends BaseDiff { + public static final String FIELD_ENABLED = "enabled"; + public static final String FIELD_SNOOZING = "snoozing"; + public static final String FIELD_NAME = "name"; + public static final String FIELD_ZEN_MODE = "zenMode"; + public static final String FIELD_CONDITION_ID = "conditionId"; + public static final String FIELD_CONDITION = "condition"; + public static final String FIELD_COMPONENT = "component"; + public static final String FIELD_CONFIGURATION_ACTIVITY = "configurationActivity"; + public static final String FIELD_ID = "id"; + public static final String FIELD_CREATION_TIME = "creationTime"; + public static final String FIELD_ENABLER = "enabler"; + public static final String FIELD_ZEN_POLICY = "zenPolicy"; + public static final String FIELD_MODIFIED = "modified"; + public static final String FIELD_PKG = "pkg"; + + // Special field to track whether this rule became active or inactive + FieldDiff<Boolean> mActiveDiff; + /** * Create a RuleDiff representing the difference between two ZenRule objects. * @param from previous ZenRule @@ -440,54 +470,64 @@ public class ZenModeDiff { if (from == null && to == null) { return; } + + // Even if added or removed, there may be a change in whether or not it was active. + // This only applies to automatic rules. + boolean fromActive = from != null ? from.isAutomaticActive() : false; + boolean toActive = to != null ? to.isAutomaticActive() : false; + if (fromActive != toActive) { + mActiveDiff = new FieldDiff<>(fromActive, toActive); + } + // Return if the diff was added or removed if (hasExistenceChange()) { return; } if (from.enabled != to.enabled) { - addField("enabled", new FieldDiff<>(from.enabled, to.enabled)); + addField(FIELD_ENABLED, new FieldDiff<>(from.enabled, to.enabled)); } if (from.snoozing != to.snoozing) { - addField("snoozing", new FieldDiff<>(from.snoozing, to.snoozing)); + addField(FIELD_SNOOZING, new FieldDiff<>(from.snoozing, to.snoozing)); } if (!Objects.equals(from.name, to.name)) { - addField("name", new FieldDiff<>(from.name, to.name)); + addField(FIELD_NAME, new FieldDiff<>(from.name, to.name)); } if (from.zenMode != to.zenMode) { - addField("zenMode", new FieldDiff<>(from.zenMode, to.zenMode)); + addField(FIELD_ZEN_MODE, new FieldDiff<>(from.zenMode, to.zenMode)); } if (!Objects.equals(from.conditionId, to.conditionId)) { - addField("conditionId", new FieldDiff<>(from.conditionId, to.conditionId)); + addField(FIELD_CONDITION_ID, new FieldDiff<>(from.conditionId, + to.conditionId)); } if (!Objects.equals(from.condition, to.condition)) { - addField("condition", new FieldDiff<>(from.condition, to.condition)); + addField(FIELD_CONDITION, new FieldDiff<>(from.condition, to.condition)); } if (!Objects.equals(from.component, to.component)) { - addField("component", new FieldDiff<>(from.component, to.component)); + addField(FIELD_COMPONENT, new FieldDiff<>(from.component, to.component)); } if (!Objects.equals(from.configurationActivity, to.configurationActivity)) { - addField("configurationActivity", new FieldDiff<>( + addField(FIELD_CONFIGURATION_ACTIVITY, new FieldDiff<>( from.configurationActivity, to.configurationActivity)); } if (!Objects.equals(from.id, to.id)) { - addField("id", new FieldDiff<>(from.id, to.id)); + addField(FIELD_ID, new FieldDiff<>(from.id, to.id)); } if (from.creationTime != to.creationTime) { - addField("creationTime", + addField(FIELD_CREATION_TIME, new FieldDiff<>(from.creationTime, to.creationTime)); } if (!Objects.equals(from.enabler, to.enabler)) { - addField("enabler", new FieldDiff<>(from.enabler, to.enabler)); + addField(FIELD_ENABLER, new FieldDiff<>(from.enabler, to.enabler)); } if (!Objects.equals(from.zenPolicy, to.zenPolicy)) { - addField("zenPolicy", new FieldDiff<>(from.zenPolicy, to.zenPolicy)); + addField(FIELD_ZEN_POLICY, new FieldDiff<>(from.zenPolicy, to.zenPolicy)); } if (from.modified != to.modified) { - addField("modified", new FieldDiff<>(from.modified, to.modified)); + addField(FIELD_MODIFIED, new FieldDiff<>(from.modified, to.modified)); } if (!Objects.equals(from.pkg, to.pkg)) { - addField("pkg", new FieldDiff<>(from.pkg, to.pkg)); + addField(FIELD_PKG, new FieldDiff<>(from.pkg, to.pkg)); } } @@ -536,7 +576,35 @@ public class ZenModeDiff { sb.append(diff); } + if (becameActive()) { + if (!first) { + sb.append(", "); + } + sb.append("(->active)"); + } else if (becameInactive()) { + if (!first) { + sb.append(", "); + } + sb.append("(->inactive)"); + } + return sb.append("}").toString(); } + + /** + * Returns whether this diff indicates that this (automatic) rule became active. + */ + public boolean becameActive() { + // if the "to" side is true, then it became active + return mActiveDiff != null && mActiveDiff.to(); + } + + /** + * Returns whether this diff indicates that this (automatic) rule became inactive. + */ + public boolean becameInactive() { + // if the "to" side is false, then it became inactive + return mActiveDiff != null && !mActiveDiff.to(); + } } } diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto index f87d9109e7f8..17ca7c80707c 100644 --- a/core/proto/android/service/notification.proto +++ b/core/proto/android/service/notification.proto @@ -360,3 +360,11 @@ message DNDPolicyProto { optional ConversationType allow_conversations_from = 19; } + +// Enum identifying the type of rule that changed; values set to match ones used in the +// DNDStateChanged proto. +enum RuleType { + RULE_TYPE_UNKNOWN = 0; + RULE_TYPE_MANUAL = 1; + RULE_TYPE_AUTOMATIC = 2; +} diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index f0ab815db2c1..f83ba875d691 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1651,7 +1651,8 @@ public class NotificationManagerService extends SystemService { if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) { // update system notification channels SystemNotificationChannels.createAll(context); - mZenModeHelper.updateDefaultZenRules(); + mZenModeHelper.updateDefaultZenRules(Binder.getCallingUid(), + isCallerIsSystemOrSystemUi()); mPreferencesHelper.onLocaleChanged(context, ActivityManager.getCurrentUser()); } } @@ -2279,7 +2280,8 @@ public class NotificationManagerService extends SystemService { mRankingHandler = rankingHandler; mConditionProviders = conditionProviders; mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders, - new SysUiStatsEvent.BuilderFactory()); + new SysUiStatsEvent.BuilderFactory(), flagResolver, + new ZenModeEventLogger(mPackageManagerClient)); mZenModeHelper.addCallback(new ZenModeHelper.Callback() { @Override public void onConfigChanged() { @@ -2861,7 +2863,8 @@ public class NotificationManagerService extends SystemService { final NotificationChannel preUpdate = mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), true); - mPreferencesHelper.updateNotificationChannel(pkg, uid, channel, true); + mPreferencesHelper.updateNotificationChannel(pkg, uid, channel, true, + Binder.getCallingUid(), isCallerIsSystemOrSystemUi()); if (mPreferencesHelper.onlyHasDefaultChannel(pkg, uid)) { mPermissionHelper.setNotificationPermission(pkg, UserHandle.getUserId(uid), channel.getImportance() != IMPORTANCE_NONE, true); @@ -2909,7 +2912,7 @@ public class NotificationManagerService extends SystemService { final NotificationChannelGroup preUpdate = mPreferencesHelper.getNotificationChannelGroup(group.getId(), pkg, uid); mPreferencesHelper.createNotificationChannelGroup(pkg, uid, group, - fromApp); + fromApp, Binder.getCallingUid(), isCallerIsSystemOrSystemUi()); if (!fromApp) { maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group); } @@ -3874,7 +3877,8 @@ public class NotificationManagerService extends SystemService { needsPolicyFileChange = mPreferencesHelper.createNotificationChannel(pkg, uid, channel, true /* fromTargetApp */, mConditionProviders.isPackageOrComponentAllowed( - pkg, UserHandle.getUserId(uid))); + pkg, UserHandle.getUserId(uid)), Binder.getCallingUid(), + isCallerIsSystemOrSystemUi()); if (needsPolicyFileChange) { mListeners.notifyNotificationChannelChanged(pkg, UserHandle.getUserHandleForUid(uid), @@ -4010,6 +4014,7 @@ public class NotificationManagerService extends SystemService { public void deleteNotificationChannel(String pkg, String channelId) { checkCallerIsSystemOrSameApp(pkg); final int callingUid = Binder.getCallingUid(); + final boolean isSystemOrSystemUi = isCallerIsSystemOrSystemUi(); final int callingUser = UserHandle.getUserId(callingUid); if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) { throw new IllegalArgumentException("Cannot delete default channel"); @@ -4019,7 +4024,7 @@ public class NotificationManagerService extends SystemService { cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true, callingUser, REASON_CHANNEL_REMOVED, null); boolean previouslyExisted = mPreferencesHelper.deleteNotificationChannel( - pkg, callingUid, channelId); + pkg, callingUid, channelId, callingUid, isSystemOrSystemUi); if (previouslyExisted) { // Remove from both recent notification archive and notification history mArchive.removeChannelNotifications(pkg, callingUser, channelId); @@ -4052,6 +4057,7 @@ public class NotificationManagerService extends SystemService { checkCallerIsSystemOrSameApp(pkg); final int callingUid = Binder.getCallingUid(); + final boolean isSystemOrSystemUi = isCallerIsSystemOrSystemUi(); NotificationChannelGroup groupToDelete = mPreferencesHelper.getNotificationChannelGroupWithChannels( pkg, callingUid, groupId, false); @@ -4065,7 +4071,8 @@ public class NotificationManagerService extends SystemService { enforceDeletingChannelHasNoUserInitiatedJob(pkg, userId, channelId); } List<NotificationChannel> deletedChannels = - mPreferencesHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId); + mPreferencesHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId, + callingUid, isSystemOrSystemUi); for (int i = 0; i < deletedChannels.size(); i++) { final NotificationChannel deletedChannel = deletedChannels.get(i); cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0, @@ -4963,11 +4970,14 @@ public class NotificationManagerService extends SystemService { @Override public void requestInterruptionFilterFromListener(INotificationListener token, int interruptionFilter) throws RemoteException { + final int callingUid = Binder.getCallingUid(); + final boolean isSystemOrSystemUi = isCallerIsSystemOrSystemUi(); final long identity = Binder.clearCallingIdentity(); try { synchronized (mNotificationLock) { final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); - mZenModeHelper.requestFromListener(info.component, interruptionFilter); + mZenModeHelper.requestFromListener(info.component, interruptionFilter, + callingUid, isSystemOrSystemUi); updateInterruptionFilterLocked(); } } finally { @@ -5007,9 +5017,12 @@ public class NotificationManagerService extends SystemService { @Override public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException { enforceSystemOrSystemUI("INotificationManager.setZenMode"); + final int callingUid = Binder.getCallingUid(); + final boolean isSystemOrSystemUi = isCallerIsSystemOrSystemUi(); final long identity = Binder.clearCallingIdentity(); try { - mZenModeHelper.setManualZenMode(mode, conditionId, null, reason); + mZenModeHelper.setManualZenMode(mode, conditionId, null, reason, callingUid, + isSystemOrSystemUi); } finally { Binder.restoreCallingIdentity(identity); } @@ -5056,7 +5069,8 @@ public class NotificationManagerService extends SystemService { } return mZenModeHelper.addAutomaticZenRule(rulePkg, automaticZenRule, - "addAutomaticZenRule"); + "addAutomaticZenRule", Binder.getCallingUid(), + isCallerIsSystemOrSystemUi()); } @Override @@ -5073,7 +5087,8 @@ public class NotificationManagerService extends SystemService { enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule"); return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule, - "updateAutomaticZenRule"); + "updateAutomaticZenRule", Binder.getCallingUid(), + isCallerIsSystemOrSystemUi()); } @Override @@ -5082,7 +5097,8 @@ public class NotificationManagerService extends SystemService { // Verify that they can modify zen rules. enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule"); - return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule"); + return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule", + Binder.getCallingUid(), isCallerIsSystemOrSystemUi()); } @Override @@ -5091,7 +5107,8 @@ public class NotificationManagerService extends SystemService { enforceSystemOrSystemUI("removeAutomaticZenRules"); return mZenModeHelper.removeAutomaticZenRules(packageName, - packageName + "|removeAutomaticZenRules"); + packageName + "|removeAutomaticZenRules", Binder.getCallingUid(), + isCallerIsSystemOrSystemUi()); } @Override @@ -5109,7 +5126,8 @@ public class NotificationManagerService extends SystemService { enforcePolicyAccess(Binder.getCallingUid(), "setAutomaticZenRuleState"); - mZenModeHelper.setAutomaticZenRuleState(id, condition); + mZenModeHelper.setAutomaticZenRuleState(id, condition, Binder.getCallingUid(), + isCallerIsSystemOrSystemUi()); } @Override @@ -5117,9 +5135,12 @@ public class NotificationManagerService extends SystemService { enforcePolicyAccess(pkg, "setInterruptionFilter"); final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1); if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter); + final int callingUid = Binder.getCallingUid(); + final boolean isSystemOrSystemUi = isCallerIsSystemOrSystemUi(); final long identity = Binder.clearCallingIdentity(); try { - mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter"); + mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter", + callingUid, isSystemOrSystemUi); } finally { Binder.restoreCallingIdentity(identity); } @@ -5420,6 +5441,7 @@ public class NotificationManagerService extends SystemService { public void setNotificationPolicy(String pkg, Policy policy) { enforcePolicyAccess(pkg, "setNotificationPolicy"); int callingUid = Binder.getCallingUid(); + boolean isSystemOrSystemUi = isCallerIsSystemOrSystemUi(); final long identity = Binder.clearCallingIdentity(); try { final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg, @@ -5459,7 +5481,7 @@ public class NotificationManagerService extends SystemService { policy.priorityCallSenders, policy.priorityMessageSenders, newVisualEffects, policy.priorityConversationSenders); ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion, policy); - mZenModeHelper.setNotificationPolicy(policy); + mZenModeHelper.setNotificationPolicy(policy, callingUid, isSystemOrSystemUi); } catch (RemoteException e) { } finally { Binder.restoreCallingIdentity(identity); @@ -6697,7 +6719,8 @@ public class NotificationManagerService extends SystemService { channel.setUserVisibleTaskShown(true); } mPreferencesHelper.updateNotificationChannel( - pkg, notificationUid, channel, false); + pkg, notificationUid, channel, false, callingUid, + isCallerIsSystemOrSystemUi()); r.updateNotificationChannel(channel); } else if (!channel.isUserVisibleTaskShown() && !TextUtils.isEmpty(channelId) && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) { @@ -6770,7 +6793,8 @@ public class NotificationManagerService extends SystemService { mHistoryManager.deleteConversations(pkg, uid, shortcuts); List<String> deletedChannelIds = - mPreferencesHelper.deleteConversations(pkg, uid, shortcuts); + mPreferencesHelper.deleteConversations(pkg, uid, shortcuts, + /* callingUid */ Process.SYSTEM_UID, /* is system */ true); for (String channelId : deletedChannelIds) { cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true, UserHandle.getUserId(uid), REASON_CHANNEL_REMOVED, @@ -9999,7 +10023,8 @@ public class NotificationManagerService extends SystemService { return isUidSystemOrPhone(Binder.getCallingUid()); } - private boolean isCallerIsSystemOrSystemUi() { + @VisibleForTesting + protected boolean isCallerIsSystemOrSystemUi() { if (isCallerSystemOrPhone()) { return true; } diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index 2460ce56f165..4399a3ca46c5 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -51,6 +51,7 @@ import android.metrics.LogMaker; import android.net.Uri; import android.os.Binder; import android.os.Build; +import android.os.Process; import android.os.UserHandle; import android.provider.Settings; import android.service.notification.ConversationChannelWrapper; @@ -217,7 +218,7 @@ public class PreferencesHelper implements RankingConfig { updateBadgingEnabled(); updateBubblesEnabled(); updateMediaNotificationFilteringEnabled(); - syncChannelsBypassingDnd(); + syncChannelsBypassingDnd(Process.SYSTEM_UID, true); // init comes from system } public void readXml(TypedXmlPullParser parser, boolean forRestore, int userId) @@ -834,7 +835,7 @@ public class PreferencesHelper implements RankingConfig { @Override public void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group, - boolean fromTargetApp) { + boolean fromTargetApp, int callingUid, boolean fromSystemOrSystemUi) { Objects.requireNonNull(pkg); Objects.requireNonNull(group); Objects.requireNonNull(group.getId()); @@ -880,13 +881,14 @@ public class PreferencesHelper implements RankingConfig { r.groups.put(group.getId(), group); } if (needsDndChange) { - updateChannelsBypassingDnd(); + updateChannelsBypassingDnd(callingUid, fromSystemOrSystemUi); } } @Override public boolean createNotificationChannel(String pkg, int uid, NotificationChannel channel, - boolean fromTargetApp, boolean hasDndAccess) { + boolean fromTargetApp, boolean hasDndAccess, int callingUid, + boolean fromSystemOrSystemUi) { Objects.requireNonNull(pkg); Objects.requireNonNull(channel); Objects.requireNonNull(channel.getId()); @@ -1027,7 +1029,7 @@ public class PreferencesHelper implements RankingConfig { } if (needsDndChange) { - updateChannelsBypassingDnd(); + updateChannelsBypassingDnd(callingUid, fromSystemOrSystemUi); } return needsPolicyFileChange; @@ -1056,7 +1058,7 @@ public class PreferencesHelper implements RankingConfig { @Override public void updateNotificationChannel(String pkg, int uid, NotificationChannel updatedChannel, - boolean fromUser) { + boolean fromUser, int callingUid, boolean fromSystemOrSystemUi) { Objects.requireNonNull(updatedChannel); Objects.requireNonNull(updatedChannel.getId()); boolean changed = false; @@ -1112,7 +1114,7 @@ public class PreferencesHelper implements RankingConfig { } } if (needsDndChange) { - updateChannelsBypassingDnd(); + updateChannelsBypassingDnd(callingUid, fromSystemOrSystemUi); } if (changed) { updateConfig(); @@ -1188,7 +1190,8 @@ public class PreferencesHelper implements RankingConfig { } @Override - public boolean deleteNotificationChannel(String pkg, int uid, String channelId) { + public boolean deleteNotificationChannel(String pkg, int uid, String channelId, + int callingUid, boolean fromSystemOrSystemUi) { boolean deletedChannel = false; boolean channelBypassedDnd = false; synchronized (mPackagePreferences) { @@ -1203,7 +1206,7 @@ public class PreferencesHelper implements RankingConfig { } } if (channelBypassedDnd) { - updateChannelsBypassingDnd(); + updateChannelsBypassingDnd(callingUid, fromSystemOrSystemUi); } return deletedChannel; } @@ -1394,7 +1397,7 @@ public class PreferencesHelper implements RankingConfig { } public List<NotificationChannel> deleteNotificationChannelGroup(String pkg, int uid, - String groupId) { + String groupId, int callingUid, boolean fromSystemOrSystemUi) { List<NotificationChannel> deletedChannels = new ArrayList<>(); boolean groupBypassedDnd = false; synchronized (mPackagePreferences) { @@ -1420,7 +1423,7 @@ public class PreferencesHelper implements RankingConfig { } } if (groupBypassedDnd) { - updateChannelsBypassingDnd(); + updateChannelsBypassingDnd(callingUid, fromSystemOrSystemUi); } return deletedChannels; } @@ -1543,7 +1546,7 @@ public class PreferencesHelper implements RankingConfig { } public @NonNull List<String> deleteConversations(String pkg, int uid, - Set<String> conversationIds) { + Set<String> conversationIds, int callingUid, boolean fromSystemOrSystemUi) { List<String> deletedChannelIds = new ArrayList<>(); synchronized (mPackagePreferences) { PackagePreferences r = getPackagePreferencesLocked(pkg, uid); @@ -1568,7 +1571,7 @@ public class PreferencesHelper implements RankingConfig { } } if (!deletedChannelIds.isEmpty() && mAreChannelsBypassingDnd) { - updateChannelsBypassingDnd(); + updateChannelsBypassingDnd(callingUid, fromSystemOrSystemUi); } return deletedChannelIds; } @@ -1673,18 +1676,18 @@ public class PreferencesHelper implements RankingConfig { * Syncs {@link #mAreChannelsBypassingDnd} with the current user's notification policy before * updating */ - private void syncChannelsBypassingDnd() { + private void syncChannelsBypassingDnd(int callingUid, boolean fromSystemOrSystemUi) { mAreChannelsBypassingDnd = (mZenModeHelper.getNotificationPolicy().state & NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND) == 1; - updateChannelsBypassingDnd(); + updateChannelsBypassingDnd(callingUid, fromSystemOrSystemUi); } /** * Updates the user's NotificationPolicy based on whether the current userId * has channels bypassing DND */ - private void updateChannelsBypassingDnd() { + private void updateChannelsBypassingDnd(int callingUid, boolean fromSystemOrSystemUi) { ArraySet<Pair<String, Integer>> candidatePkgs = new ArraySet<>(); final int currentUserId = getCurrentUser(); @@ -1714,7 +1717,7 @@ public class PreferencesHelper implements RankingConfig { boolean haveBypassingApps = candidatePkgs.size() > 0; if (mAreChannelsBypassingDnd != haveBypassingApps) { mAreChannelsBypassingDnd = haveBypassingApps; - updateZenPolicy(mAreChannelsBypassingDnd); + updateZenPolicy(mAreChannelsBypassingDnd, callingUid, fromSystemOrSystemUi); } } @@ -1739,14 +1742,15 @@ public class PreferencesHelper implements RankingConfig { return true; } - public void updateZenPolicy(boolean areChannelsBypassingDnd) { + public void updateZenPolicy(boolean areChannelsBypassingDnd, int callingUid, + boolean fromSystemOrSystemUi) { NotificationManager.Policy policy = mZenModeHelper.getNotificationPolicy(); mZenModeHelper.setNotificationPolicy(new NotificationManager.Policy( policy.priorityCategories, policy.priorityCallSenders, policy.priorityMessageSenders, policy.suppressedVisualEffects, (areChannelsBypassingDnd ? NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND : 0), - policy.priorityConversationSenders)); + policy.priorityConversationSenders), callingUid, fromSystemOrSystemUi); } public boolean areChannelsBypassingDnd() { diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java index 3e9d90c440b6..fec359198e88 100644 --- a/services/core/java/com/android/server/notification/RankingConfig.java +++ b/services/core/java/com/android/server/notification/RankingConfig.java @@ -39,19 +39,21 @@ public interface RankingConfig { Collection<NotificationChannelGroup> getNotificationChannelGroups(String pkg, int uid); void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group, - boolean fromTargetApp); + boolean fromTargetApp, int callingUid, boolean isSystemOrSystemUi); ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(String pkg, int uid, boolean includeDeleted, boolean includeNonGrouped, boolean includeEmpty); boolean createNotificationChannel(String pkg, int uid, NotificationChannel channel, - boolean fromTargetApp, boolean hasDndAccess); - void updateNotificationChannel(String pkg, int uid, NotificationChannel channel, - boolean fromUser); + boolean fromTargetApp, boolean hasDndAccess, int callingUid, + boolean isSystemOrSystemUi); + void updateNotificationChannel(String pkg, int uid, NotificationChannel updatedChannel, + boolean fromUser, int callingUid, boolean fromSystemOrSystemUi); NotificationChannel getNotificationChannel(String pkg, int uid, String channelId, boolean includeDeleted); NotificationChannel getConversationNotificationChannel(String pkg, int uid, String channelId, String conversationId, boolean returnParentIfNoConversationChannel, boolean includeDeleted); - boolean deleteNotificationChannel(String pkg, int uid, String channelId); + boolean deleteNotificationChannel(String pkg, int uid, String channelId, + int callingUid, boolean fromSystemOrSystemUi); void permanentlyDeleteNotificationChannel(String pkg, int uid, String channelId); void permanentlyDeleteNotificationChannels(String pkg, int uid); ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid, diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java index 50b4d438984c..6ecd799bf8e6 100644 --- a/services/core/java/com/android/server/notification/ZenModeConditions.java +++ b/services/core/java/com/android/server/notification/ZenModeConditions.java @@ -18,6 +18,8 @@ package com.android.server.notification; import android.content.ComponentName; import android.net.Uri; +import android.os.Binder; +import android.os.Process; import android.service.notification.Condition; import android.service.notification.IConditionProvider; import android.service.notification.ZenModeConfig; @@ -108,7 +110,9 @@ public class ZenModeConditions implements ConditionProviders.Callback { @Override public void onServiceAdded(ComponentName component) { if (DEBUG) Log.d(TAG, "onServiceAdded " + component); - mHelper.setConfig(mHelper.getConfig(), component, "zmc.onServiceAdded:" + component); + final int callingUid = Binder.getCallingUid(); + mHelper.setConfig(mHelper.getConfig(), component, "zmc.onServiceAdded:" + component, + callingUid, callingUid == Process.SYSTEM_UID); } @Override @@ -116,7 +120,9 @@ public class ZenModeConditions implements ConditionProviders.Callback { if (DEBUG) Log.d(TAG, "onConditionChanged " + id + " " + condition); ZenModeConfig config = mHelper.getConfig(); if (config == null) return; - mHelper.setAutomaticZenRuleState(id, condition); + final int callingUid = Binder.getCallingUid(); + mHelper.setAutomaticZenRuleState(id, condition, callingUid, + callingUid == Process.SYSTEM_UID); } // Only valid for CPS backed rules diff --git a/services/core/java/com/android/server/notification/ZenModeEventLogger.java b/services/core/java/com/android/server/notification/ZenModeEventLogger.java new file mode 100644 index 000000000000..1641d4a6ed46 --- /dev/null +++ b/services/core/java/com/android/server/notification/ZenModeEventLogger.java @@ -0,0 +1,611 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.notification; + +import static android.app.NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND; +import static android.provider.Settings.Global.ZEN_MODE_OFF; +import static android.service.notification.NotificationServiceProto.RULE_TYPE_AUTOMATIC; +import static android.service.notification.NotificationServiceProto.RULE_TYPE_MANUAL; +import static android.service.notification.NotificationServiceProto.RULE_TYPE_UNKNOWN; + +import android.annotation.NonNull; +import android.app.NotificationManager; +import android.content.pm.PackageManager; +import android.os.Process; +import android.service.notification.DNDPolicyProto; +import android.service.notification.ZenModeConfig; +import android.service.notification.ZenModeDiff; +import android.service.notification.ZenPolicy; +import android.util.ArrayMap; +import android.util.Log; +import android.util.Pair; +import android.util.Slog; +import android.util.proto.ProtoOutputStream; + +import com.android.internal.logging.UiEvent; +import com.android.internal.logging.UiEventLogger; +import com.android.internal.util.FrameworkStatsLog; + +import java.io.ByteArrayOutputStream; +import java.util.Objects; + +/** + * Class for writing DNDStateChanged atoms to the statsd log. + * Use ZenModeEventLoggerFake for testing. + */ +class ZenModeEventLogger { + private static final String TAG = "ZenModeEventLogger"; + + // Placeholder int for unknown zen mode, to distinguish from "off". + static final int ZEN_MODE_UNKNOWN = -1; + + // Object for tracking config changes and policy changes associated with an overall zen + // mode change. + ZenModeEventLogger.ZenStateChanges mChangeState = new ZenModeEventLogger.ZenStateChanges(); + + private PackageManager mPm; + + ZenModeEventLogger(PackageManager pm) { + mPm = pm; + } + + /** + * Enum used to log the type of DND state changed events. + * These use UiEvent IDs for ease of integrating with other UiEvents. + */ + enum ZenStateChangedEvent implements UiEventLogger.UiEventEnum { + @UiEvent(doc = "DND was turned on; may additionally include policy change.") + DND_TURNED_ON(1368), + @UiEvent(doc = "DND was turned off; may additionally include policy change.") + DND_TURNED_OFF(1369), + @UiEvent(doc = "DND policy was changed but the zen mode did not change.") + DND_POLICY_CHANGED(1370), + @UiEvent(doc = "Change in DND automatic rules active, without changing mode or policy.") + DND_ACTIVE_RULES_CHANGED(1371); + + private final int mId; + + ZenStateChangedEvent(int id) { + mId = id; + } + + @Override + public int getId() { + return mId; + } + } + + /** + * Potentially log a zen mode change if the provided config and policy changes warrant it. + * + * @param prevInfo ZenModeInfo (zen mode setting, config, policy) prior to this change + * @param newInfo ZenModeInfo after this change takes effect + * @param callingUid the calling UID associated with the change; may be used to attribute the + * change to a particular package or determine if this is a user action + * @param fromSystemOrSystemUi whether the calling UID is either system UID or system UI + */ + public final void maybeLogZenChange(ZenModeInfo prevInfo, ZenModeInfo newInfo, int callingUid, + boolean fromSystemOrSystemUi) { + mChangeState.init(prevInfo, newInfo, callingUid, fromSystemOrSystemUi); + if (mChangeState.shouldLogChanges()) { + maybeReassignCallingUid(); + logChanges(); + } + + // clear out the state for a fresh start next time + mChangeState = new ZenModeEventLogger.ZenStateChanges(); + } + + /** + * Reassign callingUid in mChangeState if we have more specific information that warrants it + * (for instance, if the change is automatic and due to an automatic rule change). + */ + private void maybeReassignCallingUid() { + int userId = Process.INVALID_UID; + String packageName = null; + + // For a manual rule, we consider reassigning the UID only when the call seems to come from + // the system and there is a non-null enabler in the new config. + // We don't consider the manual rule in the old config because if a manual rule is turning + // off with a call from system, that could easily be a user action to explicitly turn it off + if (mChangeState.getChangedRuleType() == RULE_TYPE_MANUAL) { + if (!mChangeState.mFromSystemOrSystemUi + || mChangeState.getNewManualRuleEnabler() == null) { + return; + } + packageName = mChangeState.getNewManualRuleEnabler(); + userId = mChangeState.mNewConfig.user; // mNewConfig must not be null if enabler exists + } + + // The conditions where we should consider reassigning UID for an automatic rule change: + // - we've determined it's not a user action + // - our current best guess is that the calling uid is system/sysui + if (mChangeState.getChangedRuleType() == RULE_TYPE_AUTOMATIC) { + if (mChangeState.getIsUserAction() || !mChangeState.mFromSystemOrSystemUi) { + return; + } + + // Only try to get the package UID if there's exactly one changed automatic rule. If + // there's more than one that changes simultaneously, this is likely to be a boot and + // we can leave it attributed to system. + ArrayMap<String, ZenModeDiff.RuleDiff> changedRules = + mChangeState.getChangedAutomaticRules(); + if (changedRules.size() != 1) { + return; + } + Pair<String, Integer> ruleInfo = mChangeState.getRulePackageAndUser( + changedRules.keyAt(0), + changedRules.valueAt(0)); + + if (ruleInfo == null || ruleInfo.first.equals(ZenModeConfig.SYSTEM_AUTHORITY)) { + // leave system rules as-is + return; + } + + packageName = ruleInfo.first; + userId = ruleInfo.second; + } + + if (userId == Process.INVALID_UID || packageName == null) { + // haven't found anything to look up. + return; + } + + try { + int uid = mPm.getPackageUidAsUser(packageName, userId); + mChangeState.mCallingUid = uid; + } catch (PackageManager.NameNotFoundException e) { + Slog.e(TAG, "unable to find package name " + packageName + " " + userId); + } + } + + /** + * Actually log all changes stored in the current change state to statsd output. This method + * should not be used directly by callers; visible for override by subclasses. + */ + void logChanges() { + FrameworkStatsLog.write(FrameworkStatsLog.DND_STATE_CHANGED, + /* int32 event_id = 1 */ mChangeState.getEventId().getId(), + /* android.stats.dnd.ZenMode new_mode = 2 */ mChangeState.mNewZenMode, + /* android.stats.dnd.ZenMode previous_mode = 3 */ mChangeState.mPrevZenMode, + /* android.stats.dnd.RuleType rule_type = 4 */ mChangeState.getChangedRuleType(), + /* int32 num_rules_active = 5 */ mChangeState.getNumRulesActive(), + /* bool user_action = 6 */ mChangeState.getIsUserAction(), + /* int32 package_uid = 7 */ mChangeState.getPackageUid(), + /* DNDPolicyProto current_policy = 8 */ mChangeState.getDNDPolicyProto(), + /* bool are_channels_bypassing = 9 */ mChangeState.getAreChannelsBypassing()); + } + + /** + * Helper class for storing the set of information about a zen mode configuration at a specific + * time: the current zen mode setting, ZenModeConfig, and consolidated policy (a result of + * evaluating all active zen rules at the time). + */ + public static class ZenModeInfo { + final int mZenMode; + final ZenModeConfig mConfig; + final NotificationManager.Policy mPolicy; + + ZenModeInfo(int zenMode, ZenModeConfig config, NotificationManager.Policy policy) { + mZenMode = zenMode; + // Store a copy of configs & policies to not accidentally pick up any further changes + mConfig = config != null ? config.copy() : null; + mPolicy = policy != null ? policy.copy() : null; + } + } + + /** + * Class used to track overall changes in zen mode, since changes such as config updates happen + * in multiple stages (first changing the config, then re-evaluating zen mode and the + * consolidated policy), and which contains the logic of 1) whether to log the zen mode change + * and 2) deriving the properties to log. + */ + static class ZenStateChanges { + int mPrevZenMode = ZEN_MODE_UNKNOWN; + int mNewZenMode = ZEN_MODE_UNKNOWN; + ZenModeConfig mPrevConfig, mNewConfig; + NotificationManager.Policy mPrevPolicy, mNewPolicy; + int mCallingUid = Process.INVALID_UID; + boolean mFromSystemOrSystemUi = false; + + private void init(ZenModeInfo prevInfo, ZenModeInfo newInfo, int callingUid, + boolean fromSystemOrSystemUi) { + // previous & new may be the same -- that would indicate that zen mode hasn't changed. + mPrevZenMode = prevInfo.mZenMode; + mNewZenMode = newInfo.mZenMode; + mPrevConfig = prevInfo.mConfig; + mNewConfig = newInfo.mConfig; + mPrevPolicy = prevInfo.mPolicy; + mNewPolicy = newInfo.mPolicy; + mCallingUid = callingUid; + mFromSystemOrSystemUi = fromSystemOrSystemUi; + } + + /** + * Returns whether there is a policy diff represented by this change. This doesn't count + * if the previous policy is null, as that would indicate having no information rather than + * having no previous policy. + */ + private boolean hasPolicyDiff() { + return mPrevPolicy != null && !Objects.equals(mPrevPolicy, mNewPolicy); + } + + /** + * Whether the set of changes encapsulated in this state should be logged. This should only + * be called after methods to store config and zen mode info. + */ + private boolean shouldLogChanges() { + // Did zen mode change from off to on or vice versa? If so, log in all cases. + if (zenModeFlipped()) { + return true; + } + + // If zen mode didn't change, did the policy or number of active rules change? We only + // care about changes that take effect while zen mode is on, so make sure the current + // zen mode is not "OFF" + if (mNewZenMode == ZEN_MODE_OFF) { + return false; + } + return hasPolicyDiff() || hasRuleCountDiff(); + } + + // Does the difference in zen mode go from off to on or vice versa? + private boolean zenModeFlipped() { + if (mPrevZenMode == mNewZenMode) { + return false; + } + + // then it flipped if one or the other is off. (there's only one off state; there are + // multiple states one could consider "on") + return mPrevZenMode == ZEN_MODE_OFF || mNewZenMode == ZEN_MODE_OFF; + } + + // Helper methods below to fill out the atom contents below: + + /** + * Based on the changes, returns the event ID corresponding to the change. Assumes that + * shouldLogChanges() is true and already checked (and will Log.wtf if not true). + */ + ZenStateChangedEvent getEventId() { + if (!shouldLogChanges()) { + Log.wtf(TAG, "attempt to get DNDStateChanged fields without shouldLog=true"); + } + if (zenModeFlipped()) { + if (mPrevZenMode == ZEN_MODE_OFF) { + return ZenStateChangedEvent.DND_TURNED_ON; + } else { + return ZenStateChangedEvent.DND_TURNED_OFF; + } + } + + // zen mode didn't change; we must be here because of a policy change or rule change + if (hasPolicyDiff() || hasChannelsBypassingDiff()) { + return ZenStateChangedEvent.DND_POLICY_CHANGED; + } + + // Also no policy change, so it has to be a rule change + return ZenStateChangedEvent.DND_ACTIVE_RULES_CHANGED; + } + + /** + * Based on the config diff, determine which type of rule changed (or "unknown" to indicate + * unknown or neither). + * In the (probably somewhat unusual) case that there are both, manual takes precedence over + * automatic. + */ + int getChangedRuleType() { + ZenModeDiff.ConfigDiff diff = new ZenModeDiff.ConfigDiff(mPrevConfig, mNewConfig); + if (!diff.hasDiff()) { + // no diff in the config. this probably shouldn't happen, but we can consider it + // unknown (given that if zen mode changes it is usually accompanied by some rule + // turning on or off, which should cause a config diff). + return RULE_TYPE_UNKNOWN; + } + + ZenModeDiff.RuleDiff manualDiff = diff.getManualRuleDiff(); + if (manualDiff != null && manualDiff.hasDiff()) { + // a diff in the manual rule doesn't *necessarily* mean that it's responsible for + // the change -- only if it's been added or removed. + if (manualDiff.wasAdded() || manualDiff.wasRemoved()) { + return RULE_TYPE_MANUAL; + } + } + + ArrayMap<String, ZenModeDiff.RuleDiff> autoDiffs = diff.getAllAutomaticRuleDiffs(); + if (autoDiffs != null) { + for (ZenModeDiff.RuleDiff d : autoDiffs.values()) { + if (d != null && d.hasDiff()) { + // If the rule became active or inactive, then this is probably relevant. + if (d.becameActive() || d.becameInactive()) { + return RULE_TYPE_AUTOMATIC; + } + } + } + } + return RULE_TYPE_UNKNOWN; + } + + /** + * Returns whether the previous config and new config have a different number of active + * automatic or manual rules. + */ + private boolean hasRuleCountDiff() { + return numActiveRulesInConfig(mPrevConfig) != numActiveRulesInConfig(mNewConfig); + } + + /** + * Get the number of active rules represented in a zen mode config. Because this is based + * on a config, this does not take into account the zen mode at the time of the config, + * which means callers need to take the zen mode into account for whether the rules are + * actually active. + */ + int numActiveRulesInConfig(ZenModeConfig config) { + // If the config is null, return early + if (config == null) { + return 0; + } + + int rules = 0; + // Loop through the config and check: + // - does a manual rule exist? (if it's non-null, it's active) + // - how many automatic rules are active, as defined by isAutomaticActive()? + if (config.manualRule != null) { + rules++; + } + + if (config.automaticRules != null) { + for (ZenModeConfig.ZenRule rule : config.automaticRules.values()) { + if (rule != null && rule.isAutomaticActive()) { + rules++; + } + } + } + return rules; + } + + // Determine the number of (automatic & manual) rules active after the change takes place. + int getNumRulesActive() { + // If the zen mode has turned off, that means nothing can be active. + if (mNewZenMode == ZEN_MODE_OFF) { + return 0; + } + return numActiveRulesInConfig(mNewConfig); + } + + /** + * Return our best guess as to whether the changes observed are due to a user action. + * Note that this won't be 100% accurate as we can't necessarily distinguish between a + * system uid call indicating "user interacted with Settings" vs "a system app changed + * something automatically". + */ + boolean getIsUserAction() { + // Approach: + // - if manual rule turned on or off, the calling UID is system, and the new manual + // rule does not have an enabler set, guess that this is likely to be a user action. + // This may represent a system app turning on DND automatically, but we guess "user" + // in this case. + // - note that this has a known failure mode of "manual rule turning off + // automatically after the default time runs out". We currently have no way + // of distinguishing this case from a user manually turning off the rule. + // - the reason for checking the enabler field is that a call may look like it's + // coming from a system UID, but if an enabler is set then the request came + // from an external source. "enabler" will be blank when manual rule is turned + // on from Quick Settings or Settings. + // - if an automatic rule's state changes in whether it is "enabled", then + // that is probably a user action. + // - if an automatic rule goes from "not snoozing" to "snoozing", that is probably + // a user action; that means that the user temporarily turned off DND associated + // with that rule. + // - if an automatic rule becomes active but does *not* change in its enabled state + // (covered by a previous case anyway), we guess that this is an automatic change. + // - if a rule is added or removed and the call comes from the system, we guess that + // this is a user action (as system rules can't be added or removed without a user + // action). + switch (getChangedRuleType()) { + case RULE_TYPE_MANUAL: + // TODO(b/278888961): Distinguish the automatically-turned-off state + return mFromSystemOrSystemUi && (getNewManualRuleEnabler() == null); + case RULE_TYPE_AUTOMATIC: + for (ZenModeDiff.RuleDiff d : getChangedAutomaticRules().values()) { + if (d.wasAdded() || d.wasRemoved()) { + // If the change comes from system, a rule being added/removed indicates + // a likely user action. From an app, it's harder to know for sure. + return mFromSystemOrSystemUi; + } + ZenModeDiff.FieldDiff enabled = d.getDiffForField( + ZenModeDiff.RuleDiff.FIELD_ENABLED); + if (enabled != null && enabled.hasDiff()) { + return true; + } + ZenModeDiff.FieldDiff snoozing = d.getDiffForField( + ZenModeDiff.RuleDiff.FIELD_SNOOZING); + if (snoozing != null && snoozing.hasDiff() && (boolean) snoozing.to()) { + return true; + } + } + // If the change was in an automatic rule and none of the "probably triggered + // by a user" cases apply, then it's probably an automatic change. + return false; + case RULE_TYPE_UNKNOWN: + default: + } + + // If the change wasn't in a rule, but was in the zen policy: consider to be user action + // if the calling uid is system + if (hasPolicyDiff() || hasChannelsBypassingDiff()) { + return mCallingUid == Process.SYSTEM_UID; + } + + // don't know, or none of the other things triggered; assume not a user action + return false; + } + + /** + * Get the package UID associated with this change, which is just the calling UID for the + * relevant method changes. This may get reset by ZenModeEventLogger, which has access to + * a PackageManager to get an appropriate UID for a package. + */ + int getPackageUid() { + return mCallingUid; + } + + /** + * Convert the new policy to a DNDPolicyProto format for output in logs. + */ + byte[] getDNDPolicyProto() { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + ProtoOutputStream proto = new ProtoOutputStream(bytes); + + // While we don't expect this to be null at any point, guard against any weird cases. + if (mNewPolicy != null) { + proto.write(DNDPolicyProto.CALLS, toState(mNewPolicy.allowCalls())); + proto.write(DNDPolicyProto.REPEAT_CALLERS, + toState(mNewPolicy.allowRepeatCallers())); + proto.write(DNDPolicyProto.MESSAGES, toState(mNewPolicy.allowMessages())); + proto.write(DNDPolicyProto.CONVERSATIONS, toState(mNewPolicy.allowConversations())); + proto.write(DNDPolicyProto.REMINDERS, toState(mNewPolicy.allowReminders())); + proto.write(DNDPolicyProto.EVENTS, toState(mNewPolicy.allowEvents())); + proto.write(DNDPolicyProto.ALARMS, toState(mNewPolicy.allowAlarms())); + proto.write(DNDPolicyProto.MEDIA, toState(mNewPolicy.allowMedia())); + proto.write(DNDPolicyProto.SYSTEM, toState(mNewPolicy.allowSystem())); + + proto.write(DNDPolicyProto.FULLSCREEN, toState(mNewPolicy.showFullScreenIntents())); + proto.write(DNDPolicyProto.LIGHTS, toState(mNewPolicy.showLights())); + proto.write(DNDPolicyProto.PEEK, toState(mNewPolicy.showPeeking())); + proto.write(DNDPolicyProto.STATUS_BAR, toState(mNewPolicy.showStatusBarIcons())); + proto.write(DNDPolicyProto.BADGE, toState(mNewPolicy.showBadges())); + proto.write(DNDPolicyProto.AMBIENT, toState(mNewPolicy.showAmbient())); + proto.write(DNDPolicyProto.NOTIFICATION_LIST, + toState(mNewPolicy.showInNotificationList())); + + // Note: The DND policy proto uses the people type enum from *ZenPolicy* and not + // *NotificationManager.Policy* (which is the type of the consolidated policy). + // This applies to both call and message senders, but not conversation senders, + // where they use the same enum values. + proto.write(DNDPolicyProto.ALLOW_CALLS_FROM, + ZenModeConfig.getZenPolicySenders(mNewPolicy.allowCallsFrom())); + proto.write(DNDPolicyProto.ALLOW_MESSAGES_FROM, + ZenModeConfig.getZenPolicySenders(mNewPolicy.allowMessagesFrom())); + proto.write(DNDPolicyProto.ALLOW_CONVERSATIONS_FROM, + mNewPolicy.allowConversationsFrom()); + } else { + Log.wtf(TAG, "attempted to write zen mode log event with null policy"); + } + + proto.flush(); + return bytes.toByteArray(); + } + + /** + * Get whether any channels are bypassing DND based on the current new policy. + */ + boolean getAreChannelsBypassing() { + if (mNewPolicy != null) { + return (mNewPolicy.state & STATE_CHANNELS_BYPASSING_DND) != 0; + } + return false; + } + + private boolean hasChannelsBypassingDiff() { + boolean prevChannelsBypassing = mPrevPolicy != null + ? (mPrevPolicy.state & STATE_CHANNELS_BYPASSING_DND) != 0 : false; + return prevChannelsBypassing != getAreChannelsBypassing(); + } + + /** + * helper method to turn a boolean allow or disallow state into STATE_ALLOW or + * STATE_DISALLOW (there is no concept of "unset" in NM.Policy.) + */ + private int toState(boolean allow) { + return allow ? ZenPolicy.STATE_ALLOW : ZenPolicy.STATE_DISALLOW; + } + + /** + * Get the list of automatic rules that have any diff (as a List of ZenModeDiff.RuleDiff). + * Returns an empty list if there isn't anything. + */ + private @NonNull ArrayMap<String, ZenModeDiff.RuleDiff> getChangedAutomaticRules() { + ArrayMap<String, ZenModeDiff.RuleDiff> ruleDiffs = new ArrayMap<>(); + + ZenModeDiff.ConfigDiff diff = new ZenModeDiff.ConfigDiff(mPrevConfig, mNewConfig); + if (!diff.hasDiff()) { + return ruleDiffs; + } + + ArrayMap<String, ZenModeDiff.RuleDiff> autoDiffs = diff.getAllAutomaticRuleDiffs(); + if (autoDiffs != null) { + return autoDiffs; + } + return ruleDiffs; + } + + /** + * Get the package name associated with this rule's owner, given its id and associated + * RuleDiff, as well as the user ID associated with the config it was found in. Returns null + * if none could be found. + */ + private Pair<String, Integer> getRulePackageAndUser(String id, ZenModeDiff.RuleDiff diff) { + // look for the rule info in the new config unless the rule was deleted. + ZenModeConfig configForSearch = mNewConfig; + if (diff.wasRemoved()) { + configForSearch = mPrevConfig; + } + + if (configForSearch == null) { + return null; + } + + ZenModeConfig.ZenRule rule = configForSearch.automaticRules.getOrDefault(id, null); + if (rule != null) { + if (rule.component != null) { + return new Pair(rule.component.getPackageName(), configForSearch.user); + } + if (rule.configurationActivity != null) { + return new Pair(rule.configurationActivity.getPackageName(), + configForSearch.user); + } + } + return null; + } + + /** + * Get the package name listed as the manual rule "enabler", if it exists in the new config. + */ + private String getNewManualRuleEnabler() { + if (mNewConfig == null || mNewConfig.manualRule == null) { + return null; + } + return mNewConfig.manualRule.enabler; + } + + /** + * Makes a copy for storing intermediate state for testing purposes. + */ + protected ZenStateChanges copy() { + ZenStateChanges copy = new ZenStateChanges(); + copy.mPrevZenMode = mPrevZenMode; + copy.mNewZenMode = mNewZenMode; + copy.mPrevConfig = mPrevConfig.copy(); + copy.mNewConfig = mNewConfig.copy(); + copy.mPrevPolicy = mPrevPolicy.copy(); + copy.mNewPolicy = mNewPolicy.copy(); + copy.mCallingUid = mCallingUid; + copy.mFromSystemOrSystemUi = mFromSystemOrSystemUi; + return copy; + } + } +} diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index f38c6c1aa827..36a0b0c0d8e9 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -76,6 +76,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags; import com.android.internal.logging.MetricsLogger; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; @@ -125,6 +126,8 @@ public class ZenModeHelper { @VisibleForTesting final SparseArray<ZenModeConfig> mConfigs = new SparseArray<>(); private final Metrics mMetrics = new Metrics(); private final ConditionProviders.Config mServiceConfig; + private SystemUiSystemPropertiesFlags.FlagResolver mFlagResolver; + @VisibleForTesting protected ZenModeEventLogger mZenModeEventLogger; @VisibleForTesting protected int mZenMode; @VisibleForTesting protected NotificationManager.Policy mConsolidatedPolicy; @@ -144,7 +147,9 @@ public class ZenModeHelper { private String[] mPriorityOnlyDndExemptPackages; public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders, - SysUiStatsEvent.BuilderFactory statsEventBuilderFactory) { + SysUiStatsEvent.BuilderFactory statsEventBuilderFactory, + SystemUiSystemPropertiesFlags.FlagResolver flagResolver, + ZenModeEventLogger zenModeEventLogger) { mContext = context; mHandler = new H(looper); addCallback(mMetrics); @@ -165,6 +170,8 @@ public class ZenModeHelper { mConditions = new ZenModeConditions(this, conditionProviders); mServiceConfig = conditionProviders.getConfig(); mStatsEventBuilderFactory = statsEventBuilderFactory; + mFlagResolver = flagResolver; + mZenModeEventLogger = zenModeEventLogger; } public Looper getLooper() { @@ -214,7 +221,13 @@ public class ZenModeHelper { public void initZenMode() { if (DEBUG) Log.d(TAG, "initZenMode"); - evaluateZenMode("init", true /*setRingerMode*/); + synchronized (mConfig) { + // "update" config to itself, which will have no effect in the case where a config + // was read in via XML, but will initialize zen mode if nothing was read in and the + // config remains the default. + updateConfigAndZenModeLocked(mConfig, "init", true /*setRingerMode*/, + Process.SYSTEM_UID /* callingUid */, true /* is system */); + } } public void onSystemReady() { @@ -266,7 +279,7 @@ public class ZenModeHelper { config.user = user; } synchronized (mConfig) { - setConfigLocked(config, null, reason); + setConfigLocked(config, null, reason, Process.SYSTEM_UID, true); } cleanUpZenRules(); } @@ -275,11 +288,13 @@ public class ZenModeHelper { return NotificationManager.zenModeToInterruptionFilter(mZenMode); } - public void requestFromListener(ComponentName name, int filter) { + public void requestFromListener(ComponentName name, int filter, int callingUid, + boolean fromSystemOrSystemUi) { final int newZen = NotificationManager.zenModeFromInterruptionFilter(filter, -1); if (newZen != -1) { setManualZenMode(newZen, null, name != null ? name.getPackageName() : null, - "listener:" + (name != null ? name.flattenToShortString() : null)); + "listener:" + (name != null ? name.flattenToShortString() : null), + callingUid, fromSystemOrSystemUi); } } @@ -324,7 +339,7 @@ public class ZenModeHelper { } public String addAutomaticZenRule(String pkg, AutomaticZenRule automaticZenRule, - String reason) { + String reason, int callingUid, boolean fromSystemOrSystemUi) { if (!ZenModeConfig.SYSTEM_AUTHORITY.equals(pkg)) { PackageItemInfo component = getServiceInfo(automaticZenRule.getOwner()); if (component == null) { @@ -360,7 +375,8 @@ public class ZenModeHelper { ZenRule rule = new ZenRule(); populateZenRule(pkg, automaticZenRule, rule, true); newConfig.automaticRules.put(rule.id, rule); - if (setConfigLocked(newConfig, reason, rule.component, true)) { + if (setConfigLocked(newConfig, reason, rule.component, true, callingUid, + fromSystemOrSystemUi)) { return rule.id; } else { throw new AndroidRuntimeException("Could not create rule"); @@ -369,7 +385,7 @@ public class ZenModeHelper { } public boolean updateAutomaticZenRule(String ruleId, AutomaticZenRule automaticZenRule, - String reason) { + String reason, int callingUid, boolean fromSystemOrSystemUi) { ZenModeConfig newConfig; synchronized (mConfig) { if (mConfig == null) return false; @@ -395,11 +411,13 @@ public class ZenModeHelper { } populateZenRule(rule.pkg, automaticZenRule, rule, false); - return setConfigLocked(newConfig, reason, rule.component, true); + return setConfigLocked(newConfig, reason, rule.component, true, callingUid, + fromSystemOrSystemUi); } } - public boolean removeAutomaticZenRule(String id, String reason) { + public boolean removeAutomaticZenRule(String id, String reason, int callingUid, + boolean fromSystemOrSystemUi) { ZenModeConfig newConfig; synchronized (mConfig) { if (mConfig == null) return false; @@ -424,11 +442,13 @@ public class ZenModeHelper { } dispatchOnAutomaticRuleStatusChanged( mConfig.user, ruleToRemove.getPkg(), id, AUTOMATIC_RULE_STATUS_REMOVED); - return setConfigLocked(newConfig, reason, null, true); + return setConfigLocked(newConfig, reason, null, true, callingUid, + fromSystemOrSystemUi); } } - public boolean removeAutomaticZenRules(String packageName, String reason) { + public boolean removeAutomaticZenRules(String packageName, String reason, int callingUid, + boolean fromSystemOrSystemUi) { ZenModeConfig newConfig; synchronized (mConfig) { if (mConfig == null) return false; @@ -439,11 +459,13 @@ public class ZenModeHelper { newConfig.automaticRules.removeAt(i); } } - return setConfigLocked(newConfig, reason, null, true); + return setConfigLocked(newConfig, reason, null, true, callingUid, + fromSystemOrSystemUi); } } - public void setAutomaticZenRuleState(String id, Condition condition) { + public void setAutomaticZenRuleState(String id, Condition condition, int callingUid, + boolean fromSystemOrSystemUi) { ZenModeConfig newConfig; synchronized (mConfig) { if (mConfig == null) return; @@ -451,11 +473,13 @@ public class ZenModeHelper { newConfig = mConfig.copy(); ArrayList<ZenRule> rules = new ArrayList<>(); rules.add(newConfig.automaticRules.get(id)); - setAutomaticZenRuleStateLocked(newConfig, rules, condition); + setAutomaticZenRuleStateLocked(newConfig, rules, condition, callingUid, + fromSystemOrSystemUi); } } - public void setAutomaticZenRuleState(Uri ruleDefinition, Condition condition) { + public void setAutomaticZenRuleState(Uri ruleDefinition, Condition condition, int callingUid, + boolean fromSystemOrSystemUi) { ZenModeConfig newConfig; synchronized (mConfig) { if (mConfig == null) return; @@ -463,18 +487,19 @@ public class ZenModeHelper { setAutomaticZenRuleStateLocked(newConfig, findMatchingRules(newConfig, ruleDefinition, condition), - condition); + condition, callingUid, fromSystemOrSystemUi); } } private void setAutomaticZenRuleStateLocked(ZenModeConfig config, List<ZenRule> rules, - Condition condition) { + Condition condition, int callingUid, boolean fromSystemOrSystemUi) { if (rules == null || rules.isEmpty()) return; for (ZenRule rule : rules) { rule.condition = condition; updateSnoozing(rule); - setConfigLocked(config, rule.component, "conditionChanged"); + setConfigLocked(config, rule.component, "conditionChanged", callingUid, + fromSystemOrSystemUi); } } @@ -561,7 +586,7 @@ public class ZenModeHelper { } } - protected void updateDefaultZenRules() { + protected void updateDefaultZenRules(int callingUid, boolean fromSystemOrSystemUi) { updateDefaultAutomaticRuleNames(); for (ZenRule defaultRule : mDefaultConfig.automaticRules.values()) { ZenRule currRule = mConfig.automaticRules.get(defaultRule.id); @@ -575,7 +600,7 @@ public class ZenModeHelper { // update default rule (if locale changed, name of rule will change) currRule.name = defaultRule.name; updateAutomaticZenRule(defaultRule.id, createAutomaticZenRule(currRule), - "locale changed"); + "locale changed", callingUid, fromSystemOrSystemUi); } } } @@ -650,14 +675,16 @@ public class ZenModeHelper { return azr; } - public void setManualZenMode(int zenMode, Uri conditionId, String caller, String reason) { - setManualZenMode(zenMode, conditionId, reason, caller, true /*setRingerMode*/); + public void setManualZenMode(int zenMode, Uri conditionId, String caller, String reason, + int callingUid, boolean fromSystemOrSystemUi) { + setManualZenMode(zenMode, conditionId, reason, caller, true /*setRingerMode*/, callingUid, + fromSystemOrSystemUi); Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.SHOW_ZEN_SETTINGS_SUGGESTION, 0); } private void setManualZenMode(int zenMode, Uri conditionId, String reason, String caller, - boolean setRingerMode) { + boolean setRingerMode, int callingUid, boolean fromSystemOrSystemUi) { ZenModeConfig newConfig; synchronized (mConfig) { if (mConfig == null) return; @@ -681,7 +708,8 @@ public class ZenModeHelper { newRule.enabler = caller; newConfig.manualRule = newRule; } - setConfigLocked(newConfig, reason, null, setRingerMode); + setConfigLocked(newConfig, reason, null, setRingerMode, callingUid, + fromSystemOrSystemUi); } } @@ -806,7 +834,7 @@ public class ZenModeHelper { } if (DEBUG) Log.d(TAG, reason); synchronized (mConfig) { - setConfigLocked(config, null, reason); + setConfigLocked(config, null, reason, Process.SYSTEM_UID, true); } } } @@ -838,12 +866,13 @@ public class ZenModeHelper { /** * Sets the global notification policy used for priority only do not disturb */ - public void setNotificationPolicy(Policy policy) { + public void setNotificationPolicy(Policy policy, int callingUid, boolean fromSystemOrSystemUi) { if (policy == null || mConfig == null) return; synchronized (mConfig) { final ZenModeConfig newConfig = mConfig.copy(); newConfig.applyNotificationPolicy(policy); - setConfigLocked(newConfig, null, "setNotificationPolicy"); + setConfigLocked(newConfig, null, "setNotificationPolicy", callingUid, + fromSystemOrSystemUi); } } @@ -868,7 +897,8 @@ public class ZenModeHelper { } } } - setConfigLocked(newConfig, null, "cleanUpZenRules"); + setConfigLocked(newConfig, null, "cleanUpZenRules", Process.SYSTEM_UID, + true); } } @@ -889,18 +919,21 @@ public class ZenModeHelper { } public boolean setConfigLocked(ZenModeConfig config, ComponentName triggeringComponent, - String reason) { - return setConfigLocked(config, reason, triggeringComponent, true /*setRingerMode*/); + String reason, int callingUid, boolean fromSystemOrSystemUi) { + return setConfigLocked(config, reason, triggeringComponent, true /*setRingerMode*/, + callingUid, fromSystemOrSystemUi); } - public void setConfig(ZenModeConfig config, ComponentName triggeringComponent, String reason) { + public void setConfig(ZenModeConfig config, ComponentName triggeringComponent, String reason, + int callingUid, boolean fromSystemOrSystemUi) { synchronized (mConfig) { - setConfigLocked(config, triggeringComponent, reason); + setConfigLocked(config, triggeringComponent, reason, callingUid, fromSystemOrSystemUi); } } private boolean setConfigLocked(ZenModeConfig config, String reason, - ComponentName triggeringComponent, boolean setRingerMode) { + ComponentName triggeringComponent, boolean setRingerMode, int callingUid, + boolean fromSystemOrSystemUi) { final long identity = Binder.clearCallingIdentity(); try { if (config == null || !config.isValid()) { @@ -927,17 +960,11 @@ public class ZenModeHelper { // send some broadcasts final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig), getNotificationPolicy(config)); - if (!config.equals(mConfig)) { - mConfig = config; - dispatchOnConfigChanged(); - updateConsolidatedPolicy(reason); - } if (policyChanged) { dispatchOnPolicyChanged(); } - final String val = Integer.toString(config.hashCode()); - Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val); - evaluateZenMode(reason, setRingerMode); + updateConfigAndZenModeLocked(config, reason, setRingerMode, callingUid, + fromSystemOrSystemUi); mConditions.evaluateConfig(config, triggeringComponent, true /*processSubscriptions*/); return true; } catch (SecurityException e) { @@ -948,6 +975,34 @@ public class ZenModeHelper { } } + /** + * Carries out a config update (if needed) and (re-)evaluates the zen mode value afterwards. + * If logging is enabled, will also request logging of the outcome of this change if needed. + */ + private void updateConfigAndZenModeLocked(ZenModeConfig config, String reason, + boolean setRingerMode, int callingUid, boolean fromSystemOrSystemUi) { + final boolean logZenModeEvents = mFlagResolver.isEnabled( + SystemUiSystemPropertiesFlags.NotificationFlags.LOG_DND_STATE_EVENTS); + // Store (a copy of) all config and zen mode info prior to any changes taking effect + ZenModeEventLogger.ZenModeInfo prevInfo = new ZenModeEventLogger.ZenModeInfo( + mZenMode, mConfig, mConsolidatedPolicy); + if (!config.equals(mConfig)) { + mConfig = config; + dispatchOnConfigChanged(); + updateConsolidatedPolicy(reason); + } + final String val = Integer.toString(config.hashCode()); + Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val); + evaluateZenMode(reason, setRingerMode); + // After all changes have occurred, log if requested + if (logZenModeEvents) { + ZenModeEventLogger.ZenModeInfo newInfo = new ZenModeEventLogger.ZenModeInfo( + mZenMode, mConfig, mConsolidatedPolicy); + mZenModeEventLogger.maybeLogZenChange(prevInfo, newInfo, callingUid, + fromSystemOrSystemUi); + } + } + private int getZenModeSetting() { return Global.getInt(mContext.getContentResolver(), Global.ZEN_MODE, Global.ZEN_MODE_OFF); } @@ -1366,7 +1421,7 @@ public class ZenModeHelper { if (newZen != -1) { setManualZenMode(newZen, null, "ringerModeInternal", null, - false /*setRingerMode*/); + false /*setRingerMode*/, Process.SYSTEM_UID, true); } if (isChange || newZen != -1 || ringerModeExternal != ringerModeExternalOut) { ZenLog.traceSetRingerModeInternal(ringerModeOld, ringerModeNew, caller, @@ -1404,7 +1459,7 @@ public class ZenModeHelper { } if (newZen != -1) { setManualZenMode(newZen, null, "ringerModeExternal", caller, - false /*setRingerMode*/); + false /*setRingerMode*/, Process.SYSTEM_UID, true); } ZenLog.traceSetRingerModeExternal(ringerModeOld, ringerModeNew, caller, diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index ff6c534b81ed..8218d5905a13 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -2192,6 +2192,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { any(), anyString(), anyInt(), anyString(), anyInt())) .thenReturn(SHOW_IMMEDIATELY); mService.isSystemUid = false; + mService.isSystemAppId = false; final NotificationRecord parent = generateNotificationRecord( mTestNotificationChannel, 1, "group", true); final NotificationRecord child = generateNotificationRecord( @@ -2218,6 +2219,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { any(), anyString(), anyInt(), anyString(), anyInt())) .thenReturn(SHOW_IMMEDIATELY); mService.isSystemUid = false; + mService.isSystemAppId = false; final NotificationRecord parent = generateNotificationRecord( mTestNotificationChannel, 1, "group", true); parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE; @@ -2241,6 +2243,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearChild() throws Exception { mService.isSystemUid = false; + mService.isSystemAppId = false; final NotificationRecord parent = generateNotificationRecord( mTestNotificationChannel, 1, "group", true); final NotificationRecord child = generateNotificationRecord( @@ -2264,6 +2267,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearParent() throws Exception { mService.isSystemUid = false; + mService.isSystemAppId = false; final NotificationRecord parent = generateNotificationRecord( mTestNotificationChannel, 1, "group", true); parent.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR; @@ -2290,6 +2294,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { any(), anyString(), anyInt(), anyString(), anyInt())) .thenReturn(SHOW_IMMEDIATELY); mService.isSystemUid = false; + mService.isSystemAppId = false; final NotificationRecord parent = generateNotificationRecord( mTestNotificationChannel, 1, "group", true); final NotificationRecord child = generateNotificationRecord( @@ -2318,6 +2323,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { any(), anyString(), anyInt(), anyString(), anyInt())) .thenReturn(SHOW_IMMEDIATELY); mService.isSystemUid = false; + mService.isSystemAppId = false; final NotificationRecord parent = generateNotificationRecord( mTestNotificationChannel, 1, "group", true); parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE; @@ -2343,6 +2349,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testCancelAllNotifications_fromApp_canCancelOngoingNoClearChild() throws Exception { mService.isSystemUid = false; + mService.isSystemAppId = false; final NotificationRecord parent = generateNotificationRecord( mTestNotificationChannel, 1, "group", true); final NotificationRecord child = generateNotificationRecord( @@ -2368,6 +2375,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testCancelAllNotifications_fromApp_canCancelOngoingNoClearParent() throws Exception { mService.isSystemUid = false; + mService.isSystemAppId = false; final NotificationRecord parent = generateNotificationRecord( mTestNotificationChannel, 1, "group", true); parent.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR; @@ -3207,7 +3215,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { eq(channel2.getId()), anyBoolean())) .thenReturn(channel2); when(mPreferencesHelper.createNotificationChannel(eq(PKG), anyInt(), - eq(channel2), anyBoolean(), anyBoolean())) + eq(channel2), anyBoolean(), anyBoolean(), anyInt(), anyBoolean())) .thenReturn(true); reset(mListeners); @@ -3266,7 +3274,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { eq(mTestNotificationChannel.getId()), anyBoolean())) .thenReturn(mTestNotificationChannel); when(mPreferencesHelper.deleteNotificationChannel(eq(PKG), anyInt(), - eq(mTestNotificationChannel.getId()))).thenReturn(true); + eq(mTestNotificationChannel.getId()), anyInt(), anyBoolean())).thenReturn(true); reset(mListeners); mBinderService.deleteNotificationChannel(PKG, mTestNotificationChannel.getId()); verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(PKG), @@ -3365,7 +3373,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { null, PKG, Process.myUserHandle(), mTestNotificationChannel); verify(mPreferencesHelper, times(1)).updateNotificationChannel( - anyString(), anyInt(), any(), anyBoolean()); + anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); verify(mListeners, never()).notifyNotificationChannelChanged(eq(PKG), eq(Process.myUserHandle()), eq(mTestNotificationChannel), @@ -3387,7 +3395,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } verify(mPreferencesHelper, never()).updateNotificationChannel( - anyString(), anyInt(), any(), anyBoolean()); + anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); verify(mListeners, never()).notifyNotificationChannelChanged(eq(PKG), eq(Process.myUserHandle()), eq(mTestNotificationChannel), @@ -3413,7 +3421,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } verify(mPreferencesHelper, never()).updateNotificationChannel( - anyString(), anyInt(), any(), anyBoolean()); + anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); verify(mListeners, never()).notifyNotificationChannelChanged(eq(PKG), eq(Process.myUserHandle()), eq(mTestNotificationChannel), @@ -4893,7 +4901,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.mLocaleChangeReceiver.onReceive(mContext, new Intent(Intent.ACTION_LOCALE_CHANGED)); - verify(mZenModeHelper, times(1)).updateDefaultZenRules(); + verify(mZenModeHelper, times(1)).updateDefaultZenRules( + anyInt(), anyBoolean()); } @Test @@ -6710,6 +6719,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); mService.isSystemUid = false; + mService.isSystemAppId = false; setToastRateIsWithinQuota(true); setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); @@ -6732,6 +6742,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); mService.isSystemUid = false; + mService.isSystemAppId = false; setToastRateIsWithinQuota(true); setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); @@ -6751,6 +6762,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); mService.isSystemUid = false; + mService.isSystemAppId = false; setToastRateIsWithinQuota(true); setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); @@ -6780,6 +6792,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); mService.isSystemUid = false; + mService.isSystemAppId = false; setToastRateIsWithinQuota(false); // rate limit reached setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); @@ -6803,6 +6816,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); mService.isSystemUid = false; + mService.isSystemAppId = false; setToastRateIsWithinQuota(true); setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); @@ -6837,6 +6851,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); mService.isSystemUid = false; + mService.isSystemAppId = false; setToastRateIsWithinQuota(true); setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); @@ -6856,6 +6871,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); mService.isSystemUid = false; + mService.isSystemAppId = false; setToastRateIsWithinQuota(true); setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); @@ -6875,6 +6891,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); mService.isSystemUid = false; + mService.isSystemAppId = false; setToastRateIsWithinQuota(true); setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); @@ -6905,6 +6922,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); mService.isSystemUid = false; + mService.isSystemAppId = false; setToastRateIsWithinQuota(false); // rate limit reached setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); setAppInForegroundForToasts(mUid, false); @@ -6927,6 +6945,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); mService.isSystemUid = false; + mService.isSystemAppId = false; setToastRateIsWithinQuota(false); // rate limit reached setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); setAppInForegroundForToasts(mUid, true); @@ -6948,6 +6967,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); mService.isSystemUid = false; + mService.isSystemAppId = false; setToastRateIsWithinQuota(false); // rate limit reached setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, true); setAppInForegroundForToasts(mUid, false); @@ -6969,6 +6989,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); mService.isSystemUid = false; + mService.isSystemAppId = false; setToastRateIsWithinQuota(false); // rate limit reached setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); setAppInForegroundForToasts(mUid, false); @@ -7027,6 +7048,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); mService.isSystemUid = false; + mService.isSystemAppId = false; setToastRateIsWithinQuota(true); setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); @@ -7048,6 +7070,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); mService.isSystemUid = false; + mService.isSystemAppId = false; setToastRateIsWithinQuota(true); setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); @@ -7151,6 +7174,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); mService.isSystemUid = false; + mService.isSystemAppId = false; setToastRateIsWithinQuota(true); setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); mockIsUserVisible(DEFAULT_DISPLAY, false); @@ -7171,6 +7195,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); mService.isSystemUid = false; + mService.isSystemAppId = false; setToastRateIsWithinQuota(true); setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); @@ -7193,6 +7218,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); mService.isSystemUid = false; + mService.isSystemAppId = false; setToastRateIsWithinQuota(true); setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); @@ -7237,6 +7263,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); mService.isSystemUid = false; + mService.isSystemAppId = false; setToastRateIsWithinQuota(true); setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); @@ -8128,7 +8155,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mBinderService.addAutomaticZenRule(rule, "com.android.settings"); // verify that zen mode helper gets passed in a package name of "android" - verify(mockZenModeHelper).addAutomaticZenRule(eq("android"), eq(rule), anyString()); + verify(mockZenModeHelper).addAutomaticZenRule(eq("android"), eq(rule), anyString(), + anyInt(), eq(true)); // system call counts as "is system or system ui" } @Test @@ -8149,7 +8177,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mBinderService.addAutomaticZenRule(rule, "com.android.settings"); // verify that zen mode helper gets passed in a package name of "android" - verify(mockZenModeHelper).addAutomaticZenRule(eq("android"), eq(rule), anyString()); + verify(mockZenModeHelper).addAutomaticZenRule(eq("android"), eq(rule), anyString(), + anyInt(), eq(true)); // system call counts as "system or system ui" } @Test @@ -8169,7 +8198,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // verify that zen mode helper gets passed in the package name from the arg, not the owner verify(mockZenModeHelper).addAutomaticZenRule( - eq("another.package"), eq(rule), anyString()); + eq("another.package"), eq(rule), anyString(), anyInt(), + eq(false)); // doesn't count as a system/systemui call } @Test @@ -9988,8 +10018,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testMatchesCallFilter_noPermissionShouldThrow() throws Exception { - // set the testable NMS to not system uid + // set the testable NMS to not system uid/appid mService.isSystemUid = false; + mService.isSystemAppId = false; // make sure a caller without listener access or read_contacts permission can't call // matchesCallFilter. @@ -10028,6 +10059,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testMatchesCallFilter_hasListenerPermission() throws Exception { mService.isSystemUid = false; + mService.isSystemAppId = false; // make sure a caller with only listener access and not read_contacts permission can call // matchesCallFilter. @@ -10046,6 +10078,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testMatchesCallFilter_hasContactsPermission() throws Exception { mService.isSystemUid = false; + mService.isSystemAppId = false; // make sure a caller with only read_contacts permission and not listener access can call // matchesCallFilter. @@ -11176,6 +11209,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) .thenReturn(true); mService.isSystemUid = false; + mService.isSystemAppId = false; final NotificationRecord parent = generateNotificationRecord( mTestNotificationChannel, 1, "group", true); final NotificationRecord child = generateNotificationRecord( @@ -11200,6 +11234,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) .thenReturn(true); mService.isSystemUid = false; + mService.isSystemAppId = false; final NotificationRecord parent = generateNotificationRecord( mTestNotificationChannel, 1, "group", true); parent.getNotification().flags |= FLAG_USER_INITIATED_JOB; @@ -11224,6 +11259,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) .thenReturn(true); mService.isSystemUid = false; + mService.isSystemAppId = false; final NotificationRecord parent = generateNotificationRecord( mTestNotificationChannel, 1, "group", true); final NotificationRecord child = generateNotificationRecord( @@ -11250,6 +11286,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) .thenReturn(true); mService.isSystemUid = false; + mService.isSystemAppId = false; final NotificationRecord parent = generateNotificationRecord( mTestNotificationChannel, 1, "group", true); parent.getNotification().flags |= FLAG_USER_INITIATED_JOB; @@ -11673,6 +11710,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { private void allowTestPackageToToast() throws Exception { assertWithMessage("toast queue").that(mService.mToastQueue).isEmpty(); mService.isSystemUid = false; + mService.isSystemAppId = false; setToastRateIsWithinQuota(true); setIfPackageHasPermissionToAvoidToastRateLimiting(TEST_PACKAGE, false); // package is not suspended diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index c78b03e4b5cb..48ad86da1bc5 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -60,6 +60,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; @@ -421,13 +422,15 @@ public class PreferencesHelperTest extends UiServiceTestCase { int uid0 = 1001; setUpPackageWithUid(package0, uid0); NotificationChannel channel0 = new NotificationChannel("id0", "name0", IMPORTANCE_HIGH); - assertTrue(mHelper.createNotificationChannel(package0, uid0, channel0, true, false)); + assertTrue(mHelper.createNotificationChannel(package0, uid0, channel0, true, false, + uid0, false)); String package10 = "test.package.user10"; int uid10 = 1001001; setUpPackageWithUid(package10, uid10); NotificationChannel channel10 = new NotificationChannel("id10", "name10", IMPORTANCE_HIGH); - assertTrue(mHelper.createNotificationChannel(package10, uid10, channel10, true, false)); + assertTrue(mHelper.createNotificationChannel(package10, uid10, channel10, true, false, + uid10, false)); ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>(); appPermissions.put(new Pair<>(uid0, package0), new Pair<>(false, false)); @@ -459,7 +462,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { int uid0 = 1001; setUpPackageWithUid(package0, uid0); NotificationChannel channel0 = new NotificationChannel("id0", "name0", IMPORTANCE_HIGH); - assertTrue(mHelper.createNotificationChannel(package0, uid0, channel0, true, false)); + assertTrue(mHelper.createNotificationChannel(package0, uid0, channel0, true, false, + uid0, false)); ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>(); appPermissions.put(new Pair<>(uid0, package0), new Pair<>(true, false)); @@ -506,10 +510,14 @@ public class PreferencesHelperTest extends UiServiceTestCase { channel2.setConversationId("id1", "conversation"); channel2.setDemoted(true); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true); - assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false)); - assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false)); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, + UID_N_MR1, false); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true, + UID_N_MR1, false); + assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, + UID_N_MR1, false)); + assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false, + UID_N_MR1, false)); mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true); @@ -569,12 +577,18 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel channel3 = new NotificationChannel("id3", "NAM3", IMPORTANCE_HIGH); channel3.enableVibration(true); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false); - mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, + UID_N_MR1, false); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false, + SYSTEM_UID, true); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false, + SYSTEM_UID, true); + mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false, + UID_N_MR1, false); mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true); mHelper.setInvalidMessageSent(PKG_P, UID_P); @@ -1040,12 +1054,18 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel channel3 = new NotificationChannel("id3", "NAM3", IMPORTANCE_HIGH); channel3.enableVibration(true); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false); - mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, + UID_N_MR1, false); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false, + SYSTEM_UID, true); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false, + SYSTEM_UID, true); + mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false, + UID_N_MR1, false); mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true); mHelper.setInvalidMessageSent(PKG_P, UID_P); @@ -1120,12 +1140,18 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel channel3 = new NotificationChannel("id3", "NAM3", IMPORTANCE_HIGH); channel3.enableVibration(true); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false); - mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, + UID_N_MR1, false); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false, + SYSTEM_UID, true); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false, + SYSTEM_UID, true); + mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false, + UID_N_MR1, false); mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true); mHelper.setInvalidMessageSent(PKG_P, UID_P); @@ -1202,12 +1228,18 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel channel3 = new NotificationChannel("id3", "NAM3", IMPORTANCE_HIGH); channel3.enableVibration(true); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false); - mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, + UID_N_MR1, false); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false, + SYSTEM_UID, true); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false, + SYSTEM_UID, true); + mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false, + UID_N_MR1, false); mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true); mHelper.setInvalidMessageSent(PKG_P, UID_P); @@ -1285,7 +1317,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel channel = new NotificationChannel("id", "name", IMPORTANCE_LOW); channel.setSound(SOUND_URI, mAudioAttributes); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, + UID_N_MR1, false); ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, USER_SYSTEM, channel.getId()); @@ -1312,7 +1345,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel channel = new NotificationChannel("id", "name", IMPORTANCE_LOW); channel.setSound(SOUND_URI, mAudioAttributes); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, + UID_N_MR1, false); ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, USER_SYSTEM, channel.getId()); @@ -1334,7 +1368,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel channel = new NotificationChannel("id", "name", IMPORTANCE_LOW); channel.setSound(SOUND_URI, mAudioAttributes); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, + UID_N_MR1, false); ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, USER_SYSTEM, channel.getId()); @@ -1359,7 +1394,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel channel = new NotificationChannel("id", "name", IMPORTANCE_LOW); channel.setSound(SOUND_URI, mAudioAttributes); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, + UID_N_MR1, false); ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, USER_SYSTEM, channel.getId()); @@ -1437,7 +1473,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel channel = new NotificationChannel("id", "name", IMPORTANCE_LOW); channel.setSound(null, mAudioAttributes); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, + UID_N_MR1, false); ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, USER_SYSTEM, channel.getId()); @@ -1466,7 +1503,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel channel = new NotificationChannel("id", "name", IMPORTANCE_LOW); channel.setSound(ANDROID_RES_SOUND_URI, mAudioAttributes); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, + UID_N_MR1, false); ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, USER_SYSTEM, channel.getId()); @@ -1501,7 +1539,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel channel = new NotificationChannel("id", "name", IMPORTANCE_LOW); channel.setSound(FILE_SOUND_URI, mAudioAttributes); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, + UID_N_MR1, false); ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, USER_SYSTEM, channel.getId()); @@ -1527,14 +1566,21 @@ public class PreferencesHelperTest extends UiServiceTestCase { new NotificationChannel("id3", "name3", IMPORTANCE_LOW); channel3.setGroup(ncg.getId()); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false); - - mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId()); - mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg.getId()); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, + UID_N_MR1, false); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false, + SYSTEM_UID, true); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false, + UID_N_MR1, false); + + mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), + UID_N_MR1, false); + mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg.getId(), + UID_N_MR1, false); assertEquals(channel2, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false)); @@ -1578,7 +1624,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false); defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW); - mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true); + mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true, + UID_N_MR1, false); ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false, UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID); @@ -1641,7 +1688,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testDeletesDefaultChannelAfterChannelIsCreated() throws Exception { mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, - new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false); + new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false, + UID_N_MR1, false); ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false, UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID, "bananas"); @@ -1661,7 +1709,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false, UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID, "bananas"); mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, - new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false); + new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false, + UID_N_MR1, false); loadStreamXml(baos, false, UserHandle.USER_ALL); @@ -1674,7 +1723,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { try { mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE - 1), - true, false); + true, false, UID_N_MR1, false); fail("Was allowed to create a channel with invalid importance"); } catch (IllegalArgumentException e) { // yay @@ -1682,7 +1731,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { try { mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, new NotificationChannel("bananas", "bananas", IMPORTANCE_UNSPECIFIED), - true, false); + true, false, UID_N_MR1, false); fail("Was allowed to create a channel with invalid importance"); } catch (IllegalArgumentException e) { // yay @@ -1690,57 +1739,61 @@ public class PreferencesHelperTest extends UiServiceTestCase { try { mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX + 1), - true, false); + true, false, UID_N_MR1, false); fail("Was allowed to create a channel with invalid importance"); } catch (IllegalArgumentException e) { // yay } assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, - new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE), true, false)); + new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE), true, false, + UID_N_MR1, false)); assertFalse(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, - new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX), true, false)); + new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX), true, false, + UID_N_MR1, false)); } @Test public void testUpdateChannel_downgradeImportance() { mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, new NotificationChannel("bananas", "bananas", IMPORTANCE_DEFAULT), - true, false); + true, false, UID_N_MR1, false); assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, - new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false)); + new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false, + UID_N_MR1, false)); } @Test public void testUpdateChannel_upgradeImportance_ignored() { mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, new NotificationChannel("bananas", "bananas", IMPORTANCE_DEFAULT), - true, false); + true, false, UID_N_MR1, false); assertFalse(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, - new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX), true, false)); + new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX), true, false, + UID_N_MR1, false)); } @Test public void testUpdateChannel_badImportance() { mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, new NotificationChannel("bananas", "bananas", IMPORTANCE_DEFAULT), - true, false); + true, false, UID_N_MR1, false); assertThrows(IllegalArgumentException.class, () -> mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE - 1), true, - false)); + false, UID_N_MR1, false)); assertThrows(IllegalArgumentException.class, () -> mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, new NotificationChannel("bananas", "bananas", IMPORTANCE_UNSPECIFIED), true, - false)); + false, UID_N_MR1, false)); assertThrows(IllegalArgumentException.class, () -> mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX + 1), true, - false)); + false, UID_N_MR1, false)); } @Test @@ -1753,7 +1806,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { channel.setBypassDnd(true); channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); - assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, false, false)); + assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, false, false, + SYSTEM_UID, true)); // same id, try to update all fields final NotificationChannel channel2 = @@ -1763,7 +1817,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { channel2.setBypassDnd(false); channel2.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); - mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true); + mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, + SYSTEM_UID, true); // all fields should be changed assertEquals(channel2, @@ -1788,7 +1843,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { defaultChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); mHelper.setAppImportanceLocked(PKG_N_MR1, UID_N_MR1); - mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true); + mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true, + SYSTEM_UID, true); // ensure app level fields are changed assertFalse(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1)); @@ -1801,7 +1857,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { public void testUpdate_postUpgrade_noUpdateAppFields() throws Exception { final NotificationChannel channel = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG_O, UID_O, channel, false, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channel, false, false, + SYSTEM_UID, true); assertTrue(mHelper.canShowBadge(PKG_O, UID_O)); assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_O, UID_O)); assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE, @@ -1812,7 +1869,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { channel.setBypassDnd(true); channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); - mHelper.updateNotificationChannel(PKG_O, UID_O, channel, true); + mHelper.updateNotificationChannel(PKG_O, UID_O, channel, true, + SYSTEM_UID, true); // ensure app level fields are not changed assertTrue(mHelper.canShowBadge(PKG_O, UID_O)); @@ -1825,7 +1883,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { public void testUpdate_preUpgrade_noUpdateAppFieldsWithMultipleChannels() throws Exception { final NotificationChannel channel = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, false, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, false, false, + SYSTEM_UID, true); assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1)); assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1)); assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE, @@ -1836,7 +1895,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { channel.setBypassDnd(true); channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); - mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true); + mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, + SYSTEM_UID, true); NotificationChannel defaultChannel = mHelper.getNotificationChannel( PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false); @@ -1846,7 +1906,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { defaultChannel.setBypassDnd(true); defaultChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); - mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true); + mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true, + SYSTEM_UID, true); // ensure app level fields are not changed assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1)); @@ -1877,7 +1938,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { } channel.lockFields(lockMask); - assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false)); + assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, + UID_N_MR1, false)); NotificationChannel savedChannel = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), false); @@ -1909,7 +1971,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { } channel.lockFields(lockMask); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, + UID_N_MR1, false); NotificationChannel savedChannel = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), false); @@ -1936,13 +1999,14 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testLockFields_soundAndVibration() { - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false, + UID_N_MR1, false); final NotificationChannel update1 = getChannel(); update1.setSound(new Uri.Builder().scheme("test").build(), new AudioAttributes.Builder().build()); update1.lockFields(NotificationChannel.USER_LOCKED_PRIORITY); - mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true); + mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true, SYSTEM_UID, true); assertEquals(NotificationChannel.USER_LOCKED_PRIORITY | NotificationChannel.USER_LOCKED_SOUND, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false) @@ -1950,7 +2014,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel update2 = getChannel(); update2.enableVibration(true); - mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true); + mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true, SYSTEM_UID, true); assertEquals(NotificationChannel.USER_LOCKED_PRIORITY | NotificationChannel.USER_LOCKED_SOUND | NotificationChannel.USER_LOCKED_VIBRATION, @@ -1960,18 +2024,19 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testLockFields_vibrationAndLights() { - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false, + SYSTEM_UID, true); final NotificationChannel update1 = getChannel(); update1.setVibrationPattern(new long[]{7945, 46 ,246}); - mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true); + mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true, SYSTEM_UID, true); assertEquals(NotificationChannel.USER_LOCKED_VIBRATION, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false) .getUserLockedFields()); final NotificationChannel update2 = getChannel(); update2.enableLights(true); - mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true); + mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true, SYSTEM_UID, true); assertEquals(NotificationChannel.USER_LOCKED_VIBRATION | NotificationChannel.USER_LOCKED_LIGHTS, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false) @@ -1980,18 +2045,20 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testLockFields_lightsAndImportance() { - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false, + UID_N_MR1, false); final NotificationChannel update1 = getChannel(); update1.setLightColor(Color.GREEN); - mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true); + mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true, SYSTEM_UID, true); assertEquals(NotificationChannel.USER_LOCKED_LIGHTS, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false) .getUserLockedFields()); final NotificationChannel update2 = getChannel(); update2.setImportance(IMPORTANCE_DEFAULT); - mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true); + mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true, + SYSTEM_UID, true); assertEquals(NotificationChannel.USER_LOCKED_LIGHTS | NotificationChannel.USER_LOCKED_IMPORTANCE, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false) @@ -2000,21 +2067,22 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testLockFields_visibilityAndDndAndBadge() { - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false, + UID_N_MR1, false); assertEquals(0, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel().getId(), false) .getUserLockedFields()); final NotificationChannel update1 = getChannel(); update1.setBypassDnd(true); - mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true); + mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true, SYSTEM_UID, true); assertEquals(NotificationChannel.USER_LOCKED_PRIORITY, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false) .getUserLockedFields()); final NotificationChannel update2 = getChannel(); update2.setLockscreenVisibility(Notification.VISIBILITY_SECRET); - mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true); + mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true, SYSTEM_UID, true); assertEquals(NotificationChannel.USER_LOCKED_PRIORITY | NotificationChannel.USER_LOCKED_VISIBILITY, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false) @@ -2022,7 +2090,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { final NotificationChannel update3 = getChannel(); update3.setShowBadge(false); - mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update3, true); + mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update3, true, SYSTEM_UID, true); assertEquals(NotificationChannel.USER_LOCKED_PRIORITY | NotificationChannel.USER_LOCKED_VISIBILITY | NotificationChannel.USER_LOCKED_SHOW_BADGE, @@ -2032,14 +2100,16 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testLockFields_allowBubble() { - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false, + UID_N_MR1, false); assertEquals(0, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel().getId(), false) .getUserLockedFields()); final NotificationChannel update = getChannel(); update.setAllowBubbles(true); - mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update, true); + mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update, true, + SYSTEM_UID, true); assertEquals(NotificationChannel.USER_LOCKED_ALLOW_BUBBLE, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update.getId(), false) .getUserLockedFields()); @@ -2047,15 +2117,19 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testDeleteNonExistentChannel() throws Exception { - mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, "does not exist"); + mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, "does not exist", + UID_N_MR1, false); } @Test public void testDoubleDeleteChannel() throws Exception { NotificationChannel channel = getChannel(); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false); - mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId()); - mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId()); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, + UID_N_MR1, false); + mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), + UID_N_MR1, false); + mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), + UID_N_MR1, false); assertEquals(2, mLogger.getCalls().size()); assertEquals( NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_CREATED, @@ -2076,8 +2150,10 @@ public class PreferencesHelperTest extends UiServiceTestCase { channel.enableVibration(true); channel.setVibrationPattern(new long[]{100, 67, 145, 156}); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false); - mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId()); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, + UID_N_MR1, false); + mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), + UID_N_MR1, false); // Does not return deleted channel NotificationChannel response = @@ -2105,10 +2181,13 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel channel2 = new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH); channelMap.put(channel2.getId(), channel2); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false, + UID_N_MR1, false); - mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId()); + mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), + UID_N_MR1, false); // Returns only non-deleted channels List<NotificationChannel> channels = @@ -2138,12 +2217,17 @@ public class PreferencesHelperTest extends UiServiceTestCase { new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH); NotificationChannel channel3 = new NotificationChannel("id5", "a", NotificationManager.IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false); - - mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId()); - mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId()); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false, + UID_N_MR1, false); + + mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), + UID_N_MR1, false); + mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId(), + UID_N_MR1, false); assertEquals(2, mHelper.getDeletedChannelCount(PKG_N_MR1, UID_N_MR1)); assertEquals(0, mHelper.getDeletedChannelCount("pkg2", UID_O)); @@ -2157,11 +2241,15 @@ public class PreferencesHelperTest extends UiServiceTestCase { new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_NONE); NotificationChannel channel3 = new NotificationChannel("id5", "a", NotificationManager.IMPORTANCE_NONE); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false, + UID_N_MR1, false); - mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId()); + mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId(), + UID_N_MR1, false); assertEquals(1, mHelper.getBlockedChannelCount(PKG_N_MR1, UID_N_MR1)); assertEquals(0, mHelper.getBlockedChannelCount("pkg2", UID_O)); @@ -2180,7 +2268,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel channel = new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_MAX); channel.setBypassDnd(true); - mHelper.createNotificationChannel(PKG_N_MR1, 111, channel, true, true); + mHelper.createNotificationChannel(PKG_N_MR1, 111, channel, true, true, + 111, false); assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1, uid).getList().size()); @@ -2194,15 +2283,18 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationManager.IMPORTANCE_MAX); channel1.setBypassDnd(true); channel1.setGroup(ncg.getId()); - mHelper.createNotificationChannelGroup(PKG_N_MR1, uid, ncg, /* fromTargetApp */ true); - mHelper.createNotificationChannel(PKG_N_MR1, uid, channel1, true, /*has DND access*/ true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, uid, ncg, /* fromTargetApp */ true, + uid, false); + mHelper.createNotificationChannel(PKG_N_MR1, uid, channel1, true, /*has DND access*/ true, + uid, false); assertEquals(1, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1, uid).getList().size()); // disable group ncg.setBlocked(true); - mHelper.createNotificationChannelGroup(PKG_N_MR1, uid, ncg, /* fromTargetApp */ false); + mHelper.createNotificationChannelGroup(PKG_N_MR1, uid, ncg, /* fromTargetApp */ false, + SYSTEM_UID, true); assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1, uid).getList().size()); } @@ -2220,9 +2312,12 @@ public class PreferencesHelperTest extends UiServiceTestCase { channel2.setBypassDnd(true); channel3.setBypassDnd(true); // has DND access, so can set bypassDnd attribute - mHelper.createNotificationChannel(PKG_N_MR1, uid, channel1, true, /*has DND access*/ true); - mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true); - mHelper.createNotificationChannel(PKG_N_MR1, uid, channel3, true, true); + mHelper.createNotificationChannel(PKG_N_MR1, uid, channel1, true, /*has DND access*/ true, + uid, false); + mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true, + uid, false); + mHelper.createNotificationChannel(PKG_N_MR1, uid, channel3, true, true, + uid, false); assertEquals(3, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1, uid).getList().size()); @@ -2247,29 +2342,31 @@ public class PreferencesHelperTest extends UiServiceTestCase { // expected result: areChannelsBypassingDnd = false // setNotificationPolicy isn't called since areChannelsBypassingDnd was already false NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false, + uid, false); assertFalse(mHelper.areChannelsBypassingDnd()); - verify(mMockZenModeHelper, never()).setNotificationPolicy(any()); + verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyBoolean()); resetZenModeHelper(); // create notification channel that can bypass dnd // expected result: areChannelsBypassingDnd = true NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); channel2.setBypassDnd(true); - mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true); + mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true, + uid, false); assertTrue(mHelper.areChannelsBypassingDnd()); - verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any()); + verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyBoolean()); resetZenModeHelper(); // delete channels - mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel.getId()); + mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel.getId(), uid, false); assertTrue(mHelper.areChannelsBypassingDnd()); // channel2 can still bypass DND - verify(mMockZenModeHelper, never()).setNotificationPolicy(any()); + verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyBoolean()); resetZenModeHelper(); - mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel2.getId()); + mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel2.getId(), uid, false); assertFalse(mHelper.areChannelsBypassingDnd()); - verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any()); + verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyBoolean()); resetZenModeHelper(); } @@ -2282,18 +2379,20 @@ public class PreferencesHelperTest extends UiServiceTestCase { // expected result: areChannelsBypassingDnd = false // setNotificationPolicy isn't called since areChannelsBypassingDnd was already false NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false, + uid, false); assertFalse(mHelper.areChannelsBypassingDnd()); - verify(mMockZenModeHelper, never()).setNotificationPolicy(any()); + verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyBoolean()); resetZenModeHelper(); // Recreate a channel & now the app has dnd access granted and can set the bypass dnd field NotificationChannel update = new NotificationChannel("id1", "name1", IMPORTANCE_LOW); update.setBypassDnd(true); - mHelper.createNotificationChannel(PKG_N_MR1, uid, update, true, true); + mHelper.createNotificationChannel(PKG_N_MR1, uid, update, true, true, + uid, false); assertTrue(mHelper.areChannelsBypassingDnd()); - verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any()); + verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyBoolean()); resetZenModeHelper(); } @@ -2306,29 +2405,31 @@ public class PreferencesHelperTest extends UiServiceTestCase { // expected result: areChannelsBypassingDnd = false // setNotificationPolicy isn't called since areChannelsBypassingDnd was already false NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false, + uid, false); assertFalse(mHelper.areChannelsBypassingDnd()); - verify(mMockZenModeHelper, never()).setNotificationPolicy(any()); + verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyBoolean()); resetZenModeHelper(); // create notification channel that can bypass dnd, using local app level settings // expected result: areChannelsBypassingDnd = true NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); channel2.setBypassDnd(true); - mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true); + mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true, + uid, false); assertTrue(mHelper.areChannelsBypassingDnd()); - verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any()); + verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyBoolean()); resetZenModeHelper(); // delete channels - mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel.getId()); + mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel.getId(), uid, false); assertTrue(mHelper.areChannelsBypassingDnd()); // channel2 can still bypass DND - verify(mMockZenModeHelper, never()).setNotificationPolicy(any()); + verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyBoolean()); resetZenModeHelper(); - mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel2.getId()); + mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel2.getId(), uid, false); assertFalse(mHelper.areChannelsBypassingDnd()); - verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any()); + verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyBoolean()); resetZenModeHelper(); } @@ -2350,13 +2451,16 @@ public class PreferencesHelperTest extends UiServiceTestCase { // expected result: areChannelsBypassingDnd = false NotificationChannelGroup group = new NotificationChannelGroup("group", "group"); group.setBlocked(true); - mHelper.createNotificationChannelGroup(PKG_N_MR1, uid, group, false); + mHelper.createNotificationChannelGroup(PKG_N_MR1, uid, group, false, + SYSTEM_UID, true); NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); channel2.setGroup("group"); channel2.setBypassDnd(true); - mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true); + mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true, + uid, false); assertFalse(mHelper.areChannelsBypassingDnd()); - verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any()); + verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), + anyInt(), anyBoolean()); resetZenModeHelper(); } @@ -2377,9 +2481,10 @@ public class PreferencesHelperTest extends UiServiceTestCase { // expected result: areChannelsBypassingDnd = false NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); channel2.setBypassDnd(true); - mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true); + mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true, + uid, false); assertFalse(mHelper.areChannelsBypassingDnd()); - verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any()); + verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyBoolean()); resetZenModeHelper(); } @@ -2400,9 +2505,10 @@ public class PreferencesHelperTest extends UiServiceTestCase { // expected result: areChannelsBypassingDnd = false NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); channel2.setBypassDnd(true); - mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true); + mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true, + uid, false); assertFalse(mHelper.areChannelsBypassingDnd()); - verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any()); + verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyBoolean()); resetZenModeHelper(); } @@ -2415,25 +2521,26 @@ public class PreferencesHelperTest extends UiServiceTestCase { // expected result: areChannelsBypassingDnd = false // setNotificationPolicy isn't called since areChannelsBypassingDnd was already false NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false, + uid, false); assertFalse(mHelper.areChannelsBypassingDnd()); - verify(mMockZenModeHelper, never()).setNotificationPolicy(any()); + verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyBoolean()); resetZenModeHelper(); // update channel so it CAN bypass dnd: // expected result: areChannelsBypassingDnd = true channel.setBypassDnd(true); - mHelper.updateNotificationChannel(PKG_N_MR1, uid, channel, true); + mHelper.updateNotificationChannel(PKG_N_MR1, uid, channel, true, SYSTEM_UID, true); assertTrue(mHelper.areChannelsBypassingDnd()); - verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any()); + verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyBoolean()); resetZenModeHelper(); // update channel so it can't bypass dnd: // expected result: areChannelsBypassingDnd = false channel.setBypassDnd(false); - mHelper.updateNotificationChannel(PKG_N_MR1, uid, channel, true); + mHelper.updateNotificationChannel(PKG_N_MR1, uid, channel, true, SYSTEM_UID, true); assertFalse(mHelper.areChannelsBypassingDnd()); - verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any()); + verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyBoolean()); resetZenModeHelper(); } @@ -2448,7 +2555,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false); assertFalse(mHelper.areChannelsBypassingDnd()); - verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any()); + verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyBoolean()); resetZenModeHelper(); } @@ -2461,7 +2568,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory, false); assertFalse(mHelper.areChannelsBypassingDnd()); - verify(mMockZenModeHelper, never()).setNotificationPolicy(any()); + verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyBoolean()); resetZenModeHelper(); } @@ -2472,14 +2579,17 @@ public class PreferencesHelperTest extends UiServiceTestCase { new NotificationChannel("id2", "name2", IMPORTANCE_LOW); channel.setVibrationPattern(vibration); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false); - mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId()); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, + UID_N_MR1, false); + mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), + UID_N_MR1, false); NotificationChannel newChannel = new NotificationChannel( channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH); newChannel.setVibrationPattern(new long[]{100}); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, newChannel, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, newChannel, true, false, + UID_N_MR1, false); // No long deleted, using old settings compareChannels(channel, @@ -2491,7 +2601,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { assertTrue(mHelper.onlyHasDefaultChannel(PKG_N_MR1, UID_N_MR1)); assertFalse(mHelper.onlyHasDefaultChannel(PKG_O, UID_O)); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false, + UID_N_MR1, false); assertFalse(mHelper.onlyHasDefaultChannel(PKG_N_MR1, UID_N_MR1)); } @@ -2499,7 +2610,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { public void testCreateChannel_defaultChannelId() throws Exception { try { mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, new NotificationChannel( - NotificationChannel.DEFAULT_CHANNEL_ID, "ha", IMPORTANCE_HIGH), true, false); + NotificationChannel.DEFAULT_CHANNEL_ID, "ha", IMPORTANCE_HIGH), true, false, + UID_N_MR1, false); fail("Allowed to create default channel"); } catch (IllegalArgumentException e) { // pass @@ -2513,7 +2625,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { new NotificationChannel("id2", "name2", IMPORTANCE_LOW); channel.setVibrationPattern(vibration); - assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false)); + assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, + UID_N_MR1, false)); NotificationChannel newChannel = new NotificationChannel( channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH); @@ -2524,7 +2637,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { newChannel.setShowBadge(!channel.canShowBadge()); assertFalse(mHelper.createNotificationChannel( - PKG_N_MR1, UID_N_MR1, newChannel, true, false)); + PKG_N_MR1, UID_N_MR1, newChannel, true, false, + UID_N_MR1, false)); // Old settings not overridden compareChannels(channel, @@ -2542,7 +2656,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { final NotificationChannel channel = new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_DEFAULT); channel.setSound(sound, mAudioAttributes); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, + UID_N_MR1, false); assertEquals(sound, mHelper.getNotificationChannel( PKG_N_MR1, UID_N_MR1, channel.getId(), false).getSound()); } @@ -2554,8 +2669,10 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false, + UID_N_MR1, false); mHelper.permanentlyDeleteNotificationChannels(PKG_N_MR1, UID_N_MR1); @@ -2576,14 +2693,20 @@ public class PreferencesHelperTest extends UiServiceTestCase { new NotificationChannel("deleted", "belongs to deleted", IMPORTANCE_DEFAULT); groupedAndDeleted.setGroup("totally"); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, notDeleted, true); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, deleted, true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, notDeleted, true, + UID_N_MR1, false); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, deleted, true, + UID_N_MR1, false); mHelper.createNotificationChannel( - PKG_N_MR1, UID_N_MR1, nonGroupedNonDeletedChannel, true, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedAndDeleted, true, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedButNotDeleted, true, false); + PKG_N_MR1, UID_N_MR1, nonGroupedNonDeletedChannel, true, false, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedAndDeleted, true, false, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedButNotDeleted, true, false, + UID_N_MR1, false); - mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, deleted.getId()); + mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, deleted.getId(), + UID_N_MR1, false); assertNull(mHelper.getNotificationChannelGroup(deleted.getId(), PKG_N_MR1, UID_N_MR1)); assertNotNull( @@ -2626,10 +2749,14 @@ public class PreferencesHelperTest extends UiServiceTestCase { convo.setGroup("not"); convo.setConversationId("not deleted", "banana"); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, notDeleted, true); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, base, true, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, convo, true, false); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, notDeleted, true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, notDeleted, true, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, base, true, false, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, convo, true, false, + UID_N_MR1, false); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, notDeleted, true, + UID_N_MR1, false); NotificationChannelGroup g = mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG_N_MR1, UID_N_MR1); @@ -2679,7 +2806,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { // Deleted NotificationChannel channel1 = new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, + UID_N_MR1, false); assertTrue(mHelper.onPackagesChanged(true, USER_SYSTEM, new String[]{PKG_N_MR1}, new int[]{UID_N_MR1})); @@ -2688,7 +2816,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { PKG_N_MR1, UID_N_MR1, true).getList().size()); // Not deleted - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, + UID_N_MR1, false); assertFalse(mHelper.onPackagesChanged(false, USER_SYSTEM, new String[]{PKG_N_MR1}, new int[]{UID_N_MR1})); @@ -2698,9 +2827,11 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testOnPackageChanged_packageRemoval_groups() throws Exception { NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, + UID_N_MR1, false); NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2"); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true, + UID_N_MR1, false); mHelper.onPackagesChanged(true, USER_SYSTEM, new String[]{PKG_N_MR1}, new int[]{ UID_N_MR1}); @@ -2712,7 +2843,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testOnPackageChange_downgradeTargetSdk() throws Exception { // create channel as api 26 - mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false, + UID_N_MR1, false); // install new app version targeting 25 final ApplicationInfo legacy = new ApplicationInfo(); @@ -2731,9 +2863,11 @@ public class PreferencesHelperTest extends UiServiceTestCase { public void testClearData() { ArraySet<Pair<String, Integer>> pkgPair = new ArraySet<>(); pkgPair.add(new Pair<>(PKG_O, UID_O)); - mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false, + UID_O, false); mHelper.createNotificationChannelGroup( - PKG_O, UID_O, new NotificationChannelGroup("1", "bye"), true); + PKG_O, UID_O, new NotificationChannelGroup("1", "bye"), true, + UID_O, false); mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, pkgPair); mHelper.setNotificationDelegate(PKG_O, UID_O, "", 1); mHelper.setBubblesAllowed(PKG_O, UID_O, DEFAULT_BUBBLE_PREFERENCE); @@ -2750,7 +2884,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { assertEquals(0, mHelper.getNotificationChannelGroups(PKG_O, UID_O).size()); NotificationChannel channel = getChannel(); - mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, + UID_O, false); assertTrue(channel.isImportanceLockedByCriticalDeviceFunction()); } @@ -2764,7 +2899,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testCreateGroup() { NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, + UID_N_MR1, false); assertEquals(ncg, mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1).iterator().next()); verify(mHandler, never()).requestSort(); @@ -2781,7 +2917,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); channel1.setGroup("garbage"); try { - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, + UID_N_MR1, false); fail("Created a channel with a bad group"); } catch (IllegalArgumentException e) { } @@ -2791,11 +2928,13 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testCannotCreateChannel_goodGroup() { NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, + UID_N_MR1, false); NotificationChannel channel1 = new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); channel1.setGroup(ncg.getId()); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, + UID_N_MR1, false); assertEquals(ncg.getId(), mHelper.getNotificationChannel( PKG_N_MR1, UID_N_MR1, channel1.getId(), false).getGroup()); @@ -2804,29 +2943,36 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testGetChannelGroups() { NotificationChannelGroup unused = new NotificationChannelGroup("unused", "s"); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, unused, true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, unused, true, + UID_N_MR1, false); NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, + UID_N_MR1, false); NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2"); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true, + UID_N_MR1, false); NotificationChannel channel1 = new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); channel1.setGroup(ncg.getId()); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, + UID_N_MR1, false); NotificationChannel channel1a = new NotificationChannel("id1a", "name1", NotificationManager.IMPORTANCE_HIGH); channel1a.setGroup(ncg.getId()); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1a, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1a, true, false, + UID_N_MR1, false); NotificationChannel channel2 = new NotificationChannel("id2", "name1", NotificationManager.IMPORTANCE_HIGH); channel2.setGroup(ncg2.getId()); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false, + UID_N_MR1, false); NotificationChannel channel3 = new NotificationChannel("id3", "name1", NotificationManager.IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false, + UID_N_MR1, false); List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups( PKG_N_MR1, UID_N_MR1, true, true, false).getList(); @@ -2855,16 +3001,19 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testGetChannelGroups_noSideEffects() { NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, + UID_N_MR1, false); NotificationChannel channel1 = new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); channel1.setGroup(ncg.getId()); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, + UID_N_MR1, false); mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, true, true, false).getList(); channel1.setImportance(IMPORTANCE_LOW); - mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true); + mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, + UID_N_MR1, false); List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups( PKG_N_MR1, UID_N_MR1, true, true, false).getList(); @@ -2880,14 +3029,17 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testGetChannelGroups_includeEmptyGroups() { NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, + UID_N_MR1, false); NotificationChannelGroup ncgEmpty = new NotificationChannelGroup("group2", "name2"); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncgEmpty, true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncgEmpty, true, + UID_N_MR1, false); NotificationChannel channel1 = new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); channel1.setGroup(ncg.getId()); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, + UID_N_MR1, false); List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups( PKG_N_MR1, UID_N_MR1, false, false, true).getList(); @@ -2906,13 +3058,15 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testCreateChannel_updateName() { NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT); - assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false)); + assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false, + UID_N_MR1, false)); NotificationChannel actual = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false); assertEquals("hello", actual.getName()); nc = new NotificationChannel("id", "goodbye", IMPORTANCE_HIGH); - assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false)); + assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false, + UID_N_MR1, false)); actual = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false); assertEquals("goodbye", actual.getName()); @@ -2924,16 +3078,19 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testCreateChannel_addToGroup() { NotificationChannelGroup group = new NotificationChannelGroup("group", "group"); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true, + UID_N_MR1, false); NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT); - assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false)); + assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false, + UID_N_MR1, false)); NotificationChannel actual = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false); assertNull(actual.getGroup()); nc = new NotificationChannel("id", "hello", IMPORTANCE_HIGH); nc.setGroup(group.getId()); - assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false)); + assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false, + UID_N_MR1, false)); actual = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false); assertNotNull(actual.getGroup()); @@ -2969,14 +3126,16 @@ public class PreferencesHelperTest extends UiServiceTestCase { int numChannels = ThreadLocalRandom.current().nextInt(1, 10); for (int j = 0; j < numChannels; j++) { mHelper.createNotificationChannel(pkgName, UID_N_MR1, - new NotificationChannel("" + j, "a", IMPORTANCE_HIGH), true, false); + new NotificationChannel("" + j, "a", IMPORTANCE_HIGH), true, false, + UID_N_MR1, false); } expectedChannels.put(pkgName, numChannels); } // delete the first channel of the first package String pkg = expectedChannels.keyAt(0); - mHelper.deleteNotificationChannel("pkg" + 0, UID_N_MR1, "0"); + mHelper.deleteNotificationChannel("pkg" + 0, UID_N_MR1, "0", + UID_N_MR1, false); // dump should not include deleted channels int count = expectedChannels.get(pkg); expectedChannels.put(pkg, count - 1); @@ -3012,10 +3171,14 @@ public class PreferencesHelperTest extends UiServiceTestCase { new NotificationChannel("id2", "name2", IMPORTANCE_LOW); NotificationChannel channel3 = new NotificationChannel("id3", "name3", IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG_P, UID_P, channel1, true, false); - mHelper.createNotificationChannel(PKG_P, UID_P, channel2, false, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false); - mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false); + mHelper.createNotificationChannel(PKG_P, UID_P, channel1, true, false, + UID_P, false); + mHelper.createNotificationChannel(PKG_P, UID_P, channel2, false, false, + UID_P, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false, + UID_N_MR1, false); // in the json array, all of the individual package preferences are simply elements in the // values array. this set is to collect expected outputs for each of our packages. @@ -3328,7 +3491,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testIsGroupBlocked_notBlocked() throws Exception { NotificationChannelGroup group = new NotificationChannelGroup("id", "name"); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true, + UID_N_MR1, false); assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId())); } @@ -3336,9 +3500,11 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testIsGroupBlocked_blocked() throws Exception { NotificationChannelGroup group = new NotificationChannelGroup("id", "name"); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true, + UID_N_MR1, false); group.setBlocked(true); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, false); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, false, + UID_N_MR1, false); assertTrue(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId())); } @@ -3347,27 +3513,32 @@ public class PreferencesHelperTest extends UiServiceTestCase { public void testIsGroupBlocked_appCannotCreateAsBlocked() throws Exception { NotificationChannelGroup group = new NotificationChannelGroup("id", "name"); group.setBlocked(true); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true, + UID_N_MR1, false); assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId())); NotificationChannelGroup group3 = group.clone(); group3.setBlocked(false); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group3, true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group3, true, + UID_N_MR1, false); assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId())); } @Test public void testIsGroup_appCannotResetBlock() throws Exception { NotificationChannelGroup group = new NotificationChannelGroup("id", "name"); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true, + UID_N_MR1, false); NotificationChannelGroup group2 = group.clone(); group2.setBlocked(true); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group2, false); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group2, false, + UID_N_MR1, false); assertTrue(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId())); NotificationChannelGroup group3 = group.clone(); group3.setBlocked(false); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group3, true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group3, true, + UID_N_MR1, false); assertTrue(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId())); } @@ -3375,8 +3546,10 @@ public class PreferencesHelperTest extends UiServiceTestCase { public void testGetNotificationChannelGroupWithChannels() throws Exception { NotificationChannelGroup group = new NotificationChannelGroup("group", "group"); NotificationChannelGroup other = new NotificationChannelGroup("something else", "name"); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true); - mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, other, true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true, + UID_N_MR1, false); + mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, other, true, + UID_N_MR1, false); NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT); a.setGroup(group.getId()); @@ -3386,11 +3559,16 @@ public class PreferencesHelperTest extends UiServiceTestCase { c.setGroup(group.getId()); NotificationChannel d = new NotificationChannel("d", "d", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, a, true, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, b, true, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, c, true, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, d, true, false); - mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, c.getId()); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, a, true, false, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, b, true, false, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, c, true, false, + UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, d, true, false, + UID_N_MR1, false); + mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, c.getId(), + UID_N_MR1, false); NotificationChannelGroup retrieved = mHelper.getNotificationChannelGroupWithChannels( PKG_N_MR1, UID_N_MR1, group.getId(), true); @@ -3409,7 +3587,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); test.setBypassDnd(true); - mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true, false); + mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true, false, + SYSTEM_UID, true); assertFalse(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false) .canBypassDnd()); @@ -3420,7 +3599,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); test.setBypassDnd(true); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, test, true, true); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, test, true, true, + UID_N_MR1, false); assertTrue(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "A", false).canBypassDnd()); } @@ -3430,7 +3610,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); test.setBypassDnd(true); - mHelper.createNotificationChannel(PKG_N_MR1, 1000, test, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, 1000, test, true, false, + UID_N_MR1, false); assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, 1000, "A", false).canBypassDnd()); } @@ -3438,11 +3619,13 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testAndroidPkgCannotBypassDnd_update() throws Exception { NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); - mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true, false); + mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true, false, + SYSTEM_UID, true); NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW); update.setBypassDnd(true); - assertFalse(mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, update, true, false)); + assertFalse(mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, update, true, false, + SYSTEM_UID, true)); assertFalse(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false) .canBypassDnd()); @@ -3451,11 +3634,13 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testDndPkgCanBypassDnd_update() throws Exception { NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, test, true, true); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, test, true, true, + UID_N_MR1, false); NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW); update.setBypassDnd(true); - assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, update, true, true)); + assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, update, true, true, + UID_N_MR1, false)); assertTrue(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "A", false).canBypassDnd()); } @@ -3463,10 +3648,12 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testNormalPkgCannotBypassDnd_update() { NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG_N_MR1, 1000, test, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, 1000, test, true, false, + UID_N_MR1, false); NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW); update.setBypassDnd(true); - mHelper.createNotificationChannel(PKG_N_MR1, 1000, update, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, 1000, update, true, false, + UID_N_MR1, false); assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, 1000, "A", false).canBypassDnd()); } @@ -3726,12 +3913,14 @@ public class PreferencesHelperTest extends UiServiceTestCase { assertTrue(mHelper.isImportanceLocked(PKG_O, UID_O)); NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, + UID_O, false); NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE); update.setAllowBubbles(false); - mHelper.updateNotificationChannel(PKG_O, UID_O, update, true); + mHelper.updateNotificationChannel(PKG_O, UID_O, update, true, + UID_O, false); assertEquals(IMPORTANCE_HIGH, mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance()); @@ -3745,12 +3934,12 @@ public class PreferencesHelperTest extends UiServiceTestCase { toAdd.add(new Pair<>(PKG_O, UID_O)); mHelper.updateDefaultApps(0, null, toAdd); NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE); update.setAllowBubbles(false); - mHelper.updateNotificationChannel(PKG_O, UID_O, update, true); + mHelper.updateNotificationChannel(PKG_O, UID_O, update, true, UID_O, false); assertEquals(IMPORTANCE_HIGH, mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance()); @@ -3763,12 +3952,12 @@ public class PreferencesHelperTest extends UiServiceTestCase { when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true); NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_NONE); - mHelper.createNotificationChannel(PKG_O, UID_O, a, false, false); + mHelper.createNotificationChannel(PKG_O, UID_O, a, false, false, UID_O, false); NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_HIGH); update.setAllowBubbles(false); - mHelper.updateNotificationChannel(PKG_O, UID_O, update, true); + mHelper.updateNotificationChannel(PKG_O, UID_O, update, true, UID_O, false); assertEquals(IMPORTANCE_HIGH, mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance()); @@ -3782,12 +3971,12 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); a.setBlockable(true); - mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE); update.setAllowBubbles(false); - mHelper.updateNotificationChannel(PKG_O, UID_O, update, true); + mHelper.updateNotificationChannel(PKG_O, UID_O, update, true, UID_O, false); assertEquals(IMPORTANCE_NONE, mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance()); @@ -3800,12 +3989,12 @@ public class PreferencesHelperTest extends UiServiceTestCase { when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(false); NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE); update.setAllowBubbles(false); - mHelper.updateNotificationChannel(PKG_O, UID_O, update, true); + mHelper.updateNotificationChannel(PKG_O, UID_O, update, true, UID_O, false); assertEquals(IMPORTANCE_NONE, mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance()); @@ -3819,9 +4008,11 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW); NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT); // different uids, same package - mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false); - mHelper.createNotificationChannel(PKG_O, UID_O, b, false, false); - mHelper.createNotificationChannel(PKG_O, UserHandle.PER_USER_RANGE + 1, c, true, true); + mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); + mHelper.createNotificationChannel(PKG_O, UID_O, b, false, false, + SYSTEM_UID, true); + mHelper.createNotificationChannel(PKG_O, UserHandle.PER_USER_RANGE + 1, c, true, true, + UserHandle.PER_USER_RANGE + 1, false); UserInfo user = new UserInfo(); user.id = 0; @@ -3859,7 +4050,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { mHelper.updateFixedImportance(users); NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false) .isImportanceLockedByCriticalDeviceFunction()); @@ -3871,9 +4062,10 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW); NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT); // different uids, same package - mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false); - mHelper.createNotificationChannel(PKG_O, UID_O, b, false, false); - mHelper.createNotificationChannel(PKG_O, UserHandle.PER_USER_RANGE + 1, c, true, true); + mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); + mHelper.createNotificationChannel(PKG_O, UID_O, b, false, false, UID_O, false); + mHelper.createNotificationChannel(PKG_O, UserHandle.PER_USER_RANGE + 1, c, true, true, + UID_O, false); ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>(); toAdd.add(new Pair<>(PKG_O, UID_O)); @@ -3892,8 +4084,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { public void testUpdateDefaultApps_add_onlyGivenPkg() { NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, b, false, false); + mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, b, false, false, UID_O, false); ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>(); toAdd.add(new Pair<>(PKG_O, UID_O)); @@ -3910,8 +4102,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW); // different uids, same package - mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false); - mHelper.createNotificationChannel(PKG_O, UID_O, b, false, false); + mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); + mHelper.createNotificationChannel(PKG_O, UID_O, b, false, false, SYSTEM_UID, true); ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>(); toAdd.add(new Pair<>(PKG_O, UID_O)); @@ -3936,8 +4128,10 @@ public class PreferencesHelperTest extends UiServiceTestCase { public void testUpdateDefaultApps_addAndRemove() { NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, b, false, false); + mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, + UID_O, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, b, false, false, + UID_N_MR1, false); ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>(); toAdd.add(new Pair<>(PKG_O, UID_O)); @@ -3975,7 +4169,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { public void testUpdateDefaultApps_channelDoesNotExistYet() { NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>(); toAdd.add(new Pair<>(PKG_O, UID_O)); @@ -3984,7 +4178,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false) .isImportanceLockedByCriticalDeviceFunction()); - mHelper.createNotificationChannel(PKG_O, UID_O, b, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, b, true, false, UID_O, false); assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false) .isImportanceLockedByCriticalDeviceFunction()); } @@ -3992,7 +4186,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testUpdateNotificationChannel_defaultAppLockedImportance() { NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>(); toAdd.add(new Pair<>(PKG_O, UID_O)); mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd); @@ -4000,19 +4194,20 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE); update.setAllowBubbles(false); - mHelper.updateNotificationChannel(PKG_O, UID_O, update, true); + mHelper.updateNotificationChannel(PKG_O, UID_O, update, true, SYSTEM_UID, true); assertEquals(IMPORTANCE_HIGH, mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance()); assertEquals(false, mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble()); - mHelper.updateNotificationChannel(PKG_O, UID_O, update, false); + mHelper.updateNotificationChannel(PKG_O, UID_O, update, false, UID_O, false); assertEquals(IMPORTANCE_HIGH, mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance()); NotificationChannel updateImportanceLow = new NotificationChannel("a", "a", IMPORTANCE_LOW); - mHelper.updateNotificationChannel(PKG_O, UID_O, updateImportanceLow, true); + mHelper.updateNotificationChannel(PKG_O, UID_O, updateImportanceLow, true, + SYSTEM_UID, true); assertEquals(IMPORTANCE_LOW, mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance()); } @@ -4024,7 +4219,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd); NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); assertTrue(a.isImportanceLockedByCriticalDeviceFunction()); } @@ -4050,7 +4245,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { assertTrue(mHelper.isImportanceLocked(PKG_O, UID_O)); NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); // Still locked by permission if not role assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false) @@ -4078,7 +4273,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { assertTrue(mHelper.isImportanceLocked(PKG_O, UID_O)); NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); // Still locked by role if not permission assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false) @@ -4090,7 +4285,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel channel1 = new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG_O, UID_O, channel1, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channel1, true, false, UID_O, false); // clear data ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, true, @@ -4144,14 +4339,14 @@ public class PreferencesHelperTest extends UiServiceTestCase { for (int i = 0; i < NOTIFICATION_CHANNEL_COUNT_LIMIT; i++) { NotificationChannel channel = new NotificationChannel(String.valueOf(i), String.valueOf(i), NotificationManager.IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true); + mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true, UID_O, false); } try { NotificationChannel channel = new NotificationChannel( String.valueOf(NOTIFICATION_CHANNEL_COUNT_LIMIT), String.valueOf(NOTIFICATION_CHANNEL_COUNT_LIMIT), NotificationManager.IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true); + mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true, UID_O, false); fail("Allowed to create too many notification channels"); } catch (IllegalStateException e) { // great @@ -4167,7 +4362,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { for (int i = 0; i < NOTIFICATION_CHANNEL_COUNT_LIMIT; i++) { NotificationChannel channel = new NotificationChannel(String.valueOf(i), String.valueOf(i), NotificationManager.IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true); + mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true, UID_O, false); } final String xml = "<ranking version=\"1\">\n" @@ -4200,13 +4395,15 @@ public class PreferencesHelperTest extends UiServiceTestCase { for (int i = 0; i < NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT; i++) { NotificationChannelGroup group = new NotificationChannelGroup(String.valueOf(i), String.valueOf(i)); - mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, fromTargetApp); + mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, fromTargetApp, + UID_O, false); } try { NotificationChannelGroup group = new NotificationChannelGroup( String.valueOf(NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT), String.valueOf(NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT)); - mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, fromTargetApp); + mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, fromTargetApp, + UID_O, false); fail("Allowed to create too many notification channel groups"); } catch (IllegalStateException e) { // great @@ -4222,7 +4419,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { for (int i = 0; i < NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT; i++) { NotificationChannelGroup group = new NotificationChannelGroup(String.valueOf(i), String.valueOf(i)); - mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true); + mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true, + UID_O, false); } final String xml = "<ranking version=\"1\">\n" @@ -4300,13 +4498,15 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel parent = new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, + UID_O, false); NotificationChannel friend = new NotificationChannel(String.format( CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), conversationId), "messages", IMPORTANCE_DEFAULT); friend.setConversationId(parent.getId(), conversationId); - mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false, + UID_O, false); compareChannelsParentChild(parent, mHelper.getConversationNotificationChannel( PKG_O, UID_O, parent.getId(), conversationId, false, false), conversationId); @@ -4318,7 +4518,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel parent = new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, + UID_O, false); compareChannels(parent, mHelper.getConversationNotificationChannel( PKG_O, UID_O, parent.getId(), conversationId, true, false)); @@ -4335,7 +4536,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { friend.setConversationId(parentId, conversationId); try { - mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false, + UID_O, false); fail("allowed creation of conversation channel without a parent"); } catch (IllegalArgumentException e) { // good @@ -4429,9 +4631,12 @@ public class PreferencesHelperTest extends UiServiceTestCase { mAppOpsManager, mStatsEventBuilderFactory, false); mHelper.createNotificationChannel( - PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false); - assertTrue(mHelper.deleteNotificationChannel(PKG_P, UID_P, "id")); - assertFalse(mHelper.deleteNotificationChannel(PKG_P, UID_P, "id")); + PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false, + UID_P, false); + assertTrue(mHelper.deleteNotificationChannel(PKG_P, UID_P, "id", + UID_P, false)); + assertFalse(mHelper.deleteNotificationChannel(PKG_P, UID_P, "id", + UID_P, false)); } @Test @@ -4441,8 +4646,9 @@ public class PreferencesHelperTest extends UiServiceTestCase { mAppOpsManager, mStatsEventBuilderFactory, false); mHelper.createNotificationChannel( - PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false); - mHelper.deleteNotificationChannel(PKG_P, UID_P, "id"); + PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false, + UID_P, false); + mHelper.deleteNotificationChannel(PKG_P, UID_P, "id", UID_P, false); NotificationChannel nc1 = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true); assertTrue(DateUtils.isToday(nc1.getDeletedTimeMs())); assertTrue(nc1.isDeleted()); @@ -4471,14 +4677,16 @@ public class PreferencesHelperTest extends UiServiceTestCase { mAppOpsManager, mStatsEventBuilderFactory, false); mHelper.createNotificationChannel( - PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false); - mHelper.deleteNotificationChannel(PKG_P, UID_P, "id"); + PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false, + UID_P, false); + mHelper.deleteNotificationChannel(PKG_P, UID_P, "id", UID_P, false); NotificationChannel nc1 = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true); assertTrue(DateUtils.isToday(nc1.getDeletedTimeMs())); assertTrue(nc1.isDeleted()); mHelper.createNotificationChannel( - PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false); + PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false, + UID_P, false); nc1 = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true); assertEquals(-1, nc1.getDeletedTimeMs()); assertFalse(nc1.isDeleted()); @@ -4513,29 +4721,35 @@ public class PreferencesHelperTest extends UiServiceTestCase { String convoId = "convo"; NotificationChannel messages = new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false, + UID_O, false); NotificationChannel calls = new NotificationChannel("calls", "Calls", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false, + UID_O, false); NotificationChannel p = new NotificationChannel("p calls", "Calls", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_P, UID_P, p, true, false); + mHelper.createNotificationChannel(PKG_P, UID_P, p, true, false, + UID_P, false); NotificationChannel channel = new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT); channel.setConversationId(messages.getId(), convoId); - mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, + UID_O, false); NotificationChannel diffConvo = new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT); diffConvo.setConversationId(p.getId(), "different convo"); - mHelper.createNotificationChannel(PKG_P, UID_P, diffConvo, true, false); + mHelper.createNotificationChannel(PKG_P, UID_P, diffConvo, true, false, + UID_O, false); NotificationChannel channel2 = new NotificationChannel("A person calls", "calls from A", IMPORTANCE_DEFAULT); channel2.setConversationId(calls.getId(), convoId); channel2.setImportantConversation(true); - mHelper.createNotificationChannel(PKG_O, UID_O, channel2, false, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channel2, false, false, + SYSTEM_UID, true); List<ConversationChannelWrapper> convos = mHelper.getConversations(IntArray.wrap(new int[] {0}), false); @@ -4551,23 +4765,26 @@ public class PreferencesHelperTest extends UiServiceTestCase { String convoId = "convo"; NotificationChannel messages = new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false, + UID_O, false); NotificationChannel messagesUser10 = new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); mHelper.createNotificationChannel( - PKG_O, UID_O + UserHandle.PER_USER_RANGE, messagesUser10, true, false); + PKG_O, UID_O + UserHandle.PER_USER_RANGE, messagesUser10, true, false, + UID_O + UserHandle.PER_USER_RANGE, false); NotificationChannel messagesFromB = new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT); messagesFromB.setConversationId(messages.getId(), "different convo"); - mHelper.createNotificationChannel(PKG_O, UID_O, messagesFromB, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, messagesFromB, true, false, UID_O, false); NotificationChannel messagesFromBUser10 = new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT); messagesFromBUser10.setConversationId(messagesUser10.getId(), "different convo"); mHelper.createNotificationChannel( - PKG_O, UID_O + UserHandle.PER_USER_RANGE, messagesFromBUser10, true, false); + PKG_O, UID_O + UserHandle.PER_USER_RANGE, messagesFromBUser10, true, false, + UID_O + UserHandle.PER_USER_RANGE, false); List<ConversationChannelWrapper> convos = @@ -4589,30 +4806,31 @@ public class PreferencesHelperTest extends UiServiceTestCase { String convoId = "convo"; NotificationChannel messages = new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false, UID_O, false); NotificationChannel calls = new NotificationChannel("calls", "Calls", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false, UID_O, false); NotificationChannel p = new NotificationChannel("p calls", "Calls", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_P, UID_P, p, true, false); + mHelper.createNotificationChannel(PKG_P, UID_P, p, true, false, UID_O, false); NotificationChannel channel = new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT); channel.setConversationId(messages.getId(), convoId); - mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false); NotificationChannel diffConvo = new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT); diffConvo.setConversationId(p.getId(), "different convo"); diffConvo.setDemoted(true); - mHelper.createNotificationChannel(PKG_P, UID_P, diffConvo, true, false); + mHelper.createNotificationChannel(PKG_P, UID_P, diffConvo, true, false, UID_P, false); NotificationChannel channel2 = new NotificationChannel("A person calls", "calls from A", IMPORTANCE_DEFAULT); channel2.setConversationId(calls.getId(), convoId); channel2.setImportantConversation(true); - mHelper.createNotificationChannel(PKG_O, UID_O, channel2, false, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channel2, false, false, + SYSTEM_UID, true); List<ConversationChannelWrapper> convos = mHelper.getConversations(IntArray.wrap(new int[] {0}), false); @@ -4628,30 +4846,31 @@ public class PreferencesHelperTest extends UiServiceTestCase { String convoId = "convo"; NotificationChannel messages = new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false, UID_O, false); NotificationChannel calls = new NotificationChannel("calls", "Calls", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false, UID_O, false); NotificationChannel p = new NotificationChannel("p calls", "Calls", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_P, UID_P, p, true, false); + mHelper.createNotificationChannel(PKG_P, UID_P, p, true, false, UID_P, false); NotificationChannel channel = new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT); channel.setConversationId(messages.getId(), convoId); channel.setImportantConversation(true); - mHelper.createNotificationChannel(PKG_O, UID_O, channel, false, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channel, false, false, UID_O, false); NotificationChannel diffConvo = new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT); diffConvo.setConversationId(p.getId(), "different convo"); diffConvo.setImportantConversation(true); - mHelper.createNotificationChannel(PKG_P, UID_P, diffConvo, false, false); + mHelper.createNotificationChannel(PKG_P, UID_P, diffConvo, false, false, + SYSTEM_UID, true); NotificationChannel channel2 = new NotificationChannel("A person calls", "calls from A", IMPORTANCE_DEFAULT); channel2.setConversationId(calls.getId(), convoId); - mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false, UID_O, false); List<ConversationChannelWrapper> convos = mHelper.getConversations(IntArray.wrap(new int[] {0}), true); @@ -4667,13 +4886,14 @@ public class PreferencesHelperTest extends UiServiceTestCase { String convoId = "convo"; NotificationChannel messages = new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false, UID_O, false); NotificationChannel channel = new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT); channel.setConversationId(messages.getId(), convoId); channel.setImportantConversation(true); - mHelper.createNotificationChannel(PKG_O, UID_O, channel, false, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channel, false, false, + SYSTEM_UID, true); mHelper.permanentlyDeleteNotificationChannel(PKG_O, UID_O, "messages"); @@ -4704,7 +4924,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { public void testGetConversations_noConversations() { NotificationChannel channel = new NotificationChannel("not_convo", "not_convo", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false); assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty(); } @@ -4713,15 +4933,15 @@ public class PreferencesHelperTest extends UiServiceTestCase { public void testGetConversations_noDisabledGroups() { NotificationChannelGroup group = new NotificationChannelGroup("a", "a"); group.setBlocked(true); - mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, false); + mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, false, SYSTEM_UID, true); NotificationChannel parent = new NotificationChannel("parent", "p", 1); - mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, UID_O, false); NotificationChannel channel = new NotificationChannel("convo", "convo", IMPORTANCE_DEFAULT); channel.setConversationId("parent", "convo"); channel.setGroup(group.getId()); - mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false); assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty(); } @@ -4729,12 +4949,12 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testGetConversations_noDeleted() { NotificationChannel parent = new NotificationChannel("parent", "p", 1); - mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, UID_O, false); NotificationChannel channel = new NotificationChannel("convo", "convo", IMPORTANCE_DEFAULT); channel.setConversationId("parent", "convo"); - mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false); - mHelper.deleteNotificationChannel(PKG_O, UID_O, channel.getId()); + mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false); + mHelper.deleteNotificationChannel(PKG_O, UID_O, channel.getId(), UID_O, false); assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty(); } @@ -4742,12 +4962,12 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testGetConversations_noDemoted() { NotificationChannel parent = new NotificationChannel("parent", "p", 1); - mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, UID_O, false); NotificationChannel channel = new NotificationChannel("convo", "convo", IMPORTANCE_DEFAULT); channel.setConversationId("parent", "convo"); channel.setDemoted(true); - mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false); assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty(); } @@ -4755,26 +4975,26 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testGetConversations() { NotificationChannelGroup group = new NotificationChannelGroup("acct", "account_name"); - mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true); + mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true, UID_O, false); NotificationChannel messages = new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); messages.setGroup(group.getId()); - mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false, UID_O, false); NotificationChannel calls = new NotificationChannel("calls", "Calls", IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false, UID_O, false); NotificationChannel channel = new NotificationChannel("A person", "A lovely person", IMPORTANCE_DEFAULT); channel.setGroup(group.getId()); channel.setConversationId(messages.getId(), channel.getName().toString()); - mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false); NotificationChannel channel2 = new NotificationChannel("B person", "B fabulous person", IMPORTANCE_DEFAULT); channel2.setConversationId(calls.getId(), channel2.getName().toString()); - mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false, UID_O, false); Map<String, NotificationChannel> expected = new HashMap<>(); expected.put(channel.getId(), channel); @@ -4807,35 +5027,36 @@ public class PreferencesHelperTest extends UiServiceTestCase { String convoIdC = "convoC"; NotificationChannel messages = new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false, UID_O, false); NotificationChannel calls = new NotificationChannel("calls", "Calls", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false, UID_O, false); NotificationChannel channel = new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT); channel.setConversationId(messages.getId(), convoId); - mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false); NotificationChannel noMatch = new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT); noMatch.setConversationId(messages.getId(), "different convo"); - mHelper.createNotificationChannel(PKG_O, UID_O, noMatch, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, noMatch, true, false, UID_O, false); NotificationChannel channel2 = new NotificationChannel("A person calls", "calls from A", IMPORTANCE_DEFAULT); channel2.setConversationId(calls.getId(), convoId); - mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false, UID_O, false); NotificationChannel channel3 = new NotificationChannel("C person msgs", "msgs from C", IMPORTANCE_DEFAULT); channel3.setConversationId(messages.getId(), convoIdC); - mHelper.createNotificationChannel(PKG_O, UID_O, channel3, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channel3, true, false, UID_O, false); assertEquals(channel, mHelper.getNotificationChannel(PKG_O, UID_O, channel.getId(), false)); assertEquals(channel2, mHelper.getNotificationChannel(PKG_O, UID_O, channel2.getId(), false)); - List<String> deleted = mHelper.deleteConversations(PKG_O, UID_O, Set.of(convoId, convoIdC)); + List<String> deleted = mHelper.deleteConversations(PKG_O, UID_O, Set.of(convoId, convoIdC), + UID_O, false); assertEquals(3, deleted.size()); assertEquals(messages, @@ -4950,12 +5171,12 @@ public class PreferencesHelperTest extends UiServiceTestCase { String channelId = "parent"; String name = "messages"; NotificationChannel fodderA = new NotificationChannel("a", "a", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG_O, UID_O, fodderA, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, fodderA, true, false, UID_O, false); NotificationChannel channel = new NotificationChannel(channelId, name, IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false); NotificationChannel fodderB = new NotificationChannel("b", "b", IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG_O, UID_O, fodderB, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, fodderB, true, false, UID_O, false); ArrayList<StatsEvent> events = new ArrayList<>(); mHelper.pullPackageChannelPreferencesStats(events); @@ -4980,11 +5201,11 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testPullPackageChannelPreferencesStats_one_to_one() { NotificationChannel channelA = new NotificationChannel("a", "a", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG_O, UID_O, channelA, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channelA, true, false, UID_O, false); NotificationChannel channelB = new NotificationChannel("b", "b", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG_O, UID_O, channelB, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channelB, true, false, UID_O, false); NotificationChannel channelC = new NotificationChannel("c", "c", IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG_O, UID_O, channelC, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channelC, true, false, UID_O, false); List<String> channels = new LinkedList<>(Arrays.asList("a", "b", "c")); @@ -5008,7 +5229,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel parent = new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, UID_O, false); String channelId = String.format( CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), conversationId); @@ -5016,7 +5237,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel friend = new NotificationChannel(channelId, name, IMPORTANCE_DEFAULT); friend.setConversationId(parent.getId(), conversationId); - mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false, UID_O, false); ArrayList<StatsEvent> events = new ArrayList<>(); mHelper.pullPackageChannelPreferencesStats(events); @@ -5038,14 +5259,14 @@ public class PreferencesHelperTest extends UiServiceTestCase { public void testPullPackageChannelPreferencesStats_conversation_demoted() { NotificationChannel parent = new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, UID_O, false); String channelId = String.format( CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), "friend"); NotificationChannel friend = new NotificationChannel(channelId, "conversation", IMPORTANCE_DEFAULT); friend.setConversationId(parent.getId(), "friend"); friend.setDemoted(true); - mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false, UID_O, false); ArrayList<StatsEvent> events = new ArrayList<>(); mHelper.pullPackageChannelPreferencesStats(events); @@ -5067,14 +5288,14 @@ public class PreferencesHelperTest extends UiServiceTestCase { public void testPullPackageChannelPreferencesStats_conversation_priority() { NotificationChannel parent = new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, UID_O, false); String channelId = String.format( CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), "friend"); NotificationChannel friend = new NotificationChannel(channelId, "conversation", IMPORTANCE_DEFAULT); friend.setConversationId(parent.getId(), "friend"); friend.setImportantConversation(true); - mHelper.createNotificationChannel(PKG_O, UID_O, friend, false, false); + mHelper.createNotificationChannel(PKG_O, UID_O, friend, false, false, SYSTEM_UID, true); ArrayList<StatsEvent> events = new ArrayList<>(); mHelper.pullPackageChannelPreferencesStats(events); @@ -5096,11 +5317,12 @@ public class PreferencesHelperTest extends UiServiceTestCase { public void testPullPackagePreferencesStats_postPermissionMigration() { // make sure there's at least one channel for each package we want to test NotificationChannel channelA = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channelA, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channelA, true, false, + UID_N_MR1, false); NotificationChannel channelB = new NotificationChannel("b", "b", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_O, UID_O, channelB, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channelB, true, false, UID_O, false); NotificationChannel channelC = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_P, UID_P, channelC, true, false); + mHelper.createNotificationChannel(PKG_P, UID_P, channelC, true, false, UID_P, false); // build a collection of app permissions that should be passed in and used ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>(); @@ -5143,7 +5365,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testUnlockNotificationChannelImportance() { NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false); channel.lockFields(USER_LOCKED_IMPORTANCE); assertTrue((channel.getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0); @@ -5155,11 +5377,11 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testUnlockAllNotificationChannels() { NotificationChannel channelA = new NotificationChannel("a", "a", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG_O, UID_O, channelA, true, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channelA, true, false, UID_O, false); NotificationChannel channelB = new NotificationChannel("b", "b", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_P, UID_P, channelB, true, false); + mHelper.createNotificationChannel(PKG_P, UID_P, channelB, true, false, UID_P, false); NotificationChannel channelC = new NotificationChannel("c", "c", IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG_P, UID_O, channelC, false, false); + mHelper.createNotificationChannel(PKG_P, UID_O, channelC, false, false, UID_O, false); channelA.lockFields(USER_LOCKED_IMPORTANCE); channelB.lockFields(USER_LOCKED_IMPORTANCE); @@ -5178,11 +5400,11 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void createNotificationChannel_updateDifferent_requestsSort() { NotificationChannel original = new NotificationChannel("id", "Bah", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_P, 0, original, true, false); + mHelper.createNotificationChannel(PKG_P, 0, original, true, false, 0, false); clearInvocations(mHandler); NotificationChannel updated = new NotificationChannel("id", "Wow", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_P, 0, updated, true, false); + mHelper.createNotificationChannel(PKG_P, 0, updated, true, false, 0, false); verify(mHandler).requestSort(); } @@ -5190,11 +5412,11 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void createNotificationChannel_updateSame_doesNotRequestSort() { NotificationChannel original = new NotificationChannel("id", "Bah", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_P, 0, original, true, false); + mHelper.createNotificationChannel(PKG_P, 0, original, true, false, 0, false); clearInvocations(mHandler); NotificationChannel same = new NotificationChannel("id", "Bah", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_P, 0, same, true, false); + mHelper.createNotificationChannel(PKG_P, 0, same, true, false, 0, false); verifyZeroInteractions(mHandler); } @@ -5202,11 +5424,11 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void updateNotificationChannel_different_requestsSort() { NotificationChannel original = new NotificationChannel("id", "Bah", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_P, 0, original, true, false); + mHelper.createNotificationChannel(PKG_P, 0, original, true, false, 0, false); clearInvocations(mHandler); NotificationChannel updated = new NotificationChannel("id", "Wow", IMPORTANCE_DEFAULT); - mHelper.updateNotificationChannel(PKG_P, 0, updated, false); + mHelper.updateNotificationChannel(PKG_P, 0, updated, false, 0, false); verify(mHandler).requestSort(); } @@ -5214,7 +5436,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void updateNotificationChannel_same_doesNotRequestSort() { NotificationChannel original = new NotificationChannel("id", "Bah", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG_P, 0, original, true, false); + mHelper.createNotificationChannel(PKG_P, 0, original, true, false, 0, false); clearInvocations(mHandler); // Note: Creating a NotificationChannel identical to the original is not equals(), because // of mOriginalImportance. So we create a "true copy" instead. @@ -5224,7 +5446,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel same = NotificationChannel.CREATOR.createFromParcel(parcel); parcel.recycle(); - mHelper.updateNotificationChannel(PKG_P, 0, same, false); + mHelper.updateNotificationChannel(PKG_P, 0, same, false, 0, false); verifyZeroInteractions(mHandler); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java b/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java index 61a6985d473e..9f4eee7e332f 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java @@ -67,7 +67,13 @@ public class TestableNotificationManagerService extends NotificationManagerServi @Override protected boolean isCallerSystemOrPhone() { countSystemChecks++; - return isSystemUid; + return isSystemUid || isSystemAppId; + } + + @Override + protected boolean isCallerIsSystemOrSystemUi() { + countSystemChecks++; + return isSystemUid || isSystemAppId; } @Override diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeEventLoggerFake.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeEventLoggerFake.java new file mode 100644 index 000000000000..4a1435f9ee64 --- /dev/null +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeEventLoggerFake.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.notification; + +import android.content.pm.PackageManager; + +import com.android.os.dnd.DNDPolicyProto; + +import com.google.protobuf.InvalidProtocolBufferException; + +import java.util.ArrayList; +import java.util.List; + +/** + * ZenModeEventLoggerFake extends ZenModeEventLogger for ease of verifying logging output. This + * class behaves exactly the same as its parent class except that instead of actually logging, it + * stores the full information at time of log whenever something would be logged. + */ +public class ZenModeEventLoggerFake extends ZenModeEventLogger { + // A record of the contents of each event we'd log, stored by recording the ChangeState object + // at the time of the log. + private List<ZenStateChanges> mChanges = new ArrayList<>(); + + public ZenModeEventLoggerFake(PackageManager pm) { + super(pm); + } + + @Override + void logChanges() { + // current change state being logged + mChanges.add(mChangeState.copy()); + } + + // Reset the state of the logger (remove all changes). + public void reset() { + mChanges = new ArrayList<>(); + } + + // Returns the number of changes logged. + public int numLoggedChanges() { + return mChanges.size(); + } + + // is index i out of range for the set of changes we have + private boolean outOfRange(int i) { + return i < 0 || i >= mChanges.size(); + } + + // Throw an exception if provided index is out of range + private void checkInRange(int i) throws IllegalArgumentException { + if (outOfRange(i)) { + throw new IllegalArgumentException("invalid index for logged event: " + i); + } + } + + // Get the UiEvent ID of the i'th logged event. + public int getEventId(int i) throws IllegalArgumentException { + checkInRange(i); + return mChanges.get(i).getEventId().getId(); + } + + // Get the previous zen mode associated with the change at event i. + public int getPrevZenMode(int i) throws IllegalArgumentException { + checkInRange(i); + return mChanges.get(i).mPrevZenMode; + } + + // Get the new zen mode associated with the change at event i. + public int getNewZenMode(int i) throws IllegalArgumentException { + checkInRange(i); + return mChanges.get(i).mNewZenMode; + } + + // Get the changed rule type associated with event i. + public int getChangedRuleType(int i) throws IllegalArgumentException { + checkInRange(i); + return mChanges.get(i).getChangedRuleType(); + } + + public int getNumRulesActive(int i) throws IllegalArgumentException { + checkInRange(i); + return mChanges.get(i).getNumRulesActive(); + } + + public boolean getFromSystemOrSystemUi(int i) throws IllegalArgumentException { + // While this isn't a logged output value, it's still helpful to check in tests. + checkInRange(i); + return mChanges.get(i).mFromSystemOrSystemUi; + } + + public boolean getIsUserAction(int i) throws IllegalArgumentException { + checkInRange(i); + return mChanges.get(i).getIsUserAction(); + } + + public int getPackageUid(int i) throws IllegalArgumentException { + checkInRange(i); + return mChanges.get(i).getPackageUid(); + } + + // Get the DNDPolicyProto (unmarshaled from bytes) associated with event i. + // Note that in creation of the log, we use a notification.proto mirror of DNDPolicyProto, + // but here we use the actual logging-side proto to make sure they continue to match. + public DNDPolicyProto getPolicyProto(int i) throws IllegalArgumentException { + checkInRange(i); + byte[] policyBytes = mChanges.get(i).getDNDPolicyProto(); + try { + return DNDPolicyProto.parseFrom(policyBytes); + } catch (InvalidProtocolBufferException e) { + return null; // couldn't turn it into proto + } + } + + public boolean getAreChannelsBypassing(int i) throws IllegalArgumentException { + checkInRange(i); + return mChanges.get(i).getAreChannelsBypassing(); + } +} diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index 2c95bdee3454..dedb8f170ee0 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -34,16 +34,21 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCRE import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; +import static android.service.notification.Condition.STATE_FALSE; import static android.service.notification.Condition.STATE_TRUE; import static android.util.StatsLog.ANNOTATION_ID_IS_UID; +import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.LOG_DND_STATE_EVENTS; import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE; import static com.android.os.dnd.DNDModeProto.CHANNELS_BYPASSING_FIELD_NUMBER; import static com.android.os.dnd.DNDModeProto.ENABLED_FIELD_NUMBER; import static com.android.os.dnd.DNDModeProto.ID_FIELD_NUMBER; import static com.android.os.dnd.DNDModeProto.UID_FIELD_NUMBER; import static com.android.os.dnd.DNDModeProto.ZEN_MODE_FIELD_NUMBER; +import static com.android.os.dnd.DNDProtoEnums.PEOPLE_STARRED; import static com.android.os.dnd.DNDProtoEnums.ROOT_CONFIG; +import static com.android.os.dnd.DNDProtoEnums.STATE_ALLOW; +import static com.android.os.dnd.DNDProtoEnums.STATE_DISALLOW; import static com.android.server.notification.ZenModeHelper.RULE_LIMIT_PER_PACKAGE; import static junit.framework.Assert.assertEquals; @@ -104,9 +109,12 @@ import android.util.StatsEvent; import android.util.Xml; import com.android.internal.R; +import com.android.internal.config.sysui.TestableFlagResolver; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; +import com.android.os.dnd.DNDPolicyProto; +import com.android.os.dnd.DNDProtoEnums; import com.android.server.UiServiceTestCase; import com.android.server.notification.ManagedServices.UserProfiles; @@ -152,6 +160,8 @@ public class ZenModeHelperTest extends UiServiceTestCase { private ContentResolver mContentResolver; @Mock AppOpsManager mAppOps; private WrappedSysUiStatsEvent.WrappedBuilderFactory mStatsEventBuilderFactory; + TestableFlagResolver mTestFlagResolver = new TestableFlagResolver(); + ZenModeEventLoggerFake mZenModeEventLogger; @Before public void setUp() throws PackageManager.NameNotFoundException { @@ -176,8 +186,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { AppGlobals.getPackageManager()); mConditionProviders.addSystemProvider(new CountdownConditionProvider()); mConditionProviders.addSystemProvider(new ScheduleConditionProvider()); + mZenModeEventLogger = new ZenModeEventLoggerFake(mPackageManager); mZenModeHelper = new ZenModeHelper(mContext, mTestableLooper.getLooper(), - mConditionProviders, mStatsEventBuilderFactory); + mConditionProviders, mStatsEventBuilderFactory, mTestFlagResolver, + mZenModeEventLogger); ResolveInfo ri = new ResolveInfo(); ri.activityInfo = new ActivityInfo(); @@ -188,6 +200,8 @@ public class ZenModeHelperTest extends UiServiceTestCase { when(mPackageManager.getPackagesForUid(anyInt())).thenReturn( new String[] {pkg}); mZenModeHelper.mPm = mPackageManager; + + mZenModeEventLogger.reset(); } private XmlResourceParser getDefaultConfigParser() throws IOException, XmlPullParserException { @@ -224,7 +238,8 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelper.writeXml(serializer, false, version, UserHandle.USER_ALL); serializer.endDocument(); serializer.flush(); - mZenModeHelper.setConfig(new ZenModeConfig(), null, "writing xml"); + mZenModeHelper.setConfig(new ZenModeConfig(), null, "writing xml", Process.SYSTEM_UID, + true); return baos; } @@ -239,7 +254,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { serializer.flush(); ZenModeConfig newConfig = new ZenModeConfig(); newConfig.user = userId; - mZenModeHelper.setConfig(newConfig, null, "writing xml"); + mZenModeHelper.setConfig(newConfig, null, "writing xml", Process.SYSTEM_UID, true); return baos; } @@ -822,14 +837,11 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelper.mAudioManager = mAudioManager; setupZenConfig(); - // Change the config a little bit, but enough that it would turn zen mode on - ZenModeConfig newConfig = mZenModeHelper.mConfig.copy(); - newConfig.manualRule = new ZenModeConfig.ZenRule(); - newConfig.manualRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; - newConfig.manualRule.enabled = true; - mZenModeHelper.setConfig(newConfig, null, "test"); + // Turn manual zen mode on + mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, null, + "test", CUSTOM_PKG_UID, false); - // audio manager shouldn't do anything until the handler processes its messagse + // audio manager shouldn't do anything until the handler processes its messages verify(mAudioManager, never()).updateRingerModeAffectedStreamsInternal(); // now process the looper's messages @@ -993,7 +1005,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { List<StatsEvent> events = new LinkedList<>(); mZenModeHelper.pullRules(events); - mZenModeHelper.removeAutomaticZenRule(CUSTOM_RULE_ID, "test"); + mZenModeHelper.removeAutomaticZenRule(CUSTOM_RULE_ID, "test", CUSTOM_PKG_UID, false); assertTrue(-1 == mZenModeHelper.mRulesUidCache.getOrDefault(CUSTOM_PKG_NAME + "|" + 0, -1)); } @@ -1044,12 +1056,12 @@ public class ZenModeHelperTest extends UiServiceTestCase { config10.user = 10; config10.allowAlarms = true; config10.allowMedia = true; - mZenModeHelper.setConfig(config10, null, "writeXml"); + mZenModeHelper.setConfig(config10, null, "writeXml", Process.SYSTEM_UID, true); ZenModeConfig config11 = mZenModeHelper.mConfig.copy(); config11.user = 11; config11.allowAlarms = false; config11.allowMedia = false; - mZenModeHelper.setConfig(config11, null, "writeXml"); + mZenModeHelper.setConfig(config11, null, "writeXml", Process.SYSTEM_UID, true); // Backup user 10 and reset values. ByteArrayOutputStream baos = writeXmlAndPurgeForUser(null, 10); @@ -1552,7 +1564,8 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenModeConfig config = new ZenModeConfig(); config.automaticRules = new ArrayMap<>(); mZenModeHelper.mConfig = config; - mZenModeHelper.updateDefaultZenRules(); // shouldn't throw null pointer + mZenModeHelper.updateDefaultZenRules( + Process.SYSTEM_UID, true); // shouldn't throw null pointer mZenModeHelper.pullRules(events); // shouldn't throw null pointer } @@ -1577,7 +1590,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { autoRules.put(SCHEDULE_DEFAULT_RULE_ID, updatedDefaultRule); mZenModeHelper.mConfig.automaticRules = autoRules; - mZenModeHelper.updateDefaultZenRules(); + mZenModeHelper.updateDefaultZenRules(Process.SYSTEM_UID, true); assertEquals(updatedDefaultRule, mZenModeHelper.mConfig.automaticRules.get(SCHEDULE_DEFAULT_RULE_ID)); } @@ -1603,7 +1616,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { autoRules.put(SCHEDULE_DEFAULT_RULE_ID, updatedDefaultRule); mZenModeHelper.mConfig.automaticRules = autoRules; - mZenModeHelper.updateDefaultZenRules(); + mZenModeHelper.updateDefaultZenRules(Process.SYSTEM_UID, true); assertEquals(updatedDefaultRule, mZenModeHelper.mConfig.automaticRules.get(SCHEDULE_DEFAULT_RULE_ID)); } @@ -1630,7 +1643,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { autoRules.put(SCHEDULE_DEFAULT_RULE_ID, customDefaultRule); mZenModeHelper.mConfig.automaticRules = autoRules; - mZenModeHelper.updateDefaultZenRules(); + mZenModeHelper.updateDefaultZenRules(Process.SYSTEM_UID, true); ZenModeConfig.ZenRule ruleAfterUpdating = mZenModeHelper.mConfig.automaticRules.get(SCHEDULE_DEFAULT_RULE_ID); assertEquals(customDefaultRule.enabled, ruleAfterUpdating.enabled); @@ -1653,7 +1666,8 @@ public class ZenModeHelperTest extends UiServiceTestCase { NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); // We need the package name to be something that's not "android" so there aren't any // existing rules under that package. - String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test", + CUSTOM_PKG_UID, false); assertNotNull(id); } try { @@ -1663,7 +1677,8 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test", + CUSTOM_PKG_UID, false); fail("allowed too many rules to be created"); } catch (IllegalArgumentException e) { // yay @@ -1683,7 +1698,8 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenModeConfig.toScheduleConditionId(si), new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test", + CUSTOM_PKG_UID, false); assertNotNull(id); } try { @@ -1693,7 +1709,8 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test", + CUSTOM_PKG_UID, false); fail("allowed too many rules to be created"); } catch (IllegalArgumentException e) { // yay @@ -1713,7 +1730,8 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenModeConfig.toScheduleConditionId(si), new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test", + CUSTOM_PKG_UID, false); assertNotNull(id); } try { @@ -1723,7 +1741,8 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule("pkgname", zenRule, "test", + CUSTOM_PKG_UID, false); fail("allowed too many rules to be created"); } catch (IllegalArgumentException e) { // yay @@ -1738,7 +1757,8 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelper.addAutomaticZenRule("android", zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule("android", zenRule, "test", + Process.SYSTEM_UID, true); assertTrue(id != null); ZenModeConfig.ZenRule ruleInConfig = mZenModeHelper.mConfig.automaticRules.get(id); @@ -1758,7 +1778,8 @@ public class ZenModeHelperTest extends UiServiceTestCase { new ComponentName("android", "ScheduleConditionProvider"), ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelper.addAutomaticZenRule("android", zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule("android", zenRule, "test", + Process.SYSTEM_UID, true); assertTrue(id != null); ZenModeConfig.ZenRule ruleInConfig = mZenModeHelper.mConfig.automaticRules.get(id); @@ -1781,9 +1802,11 @@ public class ZenModeHelperTest extends UiServiceTestCase { new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelper.addAutomaticZenRule(null, zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule(null, zenRule, "test", + CUSTOM_PKG_UID, false); mZenModeHelper.setAutomaticZenRuleState(zenRule.getConditionId(), - new Condition(zenRule.getConditionId(), "", STATE_TRUE)); + new Condition(zenRule.getConditionId(), "", STATE_TRUE), + CUSTOM_PKG_UID, false); ZenModeConfig.ZenRule ruleInConfig = mZenModeHelper.mConfig.automaticRules.get(id); assertEquals(STATE_TRUE, ruleInConfig.condition.state); @@ -1798,7 +1821,8 @@ public class ZenModeHelperTest extends UiServiceTestCase { new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelper.addAutomaticZenRule(null, zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule(null, zenRule, "test", + CUSTOM_PKG_UID, false); AutomaticZenRule zenRule2 = new AutomaticZenRule("NEW", null, @@ -1807,7 +1831,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - mZenModeHelper.updateAutomaticZenRule(id, zenRule2, ""); + mZenModeHelper.updateAutomaticZenRule(id, zenRule2, "", CUSTOM_PKG_UID, false); ZenModeConfig.ZenRule ruleInConfig = mZenModeHelper.mConfig.automaticRules.get(id); assertEquals("NEW", ruleInConfig.name); @@ -1822,14 +1846,15 @@ public class ZenModeHelperTest extends UiServiceTestCase { new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelper.addAutomaticZenRule(null, zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule(null, zenRule, "test", + CUSTOM_PKG_UID, false); assertTrue(id != null); ZenModeConfig.ZenRule ruleInConfig = mZenModeHelper.mConfig.automaticRules.get(id); assertTrue(ruleInConfig != null); assertEquals(zenRule.getName(), ruleInConfig.name); - mZenModeHelper.removeAutomaticZenRule(id, "test"); + mZenModeHelper.removeAutomaticZenRule(id, "test", CUSTOM_PKG_UID, false); assertNull(mZenModeHelper.mConfig.automaticRules.get(id)); } @@ -1841,14 +1866,16 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelper.addAutomaticZenRule(null, zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule(null, zenRule, "test", + CUSTOM_PKG_UID, false); assertTrue(id != null); ZenModeConfig.ZenRule ruleInConfig = mZenModeHelper.mConfig.automaticRules.get(id); assertTrue(ruleInConfig != null); assertEquals(zenRule.getName(), ruleInConfig.name); - mZenModeHelper.removeAutomaticZenRules(mContext.getPackageName(), "test"); + mZenModeHelper.removeAutomaticZenRules(mContext.getPackageName(), "test", + CUSTOM_PKG_UID, false); assertNull(mZenModeHelper.mConfig.automaticRules.get(id)); } @@ -1863,15 +1890,17 @@ public class ZenModeHelperTest extends UiServiceTestCase { new ComponentName("android", "ScheduleConditionProvider"), sharedUri, NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelper.addAutomaticZenRule("android", zenRule, "test"); + String id = mZenModeHelper.addAutomaticZenRule("android", zenRule, "test", + Process.SYSTEM_UID, true); AutomaticZenRule zenRule2 = new AutomaticZenRule("name2", new ComponentName("android", "ScheduleConditionProvider"), sharedUri, NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id2 = mZenModeHelper.addAutomaticZenRule("android", zenRule2, "test"); + String id2 = mZenModeHelper.addAutomaticZenRule("android", zenRule2, "test", + Process.SYSTEM_UID, true); Condition condition = new Condition(sharedUri, "", STATE_TRUE); - mZenModeHelper.setAutomaticZenRuleState(sharedUri, condition); + mZenModeHelper.setAutomaticZenRuleState(sharedUri, condition, Process.SYSTEM_UID, true); for (ZenModeConfig.ZenRule rule : mZenModeHelper.mConfig.automaticRules.values()) { if (rule.id.equals(id)) { @@ -1884,17 +1913,17 @@ public class ZenModeHelperTest extends UiServiceTestCase { } } - condition = new Condition(sharedUri, "", Condition.STATE_FALSE); - mZenModeHelper.setAutomaticZenRuleState(sharedUri, condition); + condition = new Condition(sharedUri, "", STATE_FALSE); + mZenModeHelper.setAutomaticZenRuleState(sharedUri, condition, Process.SYSTEM_UID, true); for (ZenModeConfig.ZenRule rule : mZenModeHelper.mConfig.automaticRules.values()) { if (rule.id.equals(id)) { assertNotNull(rule.condition); - assertTrue(rule.condition.state == Condition.STATE_FALSE); + assertTrue(rule.condition.state == STATE_FALSE); } if (rule.id.equals(id2)) { assertNotNull(rule.condition); - assertTrue(rule.condition.state == Condition.STATE_FALSE); + assertTrue(rule.condition.state == STATE_FALSE); } } } @@ -1904,14 +1933,510 @@ public class ZenModeHelperTest extends UiServiceTestCase { setupZenConfig(); // note that caller=null because that's how it comes in from NMS.setZenMode - mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, null, ""); + mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, null, "", + Process.SYSTEM_UID, true); // confirm that setting zen mode via setManualZenMode changed the zen mode correctly assertEquals(ZEN_MODE_IMPORTANT_INTERRUPTIONS, mZenModeHelper.mZenMode); // and also that it works to turn it back off again - mZenModeHelper.setManualZenMode(Global.ZEN_MODE_OFF, null, null, ""); + mZenModeHelper.setManualZenMode(Global.ZEN_MODE_OFF, null, null, "", + Process.SYSTEM_UID, true); + + assertEquals(Global.ZEN_MODE_OFF, mZenModeHelper.mZenMode); + } + + @Test + public void testZenModeEventLog_setManualZenMode() throws IllegalArgumentException { + mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true); + setupZenConfig(); + + // Turn zen mode on (to important_interruptions) + // Need to additionally call the looper in order to finish the post-apply-config process + mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, null, "", + Process.SYSTEM_UID, true); + + // Now turn zen mode off, but via a different package UID -- this should get registered as + // "not an action by the user" because some other app is changing zen mode + mZenModeHelper.setManualZenMode(Global.ZEN_MODE_OFF, null, null, "", CUSTOM_PKG_UID, + false); + + // In total, this should be 2 loggable changes + assertEquals(2, mZenModeEventLogger.numLoggedChanges()); + + // we expect the following changes from turning zen mode on: + // - manual rule added + // - zen mode -> ZEN_MODE_IMPORTANT_INTERRUPTIONS + // This should combine to 1 log event (zen mode turns on) with the following properties: + // - event ID: DND_TURNED_ON + // - new zen mode = important interruptions; prev zen mode = off + // - changed rule type = manual + // - rules active = 1 + // - user action = true (system-based turning zen mode on) + // - package uid = system (as set above) + // - resulting DNDPolicyProto the same as the values in setupZenConfig() + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_TURNED_ON.getId(), + mZenModeEventLogger.getEventId(0)); + assertEquals(Global.ZEN_MODE_OFF, mZenModeEventLogger.getPrevZenMode(0)); + assertEquals(ZEN_MODE_IMPORTANT_INTERRUPTIONS, mZenModeEventLogger.getNewZenMode(0)); + assertEquals(DNDProtoEnums.MANUAL_RULE, mZenModeEventLogger.getChangedRuleType(0)); + assertEquals(1, mZenModeEventLogger.getNumRulesActive(0)); + assertTrue(mZenModeEventLogger.getFromSystemOrSystemUi(0)); + assertTrue(mZenModeEventLogger.getIsUserAction(0)); + assertEquals(Process.SYSTEM_UID, mZenModeEventLogger.getPackageUid(0)); + checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(0)); + + // and from turning zen mode off: + // - event ID: DND_TURNED_OFF + // - new zen mode = off; previous = important interruptions + // - changed rule type = manual + // - rules active = 0 + // - user action = false + // - package uid = custom one passed in above + // - DNDPolicyProto still the same + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_TURNED_OFF.getId(), + mZenModeEventLogger.getEventId(1)); + assertEquals(ZEN_MODE_IMPORTANT_INTERRUPTIONS, mZenModeEventLogger.getPrevZenMode(1)); + assertEquals(Global.ZEN_MODE_OFF, mZenModeEventLogger.getNewZenMode(1)); + assertEquals(DNDProtoEnums.MANUAL_RULE, mZenModeEventLogger.getChangedRuleType(1)); + assertEquals(0, mZenModeEventLogger.getNumRulesActive(1)); + assertFalse(mZenModeEventLogger.getIsUserAction(1)); + assertEquals(CUSTOM_PKG_UID, mZenModeEventLogger.getPackageUid(1)); + checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(1)); + } + + @Test + public void testZenModeEventLog_automaticRules() throws IllegalArgumentException { + mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true); + setupZenConfig(); + + // Add a new automatic zen rule that's enabled + AutomaticZenRule zenRule = new AutomaticZenRule("name", + null, + new ComponentName(CUSTOM_PKG_NAME, "ScheduleConditionProvider"), + ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), + null, + NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + String id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule, + "test", Process.SYSTEM_UID, true); + + // Event 1: Mimic the rule coming on automatically by setting the Condition to STATE_TRUE + mZenModeHelper.setAutomaticZenRuleState(id, + new Condition(zenRule.getConditionId(), "", STATE_TRUE), + Process.SYSTEM_UID, true); + + // Event 2: "User" turns off the automatic rule (sets it to not enabled) + zenRule.setEnabled(false); + mZenModeHelper.updateAutomaticZenRule(id, zenRule, "", Process.SYSTEM_UID, true); + + // Add a new system rule + AutomaticZenRule systemRule = new AutomaticZenRule("systemRule", + null, + new ComponentName("android", "ScheduleConditionProvider"), + ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), + null, + NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + String systemId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), systemRule, + "test", Process.SYSTEM_UID, true); + + // Event 3: turn on the system rule + mZenModeHelper.setAutomaticZenRuleState(systemId, + new Condition(zenRule.getConditionId(), "", STATE_TRUE), + Process.SYSTEM_UID, true); + + // Event 4: "User" deletes the rule + mZenModeHelper.removeAutomaticZenRule(systemId, "", Process.SYSTEM_UID, true); + + // In total, this represents 4 events + assertEquals(4, mZenModeEventLogger.numLoggedChanges()); + + // We should see an event from the automatic rule turning on; it should have the following + // properties: + // - event ID: DND_TURNED_ON + // - zen mode: OFF -> IMPORTANT_INTERRUPTIONS + // - automatic rule change + // - 1 rule (newly) active + // - automatic (is not a user action) + // - package UID is written to be the rule *owner* even though it "comes from system" + // - zen policy is the same as the set-up zen config + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_TURNED_ON.getId(), + mZenModeEventLogger.getEventId(0)); + assertEquals(Global.ZEN_MODE_OFF, mZenModeEventLogger.getPrevZenMode(0)); + assertEquals(ZEN_MODE_IMPORTANT_INTERRUPTIONS, mZenModeEventLogger.getNewZenMode(0)); + assertEquals(DNDProtoEnums.AUTOMATIC_RULE, mZenModeEventLogger.getChangedRuleType(0)); + assertEquals(1, mZenModeEventLogger.getNumRulesActive(0)); + assertFalse(mZenModeEventLogger.getIsUserAction(0)); + assertEquals(CUSTOM_PKG_UID, mZenModeEventLogger.getPackageUid(0)); + checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(0)); + + // When the automatic rule is disabled, this should turn off zen mode and also count as a + // user action. + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_TURNED_OFF.getId(), + mZenModeEventLogger.getEventId(1)); + assertEquals(ZEN_MODE_IMPORTANT_INTERRUPTIONS, mZenModeEventLogger.getPrevZenMode(1)); + assertEquals(Global.ZEN_MODE_OFF, mZenModeEventLogger.getNewZenMode(1)); + assertEquals(DNDProtoEnums.AUTOMATIC_RULE, mZenModeEventLogger.getChangedRuleType(1)); + assertEquals(0, mZenModeEventLogger.getNumRulesActive(1)); + assertTrue(mZenModeEventLogger.getIsUserAction(1)); + assertEquals(Process.SYSTEM_UID, mZenModeEventLogger.getPackageUid(1)); + checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(1)); + + // When the system rule is enabled, this counts as an automatic action that comes from the + // system and turns on DND + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_TURNED_ON.getId(), + mZenModeEventLogger.getEventId(2)); + assertEquals(DNDProtoEnums.AUTOMATIC_RULE, mZenModeEventLogger.getChangedRuleType(2)); + assertEquals(1, mZenModeEventLogger.getNumRulesActive(2)); + assertFalse(mZenModeEventLogger.getIsUserAction(2)); + assertEquals(Process.SYSTEM_UID, mZenModeEventLogger.getPackageUid(2)); + + // When the system rule is deleted, we consider this a user action that turns DND off + // (again) + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_TURNED_OFF.getId(), + mZenModeEventLogger.getEventId(3)); + assertEquals(DNDProtoEnums.AUTOMATIC_RULE, mZenModeEventLogger.getChangedRuleType(3)); + assertEquals(0, mZenModeEventLogger.getNumRulesActive(3)); + assertTrue(mZenModeEventLogger.getIsUserAction(3)); + assertEquals(Process.SYSTEM_UID, mZenModeEventLogger.getPackageUid(3)); + } + + @Test + public void testZenModeEventLog_policyChanges() throws IllegalArgumentException { + mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true); + setupZenConfig(); + + // First just turn zen mode on + mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, null, "", + Process.SYSTEM_UID, true); + + // Now change the policy slightly; want to confirm that this'll be reflected in the logs + ZenModeConfig newConfig = mZenModeHelper.mConfig.copy(); + newConfig.allowAlarms = true; + newConfig.allowRepeatCallers = false; + mZenModeHelper.setNotificationPolicy(newConfig.toNotificationPolicy(), Process.SYSTEM_UID, + true); + + // Turn zen mode off; we want to make sure policy changes do not get logged when zen mode + // is off. + mZenModeHelper.setManualZenMode(Global.ZEN_MODE_OFF, null, null, "", + Process.SYSTEM_UID, true); + + // Change the policy again + newConfig.allowMessages = false; + newConfig.allowRepeatCallers = true; + mZenModeHelper.setNotificationPolicy(newConfig.toNotificationPolicy(), Process.SYSTEM_UID, + true); + + // Total events: we only expect ones for turning on, changing policy, and turning off + assertEquals(3, mZenModeEventLogger.numLoggedChanges()); + + // The first event is just turning DND on; make sure the policy is what we expect there + // before it changes in the next stage + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_TURNED_ON.getId(), + mZenModeEventLogger.getEventId(0)); + checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(0)); + + // Second message where we change the policy: + // - DND_POLICY_CHANGED (indicates only the policy changed and nothing else) + // - rule type: unknown (it's a policy change, not a rule change) + // - user action (because it comes from a "system" uid) + // - check the specific things changed above + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_POLICY_CHANGED.getId(), + mZenModeEventLogger.getEventId(1)); + assertEquals(DNDProtoEnums.UNKNOWN_RULE, mZenModeEventLogger.getChangedRuleType(1)); + assertTrue(mZenModeEventLogger.getIsUserAction(1)); + assertEquals(Process.SYSTEM_UID, mZenModeEventLogger.getPackageUid(1)); + DNDPolicyProto dndProto = mZenModeEventLogger.getPolicyProto(1); + assertEquals(STATE_ALLOW, dndProto.getAlarms().getNumber()); + assertEquals(STATE_DISALLOW, dndProto.getRepeatCallers().getNumber()); + + // The third and final event should turn DND off + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_TURNED_OFF.getId(), + mZenModeEventLogger.getEventId(2)); + + // There should be no fourth event for changing the policy the second time. + } + + @Test + public void testZenModeEventLog_ruleCounts() throws IllegalArgumentException { + mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true); + setupZenConfig(); + + AutomaticZenRule zenRule = new AutomaticZenRule("name", + null, + new ComponentName(CUSTOM_PKG_NAME, "ScheduleConditionProvider"), + ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), + null, + NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + String id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule, "test", + Process.SYSTEM_UID, true); + + // Rule 2, same as rule 1 + AutomaticZenRule zenRule2 = new AutomaticZenRule("name2", + null, + new ComponentName(CUSTOM_PKG_NAME, "ScheduleConditionProvider"), + ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), + null, + NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + String id2 = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule2, "test", + Process.SYSTEM_UID, true); + + // Rule 3, has stricter settings than the default settings + ZenModeConfig ruleConfig = mZenModeHelper.mConfig.copy(); + ruleConfig.allowReminders = false; + ruleConfig.allowCalls = false; + ruleConfig.allowMessages = false; + AutomaticZenRule zenRule3 = new AutomaticZenRule("name3", + null, + new ComponentName("android", "ScheduleConditionProvider"), + ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), + ruleConfig.toZenPolicy(), + NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + String id3 = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule3, "test", + Process.SYSTEM_UID, true); + + // First: turn on rule 1 + mZenModeHelper.setAutomaticZenRuleState(id, + new Condition(zenRule.getConditionId(), "", STATE_TRUE), + Process.SYSTEM_UID, true); + + // Second: turn on rule 2 + mZenModeHelper.setAutomaticZenRuleState(id2, + new Condition(zenRule2.getConditionId(), "", STATE_TRUE), + Process.SYSTEM_UID, true); + + // Third: turn on rule 3 + mZenModeHelper.setAutomaticZenRuleState(id3, + new Condition(zenRule3.getConditionId(), "", STATE_TRUE), + Process.SYSTEM_UID, true); + + // Fourth: Turn *off* rule 2 + mZenModeHelper.setAutomaticZenRuleState(id2, + new Condition(zenRule2.getConditionId(), "", STATE_FALSE), + Process.SYSTEM_UID, true); + + // This should result in a total of four events + assertEquals(4, mZenModeEventLogger.numLoggedChanges()); + + // Event 1: rule 1 turns on. We expect this to turn on DND (zen mode) overall, so that's + // what the event should reflect. At this time, the policy is the same as initial setup. + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_TURNED_ON.getId(), + mZenModeEventLogger.getEventId(0)); + assertEquals(Global.ZEN_MODE_OFF, mZenModeEventLogger.getPrevZenMode(0)); + assertEquals(ZEN_MODE_IMPORTANT_INTERRUPTIONS, mZenModeEventLogger.getNewZenMode(0)); + assertEquals(1, mZenModeEventLogger.getNumRulesActive(0)); + assertFalse(mZenModeEventLogger.getIsUserAction(0)); + assertEquals(CUSTOM_PKG_UID, mZenModeEventLogger.getPackageUid(0)); + checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(0)); + + // Event 2: rule 2 turns on. This should not change anything about the policy, so the only + // change is that there are more rules active now. + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_ACTIVE_RULES_CHANGED.getId(), + mZenModeEventLogger.getEventId(1)); + assertEquals(2, mZenModeEventLogger.getNumRulesActive(1)); + assertFalse(mZenModeEventLogger.getIsUserAction(1)); + assertEquals(CUSTOM_PKG_UID, mZenModeEventLogger.getPackageUid(1)); + checkDndProtoMatchesSetupZenConfig(mZenModeEventLogger.getPolicyProto(1)); + + // Event 3: rule 3 turns on. This should trigger a policy change, and be classified as such, + // but meanwhile also change the number of active rules. + // Rule 3 is also set up to be a "system"-owned rule, so the caller UID should remain system + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_POLICY_CHANGED.getId(), + mZenModeEventLogger.getEventId(2)); + assertEquals(3, mZenModeEventLogger.getNumRulesActive(2)); + assertFalse(mZenModeEventLogger.getIsUserAction(2)); + assertEquals(Process.SYSTEM_UID, mZenModeEventLogger.getPackageUid(2)); + DNDPolicyProto dndProto = mZenModeEventLogger.getPolicyProto(2); + assertEquals(STATE_DISALLOW, dndProto.getReminders().getNumber()); + assertEquals(STATE_DISALLOW, dndProto.getCalls().getNumber()); + assertEquals(STATE_DISALLOW, dndProto.getMessages().getNumber()); + + // Event 4: rule 2 turns off. Because rule 3 is still on and stricter than rule 1 (also + // still on), there should be no policy change as a result of rule 2 going away. Therefore + // this event should again only be an active rule change. + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_ACTIVE_RULES_CHANGED.getId(), + mZenModeEventLogger.getEventId(3)); + assertEquals(2, mZenModeEventLogger.getNumRulesActive(3)); + assertFalse(mZenModeEventLogger.getIsUserAction(3)); + } + + @Test + public void testZenModeEventLog_noLogWithNoConfigChange() throws IllegalArgumentException { + // If evaluateZenMode is called independently of a config change, don't log. + mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true); + setupZenConfig(); + + // Artificially turn zen mode "on". Re-evaluating zen mode should cause it to turn back off + // given that we don't have any zen rules active. + mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelper.evaluateZenMode("test", true); + + // Check that the change actually took: zen mode should be off now assertEquals(Global.ZEN_MODE_OFF, mZenModeHelper.mZenMode); + + // but still, nothing should've been logged + assertEquals(0, mZenModeEventLogger.numLoggedChanges()); + } + + @Test + public void testZenModeEventLog_reassignUid() throws IllegalArgumentException { + // Test that, only in specific cases, we reassign the calling UID to one associated with + // the automatic rule owner. + mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true); + setupZenConfig(); + + // Rule 1, owned by a package + AutomaticZenRule zenRule = new AutomaticZenRule("name", + null, + new ComponentName(CUSTOM_PKG_NAME, "ScheduleConditionProvider"), + ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), + null, + NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + String id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule, "test", + Process.SYSTEM_UID, true); + + // Rule 2, same as rule 1 but owned by the system + AutomaticZenRule zenRule2 = new AutomaticZenRule("name2", + null, + new ComponentName("android", "ScheduleConditionProvider"), + ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), + null, + NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + String id2 = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule2, "test", + Process.SYSTEM_UID, true); + + // Turn on rule 1; call looks like it's from the system. Because setting a condition is + // typically an automatic (non-user-initiated) action, expect the calling UID to be + // re-evaluated to the one associat.d with CUSTOM_PKG_NAME. + mZenModeHelper.setAutomaticZenRuleState(id, + new Condition(zenRule.getConditionId(), "", STATE_TRUE), + Process.SYSTEM_UID, true); + + // Second: turn on rule 2. This is a system-owned rule and the UID should not be modified + // (nor even looked up; the mock PackageManager won't handle "android" as input). + mZenModeHelper.setAutomaticZenRuleState(id2, + new Condition(zenRule2.getConditionId(), "", STATE_TRUE), + Process.SYSTEM_UID, true); + + // Disable rule 1. Because this looks like a user action, the UID should not be modified + // from the system-provided one. + zenRule.setEnabled(false); + mZenModeHelper.updateAutomaticZenRule(id, zenRule, "", Process.SYSTEM_UID, true); + + // Add a manual rule. Any manual rule changes should not get calling uids reassigned. + mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, null, "", + CUSTOM_PKG_UID, false); + + // Change rule 2's condition, but from some other UID. Since it doesn't look like it's from + // the system, we keep the UID info. + mZenModeHelper.setAutomaticZenRuleState(id2, + new Condition(zenRule2.getConditionId(), "", STATE_FALSE), + 12345, false); + + // That was 5 events total + assertEquals(5, mZenModeEventLogger.numLoggedChanges()); + + // The first event (activating rule 1) should be of type "zen mode turns on", automatic, + // have a package UID of CUSTOM_PKG_UID + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_TURNED_ON.getId(), + mZenModeEventLogger.getEventId(0)); + assertEquals(DNDProtoEnums.AUTOMATIC_RULE, mZenModeEventLogger.getChangedRuleType(0)); + assertFalse(mZenModeEventLogger.getIsUserAction(0)); + assertEquals(CUSTOM_PKG_UID, mZenModeEventLogger.getPackageUid(0)); + + // The second event (activating rule 2) should have similar other properties but the UID + // should be system. + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_ACTIVE_RULES_CHANGED.getId(), + mZenModeEventLogger.getEventId(1)); + assertEquals(DNDProtoEnums.AUTOMATIC_RULE, mZenModeEventLogger.getChangedRuleType(1)); + assertFalse(mZenModeEventLogger.getIsUserAction(1)); + assertEquals(Process.SYSTEM_UID, mZenModeEventLogger.getPackageUid(1)); + + // Third event: disable rule 1. This looks like a user action so UID should be left alone. + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_ACTIVE_RULES_CHANGED.getId(), + mZenModeEventLogger.getEventId(2)); + assertEquals(DNDProtoEnums.AUTOMATIC_RULE, mZenModeEventLogger.getChangedRuleType(2)); + assertTrue(mZenModeEventLogger.getIsUserAction(2)); + assertEquals(Process.SYSTEM_UID, mZenModeEventLogger.getPackageUid(2)); + + // Fourth event: turns on manual mode. Doesn't change effective policy so this is just a + // change in active rules. Confirm that the package UID is left unchanged. + // Because it's a manual mode change not from the system, isn't considered a user action. + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_ACTIVE_RULES_CHANGED.getId(), + mZenModeEventLogger.getEventId(3)); + assertEquals(DNDProtoEnums.MANUAL_RULE, mZenModeEventLogger.getChangedRuleType(3)); + assertFalse(mZenModeEventLogger.getIsUserAction(3)); + assertEquals(CUSTOM_PKG_UID, mZenModeEventLogger.getPackageUid(3)); + + // Fourth event: changed condition on rule 2 (turning it off via condition). + // This comes from a random different UID so we expect that to remain untouched. + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_ACTIVE_RULES_CHANGED.getId(), + mZenModeEventLogger.getEventId(4)); + assertEquals(DNDProtoEnums.AUTOMATIC_RULE, mZenModeEventLogger.getChangedRuleType(4)); + assertFalse(mZenModeEventLogger.getIsUserAction(4)); + assertEquals(12345, mZenModeEventLogger.getPackageUid(4)); + } + + @Test + public void testZenModeEventLog_channelsBypassingChanges() { + // Verify that the right thing happens when the canBypassDnd value changes. + mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true); + setupZenConfig(); + + // Turn on zen mode with a manual rule with an enabler set. This should *not* count + // as a user action, and *should* get its UID reassigned. + mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, + CUSTOM_PKG_NAME, "", Process.SYSTEM_UID, true); + + // Now change apps bypassing to true + ZenModeConfig newConfig = mZenModeHelper.mConfig.copy(); + newConfig.areChannelsBypassingDnd = true; + mZenModeHelper.setNotificationPolicy(newConfig.toNotificationPolicy(), Process.SYSTEM_UID, + true); + + // and then back to false, all without changing anything else + newConfig.areChannelsBypassingDnd = false; + mZenModeHelper.setNotificationPolicy(newConfig.toNotificationPolicy(), Process.SYSTEM_UID, + true); + + // Turn off manual mode, call from a package: don't reset UID even though enabler is set + mZenModeHelper.setManualZenMode(Global.ZEN_MODE_OFF, null, + CUSTOM_PKG_NAME, "", 12345, false); + + // And likewise when turning it back on again + mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, + CUSTOM_PKG_NAME, "", 12345, false); + + // These are 5 events in total. + assertEquals(5, mZenModeEventLogger.numLoggedChanges()); + + // First event: turns on, UID reassigned for manual mode + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_TURNED_ON.getId(), + mZenModeEventLogger.getEventId(0)); + assertFalse(mZenModeEventLogger.getIsUserAction(0)); + assertEquals(CUSTOM_PKG_UID, mZenModeEventLogger.getPackageUid(0)); + + // Second event should be a policy-only change with are channels bypassing = true + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_POLICY_CHANGED.getId(), + mZenModeEventLogger.getEventId(1)); + assertTrue(mZenModeEventLogger.getAreChannelsBypassing(1)); + + // Third event also a policy-only change but with channels bypassing now false + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_POLICY_CHANGED.getId(), + mZenModeEventLogger.getEventId(2)); + assertFalse(mZenModeEventLogger.getAreChannelsBypassing(2)); + + // Fourth event: should turn DND off, not have UID reassigned + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_TURNED_OFF.getId(), + mZenModeEventLogger.getEventId(3)); + assertFalse(mZenModeEventLogger.getIsUserAction(3)); + assertEquals(12345, mZenModeEventLogger.getPackageUid(3)); + + // Fifth event: turn DND back on, not have UID reassigned + assertEquals(ZenModeEventLogger.ZenStateChangedEvent.DND_TURNED_ON.getId(), + mZenModeEventLogger.getEventId(4)); + assertFalse(mZenModeEventLogger.getIsUserAction(4)); + assertEquals(12345, mZenModeEventLogger.getPackageUid(4)); } private void setupZenConfig() { @@ -1921,7 +2446,9 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelper.mConfig.allowSystem = false; mZenModeHelper.mConfig.allowReminders = true; mZenModeHelper.mConfig.allowCalls = true; + mZenModeHelper.mConfig.allowCallsFrom = PRIORITY_SENDERS_STARRED; mZenModeHelper.mConfig.allowMessages = true; + mZenModeHelper.mConfig.allowConversations = true; mZenModeHelper.mConfig.allowEvents = true; mZenModeHelper.mConfig.allowRepeatCallers = true; mZenModeHelper.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE; @@ -1935,12 +2462,33 @@ public class ZenModeHelperTest extends UiServiceTestCase { assertFalse(mZenModeHelper.mConfig.allowSystem); assertTrue(mZenModeHelper.mConfig.allowReminders); assertTrue(mZenModeHelper.mConfig.allowCalls); + assertEquals(PRIORITY_SENDERS_STARRED, mZenModeHelper.mConfig.allowCallsFrom); assertTrue(mZenModeHelper.mConfig.allowMessages); + assertTrue(mZenModeHelper.mConfig.allowConversations); assertTrue(mZenModeHelper.mConfig.allowEvents); assertTrue(mZenModeHelper.mConfig.allowRepeatCallers); assertEquals(SUPPRESSED_EFFECT_BADGE, mZenModeHelper.mConfig.suppressedVisualEffects); } + private void checkDndProtoMatchesSetupZenConfig(DNDPolicyProto dndProto) { + assertEquals(STATE_DISALLOW, dndProto.getAlarms().getNumber()); + assertEquals(STATE_DISALLOW, dndProto.getMedia().getNumber()); + assertEquals(STATE_DISALLOW, dndProto.getSystem().getNumber()); + assertEquals(STATE_ALLOW, dndProto.getReminders().getNumber()); + assertEquals(STATE_ALLOW, dndProto.getCalls().getNumber()); + assertEquals(PEOPLE_STARRED, dndProto.getAllowCallsFrom().getNumber()); + assertEquals(STATE_ALLOW, dndProto.getMessages().getNumber()); + assertEquals(STATE_ALLOW, dndProto.getEvents().getNumber()); + assertEquals(STATE_ALLOW, dndProto.getRepeatCallers().getNumber()); + assertEquals(STATE_ALLOW, dndProto.getFullscreen().getNumber()); + assertEquals(STATE_ALLOW, dndProto.getLights().getNumber()); + assertEquals(STATE_ALLOW, dndProto.getPeek().getNumber()); + assertEquals(STATE_ALLOW, dndProto.getStatusBar().getNumber()); + assertEquals(STATE_DISALLOW, dndProto.getBadge().getNumber()); + assertEquals(STATE_ALLOW, dndProto.getAmbient().getNumber()); + assertEquals(STATE_ALLOW, dndProto.getNotificationList().getNumber()); + } + /** * Wrapper to use TypedXmlPullParser as XmlResourceParser for Resources.getXml() */ |