Add a broadcast for automatic zen rule status
This allows apps to unregister potentially expensive device
monitoring systems when rules are disabled or removed, and provides
parity with ConditionProviderService.onUnsubscribe().
Test: cts
Fixes: 131812774
Change-Id: I2b359ca3262ccc6098bafa1611172b99f158c0c8
diff --git a/api/current.txt b/api/current.txt
index 25801ca..7c13dc1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5842,12 +5842,19 @@
method public boolean updateAutomaticZenRule(String, android.app.AutomaticZenRule);
field public static final String ACTION_APP_BLOCK_STATE_CHANGED = "android.app.action.APP_BLOCK_STATE_CHANGED";
field public static final String ACTION_AUTOMATIC_ZEN_RULE = "android.app.action.AUTOMATIC_ZEN_RULE";
+ field public static final String ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED = "android.app.action.AUTOMATIC_ZEN_RULE_STATUS_CHANGED";
field public static final String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
field public static final String ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED = "android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED";
field public static final String ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED = "android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED";
field public static final String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
field public static final String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
+ field public static final int AUTOMATIC_RULE_STATUS_DISABLED = 2; // 0x2
+ field public static final int AUTOMATIC_RULE_STATUS_ENABLED = 1; // 0x1
+ field public static final int AUTOMATIC_RULE_STATUS_REMOVED = 3; // 0x3
+ field public static final int AUTOMATIC_RULE_STATUS_UNKNOWN = -1; // 0xffffffff
field public static final String EXTRA_AUTOMATIC_RULE_ID = "android.app.extra.AUTOMATIC_RULE_ID";
+ field public static final String EXTRA_AUTOMATIC_ZEN_RULE_ID = "android.app.extra.AUTOMATIC_ZEN_RULE_ID";
+ field public static final String EXTRA_AUTOMATIC_ZEN_RULE_STATUS = "android.app.extra.AUTOMATIC_ZEN_RULE_STATUS";
field public static final String EXTRA_BLOCKED_STATE = "android.app.extra.BLOCKED_STATE";
field public static final String EXTRA_NOTIFICATION_CHANNEL_GROUP_ID = "android.app.extra.NOTIFICATION_CHANNEL_GROUP_ID";
field public static final String EXTRA_NOTIFICATION_CHANNEL_ID = "android.app.extra.NOTIFICATION_CHANNEL_ID";
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index c1cee77..316cab8 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -171,6 +171,78 @@
"android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED";
/**
+ * Intent that is broadcast when the status of an {@link AutomaticZenRule} has changed.
+ *
+ * <p>Use this to know whether you need to continue monitor to device state in order to
+ * provide up-to-date states (with {@link #setAutomaticZenRuleState(String, Condition)}) for
+ * this rule.</p>
+ *
+ * Input: nothing
+ * Output: {@link #EXTRA_AUTOMATIC_ZEN_RULE_ID}
+ * Output: {@link #EXTRA_AUTOMATIC_ZEN_RULE_STATUS}
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED =
+ "android.app.action.AUTOMATIC_ZEN_RULE_STATUS_CHANGED";
+
+ /**
+ * Integer extra for {@link #ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED} containing the state of
+ * the {@link AutomaticZenRule}.
+ *
+ * <p>
+ * The value will be one of {@link #AUTOMATIC_RULE_STATUS_ENABLED},
+ * {@link #AUTOMATIC_RULE_STATUS_DISABLED}, {@link #AUTOMATIC_RULE_STATUS_REMOVED},
+ * {@link #AUTOMATIC_RULE_STATUS_UNKNOWN}.
+ * </p>
+ */
+ public static final String EXTRA_AUTOMATIC_ZEN_RULE_STATUS =
+ "android.app.extra.AUTOMATIC_ZEN_RULE_STATUS";
+
+ /**
+ * String extra for {@link #ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED} containing the id of the
+ * {@link AutomaticZenRule} (see {@link #addAutomaticZenRule(AutomaticZenRule)}) that has
+ * changed.
+ */
+ public static final String EXTRA_AUTOMATIC_ZEN_RULE_ID =
+ "android.app.extra.AUTOMATIC_ZEN_RULE_ID";
+
+ /** @hide */
+ @IntDef(prefix = { "AUTOMATIC_RULE_STATUS" }, value = {
+ AUTOMATIC_RULE_STATUS_ENABLED, AUTOMATIC_RULE_STATUS_DISABLED,
+ AUTOMATIC_RULE_STATUS_REMOVED, AUTOMATIC_RULE_STATUS_UNKNOWN
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AutomaticZenRuleStatus {}
+
+ /**
+ * Constant value for {@link #EXTRA_AUTOMATIC_ZEN_RULE_STATUS} - the current status of the
+ * rule is unknown at your target sdk version, and you should continue to provide state changes
+ * via {@link #setAutomaticZenRuleState(String, Condition)}.
+ */
+ public static final int AUTOMATIC_RULE_STATUS_UNKNOWN = -1;
+
+ /**
+ * Constant value for {@link #EXTRA_AUTOMATIC_ZEN_RULE_STATUS} - the given rule currently
+ * exists and is enabled. You should continue to provide state changes via
+ * {@link #setAutomaticZenRuleState(String, Condition)}.
+ */
+ public static final int AUTOMATIC_RULE_STATUS_ENABLED = 1;
+
+ /**
+ * Constant value for {@link #EXTRA_AUTOMATIC_ZEN_RULE_STATUS} - the given rule currently
+ * exists but is disabled. You do not need to continue to provide state changes via
+ * {@link #setAutomaticZenRuleState(String, Condition)} until the rule is reenabled.
+ */
+ public static final int AUTOMATIC_RULE_STATUS_DISABLED = 2;
+
+ /**
+ * Constant value for {@link #EXTRA_AUTOMATIC_ZEN_RULE_STATUS} - the given rule has been
+ * deleted. Further calls to {@link #setAutomaticZenRuleState(String, Condition)} will be
+ * ignored.
+ */
+ public static final int AUTOMATIC_RULE_STATUS_REMOVED = 3;
+
+ /**
* Intent that is broadcast when the state of {@link #getEffectsSuppressor()} changes.
* This broadcast is only sent to registered receivers.
*
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 119d5ea..ebf5b93 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -536,6 +536,7 @@
<protected-broadcast android:name="android.app.action.INTERRUPTION_FILTER_CHANGED_INTERNAL" />
<protected-broadcast android:name="android.app.action.NOTIFICATION_POLICY_CHANGED" />
<protected-broadcast android:name="android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED" />
+ <protected-broadcast android:name="android.app.action.AUTOMATIC_ZEN_RULE_STATUS_CHANGED" />
<protected-broadcast android:name="android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED" />
<protected-broadcast android:name="android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED" />
<protected-broadcast android:name="android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED" />
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 976931c..07fd322 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -25,9 +25,12 @@
import static android.app.Notification.FLAG_ONGOING_EVENT;
import static android.app.Notification.FLAG_ONLY_ALERT_ONCE;
import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED;
+import static android.app.NotificationManager.ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED;
import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED;
import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED;
import static android.app.NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED;
+import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_ID;
+import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_STATUS;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.NotificationManager.IMPORTANCE_NONE;
@@ -1645,6 +1648,15 @@
sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
mRankingHandler.requestSort();
}
+
+ @Override
+ void onAutomaticRuleStatusChanged(int userId, String pkg, String id, int status) {
+ Intent intent = new Intent(ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED);
+ intent.setPackage(pkg);
+ intent.putExtra(EXTRA_AUTOMATIC_ZEN_RULE_ID, id);
+ intent.putExtra(EXTRA_AUTOMATIC_ZEN_RULE_STATUS, status);
+ getContext().sendBroadcastAsUser(intent, UserHandle.of(userId));
+ }
});
mPreferencesHelper = new PreferencesHelper(getContext(),
mPackageManagerClient,
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index f81015d..ee948b2 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -16,6 +16,10 @@
package com.android.server.notification;
+import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_DISABLED;
+import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ENABLED;
+import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_REMOVED;
+
import android.app.AppOpsManager;
import android.app.AutomaticZenRule;
import android.app.Notification;
@@ -351,6 +355,12 @@
"Cannot update rules not owned by your condition provider");
}
}
+ if (rule.enabled != automaticZenRule.isEnabled()) {
+ dispatchOnAutomaticRuleStatusChanged(mConfig.user, rule.pkg, ruleId,
+ automaticZenRule.isEnabled()
+ ? AUTOMATIC_RULE_STATUS_ENABLED : AUTOMATIC_RULE_STATUS_DISABLED);
+ }
+
populateZenRule(automaticZenRule, rule, false);
return setConfigLocked(newConfig, reason, rule.component, true);
}
@@ -370,6 +380,8 @@
throw new SecurityException(
"Cannot delete rules not owned by your condition provider");
}
+ dispatchOnAutomaticRuleStatusChanged(
+ mConfig.user, rule.pkg, id, AUTOMATIC_RULE_STATUS_REMOVED);
return setConfigLocked(newConfig, reason, null, true);
}
}
@@ -1120,6 +1132,13 @@
}
}
+ private void dispatchOnAutomaticRuleStatusChanged(int userId, String pkg, String id,
+ int status) {
+ for (Callback callback : mCallbacks) {
+ callback.onAutomaticRuleStatusChanged(userId, pkg, id, status);
+ }
+ }
+
private ZenModeConfig readDefaultConfig(Resources resources) {
XmlResourceParser parser = null;
try {
@@ -1509,5 +1528,6 @@
void onZenModeChanged() {}
void onPolicyChanged() {}
void onConsolidatedPolicyChanged() {}
+ void onAutomaticRuleStatusChanged(int userId, String pkg, String id, int status) {}
}
}