1b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock/** 2b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock * Copyright (c) 2015, The Android Open Source Project 3b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock * 4b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock * Licensed under the Apache License, Version 2.0 (the "License"); 5b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock * you may not use this file except in compliance with the License. 6b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock * You may obtain a copy of the License at 7b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock * 8b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock * http://www.apache.org/licenses/LICENSE-2.0 9b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock * 10b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock * Unless required by applicable law or agreed to in writing, software 11b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock * distributed under the License is distributed on an "AS IS" BASIS, 12b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock * See the License for the specific language governing permissions and 14b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock * limitations under the License. 15b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock */ 16b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock 17b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlockpackage com.android.server.notification; 18b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock 19b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlockimport android.content.ComponentName; 20b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlockimport android.net.Uri; 21b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlockimport android.service.notification.Condition; 22b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlockimport android.service.notification.IConditionListener; 2339581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlockimport android.service.notification.IConditionProvider; 24b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlockimport android.service.notification.ZenModeConfig; 25b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlockimport android.service.notification.ZenModeConfig.ZenRule; 26b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlockimport android.util.ArrayMap; 27b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlockimport android.util.ArraySet; 28b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlockimport android.util.Log; 29b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock 30b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlockimport java.io.PrintWriter; 31b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlockimport java.util.Objects; 32b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock 33b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlockpublic class ZenModeConditions implements ConditionProviders.Callback { 34b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock private static final String TAG = ZenModeHelper.TAG; 35b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock private static final boolean DEBUG = ZenModeHelper.DEBUG; 36b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock 37b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock private final ZenModeHelper mHelper; 38b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock private final ConditionProviders mConditionProviders; 39b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock private final ArrayMap<Uri, ComponentName> mSubscriptions = new ArrayMap<>(); 40b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock 4139581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock private boolean mFirstEvaluation = true; 42b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock 43b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock public ZenModeConditions(ZenModeHelper helper, ConditionProviders conditionProviders) { 44b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock mHelper = helper; 45b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock mConditionProviders = conditionProviders; 46b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.COUNTDOWN_PATH)) { 47d60258f2d33214077a22c1a682944fa9e47c0461John Spurlock mConditionProviders.addSystemProvider(new CountdownConditionProvider()); 48b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock } 49b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.SCHEDULE_PATH)) { 50d60258f2d33214077a22c1a682944fa9e47c0461John Spurlock mConditionProviders.addSystemProvider(new ScheduleConditionProvider()); 51d60258f2d33214077a22c1a682944fa9e47c0461John Spurlock } 52d60258f2d33214077a22c1a682944fa9e47c0461John Spurlock if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.EVENT_PATH)) { 537034caf2944962e67291f3e88888c6143c19161aJulia Reynolds mConditionProviders.addSystemProvider(new EventConditionProvider()); 54b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock } 55b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock mConditionProviders.setCallback(this); 56b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock } 57b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock 58b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock public void dump(PrintWriter pw, String prefix) { 59b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock pw.print(prefix); pw.print("mSubscriptions="); pw.println(mSubscriptions); 60b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock } 61b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock 6221258a3703fe16b7c4754aec743215f3063bcdacJohn Spurlock public void evaluateConfig(ZenModeConfig config, boolean processSubscriptions) { 63b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock if (config == null) return; 6439581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock if (config.manualRule != null && config.manualRule.condition != null 6539581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock && !config.manualRule.isTrueOrUnknown()) { 66b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock if (DEBUG) Log.d(TAG, "evaluateConfig: clearing manual rule"); 67b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock config.manualRule = null; 68b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock } 69b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock final ArraySet<Uri> current = new ArraySet<>(); 7021258a3703fe16b7c4754aec743215f3063bcdacJohn Spurlock evaluateRule(config.manualRule, current, processSubscriptions); 71b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock for (ZenRule automaticRule : config.automaticRules.values()) { 7221258a3703fe16b7c4754aec743215f3063bcdacJohn Spurlock evaluateRule(automaticRule, current, processSubscriptions); 7339581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock updateSnoozing(automaticRule); 74b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock } 75b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock final int N = mSubscriptions.size(); 76b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock for (int i = N - 1; i >= 0; i--) { 77b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock final Uri id = mSubscriptions.keyAt(i); 78b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock final ComponentName component = mSubscriptions.valueAt(i); 7921258a3703fe16b7c4754aec743215f3063bcdacJohn Spurlock if (processSubscriptions) { 80a7d92b19c048fe2b3115073286103e9194a915d6John Spurlock if (!current.contains(id)) { 81a7d92b19c048fe2b3115073286103e9194a915d6John Spurlock mConditionProviders.unsubscribeIfNecessary(component, id); 82a7d92b19c048fe2b3115073286103e9194a915d6John Spurlock mSubscriptions.removeAt(i); 83a7d92b19c048fe2b3115073286103e9194a915d6John Spurlock } 84b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock } 85b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock } 8639581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock mFirstEvaluation = false; 87b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock } 88b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock 89b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock @Override 90b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock public void onBootComplete() { 91b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock // noop 92b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock } 93b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock 94b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock @Override 95b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock public void onUserSwitched() { 96b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock // noop 97b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock } 98b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock 99b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock @Override 10039581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock public void onServiceAdded(ComponentName component) { 10139581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock if (DEBUG) Log.d(TAG, "onServiceAdded " + component); 1027c9350a940b4f96eb092c0dc2a7169b9e20b35efJulia Reynolds mHelper.setConfigAsync(mHelper.getConfig(), "zmc.onServiceAdded"); 10339581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock } 10439581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock 10539581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock @Override 106b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock public void onConditionChanged(Uri id, Condition condition) { 107b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock if (DEBUG) Log.d(TAG, "onConditionChanged " + id + " " + condition); 108b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock ZenModeConfig config = mHelper.getConfig(); 109b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock if (config == null) return; 110b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock boolean updated = updateCondition(id, condition, config.manualRule); 111b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock for (ZenRule automaticRule : config.automaticRules.values()) { 112b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock updated |= updateCondition(id, condition, automaticRule); 113b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock updated |= updateSnoozing(automaticRule); 114b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock } 115b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock if (updated) { 116e0ced4da1990583d6438cb3e99a8e16b5d1e8cc6Eric Laurent mHelper.setConfigAsync(config, "conditionChanged"); 117b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock } 118b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock } 119b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock 120a7d92b19c048fe2b3115073286103e9194a915d6John Spurlock private void evaluateRule(ZenRule rule, ArraySet<Uri> current, boolean processSubscriptions) { 12139581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock if (rule == null || rule.conditionId == null) return; 12239581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock final Uri id = rule.conditionId; 12339581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock boolean isSystemCondition = false; 12439581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock for (SystemConditionProviderService sp : mConditionProviders.getSystemProviders()) { 125d60258f2d33214077a22c1a682944fa9e47c0461John Spurlock if (sp.isValidConditionId(id)) { 12639581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock mConditionProviders.ensureRecordExists(sp.getComponent(), id, sp.asInterface()); 12739581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock rule.component = sp.getComponent(); 12839581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock isSystemCondition = true; 12939581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock } 13039581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock } 13139581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock if (!isSystemCondition) { 13239581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock final IConditionProvider cp = mConditionProviders.findConditionProvider(rule.component); 13339581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock if (DEBUG) Log.d(TAG, "Ensure external rule exists: " + (cp != null) + " for " + id); 13439581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock if (cp != null) { 13539581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock mConditionProviders.ensureRecordExists(rule.component, id, cp); 13639581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock } 13739581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock } 13839581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock if (rule.component == null) { 13939581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock Log.w(TAG, "No component found for automatic rule: " + rule.conditionId); 14039581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock rule.enabled = false; 14139581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock return; 14239581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock } 14339581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock if (current != null) { 14439581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock current.add(id); 14539581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock } 146a7d92b19c048fe2b3115073286103e9194a915d6John Spurlock if (processSubscriptions) { 147a7d92b19c048fe2b3115073286103e9194a915d6John Spurlock if (mConditionProviders.subscribeIfNecessary(rule.component, rule.conditionId)) { 148a7d92b19c048fe2b3115073286103e9194a915d6John Spurlock mSubscriptions.put(rule.conditionId, rule.component); 149a7d92b19c048fe2b3115073286103e9194a915d6John Spurlock } else { 150a7d92b19c048fe2b3115073286103e9194a915d6John Spurlock if (DEBUG) Log.d(TAG, "zmc failed to subscribe"); 151a7d92b19c048fe2b3115073286103e9194a915d6John Spurlock } 15239581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock } 15321258a3703fe16b7c4754aec743215f3063bcdacJohn Spurlock if (rule.condition == null) { 15421258a3703fe16b7c4754aec743215f3063bcdacJohn Spurlock rule.condition = mConditionProviders.findCondition(rule.component, rule.conditionId); 15521258a3703fe16b7c4754aec743215f3063bcdacJohn Spurlock if (rule.condition != null && DEBUG) Log.d(TAG, "Found existing condition for: " 15621258a3703fe16b7c4754aec743215f3063bcdacJohn Spurlock + rule.conditionId); 15721258a3703fe16b7c4754aec743215f3063bcdacJohn Spurlock } 15839581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock } 15939581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock 16039581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock private boolean isAutomaticActive(ComponentName component) { 16139581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock if (component == null) return false; 16239581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock final ZenModeConfig config = mHelper.getConfig(); 16339581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock if (config == null) return false; 16439581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock for (ZenRule rule : config.automaticRules.values()) { 16539581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock if (component.equals(rule.component) && rule.isAutomaticActive()) { 16639581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock return true; 16739581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock } 16839581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock } 16939581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock return false; 17039581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock } 17139581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock 172b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock private boolean updateSnoozing(ZenRule rule) { 17339581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock if (rule != null && rule.snoozing && (mFirstEvaluation || !rule.isTrueOrUnknown())) { 174b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock rule.snoozing = false; 175b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock if (DEBUG) Log.d(TAG, "Snoozing reset for " + rule.conditionId); 176b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock return true; 177b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock } 178b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock return false; 179b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock } 180b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock 181b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock private boolean updateCondition(Uri id, Condition condition, ZenRule rule) { 182b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock if (id == null || rule == null || rule.conditionId == null) return false; 183b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock if (!rule.conditionId.equals(id)) return false; 184b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock if (Objects.equals(condition, rule.condition)) return false; 185b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock rule.condition = condition; 186b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock return true; 187b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock } 18839581cc16d3c44acc8f0881d8e63afe53acaa1c1John Spurlock 189b2278d65714c0dd0a6f94d1913db1ebc8bfc8b06John Spurlock} 190