diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3087e1dc3bb2b..9edf6ad42b202 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -888,6 +888,15 @@ public final class Settings {
public static final String ACTION_ZEN_MODE_SCHEDULE_RULE_SETTINGS
= "android.settings.ZEN_MODE_SCHEDULE_RULE_SETTINGS";
+ /**
+ * Activity Action: Show Zen Mode external rule configuration settings.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_ZEN_MODE_EXTERNAL_RULE_SETTINGS
+ = "android.settings.ZEN_MODE_EXTERNAL_RULE_SETTINGS";
+
/**
* Activity Action: Show the regulatory information screen for the device.
*
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 56eb51066db29..1ed47791aa5f3 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -654,8 +654,7 @@ public class ZenModeConfig implements Parcelable {
}
String summary = "";
for (ZenRule automaticRule : config.automaticRules.values()) {
- if (automaticRule.enabled && !automaticRule.snoozing
- && automaticRule.isTrueOrUnknown()) {
+ if (automaticRule.isAutomaticActive()) {
if (summary.isEmpty()) {
summary = automaticRule.name;
} else {
@@ -745,9 +744,13 @@ public class ZenModeConfig implements Parcelable {
component);
}
+ public boolean isAutomaticActive() {
+ return enabled && !snoozing && component != null && isTrueOrUnknown();
+ }
+
public boolean isTrueOrUnknown() {
- return condition == null || condition.state == Condition.STATE_TRUE
- || condition.state == Condition.STATE_UNKNOWN;
+ return condition != null && (condition.state == Condition.STATE_TRUE
+ || condition.state == Condition.STATE_UNKNOWN);
}
public static final Parcelable.Creator CREATOR
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index 6be6389ae314f..24b5d0da36500 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -26,9 +26,10 @@ import android.os.Build;
*/
public class MetricsLogger implements MetricsConstants {
// These constants are temporary, they should migrate to MetricsConstants.
- // next value is 145;
+ // next value is 146;
public static final int NOTIFICATION_ZEN_MODE_SCHEDULE_RULE = 144;
+ public static final int NOTIFICATION_ZEN_MODE_EXTERNAL_RULE = 145;
public static void visible(Context context, int category) throws IllegalArgumentException {
if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index fc2eceda17feb..b36fcd2cc09c6 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -142,6 +142,9 @@ public class ConditionProviders extends ManagedServices {
} catch (RemoteException e) {
// we tried
}
+ if (mCallback != null) {
+ mCallback.onServiceAdded(info.component);
+ }
}
@Override
@@ -246,6 +249,16 @@ public class ConditionProviders extends ManagedServices {
}
}
+ public IConditionProvider findConditionProvider(ComponentName component) {
+ if (component == null) return null;
+ for (ManagedServiceInfo service : mServices) {
+ if (component.equals(service.component)) {
+ return provider(service);
+ }
+ }
+ return null;
+ }
+
public void ensureRecordExists(ComponentName component, Uri conditionId,
IConditionProvider provider) {
// constructed by convention, make sure the record exists...
@@ -378,6 +391,7 @@ public class ConditionProviders extends ManagedServices {
public interface Callback {
void onBootComplete();
+ void onServiceAdded(ComponentName component);
void onConditionChanged(Uri id, Condition condition);
void onUserSwitched();
}
diff --git a/services/core/java/com/android/server/notification/CountdownConditionProvider.java b/services/core/java/com/android/server/notification/CountdownConditionProvider.java
index d223353f95821..6a04688cf5ad1 100644
--- a/services/core/java/com/android/server/notification/CountdownConditionProvider.java
+++ b/services/core/java/com/android/server/notification/CountdownConditionProvider.java
@@ -38,7 +38,7 @@ import java.util.Date;
/** Built-in zen condition provider for simple time-based conditions */
public class CountdownConditionProvider extends SystemConditionProviderService {
- private static final String TAG = "CountdownConditions";
+ private static final String TAG = "ConditionProviders";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final ComponentName COMPONENT =
diff --git a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
index c997e45530d14..383d56c62fc5b 100644
--- a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
+++ b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
@@ -43,7 +43,7 @@ import java.util.TimeZone;
* Built-in zen condition provider for daily scheduled time-based conditions.
*/
public class ScheduleConditionProvider extends SystemConditionProviderService {
- private static final String TAG = "ScheduleConditions";
+ private static final String TAG = "ConditionProviders";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final ComponentName COMPONENT =
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
index 67a2a5439efbe..766d6c55e71ec 100644
--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -20,6 +20,7 @@ import android.content.ComponentName;
import android.net.Uri;
import android.service.notification.Condition;
import android.service.notification.IConditionListener;
+import android.service.notification.IConditionProvider;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.ZenRule;
import android.util.ArrayMap;
@@ -39,6 +40,7 @@ public class ZenModeConditions implements ConditionProviders.Callback {
private CountdownConditionProvider mCountdown;
private ScheduleConditionProvider mSchedule;
+ private boolean mFirstEvaluation = true;
public ZenModeConditions(ZenModeHelper helper, ConditionProviders conditionProviders) {
mHelper = helper;
@@ -64,7 +66,8 @@ public class ZenModeConditions implements ConditionProviders.Callback {
public void evaluateConfig(ZenModeConfig config) {
if (config == null) return;
- if (config.manualRule != null && !config.manualRule.isTrueOrUnknown()) {
+ if (config.manualRule != null && config.manualRule.condition != null
+ && !config.manualRule.isTrueOrUnknown()) {
if (DEBUG) Log.d(TAG, "evaluateConfig: clearing manual rule");
config.manualRule = null;
}
@@ -72,6 +75,7 @@ public class ZenModeConditions implements ConditionProviders.Callback {
evaluateRule(config.manualRule, current);
for (ZenRule automaticRule : config.automaticRules.values()) {
evaluateRule(automaticRule, current);
+ updateSnoozing(automaticRule);
}
final int N = mSubscriptions.size();
for (int i = N - 1; i >= 0; i--) {
@@ -82,21 +86,7 @@ public class ZenModeConditions implements ConditionProviders.Callback {
mSubscriptions.removeAt(i);
}
}
- }
-
- private void evaluateRule(ZenRule rule, ArraySet current) {
- if (rule == null || rule.conditionId == null) return;
- final Uri id = rule.conditionId;
- for (SystemConditionProviderService sp : mConditionProviders.getSystemProviders()) {
- if (sp.isValidConditionid(id)) {
- mConditionProviders.ensureRecordExists(sp.getComponent(), id, sp.asInterface());
- rule.component = sp.getComponent();
- }
- }
- current.add(id);
- if (mConditionProviders.subscribeIfNecessary(rule.component, rule.conditionId)) {
- mSubscriptions.put(rule.conditionId, rule.component);
- }
+ mFirstEvaluation = false;
}
@Override
@@ -109,6 +99,14 @@ public class ZenModeConditions implements ConditionProviders.Callback {
// noop
}
+ @Override
+ public void onServiceAdded(ComponentName component) {
+ if (DEBUG) Log.d(TAG, "onServiceAdded " + component);
+ if (isAutomaticActive(component)) {
+ mHelper.setConfig(mHelper.getConfig(), "zmc.onServiceAdded");
+ }
+ }
+
@Override
public void onConditionChanged(Uri id, Condition condition) {
if (DEBUG) Log.d(TAG, "onConditionChanged " + id + " " + condition);
@@ -125,8 +123,53 @@ public class ZenModeConditions implements ConditionProviders.Callback {
}
}
+ private void evaluateRule(ZenRule rule, ArraySet current) {
+ if (rule == null || rule.conditionId == null) return;
+ final Uri id = rule.conditionId;
+ boolean isSystemCondition = false;
+ for (SystemConditionProviderService sp : mConditionProviders.getSystemProviders()) {
+ if (sp.isValidConditionid(id)) {
+ mConditionProviders.ensureRecordExists(sp.getComponent(), id, sp.asInterface());
+ rule.component = sp.getComponent();
+ isSystemCondition = true;
+ }
+ }
+ if (!isSystemCondition) {
+ final IConditionProvider cp = mConditionProviders.findConditionProvider(rule.component);
+ if (DEBUG) Log.d(TAG, "Ensure external rule exists: " + (cp != null) + " for " + id);
+ if (cp != null) {
+ mConditionProviders.ensureRecordExists(rule.component, id, cp);
+ }
+ }
+ if (rule.component == null) {
+ Log.w(TAG, "No component found for automatic rule: " + rule.conditionId);
+ rule.enabled = false;
+ return;
+ }
+ if (current != null) {
+ current.add(id);
+ }
+ if (mConditionProviders.subscribeIfNecessary(rule.component, rule.conditionId)) {
+ mSubscriptions.put(rule.conditionId, rule.component);
+ } else {
+ if (DEBUG) Log.d(TAG, "zmc failed to subscribe");
+ }
+ }
+
+ private boolean isAutomaticActive(ComponentName component) {
+ if (component == null) return false;
+ final ZenModeConfig config = mHelper.getConfig();
+ if (config == null) return false;
+ for (ZenRule rule : config.automaticRules.values()) {
+ if (component.equals(rule.component) && rule.isAutomaticActive()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private boolean updateSnoozing(ZenRule rule) {
- if (rule != null && rule.snoozing && !rule.isTrueOrUnknown()) {
+ if (rule != null && rule.snoozing && (mFirstEvaluation || !rule.isTrueOrUnknown())) {
rule.snoozing = false;
if (DEBUG) Log.d(TAG, "Snoozing reset for " + rule.conditionId);
return true;
@@ -141,4 +184,5 @@ public class ZenModeConditions implements ConditionProviders.Callback {
rule.condition = condition;
return true;
}
+
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index e5925fede62b0..683d1fdcbafd3 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -175,7 +175,7 @@ public class ZenModeHelper {
if (zenMode == Global.ZEN_MODE_OFF) {
newConfig.manualRule = null;
for (ZenRule automaticRule : newConfig.automaticRules.values()) {
- if (automaticRule.isTrueOrUnknown()) {
+ if (automaticRule.isAutomaticActive()) {
automaticRule.snoozing = true;
}
}
@@ -286,8 +286,7 @@ public class ZenModeHelper {
if (mConfig.manualRule != null) return mConfig.manualRule.zenMode;
int zen = Global.ZEN_MODE_OFF;
for (ZenRule automaticRule : mConfig.automaticRules.values()) {
- if (automaticRule.enabled && !automaticRule.snoozing
- && automaticRule.isTrueOrUnknown()) {
+ if (automaticRule.isAutomaticActive()) {
if (zenSeverity(automaticRule.zenMode) > zenSeverity(zen)) {
zen = automaticRule.zenMode;
}