Home | History | Annotate | Download | only in notification
      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.IConditionListener;
     23 import android.service.notification.IConditionProvider;
     24 import android.service.notification.ZenModeConfig;
     25 import android.service.notification.ZenModeConfig.ZenRule;
     26 import android.util.ArrayMap;
     27 import android.util.ArraySet;
     28 import android.util.Log;
     29 
     30 import java.io.PrintWriter;
     31 import java.util.Objects;
     32 
     33 public class ZenModeConditions implements ConditionProviders.Callback {
     34     private static final String TAG = ZenModeHelper.TAG;
     35     private static final boolean DEBUG = ZenModeHelper.DEBUG;
     36 
     37     private final ZenModeHelper mHelper;
     38     private final ConditionProviders mConditionProviders;
     39     private final ArrayMap<Uri, ComponentName> mSubscriptions = new ArrayMap<>();
     40 
     41     private boolean mFirstEvaluation = true;
     42 
     43     public ZenModeConditions(ZenModeHelper helper, ConditionProviders conditionProviders) {
     44         mHelper = helper;
     45         mConditionProviders = conditionProviders;
     46         if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.COUNTDOWN_PATH)) {
     47             mConditionProviders.addSystemProvider(new CountdownConditionProvider());
     48         }
     49         if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.SCHEDULE_PATH)) {
     50             mConditionProviders.addSystemProvider(new ScheduleConditionProvider());
     51         }
     52         if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.EVENT_PATH)) {
     53             mConditionProviders.addSystemProvider(new EventConditionProvider());
     54         }
     55         mConditionProviders.setCallback(this);
     56     }
     57 
     58     public void dump(PrintWriter pw, String prefix) {
     59         pw.print(prefix); pw.print("mSubscriptions="); pw.println(mSubscriptions);
     60     }
     61 
     62     public void evaluateConfig(ZenModeConfig config, boolean processSubscriptions) {
     63         if (config == null) return;
     64         if (config.manualRule != null && config.manualRule.condition != null
     65                 && !config.manualRule.isTrueOrUnknown()) {
     66             if (DEBUG) Log.d(TAG, "evaluateConfig: clearing manual rule");
     67             config.manualRule = null;
     68         }
     69         final ArraySet<Uri> current = new ArraySet<>();
     70         evaluateRule(config.manualRule, current, processSubscriptions);
     71         for (ZenRule automaticRule : config.automaticRules.values()) {
     72             evaluateRule(automaticRule, current, processSubscriptions);
     73             updateSnoozing(automaticRule);
     74         }
     75         final int N = mSubscriptions.size();
     76         for (int i = N - 1; i >= 0; i--) {
     77             final Uri id = mSubscriptions.keyAt(i);
     78             final ComponentName component = mSubscriptions.valueAt(i);
     79             if (processSubscriptions) {
     80                 if (!current.contains(id)) {
     81                     mConditionProviders.unsubscribeIfNecessary(component, id);
     82                     mSubscriptions.removeAt(i);
     83                 }
     84             }
     85         }
     86         mFirstEvaluation = false;
     87     }
     88 
     89     @Override
     90     public void onBootComplete() {
     91         // noop
     92     }
     93 
     94     @Override
     95     public void onUserSwitched() {
     96         // noop
     97     }
     98 
     99     @Override
    100     public void onServiceAdded(ComponentName component) {
    101         if (DEBUG) Log.d(TAG, "onServiceAdded " + component);
    102         mHelper.setConfigAsync(mHelper.getConfig(), "zmc.onServiceAdded");
    103     }
    104 
    105     @Override
    106     public void onConditionChanged(Uri id, Condition condition) {
    107         if (DEBUG) Log.d(TAG, "onConditionChanged " + id + " " + condition);
    108         ZenModeConfig config = mHelper.getConfig();
    109         if (config == null) return;
    110         boolean updated = updateCondition(id, condition, config.manualRule);
    111         for (ZenRule automaticRule : config.automaticRules.values()) {
    112             updated |= updateCondition(id, condition, automaticRule);
    113             updated |= updateSnoozing(automaticRule);
    114         }
    115         if (updated) {
    116             mHelper.setConfigAsync(config, "conditionChanged");
    117         }
    118     }
    119 
    120     private void evaluateRule(ZenRule rule, ArraySet<Uri> current, boolean processSubscriptions) {
    121         if (rule == null || rule.conditionId == null) return;
    122         final Uri id = rule.conditionId;
    123         boolean isSystemCondition = false;
    124         for (SystemConditionProviderService sp : mConditionProviders.getSystemProviders()) {
    125             if (sp.isValidConditionId(id)) {
    126                 mConditionProviders.ensureRecordExists(sp.getComponent(), id, sp.asInterface());
    127                 rule.component = sp.getComponent();
    128                 isSystemCondition = true;
    129             }
    130         }
    131         if (!isSystemCondition) {
    132             final IConditionProvider cp = mConditionProviders.findConditionProvider(rule.component);
    133             if (DEBUG) Log.d(TAG, "Ensure external rule exists: " + (cp != null) + " for " + id);
    134             if (cp != null) {
    135                 mConditionProviders.ensureRecordExists(rule.component, id, cp);
    136             }
    137         }
    138         if (rule.component == null) {
    139             Log.w(TAG, "No component found for automatic rule: " + rule.conditionId);
    140             rule.enabled = false;
    141             return;
    142         }
    143         if (current != null) {
    144             current.add(id);
    145         }
    146         if (processSubscriptions) {
    147             if (mConditionProviders.subscribeIfNecessary(rule.component, rule.conditionId)) {
    148                 mSubscriptions.put(rule.conditionId, rule.component);
    149             } else {
    150                 rule.condition = null;
    151                 if (DEBUG) Log.d(TAG, "zmc failed to subscribe");
    152             }
    153         }
    154         if (rule.condition == null) {
    155             rule.condition = mConditionProviders.findCondition(rule.component, rule.conditionId);
    156             if (rule.condition != null && DEBUG) Log.d(TAG, "Found existing condition for: "
    157                     + rule.conditionId);
    158         }
    159     }
    160 
    161     private boolean isAutomaticActive(ComponentName component) {
    162         if (component == null) return false;
    163         final ZenModeConfig config = mHelper.getConfig();
    164         if (config == null) return false;
    165         for (ZenRule rule : config.automaticRules.values()) {
    166             if (component.equals(rule.component) && rule.isAutomaticActive()) {
    167                 return true;
    168             }
    169         }
    170         return false;
    171     }
    172 
    173     private boolean updateSnoozing(ZenRule rule) {
    174         if (rule != null && rule.snoozing && (mFirstEvaluation || !rule.isTrueOrUnknown())) {
    175             rule.snoozing = false;
    176             if (DEBUG) Log.d(TAG, "Snoozing reset for " + rule.conditionId);
    177             return true;
    178         }
    179         return false;
    180     }
    181 
    182     private boolean updateCondition(Uri id, Condition condition, ZenRule rule) {
    183         if (id == null || rule == null || rule.conditionId == null) return false;
    184         if (!rule.conditionId.equals(id)) return false;
    185         if (Objects.equals(condition, rule.condition)) return false;
    186         rule.condition = condition;
    187         return true;
    188     }
    189 
    190 }
    191