Zen: Support external condition providers.

- Manage provider subscriptions for external condition providers
   within ZenModeConditions.
 - Move "is automatic rule active" check into common location.
 - Add constant for external rule setting configuration page.
 - Consolidate log tags.
 - Reset rule snoozing on boot.

Bug: 20064962
Change-Id: Ida207dbf363f61e1727974e611f43f27c23accfb
This commit is contained in:
John Spurlock
2015-04-10 11:59:01 -04:00
parent d10bd48522
commit 39581cc16d
8 changed files with 97 additions and 27 deletions

View File

@@ -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.
* <p>

View File

@@ -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<ZenRule> CREATOR

View File

@@ -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) {

View File

@@ -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();
}

View File

@@ -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 =

View File

@@ -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 =

View File

@@ -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<Uri> 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<Uri> 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;
}
}

View File

@@ -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;
}