Merge "Add logging for zen mode events." into udc-dev am: 34bc8be6c5
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22605299 Change-Id: I89230c191827cf6a4bc21855bba6069333b3b1d7 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1652,7 +1652,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());
|
||||
}
|
||||
}
|
||||
@@ -2280,7 +2281,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() {
|
||||
@@ -2862,7 +2864,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);
|
||||
@@ -2910,7 +2913,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);
|
||||
}
|
||||
@@ -3875,7 +3878,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),
|
||||
@@ -4011,6 +4015,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");
|
||||
@@ -4020,7 +4025,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);
|
||||
@@ -4053,6 +4058,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);
|
||||
@@ -4066,7 +4072,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,
|
||||
@@ -4964,11 +4971,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 {
|
||||
@@ -5008,9 +5018,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);
|
||||
}
|
||||
@@ -5057,7 +5070,8 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
|
||||
return mZenModeHelper.addAutomaticZenRule(rulePkg, automaticZenRule,
|
||||
"addAutomaticZenRule");
|
||||
"addAutomaticZenRule", Binder.getCallingUid(),
|
||||
isCallerIsSystemOrSystemUi());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -5074,7 +5088,8 @@ public class NotificationManagerService extends SystemService {
|
||||
enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
|
||||
|
||||
return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
|
||||
"updateAutomaticZenRule");
|
||||
"updateAutomaticZenRule", Binder.getCallingUid(),
|
||||
isCallerIsSystemOrSystemUi());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -5083,7 +5098,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
|
||||
@@ -5092,7 +5108,8 @@ public class NotificationManagerService extends SystemService {
|
||||
enforceSystemOrSystemUI("removeAutomaticZenRules");
|
||||
|
||||
return mZenModeHelper.removeAutomaticZenRules(packageName,
|
||||
packageName + "|removeAutomaticZenRules");
|
||||
packageName + "|removeAutomaticZenRules", Binder.getCallingUid(),
|
||||
isCallerIsSystemOrSystemUi());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -5110,7 +5127,8 @@ public class NotificationManagerService extends SystemService {
|
||||
|
||||
enforcePolicyAccess(Binder.getCallingUid(), "setAutomaticZenRuleState");
|
||||
|
||||
mZenModeHelper.setAutomaticZenRuleState(id, condition);
|
||||
mZenModeHelper.setAutomaticZenRuleState(id, condition, Binder.getCallingUid(),
|
||||
isCallerIsSystemOrSystemUi());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -5118,9 +5136,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);
|
||||
}
|
||||
@@ -5421,6 +5442,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,
|
||||
@@ -5460,7 +5482,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);
|
||||
@@ -6698,7 +6720,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)) {
|
||||
@@ -6771,7 +6794,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,
|
||||
@@ -10000,7 +10024,8 @@ public class NotificationManagerService extends SystemService {
|
||||
return isUidSystemOrPhone(Binder.getCallingUid());
|
||||
}
|
||||
|
||||
private boolean isCallerIsSystemOrSystemUi() {
|
||||
@VisibleForTesting
|
||||
protected boolean isCallerIsSystemOrSystemUi() {
|
||||
if (isCallerSystemOrPhone()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -2194,6 +2194,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(
|
||||
@@ -2220,6 +2221,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;
|
||||
@@ -2243,6 +2245,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(
|
||||
@@ -2266,6 +2269,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;
|
||||
@@ -2292,6 +2296,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(
|
||||
@@ -2320,6 +2325,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;
|
||||
@@ -2345,6 +2351,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(
|
||||
@@ -2370,6 +2377,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;
|
||||
@@ -3209,7 +3217,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);
|
||||
@@ -3268,7 +3276,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),
|
||||
@@ -3367,7 +3375,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),
|
||||
@@ -3389,7 +3397,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),
|
||||
@@ -3415,7 +3423,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),
|
||||
@@ -4895,7 +4903,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
|
||||
@@ -6759,6 +6768,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);
|
||||
|
||||
@@ -6781,6 +6791,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);
|
||||
|
||||
@@ -6800,6 +6811,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);
|
||||
|
||||
@@ -6829,6 +6841,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);
|
||||
|
||||
@@ -6852,6 +6865,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);
|
||||
|
||||
@@ -6886,6 +6900,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 +6920,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);
|
||||
|
||||
@@ -6924,6 +6940,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);
|
||||
|
||||
@@ -6954,6 +6971,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);
|
||||
@@ -6976,6 +6994,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);
|
||||
@@ -6997,6 +7016,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);
|
||||
@@ -7018,6 +7038,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);
|
||||
@@ -7076,6 +7097,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);
|
||||
|
||||
@@ -7097,6 +7119,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);
|
||||
|
||||
@@ -7200,6 +7223,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);
|
||||
@@ -7220,6 +7244,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);
|
||||
|
||||
@@ -7242,6 +7267,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);
|
||||
|
||||
@@ -7286,6 +7312,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);
|
||||
|
||||
@@ -8177,7 +8204,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
|
||||
@@ -8198,7 +8226,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
|
||||
@@ -8218,7 +8247,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
|
||||
@@ -10037,8 +10067,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.
|
||||
@@ -10077,6 +10108,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.
|
||||
@@ -10095,6 +10127,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.
|
||||
@@ -11225,6 +11258,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(
|
||||
@@ -11249,6 +11283,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;
|
||||
@@ -11273,6 +11308,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(
|
||||
@@ -11299,6 +11335,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;
|
||||
@@ -11722,6 +11759,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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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,16 +1933,512 @@ 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() {
|
||||
mZenModeHelper.mZenMode = Global.ZEN_MODE_OFF;
|
||||
mZenModeHelper.mConfig.allowAlarms = false;
|
||||
@@ -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()
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user