Merge "Update behavior of "global" DND APIs" into main
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index b0332c3..ffb79b3 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1642,6 +1642,7 @@
*
* <p>
*/
+ // TODO(b/309457271): Update documentation with VANILLA_ICE_CREAM behavior.
public Policy getNotificationPolicy() {
INotificationManager service = getService();
try {
@@ -1660,6 +1661,7 @@
*
* @param policy The new desired policy.
*/
+ // TODO(b/309457271): Update documentation with VANILLA_ICE_CREAM behavior.
public void setNotificationPolicy(@NonNull Policy policy) {
checkRequired("policy", policy);
INotificationManager service = getService();
@@ -2608,6 +2610,7 @@
* Only available if policy access is granted to this package. See
* {@link #isNotificationPolicyAccessGranted}.
*/
+ // TODO(b/309457271): Update documentation with VANILLA_ICE_CREAM behavior.
public final void setInterruptionFilter(@InterruptionFilter int interruptionFilter) {
final INotificationManager service = getService();
try {
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index ff4dfc7..305b751 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -1004,6 +1004,8 @@
priorityCategories |= Policy.PRIORITY_CATEGORY_CONVERSATIONS;
conversationSenders = getConversationSendersWithDefault(
zenPolicy.getPriorityConversationSenders(), conversationSenders);
+ } else {
+ conversationSenders = CONVERSATION_SENDERS_NONE;
}
if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_CALLS,
@@ -1102,7 +1104,7 @@
return (policy.suppressedVisualEffects & visualEffect) == 0;
}
- private int getNotificationPolicySenders(@ZenPolicy.PeopleType int senders,
+ private static int getNotificationPolicySenders(@ZenPolicy.PeopleType int senders,
int defaultPolicySender) {
switch (senders) {
case ZenPolicy.PEOPLE_TYPE_ANYONE:
@@ -1116,7 +1118,7 @@
}
}
- private int getConversationSendersWithDefault(@ZenPolicy.ConversationSenders int senders,
+ private static int getConversationSendersWithDefault(@ZenPolicy.ConversationSenders int senders,
int defaultPolicySender) {
switch (senders) {
case ZenPolicy.CONVERSATION_SENDERS_ANYONE:
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 15c188d..cec83de 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5245,6 +5245,11 @@
<!-- Zen mode - name of default automatic calendar time-based rule that is triggered every night (when sleeping). [CHAR LIMIT=40] -->
<string name="zen_mode_default_every_night_name">Sleeping</string>
+ <!-- Zen mode - Condition summary when a rule is activated due to a call to setInterruptionFilter(). [CHAR_LIMIT=NONE] -->
+ <string name="zen_mode_implicit_activated">On</string>
+ <!-- Zen mode - Condition summary when a rule is deactivated due to a call to setInterruptionFilter(). [CHAR_LIMIT=NONE] -->
+ <string name="zen_mode_implicit_deactivated">Off</string>
+
<!-- Indication that the current volume and other effects (vibration) are being suppressed by a third party, such as a notification listener. [CHAR LIMIT=30] -->
<string name="muted_by"><xliff:g id="third_party">%1$s</xliff:g> is muting some sounds</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e19d548..16ad5c9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2574,6 +2574,8 @@
<java-symbol type="string" name="zen_mode_default_weekends_name" />
<java-symbol type="string" name="zen_mode_default_events_name" />
<java-symbol type="string" name="zen_mode_default_every_night_name" />
+ <java-symbol type="string" name="zen_mode_implicit_activated" />
+ <java-symbol type="string" name="zen_mode_implicit_deactivated" />
<java-symbol type="string" name="display_rotation_camera_compat_toast_after_rotation" />
<java-symbol type="string" name="display_rotation_camera_compat_toast_in_multi_window" />
<java-symbol type="array" name="config_system_condition_providers" />
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 1bdd402..707e990 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -179,6 +179,8 @@
import android.app.role.RoleManager;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
+import android.companion.AssociationInfo;
+import android.companion.AssociationRequest;
import android.companion.ICompanionDeviceManager;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
@@ -546,6 +548,15 @@
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
static final long ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION = 264179692L;
+ /**
+ * App calls to {@link android.app.NotificationManager#setInterruptionFilter} and
+ * {@link android.app.NotificationManager#setNotificationPolicy} manage DND through the
+ * creation and activation of an implicit {@link android.app.AutomaticZenRule}.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ static final long MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES = 308670109L;
+
private static final Duration POST_WAKE_LOCK_TIMEOUT = Duration.ofSeconds(30);
private IActivityManager mAm;
@@ -5343,6 +5354,12 @@
if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
final int callingUid = Binder.getCallingUid();
final boolean isSystemOrSystemUi = isCallerIsSystemOrSystemUi();
+
+ if (android.app.Flags.modesApi() && !canManageGlobalZenPolicy(pkg, callingUid)) {
+ mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(pkg, callingUid, zen);
+ return;
+ }
+
final long identity = Binder.clearCallingIdentity();
try {
mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter",
@@ -5426,6 +5443,16 @@
}
}
+ private boolean canManageGlobalZenPolicy(String callingPkg, int callingUid) {
+ boolean isCompatChangeEnabled = Binder.withCleanCallingIdentity(
+ () -> CompatChanges.isChangeEnabled(MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES,
+ callingUid));
+ return !isCompatChangeEnabled
+ || isCallerIsSystemOrSystemUi()
+ || hasCompanionDevice(callingPkg, UserHandle.getUserId(callingUid),
+ AssociationRequest.DEVICE_PROFILE_WATCH);
+ }
+
private void enforcePolicyAccess(String pkg, String method) {
if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
@@ -5619,6 +5646,10 @@
@Override
public Policy getNotificationPolicy(String pkg) {
+ final int callingUid = Binder.getCallingUid();
+ if (android.app.Flags.modesApi() && !canManageGlobalZenPolicy(pkg, callingUid)) {
+ return mZenModeHelper.getNotificationPolicyFromImplicitZenRule(pkg);
+ }
final long identity = Binder.clearCallingIdentity();
try {
return mZenModeHelper.getNotificationPolicy();
@@ -5649,6 +5680,10 @@
enforcePolicyAccess(pkg, "setNotificationPolicy");
int callingUid = Binder.getCallingUid();
boolean isSystemOrSystemUi = isCallerIsSystemOrSystemUi();
+
+ boolean shouldApplyAsImplicitRule = android.app.Flags.modesApi()
+ && !canManageGlobalZenPolicy(pkg, callingUid);
+
final long identity = Binder.clearCallingIdentity();
try {
final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
@@ -5687,16 +5722,21 @@
policy = new Policy(policy.priorityCategories,
policy.priorityCallSenders, policy.priorityMessageSenders,
newVisualEffects, policy.priorityConversationSenders);
- ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion, policy);
- mZenModeHelper.setNotificationPolicy(policy, callingUid, isSystemOrSystemUi);
+
+ if (shouldApplyAsImplicitRule) {
+ mZenModeHelper.applyGlobalPolicyAsImplicitZenRule(pkg, callingUid, policy);
+ } else {
+ ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion,
+ policy);
+ mZenModeHelper.setNotificationPolicy(policy, callingUid, isSystemOrSystemUi);
+ }
} catch (RemoteException e) {
+ Slog.e(TAG, "Failed to set notification policy", e);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
-
-
@Override
public List<String> getEnabledNotificationListenerPackages() {
checkCallerIsSystem();
@@ -10556,6 +10596,12 @@
}
boolean hasCompanionDevice(ManagedServiceInfo info) {
+ return hasCompanionDevice(info.component.getPackageName(),
+ info.userid, /* withDeviceProfile= */ null);
+ }
+
+ private boolean hasCompanionDevice(String pkg, @UserIdInt int userId,
+ @Nullable @AssociationRequest.DeviceProfile String withDeviceProfile) {
if (mCompanionManager == null) {
mCompanionManager = getCompanionManager();
}
@@ -10565,17 +10611,19 @@
}
final long identity = Binder.clearCallingIdentity();
try {
- List<?> associations = mCompanionManager.getAssociations(
- info.component.getPackageName(), info.userid);
- if (!ArrayUtils.isEmpty(associations)) {
- return true;
+ List<AssociationInfo> associations = mCompanionManager.getAssociations(pkg, userId);
+ for (AssociationInfo association : associations) {
+ if (withDeviceProfile == null || withDeviceProfile.equals(
+ association.getDeviceProfile())) {
+ return true;
+ }
}
} catch (SecurityException se) {
// Not a privileged listener
} catch (RemoteException re) {
Slog.e(TAG, "Cannot reach companion device service", re);
} catch (Exception e) {
- Slog.e(TAG, "Cannot verify listener " + info, e);
+ Slog.e(TAG, "Cannot verify caller pkg=" + pkg + ", userId=" + userId, e);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/notification/ZenAdapters.java b/services/core/java/com/android/server/notification/ZenAdapters.java
new file mode 100644
index 0000000..2a65aff
--- /dev/null
+++ b/services/core/java/com/android/server/notification/ZenAdapters.java
@@ -0,0 +1,78 @@
+/*
+ * 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.app.NotificationManager.Policy;
+import android.service.notification.ZenModeConfig;
+import android.service.notification.ZenPolicy;
+
+/**
+ * Converters between different Zen representations.
+ */
+class ZenAdapters {
+
+ static ZenPolicy notificationPolicyToZenPolicy(Policy policy) {
+ ZenPolicy.Builder zenPolicyBuilder = new ZenPolicy.Builder()
+ .allowAlarms(policy.allowAlarms())
+ .allowCalls(
+ policy.allowCalls()
+ ? ZenModeConfig.getZenPolicySenders(policy.allowCallsFrom())
+ : ZenPolicy.PEOPLE_TYPE_NONE)
+ .allowConversations(
+ policy.allowConversations()
+ ? notificationPolicyConversationSendersToZenPolicy(
+ policy.allowConversationsFrom())
+ : ZenPolicy.CONVERSATION_SENDERS_NONE)
+ .allowEvents(policy.allowEvents())
+ .allowMedia(policy.allowMedia())
+ .allowMessages(
+ policy.allowMessages()
+ ? ZenModeConfig.getZenPolicySenders(policy.allowMessagesFrom())
+ : ZenPolicy.PEOPLE_TYPE_NONE)
+ .allowReminders(policy.allowReminders())
+ .allowRepeatCallers(policy.allowRepeatCallers())
+ .allowSystem(policy.allowSystem());
+
+ if (policy.suppressedVisualEffects != Policy.SUPPRESSED_EFFECTS_UNSET) {
+ zenPolicyBuilder.showBadges(policy.showBadges())
+ .showFullScreenIntent(policy.showFullScreenIntents())
+ .showInAmbientDisplay(policy.showAmbient())
+ .showInNotificationList(policy.showInNotificationList())
+ .showLights(policy.showLights())
+ .showPeeking(policy.showPeeking())
+ .showStatusBarIcons(policy.showStatusBarIcons());
+ }
+
+ return zenPolicyBuilder.build();
+ }
+
+ @ZenPolicy.ConversationSenders
+ private static int notificationPolicyConversationSendersToZenPolicy(
+ int npPriorityConversationSenders) {
+ switch (npPriorityConversationSenders) {
+ case Policy.CONVERSATION_SENDERS_ANYONE:
+ return ZenPolicy.CONVERSATION_SENDERS_ANYONE;
+ case Policy.CONVERSATION_SENDERS_IMPORTANT:
+ return ZenPolicy.CONVERSATION_SENDERS_IMPORTANT;
+ case Policy.CONVERSATION_SENDERS_NONE:
+ return ZenPolicy.CONVERSATION_SENDERS_NONE;
+ case Policy.CONVERSATION_SENDERS_UNSET:
+ default:
+ return ZenPolicy.CONVERSATION_SENDERS_UNSET;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 762c1a1..c637df2 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -27,6 +27,7 @@
import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
+import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
@@ -44,6 +45,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -349,11 +351,11 @@
ZenRule rule;
synchronized (mConfigLock) {
if (mConfig == null) return null;
- rule = mConfig.automaticRules.get(id);
+ rule = mConfig.automaticRules.get(id);
}
if (rule == null) return null;
if (canManageAutomaticZenRule(rule)) {
- return createAutomaticZenRule(rule);
+ return zenRuleToAutomaticZenRule(rule);
}
return null;
}
@@ -439,6 +441,167 @@
}
}
+ /**
+ * Create (or activate, or deactivate) an "implicit" {@link ZenRule} when an app that has
+ * Notification Policy Access but is not allowed to manage the global zen state
+ * calls {@link NotificationManager#setInterruptionFilter}.
+ *
+ * <p>When the {@code zenMode} is {@link Global#ZEN_MODE_OFF}, an existing implicit rule will be
+ * deactivated (if there is no implicit rule, the call will be ignored). For other modes, the
+ * rule's interruption filter will match the supplied {@code zenMode}. The policy of the last
+ * call to {@link NotificationManager#setNotificationPolicy} will be used (or, if never called,
+ * the global policy).
+ *
+ * <p>The created rule is owned by the calling package, but it has neither a
+ * {@link ConditionProviderService} nor an associated
+ * {@link AutomaticZenRule#configurationActivity}.
+ *
+ * @param zenMode one of the {@code Global#ZEN_MODE_x} values
+ */
+ void applyGlobalZenModeAsImplicitZenRule(String callingPkg, int callingUid, int zenMode) {
+ if (!android.app.Flags.modesApi()) {
+ Log.wtf(TAG, "applyGlobalZenModeAsImplicitZenRule called with flag off!");
+ return;
+ }
+ synchronized (mConfigLock) {
+ if (mConfig == null) {
+ return;
+ }
+ if (zenMode == Global.ZEN_MODE_OFF) {
+ // Deactivate implicit rule if it exists and is active; otherwise ignore.
+ ZenRule rule = mConfig.automaticRules.get(implicitRuleId(callingPkg));
+ if (rule != null) {
+ Condition deactivated = new Condition(rule.conditionId,
+ mContext.getString(R.string.zen_mode_implicit_deactivated),
+ Condition.STATE_FALSE);
+ setAutomaticZenRuleState(rule.id, deactivated,
+ callingUid, /* fromSystemOrSystemUi= */ false);
+ }
+ } else {
+ // Either create a new rule with a default ZenPolicy, or update an existing rule's
+ // filter value. In both cases, also activate (and unsnooze) it.
+ ZenModeConfig newConfig = mConfig.copy();
+ ZenRule rule = newConfig.automaticRules.get(implicitRuleId(callingPkg));
+ if (rule == null) {
+ rule = newImplicitZenRule(callingPkg);
+ newConfig.automaticRules.put(rule.id, rule);
+ }
+ rule.zenMode = zenMode;
+ rule.snoozing = false;
+ rule.condition = new Condition(rule.conditionId,
+ mContext.getString(R.string.zen_mode_implicit_activated),
+ Condition.STATE_TRUE);
+ setConfigLocked(newConfig, /* triggeringComponent= */ null,
+ "applyGlobalZenModeAsImplicitZenRule",
+ callingUid, /* fromSystemOrSystemUi= */ false);
+ }
+ }
+ }
+
+ /**
+ * Create (or update) an "implicit" {@link ZenRule} when an app that has Notification Policy
+ * Access but is not allowed to manage the global zen state calls
+ * {@link NotificationManager#setNotificationPolicy}.
+ *
+ * <p>The created rule is owned by the calling package and has the {@link ZenPolicy}
+ * corresponding to the supplied {@code policy}, but it has neither a
+ * {@link ConditionProviderService} nor an associated
+ * {@link AutomaticZenRule#configurationActivity}. Its zen mode will be set to
+ * {@link Global#ZEN_MODE_IMPORTANT_INTERRUPTIONS}.
+ */
+ void applyGlobalPolicyAsImplicitZenRule(String callingPkg, int callingUid,
+ NotificationManager.Policy policy) {
+ if (!android.app.Flags.modesApi()) {
+ Log.wtf(TAG, "applyGlobalPolicyAsImplicitZenRule called with flag off!");
+ return;
+ }
+ synchronized (mConfigLock) {
+ if (mConfig == null) {
+ return;
+ }
+ ZenModeConfig newConfig = mConfig.copy();
+ ZenRule rule = newConfig.automaticRules.get(implicitRuleId(callingPkg));
+ if (rule == null) {
+ rule = newImplicitZenRule(callingPkg);
+ rule.zenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ newConfig.automaticRules.put(rule.id, rule);
+ }
+ // TODO: b/308673679 - Keep user customization of this rule!
+ rule.zenPolicy = ZenAdapters.notificationPolicyToZenPolicy(policy);
+ setConfigLocked(newConfig, /* triggeringComponent= */ null,
+ "applyGlobalPolicyAsImplicitZenRule",
+ callingUid, /* fromSystemOrSystemUi= */ false);
+ }
+ }
+
+ /**
+ * Returns the {@link Policy} associated to the "implicit" {@link ZenRule} of a package that has
+ * Notification Policy Access but is not allowed to manage the global zen state.
+ *
+ * <p>If the implicit rule doesn't exist, or it doesn't specify a {@link ZenPolicy} (because the
+ * app never called {@link NotificationManager#setNotificationPolicy}) then the default policy
+ * is returned (i.e. same as {@link #getNotificationPolicy}.
+ *
+ * <p>Any unset values in the {@link ZenPolicy} will be mapped to their current defaults.
+ */
+ @Nullable
+ Policy getNotificationPolicyFromImplicitZenRule(String callingPkg) {
+ if (!android.app.Flags.modesApi()) {
+ Log.wtf(TAG, "getNotificationPolicyFromImplicitZenRule called with flag off!");
+ return getNotificationPolicy();
+ }
+ synchronized (mConfigLock) {
+ if (mConfig == null) {
+ return null;
+ }
+ ZenRule implicitRule = mConfig.automaticRules.get(implicitRuleId(callingPkg));
+ if (implicitRule != null && implicitRule.zenPolicy != null) {
+ return mConfig.toNotificationPolicy(implicitRule.zenPolicy);
+ } else {
+ return getNotificationPolicy();
+ }
+ }
+ }
+
+ /**
+ * Creates an empty {@link ZenRule} to be used as the implicit rule for {@code pkg}.
+ * Both {@link ZenRule#zenMode} and {@link ZenRule#zenPolicy} are unset.
+ */
+ private ZenRule newImplicitZenRule(String pkg) {
+ ZenRule rule = new ZenRule();
+ rule.id = implicitRuleId(pkg);
+ rule.pkg = pkg;
+ rule.creationTime = System.currentTimeMillis();
+
+ Binder.withCleanCallingIdentity(() -> {
+ try {
+ ApplicationInfo applicationInfo = mPm.getApplicationInfo(pkg, 0);
+ rule.name = applicationInfo.loadLabel(mPm).toString();
+ } catch (PackageManager.NameNotFoundException e) {
+ // Should not happen, since it's the app calling us (?)
+ Log.w(TAG, "Package not found for creating implicit zen rule");
+ rule.name = "Unknown";
+ }
+ });
+
+ rule.condition = null;
+ rule.conditionId = new Uri.Builder()
+ .scheme(Condition.SCHEME)
+ .authority("android")
+ .appendPath("implicit")
+ .appendPath(pkg)
+ .build();
+ rule.enabled = true;
+ rule.modified = false;
+ rule.component = null;
+ rule.configurationActivity = null;
+ return rule;
+ }
+
+ private static String implicitRuleId(String forPackage) {
+ return "implicit_" + forPackage;
+ }
+
public boolean removeAutomaticZenRule(String id, String reason, int callingUid,
boolean fromSystemOrSystemUi) {
ZenModeConfig newConfig;
@@ -626,7 +789,7 @@
}
// update default rule (if locale changed, name of rule will change)
currRule.name = defaultRule.name;
- updateAutomaticZenRule(defaultRule.id, createAutomaticZenRule(currRule),
+ updateAutomaticZenRule(defaultRule.id, zenRuleToAutomaticZenRule(currRule),
"locale changed", callingUid, fromSystemOrSystemUi);
}
}
@@ -669,7 +832,7 @@
return null;
}
- private void populateZenRule(String pkg, AutomaticZenRule automaticZenRule, ZenRule rule,
+ private static void populateZenRule(String pkg, AutomaticZenRule automaticZenRule, ZenRule rule,
boolean isNew) {
if (rule.enabled != automaticZenRule.isEnabled()) {
rule.snoozing = false;
@@ -699,7 +862,7 @@
}
}
- protected AutomaticZenRule createAutomaticZenRule(ZenRule rule) {
+ private static AutomaticZenRule zenRuleToAutomaticZenRule(ZenRule rule) {
AutomaticZenRule azr;
if (Flags.modesApi()) {
azr = new AutomaticZenRule.Builder(rule.name, rule.conditionId)
diff --git a/services/core/java/com/android/server/notification/flags.aconfig b/services/core/java/com/android/server/notification/flags.aconfig
index 25b7ca1..dcac8c9 100644
--- a/services/core/java/com/android/server/notification/flags.aconfig
+++ b/services/core/java/com/android/server/notification/flags.aconfig
@@ -7,8 +7,6 @@
bug: "290381858"
}
-
-
flag {
name: "polite_notifications"
namespace: "systemui"
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 6792cfe..3803244 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -43,6 +43,7 @@
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MAX;
import static android.app.NotificationManager.IMPORTANCE_NONE;
+import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS;
import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CONVERSATIONS;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
@@ -72,6 +73,7 @@
import static android.os.UserManager.USER_TYPE_PROFILE_CLONE;
import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE;
+import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
import static android.service.notification.Adjustment.KEY_IMPORTANCE;
import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
@@ -163,6 +165,7 @@
import android.app.admin.DevicePolicyManagerInternal;
import android.app.usage.UsageStatsManagerInternal;
import android.companion.AssociationInfo;
+import android.companion.AssociationRequest;
import android.companion.ICompanionDeviceManager;
import android.compat.testing.PlatformCompatChangeRule;
import android.content.BroadcastReceiver;
@@ -3820,6 +3823,7 @@
when(mCompanionMgr.getAssociations(PKG, mUserId))
.thenReturn(singletonList(mock(AssociationInfo.class)));
mListener = mock(ManagedServices.ManagedServiceInfo.class);
+ mListener.component = new ComponentName(PKG, PKG);
when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
@@ -3870,6 +3874,7 @@
when(mCompanionMgr.getAssociations(PKG, mUserId))
.thenReturn(emptyList());
mListener = mock(ManagedServices.ManagedServiceInfo.class);
+ mListener.component = new ComponentName(PKG, PKG);
when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
try {
@@ -12777,6 +12782,145 @@
verify(mSnoozeHelper).clearData(anyInt());
}
+ @Test
+ @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
+ public void setNotificationPolicy_mappedToImplicitRule() throws RemoteException {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ mService.setCallerIsNormalPackage();
+ ZenModeHelper zenHelper = mock(ZenModeHelper.class);
+ mService.mZenModeHelper = zenHelper;
+ when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
+ .thenReturn(true);
+
+ NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0);
+ mBinderService.setNotificationPolicy("package", policy);
+
+ verify(zenHelper).applyGlobalPolicyAsImplicitZenRule(eq("package"), anyInt(), eq(policy));
+ }
+
+ @Test
+ @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
+ public void setNotificationPolicy_systemCaller_setsGlobalPolicy() throws RemoteException {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
+ mService.mZenModeHelper = zenModeHelper;
+ when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
+ .thenReturn(true);
+ mService.isSystemUid = true;
+
+ NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0);
+ mBinderService.setNotificationPolicy("package", policy);
+
+ verify(zenModeHelper).setNotificationPolicy(eq(policy), anyInt(), anyBoolean());
+ }
+
+ @Test
+ @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
+ public void setNotificationPolicy_watchCompanionApp_setsGlobalPolicy() throws RemoteException {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ mService.setCallerIsNormalPackage();
+ ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
+ mService.mZenModeHelper = zenModeHelper;
+ when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
+ .thenReturn(true);
+ when(mCompanionMgr.getAssociations(anyString(), anyInt()))
+ .thenReturn(ImmutableList.of(
+ new AssociationInfo.Builder(1, mUserId, "package")
+ .setDisplayName("My watch")
+ .setDeviceProfile(AssociationRequest.DEVICE_PROFILE_WATCH)
+ .build()));
+
+ NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0);
+ mBinderService.setNotificationPolicy("package", policy);
+
+ verify(zenModeHelper).setNotificationPolicy(eq(policy), anyInt(), anyBoolean());
+ }
+
+ @Test
+ @DisableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
+ public void setNotificationPolicy_withoutCompat_setsGlobalPolicy() throws RemoteException {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ mService.setCallerIsNormalPackage();
+ ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
+ mService.mZenModeHelper = zenModeHelper;
+ when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
+ .thenReturn(true);
+
+ NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0);
+ mBinderService.setNotificationPolicy("package", policy);
+
+ verify(zenModeHelper).setNotificationPolicy(eq(policy), anyInt(), anyBoolean());
+ }
+
+ @Test
+ @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
+ public void getNotificationPolicy_mappedFromImplicitRule() throws RemoteException {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ mService.setCallerIsNormalPackage();
+ ZenModeHelper zenHelper = mock(ZenModeHelper.class);
+ mService.mZenModeHelper = zenHelper;
+ when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
+ .thenReturn(true);
+
+ mBinderService.getNotificationPolicy("package");
+
+ verify(zenHelper).getNotificationPolicyFromImplicitZenRule(eq("package"));
+ }
+
+ @Test
+ @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
+ public void setInterruptionFilter_mappedToImplicitRule() throws RemoteException {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ mService.setCallerIsNormalPackage();
+ ZenModeHelper zenHelper = mock(ZenModeHelper.class);
+ mService.mZenModeHelper = zenHelper;
+ when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
+ .thenReturn(true);
+
+ mBinderService.setInterruptionFilter("package", INTERRUPTION_FILTER_PRIORITY);
+
+ verify(zenHelper).applyGlobalZenModeAsImplicitZenRule(eq("package"), anyInt(),
+ eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS));
+ }
+
+ @Test
+ @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
+ public void setInterruptionFilter_systemCaller_setsGlobalPolicy() throws RemoteException {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ mService.setCallerIsNormalPackage();
+ ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
+ mService.mZenModeHelper = zenModeHelper;
+ when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
+ .thenReturn(true);
+ mService.isSystemUid = true;
+
+ mBinderService.setInterruptionFilter("package", INTERRUPTION_FILTER_PRIORITY);
+
+ verify(zenModeHelper).setManualZenMode(eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS), eq(null),
+ eq("package"), anyString(), anyInt(), anyBoolean());
+ }
+
+ @Test
+ @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
+ public void setInterruptionFilter_watchCompanionApp_setsGlobalPolicy() throws RemoteException {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ ZenModeHelper zenModeHelper = mock(ZenModeHelper.class);
+ mService.mZenModeHelper = zenModeHelper;
+ when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
+ .thenReturn(true);
+ when(mCompanionMgr.getAssociations(anyString(), anyInt()))
+ .thenReturn(ImmutableList.of(
+ new AssociationInfo.Builder(1, mUserId, "package")
+ .setDisplayName("My watch")
+ .setDeviceProfile(AssociationRequest.DEVICE_PROFILE_WATCH)
+ .build()));
+
+ mBinderService.setInterruptionFilter("package", INTERRUPTION_FILTER_PRIORITY);
+
+ verify(zenModeHelper).setManualZenMode(eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS), eq(null),
+ eq("package"), anyString(), anyInt(), anyBoolean());
+ }
+
private NotificationRecord createAndPostNotification(Notification.Builder nb, String testName)
throws RemoteException {
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, testName, mUid, 0,
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java b/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java
index 27e8f36..8f30f41 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java
@@ -54,6 +54,15 @@
return mRankingHelper;
}
+ /**
+ * Sets {@link #isSystemUid} and {@link #isSystemAppId} to {@code false}, so that calls to NMS
+ * methods don't succeed {@link #isCallingUidSystem()} and similar checks.
+ */
+ void setCallerIsNormalPackage() {
+ isSystemUid = false;
+ isSystemAppId = false;
+ }
+
@Override
protected boolean isCallingUidSystem() {
countSystemChecks++;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenAdaptersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenAdaptersTest.java
new file mode 100644
index 0000000..6cc1c43
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenAdaptersTest.java
@@ -0,0 +1,130 @@
+/*
+ * 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 com.android.server.notification.ZenAdapters.notificationPolicyToZenPolicy;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.NotificationManager.Policy;
+import android.service.notification.ZenPolicy;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.UiServiceTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ZenAdaptersTest extends UiServiceTestCase {
+
+ @Test
+ public void notificationPolicyToZenPolicy_allCallers() {
+ Policy policy = new Policy(Policy.PRIORITY_CATEGORY_CALLS, Policy.PRIORITY_SENDERS_ANY, 0);
+
+ ZenPolicy zenPolicy = notificationPolicyToZenPolicy(policy);
+
+ assertThat(zenPolicy.getPriorityCategoryCalls()).isEqualTo(ZenPolicy.STATE_ALLOW);
+ assertThat(zenPolicy.getPriorityCallSenders()).isEqualTo(ZenPolicy.PEOPLE_TYPE_ANYONE);
+ }
+
+ @Test
+ public void notificationPolicyToZenPolicy_starredCallers() {
+ Policy policy = new Policy(Policy.PRIORITY_CATEGORY_CALLS, Policy.PRIORITY_SENDERS_STARRED,
+ 0);
+
+ ZenPolicy zenPolicy = notificationPolicyToZenPolicy(policy);
+
+ assertThat(zenPolicy.getPriorityCategoryCalls()).isEqualTo(ZenPolicy.STATE_ALLOW);
+ assertThat(zenPolicy.getPriorityCallSenders()).isEqualTo(ZenPolicy.PEOPLE_TYPE_STARRED);
+ }
+
+ @Test
+ public void notificationPolicyToZenPolicy_repeatCallers() {
+ Policy policy = new Policy(Policy.PRIORITY_CATEGORY_REPEAT_CALLERS, 0, 0);
+
+ ZenPolicy zenPolicy = notificationPolicyToZenPolicy(policy);
+
+ assertThat(zenPolicy.getPriorityCategoryCalls()).isEqualTo(ZenPolicy.STATE_DISALLOW);
+ assertThat(zenPolicy.getPriorityCategoryRepeatCallers()).isEqualTo(ZenPolicy.STATE_ALLOW);
+ assertThat(zenPolicy.getPriorityCallSenders()).isEqualTo(ZenPolicy.PEOPLE_TYPE_NONE);
+ }
+
+ @Test
+ public void notificationPolicyToZenPolicy_noCallers() {
+ Policy policy = new Policy(0, 0, 0);
+
+ ZenPolicy zenPolicy = notificationPolicyToZenPolicy(policy);
+
+ assertThat(zenPolicy.getPriorityCategoryCalls()).isEqualTo(ZenPolicy.STATE_DISALLOW);
+ assertThat(zenPolicy.getPriorityCallSenders()).isEqualTo(ZenPolicy.PEOPLE_TYPE_NONE);
+ }
+
+ @Test
+ public void notificationPolicyToZenPolicy_conversationsAllowedSendersUnset() {
+ Policy policy = new Policy(Policy.PRIORITY_CATEGORY_CONVERSATIONS, 0, 0);
+
+ ZenPolicy zenPolicy = notificationPolicyToZenPolicy(policy);
+
+ assertThat(zenPolicy.getPriorityCategoryConversations()).isEqualTo(ZenPolicy.STATE_UNSET);
+ }
+
+ @Test
+ public void notificationPolicyToZenPolicy_conversationsNotAllowedSendersUnset() {
+ Policy policy = new Policy(0, 0, 0);
+
+ ZenPolicy zenPolicy = notificationPolicyToZenPolicy(policy);
+
+ assertThat(zenPolicy.getPriorityCategoryConversations()).isEqualTo(
+ ZenPolicy.STATE_DISALLOW);
+ }
+
+ @Test
+ public void notificationPolicyToZenPolicy_setEffects() {
+ Policy policy = new Policy(0, 0, 0,
+ Policy.SUPPRESSED_EFFECT_BADGE | Policy.SUPPRESSED_EFFECT_LIGHTS);
+
+ ZenPolicy zenPolicy = notificationPolicyToZenPolicy(policy);
+
+ assertThat(zenPolicy.getVisualEffectBadge()).isEqualTo(ZenPolicy.STATE_DISALLOW);
+ assertThat(zenPolicy.getVisualEffectLights()).isEqualTo(ZenPolicy.STATE_DISALLOW);
+
+ assertThat(zenPolicy.getVisualEffectAmbient()).isEqualTo(ZenPolicy.STATE_ALLOW);
+ assertThat(zenPolicy.getVisualEffectFullScreenIntent()).isEqualTo(ZenPolicy.STATE_ALLOW);
+ assertThat(zenPolicy.getVisualEffectNotificationList()).isEqualTo(ZenPolicy.STATE_ALLOW);
+ assertThat(zenPolicy.getVisualEffectPeek()).isEqualTo(ZenPolicy.STATE_ALLOW);
+ assertThat(zenPolicy.getVisualEffectStatusBar()).isEqualTo(ZenPolicy.STATE_ALLOW);
+ }
+
+ @Test
+ public void notificationPolicyToZenPolicy_unsetEffects() {
+ Policy policy = new Policy(0, 0, 0);
+
+ ZenPolicy zenPolicy = notificationPolicyToZenPolicy(policy);
+
+ assertThat(zenPolicy.getVisualEffectAmbient()).isEqualTo(ZenPolicy.STATE_UNSET);
+ assertThat(zenPolicy.getVisualEffectBadge()).isEqualTo(ZenPolicy.STATE_UNSET);
+ assertThat(zenPolicy.getVisualEffectFullScreenIntent()).isEqualTo(ZenPolicy.STATE_UNSET);
+ assertThat(zenPolicy.getVisualEffectLights()).isEqualTo(ZenPolicy.STATE_UNSET);
+ assertThat(zenPolicy.getVisualEffectNotificationList()).isEqualTo(ZenPolicy.STATE_UNSET);
+ assertThat(zenPolicy.getVisualEffectPeek()).isEqualTo(ZenPolicy.STATE_UNSET);
+ assertThat(zenPolicy.getVisualEffectStatusBar()).isEqualTo(ZenPolicy.STATE_UNSET);
+ }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index e8201fd..37aeb57 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -22,6 +22,7 @@
import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_DISABLED;
import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ENABLED;
import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_ANYONE;
+import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT;
import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS;
import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS;
import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CONVERSATIONS;
@@ -32,6 +33,7 @@
import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REPEAT_CALLERS;
import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM;
import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_ANY;
+import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_CONTACTS;
import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_STARRED;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
@@ -40,8 +42,11 @@
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static android.provider.Settings.Global.ZEN_MODE_ALARMS;
import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+import static android.provider.Settings.Global.ZEN_MODE_OFF;
import static android.service.notification.Condition.STATE_FALSE;
import static android.service.notification.Condition.STATE_TRUE;
+import static android.service.notification.ZenPolicy.PEOPLE_TYPE_CONTACTS;
+import static android.service.notification.ZenPolicy.PEOPLE_TYPE_STARRED;
import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.LOG_DND_STATE_EVENTS;
import static com.android.os.dnd.DNDProtoEnums.PEOPLE_STARRED;
@@ -50,6 +55,8 @@
import static com.android.os.dnd.DNDProtoEnums.STATE_DISALLOW;
import static com.android.server.notification.ZenModeHelper.RULE_LIMIT_PER_PACKAGE;
+import static com.google.common.truth.Truth.assertThat;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
@@ -72,6 +79,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.AppGlobals;
import android.app.AppOpsManager;
@@ -82,6 +90,7 @@
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
@@ -92,6 +101,7 @@
import android.media.AudioSystem;
import android.media.VolumePolicy;
import android.net.Uri;
+import android.os.Parcel;
import android.os.Process;
import android.os.UserHandle;
import android.platform.test.flag.junit.SetFlagsRule;
@@ -100,6 +110,7 @@
import android.service.notification.Condition;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.ScheduleInfo;
+import android.service.notification.ZenModeConfig.ZenRule;
import android.service.notification.ZenModeDiff;
import android.service.notification.ZenPolicy;
import android.test.suitebuilder.annotation.SmallTest;
@@ -124,6 +135,7 @@
import com.android.server.notification.ManagedServices.UserProfiles;
import com.google.common.collect.ImmutableList;
+import com.google.common.truth.Correspondence;
import com.google.protobuf.InvalidProtocolBufferException;
import org.junit.Before;
@@ -157,27 +169,29 @@
private static final String EVENTS_DEFAULT_RULE_ID = "EVENTS_DEFAULT_RULE";
private static final String SCHEDULE_DEFAULT_RULE_ID = "EVERY_NIGHT_DEFAULT_RULE";
private static final String CUSTOM_PKG_NAME = "not.android";
+ private static final String CUSTOM_APP_LABEL = "This is not Android";
private static final int CUSTOM_PKG_UID = 1;
private static final String CUSTOM_RULE_ID = "custom_rule";
- private final String NAME = "name";
- private final ComponentName OWNER = new ComponentName("pkg", "cls");
- private final ComponentName CONFIG_ACTIVITY = new ComponentName("pkg", "act");
- private final ZenPolicy POLICY = new ZenPolicy.Builder().allowAlarms(true).build();
- private final Uri CONDITION_ID = new Uri.Builder().scheme("scheme")
+ private static final String NAME = "name";
+ private static final ComponentName OWNER = new ComponentName("pkg", "cls");
+ private static final ComponentName CONFIG_ACTIVITY = new ComponentName("pkg", "act");
+ private static final ZenPolicy POLICY = new ZenPolicy.Builder().allowAlarms(true).build();
+ private static final Uri CONDITION_ID = new Uri.Builder().scheme("scheme")
.authority("authority")
.appendPath("path")
.appendPath("test")
.build();
- private final Condition CONDITION = new Condition(CONDITION_ID, "", Condition.STATE_TRUE);
- private final String TRIGGER_DESC = "Every Night, 10pm to 6am";
- private final int TYPE = TYPE_BEDTIME;
- private final boolean ALLOW_MANUAL = true;
- private final int ICON_RES_ID = 1234;
- private final int INTERRUPTION_FILTER = Settings.Global.ZEN_MODE_ALARMS;
- private final boolean ENABLED = true;
- private final int CREATION_TIME = 123;
+ private static final Condition CONDITION = new Condition(CONDITION_ID, "",
+ Condition.STATE_TRUE);
+ private static final String TRIGGER_DESC = "Every Night, 10pm to 6am";
+ private static final int TYPE = TYPE_BEDTIME;
+ private static final boolean ALLOW_MANUAL = true;
+ private static final int ICON_RES_ID = 1234;
+ private static final int INTERRUPTION_FILTER = Settings.Global.ZEN_MODE_ALARMS;
+ private static final boolean ENABLED = true;
+ private static final int CREATION_TIME = 123;
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@@ -227,6 +241,10 @@
.thenReturn(CUSTOM_PKG_UID);
when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(
new String[] {pkg});
+ ApplicationInfo mockAppInfo = mock(ApplicationInfo.class);
+ when(mockAppInfo.loadLabel(any())).thenReturn(CUSTOM_APP_LABEL);
+ when(mPackageManager.getApplicationInfo(eq(CUSTOM_PKG_NAME), anyInt()))
+ .thenReturn(mockAppInfo);
mZenModeHelper.mPm = mPackageManager;
mZenModeEventLogger.reset();
@@ -334,7 +352,7 @@
@Test
public void testZenOff_NoMuteApplied() {
- mZenModeHelper.mZenMode = Settings.Global.ZEN_MODE_OFF;
+ mZenModeHelper.mZenMode = ZEN_MODE_OFF;
mZenModeHelper.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
mZenModeHelper.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS
| PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0);
@@ -635,7 +653,7 @@
// 3. apply zen off - verify zen is set to previous ringer (normal)
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
- mZenModeHelper.mZenMode = Global.ZEN_MODE_OFF;
+ mZenModeHelper.mZenMode = ZEN_MODE_OFF;
mZenModeHelper.applyZenToRingerMode();
verify(mAudioManager, atLeastOnce()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL,
mZenModeHelper.TAG);
@@ -721,7 +739,7 @@
// 3. apply zen off - verify ringer remains normal
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
- mZenModeHelper.mZenMode = Global.ZEN_MODE_OFF;
+ mZenModeHelper.mZenMode = ZEN_MODE_OFF;
mZenModeHelper.applyZenToRingerMode();
verify(mAudioManager, atLeastOnce()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL,
mZenModeHelper.TAG);
@@ -746,7 +764,7 @@
// 3. apply zen-off - verify ringer is still silent
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
- mZenModeHelper.mZenMode = Global.ZEN_MODE_OFF;
+ mZenModeHelper.mZenMode = ZEN_MODE_OFF;
mZenModeHelper.applyZenToRingerMode();
verify(mAudioManager, atLeastOnce()).setRingerModeInternal(AudioManager.RINGER_MODE_SILENT,
mZenModeHelper.TAG);
@@ -781,7 +799,7 @@
// 4. apply zen off - verify ringer still silenced
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
- mZenModeHelper.mZenMode = Global.ZEN_MODE_OFF;
+ mZenModeHelper.mZenMode = ZEN_MODE_OFF;
mZenModeHelper.applyZenToRingerMode();
verify(mAudioManager, atLeastOnce()).setRingerModeInternal(AudioManager.RINGER_MODE_SILENT,
mZenModeHelper.TAG);
@@ -795,7 +813,7 @@
// apply zen off multiple times - verify ringer is not set to normal
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
- mZenModeHelper.mZenMode = Global.ZEN_MODE_OFF;
+ mZenModeHelper.mZenMode = ZEN_MODE_OFF;
mZenModeHelper.mConfig = null; // will evaluate config to zen mode off
for (int i = 0; i < 3; i++) {
// if zen doesn't change, zen should not reapply itself to the ringer
@@ -809,7 +827,7 @@
public void testSilentRingerSavedOnZenOff_startsZenOn() {
AudioManagerInternal mAudioManager = mock(AudioManagerInternal.class);
mZenModeHelper.mAudioManager = mAudioManager;
- mZenModeHelper.mZenMode = Global.ZEN_MODE_OFF;
+ mZenModeHelper.mZenMode = ZEN_MODE_OFF;
mZenModeHelper.mConfig = new ZenModeConfig();
// previously set silent ringer
@@ -836,7 +854,7 @@
public void testVibrateRingerSavedOnZenOff_startsZenOn() {
AudioManagerInternal mAudioManager = mock(AudioManagerInternal.class);
mZenModeHelper.mAudioManager = mAudioManager;
- mZenModeHelper.mZenMode = Global.ZEN_MODE_OFF;
+ mZenModeHelper.mZenMode = ZEN_MODE_OFF;
mZenModeHelper.mConfig = new ZenModeConfig();
// previously set silent ringer
@@ -1209,7 +1227,7 @@
.allowMedia(false)
.allowRepeatCallers(false)
.allowCalls(ZenPolicy.PEOPLE_TYPE_NONE)
- .allowMessages(ZenPolicy.PEOPLE_TYPE_CONTACTS)
+ .allowMessages(PEOPLE_TYPE_CONTACTS)
.allowEvents(true)
.allowReminders(false)
.build();
@@ -2023,10 +2041,10 @@
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(ZEN_MODE_OFF, null, null, "",
Process.SYSTEM_UID, true);
- assertEquals(Global.ZEN_MODE_OFF, mZenModeHelper.mZenMode);
+ assertEquals(ZEN_MODE_OFF, mZenModeHelper.mZenMode);
}
@Test
@@ -2041,7 +2059,7 @@
// 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,
+ mZenModeHelper.setManualZenMode(ZEN_MODE_OFF, null, null, "", CUSTOM_PKG_UID,
false);
// In total, this should be 2 loggable changes
@@ -2060,7 +2078,7 @@
// - 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_OFF, mZenModeEventLogger.getPrevZenMode(0));
assertEquals(ZEN_MODE_IMPORTANT_INTERRUPTIONS, mZenModeEventLogger.getNewZenMode(0));
assertEquals(DNDProtoEnums.MANUAL_RULE, mZenModeEventLogger.getChangedRuleType(0));
assertEquals(1, mZenModeEventLogger.getNumRulesActive(0));
@@ -2080,7 +2098,7 @@
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(ZEN_MODE_OFF, mZenModeEventLogger.getNewZenMode(1));
assertEquals(DNDProtoEnums.MANUAL_RULE, mZenModeEventLogger.getChangedRuleType(1));
assertEquals(0, mZenModeEventLogger.getNumRulesActive(1));
assertFalse(mZenModeEventLogger.getIsUserAction(1));
@@ -2144,7 +2162,7 @@
// - 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_OFF, mZenModeEventLogger.getPrevZenMode(0));
assertEquals(ZEN_MODE_IMPORTANT_INTERRUPTIONS, mZenModeEventLogger.getNewZenMode(0));
assertEquals(DNDProtoEnums.AUTOMATIC_RULE, mZenModeEventLogger.getChangedRuleType(0));
assertEquals(1, mZenModeEventLogger.getNumRulesActive(0));
@@ -2157,7 +2175,7 @@
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(ZEN_MODE_OFF, mZenModeEventLogger.getNewZenMode(1));
assertEquals(DNDProtoEnums.AUTOMATIC_RULE, mZenModeEventLogger.getChangedRuleType(1));
assertEquals(0, mZenModeEventLogger.getNumRulesActive(1));
assertTrue(mZenModeEventLogger.getIsUserAction(1));
@@ -2201,7 +2219,7 @@
// 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, "",
+ mZenModeHelper.setManualZenMode(ZEN_MODE_OFF, null, null, "",
Process.SYSTEM_UID, true);
// Change the policy again
@@ -2305,7 +2323,7 @@
// 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_OFF, mZenModeEventLogger.getPrevZenMode(0));
assertEquals(ZEN_MODE_IMPORTANT_INTERRUPTIONS, mZenModeEventLogger.getNewZenMode(0));
assertEquals(1, mZenModeEventLogger.getNumRulesActive(0));
assertFalse(mZenModeEventLogger.getIsUserAction(0));
@@ -2355,7 +2373,7 @@
mZenModeHelper.evaluateZenModeLocked("test", true);
// Check that the change actually took: zen mode should be off now
- assertEquals(Global.ZEN_MODE_OFF, mZenModeHelper.mZenMode);
+ assertEquals(ZEN_MODE_OFF, mZenModeHelper.mZenMode);
// but still, nothing should've been logged
assertEquals(0, mZenModeEventLogger.numLoggedChanges());
@@ -2483,7 +2501,7 @@
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,
+ mZenModeHelper.setManualZenMode(ZEN_MODE_OFF, null,
CUSTOM_PKG_NAME, "", 12345, false);
// And likewise when turning it back on again
@@ -2660,8 +2678,11 @@
}
@Test
- public void testCreateAutomaticZenRule_allFields() {
+ public void zenRuleToAutomaticZenRule_allFields() {
mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
+ when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(
+ new String[] {OWNER.getPackageName()});
+
ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
rule.configurationActivity = CONFIG_ACTIVITY;
rule.component = OWNER;
@@ -2682,7 +2703,8 @@
rule.iconResId = ICON_RES_ID;
rule.triggerDescription = TRIGGER_DESC;
- AutomaticZenRule actual = mZenModeHelper.createAutomaticZenRule(rule);
+ mZenModeHelper.mConfig.automaticRules.put(rule.id, rule);
+ AutomaticZenRule actual = mZenModeHelper.getAutomaticZenRule(rule.id);
assertEquals(NAME, actual.getName());
assertEquals(OWNER, actual.getOwner());
@@ -2915,8 +2937,253 @@
assertEquals(false, mZenModeHelper.mConfig.automaticRules.get(createdId).snoozing);
}
+ @Test
+ public void applyGlobalZenModeAsImplicitZenRule_createsImplicitRuleAndActivatesIt() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ mZenModeHelper.mConfig.automaticRules.clear();
+
+ mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(CUSTOM_PKG_NAME, CUSTOM_PKG_UID,
+ ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+
+ assertThat(mZenModeHelper.mConfig.automaticRules.values())
+ .comparingElementsUsing(IGNORE_TIMESTAMPS)
+ .containsExactly(
+ expectedImplicitRule(CUSTOM_PKG_NAME, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ null, true));
+ }
+
+ @Test
+ public void applyGlobalZenModeAsImplicitZenRule_updatesImplicitRuleAndActivatesIt() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ mZenModeHelper.mConfig.automaticRules.clear();
+
+ mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(CUSTOM_PKG_NAME, CUSTOM_PKG_UID,
+ ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+ mZenModeHelper.setManualZenMode(ZEN_MODE_OFF, null, "test", "test", 0, true);
+ assertThat(mZenModeHelper.mConfig.automaticRules).hasSize(1);
+
+ mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(CUSTOM_PKG_NAME, CUSTOM_PKG_UID,
+ ZEN_MODE_ALARMS);
+
+ assertThat(mZenModeHelper.mConfig.automaticRules.values())
+ .comparingElementsUsing(IGNORE_TIMESTAMPS)
+ .containsExactly(
+ expectedImplicitRule(CUSTOM_PKG_NAME, ZEN_MODE_ALARMS, null, true));
+ }
+
+ @Test
+ public void applyGlobalZenModeAsImplicitZenRule_modeOff_deactivatesImplicitRule() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ mZenModeHelper.mConfig.automaticRules.clear();
+ mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(CUSTOM_PKG_NAME, CUSTOM_PKG_UID,
+ ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+ assertThat(mZenModeHelper.mConfig.automaticRules).hasSize(1);
+ assertThat(mZenModeHelper.mConfig.automaticRules.valueAt(0).condition.state)
+ .isEqualTo(STATE_TRUE);
+
+ mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(CUSTOM_PKG_NAME, CUSTOM_PKG_UID,
+ ZEN_MODE_OFF);
+
+ assertThat(mZenModeHelper.mConfig.automaticRules.valueAt(0).condition.state)
+ .isEqualTo(STATE_FALSE);
+ }
+
+ @Test
+ public void applyGlobalZenModeAsImplicitZenRule_modeOffButNoPreviousRule_ignored() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ mZenModeHelper.mConfig.automaticRules.clear();
+
+ mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(CUSTOM_PKG_NAME, CUSTOM_PKG_UID,
+ ZEN_MODE_OFF);
+
+ assertThat(mZenModeHelper.mConfig.automaticRules).isEmpty();
+ }
+
+ @Test
+ public void applyGlobalZenModeAsImplicitZenRule_update_unsnoozesRule() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ mZenModeHelper.mConfig.automaticRules.clear();
+
+ mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(CUSTOM_PKG_NAME, CUSTOM_PKG_UID,
+ ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+ assertThat(mZenModeHelper.mConfig.automaticRules).hasSize(1);
+ assertThat(mZenModeHelper.mConfig.automaticRules.valueAt(0).snoozing).isFalse();
+
+ mZenModeHelper.setManualZenMode(ZEN_MODE_OFF, null, "test", "test", 0, true);
+ assertThat(mZenModeHelper.mConfig.automaticRules.valueAt(0).snoozing).isTrue();
+
+ mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(CUSTOM_PKG_NAME, CUSTOM_PKG_UID,
+ ZEN_MODE_ALARMS);
+
+ assertThat(mZenModeHelper.mConfig.automaticRules.valueAt(0).snoozing).isFalse();
+ assertThat(mZenModeHelper.mConfig.automaticRules.valueAt(0).condition.state)
+ .isEqualTo(STATE_TRUE);
+ }
+
+ @Test
+ public void applyGlobalZenModeAsImplicitZenRule_flagOff_ignored() {
+ mSetFlagsRule.disableFlags(android.app.Flags.FLAG_MODES_API);
+ mZenModeHelper.mConfig.automaticRules.clear();
+
+ withoutWtfCrash(
+ () -> mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(CUSTOM_PKG_NAME,
+ CUSTOM_PKG_UID,
+ ZEN_MODE_IMPORTANT_INTERRUPTIONS));
+
+ assertThat(mZenModeHelper.mConfig.automaticRules).isEmpty();
+ }
+
+ @Test
+ public void applyGlobalPolicyAsImplicitZenRule_createsImplicitRule() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ mZenModeHelper.mConfig.automaticRules.clear();
+
+ Policy policy = new Policy(PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS,
+ PRIORITY_SENDERS_CONTACTS, PRIORITY_SENDERS_STARRED,
+ Policy.getAllSuppressedVisualEffects(), CONVERSATION_SENDERS_IMPORTANT);
+ mZenModeHelper.applyGlobalPolicyAsImplicitZenRule(CUSTOM_PKG_NAME, CUSTOM_PKG_UID, policy);
+
+ ZenPolicy expectedZenPolicy = new ZenPolicy.Builder()
+ .disallowAllSounds()
+ .allowCalls(PEOPLE_TYPE_CONTACTS)
+ .allowConversations(CONVERSATION_SENDERS_IMPORTANT)
+ .hideAllVisualEffects()
+ .build();
+ assertThat(mZenModeHelper.mConfig.automaticRules.values())
+ .comparingElementsUsing(IGNORE_TIMESTAMPS)
+ .containsExactly(
+ expectedImplicitRule(CUSTOM_PKG_NAME, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ expectedZenPolicy, /* conditionActive= */ null));
+ }
+
+ @Test
+ public void applyGlobalPolicyAsImplicitZenRule_updatesImplicitRule() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ mZenModeHelper.mConfig.automaticRules.clear();
+
+ Policy original = new Policy(PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS,
+ PRIORITY_SENDERS_CONTACTS, PRIORITY_SENDERS_STARRED,
+ Policy.getAllSuppressedVisualEffects(), CONVERSATION_SENDERS_IMPORTANT);
+ mZenModeHelper.applyGlobalPolicyAsImplicitZenRule(CUSTOM_PKG_NAME, CUSTOM_PKG_UID,
+ original);
+
+ // Change priorityCallSenders: contacts -> starred.
+ Policy updated = new Policy(PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS,
+ PRIORITY_SENDERS_STARRED, PRIORITY_SENDERS_STARRED,
+ Policy.getAllSuppressedVisualEffects(), CONVERSATION_SENDERS_IMPORTANT);
+ mZenModeHelper.applyGlobalPolicyAsImplicitZenRule(CUSTOM_PKG_NAME, CUSTOM_PKG_UID, updated);
+
+ ZenPolicy expectedZenPolicy = new ZenPolicy.Builder()
+ .disallowAllSounds()
+ .allowCalls(PEOPLE_TYPE_STARRED)
+ .allowConversations(CONVERSATION_SENDERS_IMPORTANT)
+ .hideAllVisualEffects()
+ .build();
+ assertThat(mZenModeHelper.mConfig.automaticRules.values())
+ .comparingElementsUsing(IGNORE_TIMESTAMPS)
+ .containsExactly(
+ expectedImplicitRule(CUSTOM_PKG_NAME, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ expectedZenPolicy, /* conditionActive= */ null));
+ }
+
+ @Test
+ public void applyGlobalPolicyAsImplicitZenRule_flagOff_ignored() {
+ mSetFlagsRule.disableFlags(android.app.Flags.FLAG_MODES_API);
+ mZenModeHelper.mConfig.automaticRules.clear();
+
+ withoutWtfCrash(
+ () -> mZenModeHelper.applyGlobalPolicyAsImplicitZenRule(CUSTOM_PKG_NAME,
+ CUSTOM_PKG_UID, new Policy(0, 0, 0)));
+
+ assertThat(mZenModeHelper.mConfig.automaticRules).isEmpty();
+ }
+
+ @Test
+ public void getNotificationPolicyFromImplicitZenRule_returnsSetPolicy() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ Policy writtenPolicy = new Policy(PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS,
+ PRIORITY_SENDERS_CONTACTS, PRIORITY_SENDERS_STARRED,
+ Policy.getAllSuppressedVisualEffects(), STATE_FALSE,
+ CONVERSATION_SENDERS_IMPORTANT);
+ mZenModeHelper.applyGlobalPolicyAsImplicitZenRule(CUSTOM_PKG_NAME, CUSTOM_PKG_UID,
+ writtenPolicy);
+
+ Policy readPolicy = mZenModeHelper.getNotificationPolicyFromImplicitZenRule(
+ CUSTOM_PKG_NAME);
+
+ assertThat(readPolicy).isEqualTo(writtenPolicy);
+ }
+
+ @Test
+ public void getNotificationPolicyFromImplicitZenRule_ruleWithoutPolicy_returnsGlobalPolicy() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+
+ mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(CUSTOM_PKG_NAME, CUSTOM_PKG_UID,
+ ZEN_MODE_ALARMS);
+ mZenModeHelper.mConfig.allowCalls = true;
+ mZenModeHelper.mConfig.allowConversations = false;
+
+ Policy readPolicy = mZenModeHelper.getNotificationPolicyFromImplicitZenRule(
+ CUSTOM_PKG_NAME);
+
+ assertThat(readPolicy).isNotNull();
+ assertThat(readPolicy.allowCalls()).isTrue();
+ assertThat(readPolicy.allowConversations()).isFalse();
+ }
+
+ @Test
+ public void getNotificationPolicyFromImplicitZenRule_noImplicitRule_returnsGlobalPolicy() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+
+ mZenModeHelper.mConfig.allowCalls = true;
+ mZenModeHelper.mConfig.allowConversations = false;
+
+ Policy readPolicy = mZenModeHelper.getNotificationPolicyFromImplicitZenRule(
+ CUSTOM_PKG_NAME);
+
+ assertThat(readPolicy).isNotNull();
+ assertThat(readPolicy.allowCalls()).isTrue();
+ assertThat(readPolicy.allowConversations()).isFalse();
+ }
+
+ private static final Correspondence<ZenRule, ZenRule> IGNORE_TIMESTAMPS =
+ Correspondence.transforming(zr -> {
+ Parcel p = Parcel.obtain();
+ try {
+ zr.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ ZenRule copy = new ZenRule(p);
+ copy.creationTime = 0;
+ return copy;
+ } finally {
+ p.recycle();
+ }
+ },
+ "Ignoring timestamps");
+
+ private ZenRule expectedImplicitRule(String ownerPkg, int zenMode, ZenPolicy policy,
+ @Nullable Boolean conditionActive) {
+ ZenRule rule = new ZenModeConfig.ZenRule();
+ rule.id = "implicit_" + ownerPkg;
+ rule.conditionId = Uri.parse("condition://android/implicit/" + ownerPkg);
+ if (conditionActive != null) {
+ rule.condition = conditionActive
+ ? new Condition(rule.conditionId,
+ mContext.getString(R.string.zen_mode_implicit_activated), STATE_TRUE)
+ : new Condition(rule.conditionId,
+ mContext.getString(R.string.zen_mode_implicit_deactivated),
+ STATE_FALSE);
+ }
+ rule.zenMode = zenMode;
+ rule.zenPolicy = policy;
+ rule.pkg = ownerPkg;
+ rule.name = CUSTOM_APP_LABEL;
+ rule.enabled = true;
+ return rule;
+ }
+
private void setupZenConfig() {
- mZenModeHelper.mZenMode = Global.ZEN_MODE_OFF;
+ mZenModeHelper.mZenMode = ZEN_MODE_OFF;
mZenModeHelper.mConfig.allowAlarms = false;
mZenModeHelper.mConfig.allowMedia = false;
mZenModeHelper.mConfig.allowSystem = false;
@@ -2965,6 +3232,15 @@
assertEquals(STATE_ALLOW, dndProto.getNotificationList().getNumber());
}
+ private static void withoutWtfCrash(Runnable test) {
+ Log.TerribleFailureHandler oldHandler = Log.setWtfHandler((tag, what, system) -> {});
+ try {
+ test.run();
+ } finally {
+ Log.setWtfHandler(oldHandler);
+ }
+ }
+
/**
* Wrapper to use TypedXmlPullParser as XmlResourceParser for Resources.getXml()
*/