• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2015, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.notification;
18 
19 import android.content.ComponentName;
20 import android.net.Uri;
21 import android.service.notification.Condition;
22 import android.service.notification.IConditionProvider;
23 import android.service.notification.ZenModeConfig;
24 import android.service.notification.ZenModeConfig.ZenRule;
25 import android.util.ArrayMap;
26 import android.util.ArraySet;
27 import android.util.Log;
28 
29 import com.android.internal.annotations.VisibleForTesting;
30 
31 import java.io.PrintWriter;
32 
33 /**
34  * Helper class for managing active rules from
35  * {@link android.service.notification.ConditionProviderService CPSes}.
36  */
37 public class ZenModeConditions implements ConditionProviders.Callback {
38     private static final String TAG = ZenModeHelper.TAG;
39     private static final boolean DEBUG = ZenModeHelper.DEBUG;
40 
41     private final ZenModeHelper mHelper;
42     private final ConditionProviders mConditionProviders;
43 
44     @VisibleForTesting
45     protected final ArrayMap<Uri, ComponentName> mSubscriptions = new ArrayMap<>();
46 
ZenModeConditions(ZenModeHelper helper, ConditionProviders conditionProviders)47     public ZenModeConditions(ZenModeHelper helper, ConditionProviders conditionProviders) {
48         mHelper = helper;
49         mConditionProviders = conditionProviders;
50         if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.COUNTDOWN_PATH)) {
51             mConditionProviders.addSystemProvider(new CountdownConditionProvider());
52         }
53         if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.SCHEDULE_PATH)) {
54             mConditionProviders.addSystemProvider(new ScheduleConditionProvider());
55         }
56         if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.EVENT_PATH)) {
57             mConditionProviders.addSystemProvider(new EventConditionProvider());
58         }
59         mConditionProviders.setCallback(this);
60     }
61 
dump(PrintWriter pw, String prefix)62     public void dump(PrintWriter pw, String prefix) {
63         pw.print(prefix); pw.print("mSubscriptions="); pw.println(mSubscriptions);
64     }
65 
evaluateConfig(ZenModeConfig config, ComponentName trigger, boolean processSubscriptions)66     public void evaluateConfig(ZenModeConfig config, ComponentName trigger,
67             boolean processSubscriptions) {
68         if (config == null) return;
69         if (config.manualRule != null && config.manualRule.condition != null
70                 && !config.manualRule.isTrueOrUnknown()) {
71             if (DEBUG) Log.d(TAG, "evaluateConfig: clearing manual rule");
72             config.manualRule = null;
73         }
74         final ArraySet<Uri> current = new ArraySet<>();
75         evaluateRule(config.manualRule, current, null, processSubscriptions);
76         for (ZenRule automaticRule : config.automaticRules.values()) {
77             if (automaticRule.component != null) {
78                 evaluateRule(automaticRule, current, trigger, processSubscriptions);
79                 updateSnoozing(automaticRule);
80             }
81         }
82 
83         synchronized (mSubscriptions) {
84             final int N = mSubscriptions.size();
85             for (int i = N - 1; i >= 0; i--) {
86                 final Uri id = mSubscriptions.keyAt(i);
87                 final ComponentName component = mSubscriptions.valueAt(i);
88                 if (processSubscriptions) {
89                     if (!current.contains(id)) {
90                         mConditionProviders.unsubscribeIfNecessary(component, id);
91                         mSubscriptions.removeAt(i);
92                     }
93                 }
94             }
95         }
96     }
97 
98     @Override
onBootComplete()99     public void onBootComplete() {
100         // noop
101     }
102 
103     @Override
onUserSwitched()104     public void onUserSwitched() {
105         // noop
106     }
107 
108     @Override
onServiceAdded(ComponentName component)109     public void onServiceAdded(ComponentName component) {
110         if (DEBUG) Log.d(TAG, "onServiceAdded " + component);
111         mHelper.setConfig(mHelper.getConfig(), component, "zmc.onServiceAdded");
112     }
113 
114     @Override
onConditionChanged(Uri id, Condition condition)115     public void onConditionChanged(Uri id, Condition condition) {
116         if (DEBUG) Log.d(TAG, "onConditionChanged " + id + " " + condition);
117         ZenModeConfig config = mHelper.getConfig();
118         if (config == null) return;
119         mHelper.setAutomaticZenRuleState(id, condition);
120     }
121 
122     // Only valid for CPS backed rules
evaluateRule(ZenRule rule, ArraySet<Uri> current, ComponentName trigger, boolean processSubscriptions)123     private void evaluateRule(ZenRule rule, ArraySet<Uri> current, ComponentName trigger,
124             boolean processSubscriptions) {
125         if (rule == null || rule.conditionId == null) return;
126         if (rule.configurationActivity != null) return;
127         final Uri id = rule.conditionId;
128         boolean isSystemCondition = false;
129         for (SystemConditionProviderService sp : mConditionProviders.getSystemProviders()) {
130             if (sp.isValidConditionId(id)) {
131                 mConditionProviders.ensureRecordExists(sp.getComponent(), id, sp.asInterface());
132                 rule.component = sp.getComponent();
133                 isSystemCondition = true;
134             }
135         }
136         // ensure that we have a record of the rule if it's backed by an currently alive CPS
137         if (!isSystemCondition) {
138             final IConditionProvider cp = mConditionProviders.findConditionProvider(rule.component);
139             if (DEBUG) Log.d(TAG, "Ensure external rule exists: " + (cp != null) + " for " + id);
140             if (cp != null) {
141                 mConditionProviders.ensureRecordExists(rule.component, id, cp);
142             }
143         }
144         // empty rule? disable and bail early
145         if (rule.component == null && rule.enabler == null) {
146             Log.w(TAG, "No component found for automatic rule: " + rule.conditionId);
147             rule.enabled = false;
148             return;
149         }
150         if (current != null) {
151             current.add(id);
152         }
153 
154         // If the rule is bound by a CPS and the CPS is alive, tell them about the rule
155         if (processSubscriptions && ((trigger != null && trigger.equals(rule.component))
156                 || isSystemCondition)) {
157             if (DEBUG) Log.d(TAG, "Subscribing to " + rule.component);
158             if (mConditionProviders.subscribeIfNecessary(rule.component, rule.conditionId)) {
159                 synchronized (mSubscriptions) {
160                     mSubscriptions.put(rule.conditionId, rule.component);
161                 }
162             } else {
163                 rule.condition = null;
164                 if (DEBUG) Log.d(TAG, "zmc failed to subscribe");
165             }
166         }
167         // backfill the rule state from CPS backed components if it's missing
168         if (rule.component != null && rule.condition == null) {
169             rule.condition = mConditionProviders.findCondition(rule.component, rule.conditionId);
170             if (rule.condition != null && DEBUG) Log.d(TAG, "Found existing condition for: "
171                     + rule.conditionId);
172         }
173     }
174 
updateSnoozing(ZenRule rule)175     private boolean updateSnoozing(ZenRule rule) {
176         if (rule != null && rule.snoozing && !rule.isTrueOrUnknown()) {
177             rule.snoozing = false;
178             if (DEBUG) Log.d(TAG, "Snoozing reset for " + rule.conditionId);
179             return true;
180         }
181         return false;
182     }
183 }
184