Home | History | Annotate | Download | only in notification
      1 /**
      2  * Copyright (c) 2014, 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 static android.media.AudioAttributes.USAGE_NOTIFICATION;
     20 import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
     21 import static android.media.AudioAttributes.USAGE_UNKNOWN;
     22 import static android.media.AudioAttributes.USAGE_VIRTUAL_SOURCE;
     23 
     24 import android.app.AppOpsManager;
     25 import android.app.AutomaticZenRule;
     26 import android.app.NotificationManager;
     27 import android.app.NotificationManager.Policy;
     28 import android.content.ComponentName;
     29 import android.content.ContentResolver;
     30 import android.content.Context;
     31 import android.content.Intent;
     32 import android.content.pm.PackageManager;
     33 import android.content.pm.ResolveInfo;
     34 import android.content.pm.ServiceInfo;
     35 import android.content.res.Resources;
     36 import android.content.res.XmlResourceParser;
     37 import android.database.ContentObserver;
     38 import android.media.AudioAttributes;
     39 import android.media.AudioManager;
     40 import android.media.AudioManagerInternal;
     41 import android.media.AudioSystem;
     42 import android.media.VolumePolicy;
     43 import android.net.Uri;
     44 import android.os.Binder;
     45 import android.os.Bundle;
     46 import android.os.Handler;
     47 import android.os.Looper;
     48 import android.os.Message;
     49 import android.os.Process;
     50 import android.os.SystemClock;
     51 import android.os.UserHandle;
     52 import android.provider.Settings.Global;
     53 import android.service.notification.ConditionProviderService;
     54 import android.service.notification.ZenModeConfig;
     55 import android.service.notification.ZenModeConfig.EventInfo;
     56 import android.service.notification.ZenModeConfig.ScheduleInfo;
     57 import android.service.notification.ZenModeConfig.ZenRule;
     58 import android.util.AndroidRuntimeException;
     59 import android.util.Log;
     60 import android.util.SparseArray;
     61 
     62 import com.android.internal.R;
     63 import com.android.internal.logging.MetricsLogger;
     64 import com.android.server.LocalServices;
     65 
     66 import libcore.io.IoUtils;
     67 
     68 import org.xmlpull.v1.XmlPullParser;
     69 import org.xmlpull.v1.XmlPullParserException;
     70 import org.xmlpull.v1.XmlSerializer;
     71 
     72 import java.io.IOException;
     73 import java.io.PrintWriter;
     74 import java.util.ArrayList;
     75 import java.util.List;
     76 import java.util.Objects;
     77 
     78 /**
     79  * NotificationManagerService helper for functionality related to zen mode.
     80  */
     81 public class ZenModeHelper {
     82     static final String TAG = "ZenModeHelper";
     83     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     84 
     85     // The amount of time rules instances can exist without their owning app being installed.
     86     private static final int RULE_INSTANCE_GRACE_PERIOD = 1000 * 60 * 60 * 72;
     87 
     88     private final Context mContext;
     89     private final H mHandler;
     90     private final SettingsObserver mSettingsObserver;
     91     private final AppOpsManager mAppOps;
     92     private final ZenModeConfig mDefaultConfig;
     93     private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
     94     private final ZenModeFiltering mFiltering;
     95     private final RingerModeDelegate mRingerModeDelegate = new RingerModeDelegate();
     96     private final ZenModeConditions mConditions;
     97     private final SparseArray<ZenModeConfig> mConfigs = new SparseArray<>();
     98     private final Metrics mMetrics = new Metrics();
     99     private final ConditionProviders.Config mServiceConfig;
    100 
    101     private int mZenMode;
    102     private int mUser = UserHandle.USER_SYSTEM;
    103     private ZenModeConfig mConfig;
    104     private AudioManagerInternal mAudioManager;
    105     private PackageManager mPm;
    106     private long mSuppressedEffects;
    107 
    108     public static final long SUPPRESSED_EFFECT_NOTIFICATIONS = 1;
    109     public static final long SUPPRESSED_EFFECT_CALLS = 1 << 1;
    110     public static final long SUPPRESSED_EFFECT_ALL = SUPPRESSED_EFFECT_CALLS
    111             | SUPPRESSED_EFFECT_NOTIFICATIONS;
    112 
    113     public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) {
    114         mContext = context;
    115         mHandler = new H(looper);
    116         addCallback(mMetrics);
    117         mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
    118         mDefaultConfig = readDefaultConfig(context.getResources());
    119         appendDefaultScheduleRules(mDefaultConfig);
    120         appendDefaultEventRules(mDefaultConfig);
    121         mConfig = mDefaultConfig;
    122         mConfigs.put(UserHandle.USER_SYSTEM, mConfig);
    123         mSettingsObserver = new SettingsObserver(mHandler);
    124         mSettingsObserver.observe();
    125         mFiltering = new ZenModeFiltering(mContext);
    126         mConditions = new ZenModeConditions(this, conditionProviders);
    127         mServiceConfig = conditionProviders.getConfig();
    128     }
    129 
    130     public Looper getLooper() {
    131         return mHandler.getLooper();
    132     }
    133 
    134     @Override
    135     public String toString() {
    136         return TAG;
    137     }
    138 
    139     public boolean matchesCallFilter(UserHandle userHandle, Bundle extras,
    140             ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity) {
    141         synchronized (mConfig) {
    142             return ZenModeFiltering.matchesCallFilter(mContext, mZenMode, mConfig, userHandle,
    143                     extras, validator, contactsTimeoutMs, timeoutAffinity);
    144         }
    145     }
    146 
    147     public boolean isCall(NotificationRecord record) {
    148         return mFiltering.isCall(record);
    149     }
    150 
    151     public void recordCaller(NotificationRecord record) {
    152         mFiltering.recordCall(record);
    153     }
    154 
    155     public boolean shouldIntercept(NotificationRecord record) {
    156         synchronized (mConfig) {
    157             return mFiltering.shouldIntercept(mZenMode, mConfig, record);
    158         }
    159     }
    160 
    161     public boolean shouldSuppressWhenScreenOff() {
    162         synchronized (mConfig) {
    163             return !mConfig.allowWhenScreenOff;
    164         }
    165     }
    166 
    167     public boolean shouldSuppressWhenScreenOn() {
    168         synchronized (mConfig) {
    169             return !mConfig.allowWhenScreenOn;
    170         }
    171     }
    172 
    173     public void addCallback(Callback callback) {
    174         mCallbacks.add(callback);
    175     }
    176 
    177     public void removeCallback(Callback callback) {
    178         mCallbacks.remove(callback);
    179     }
    180 
    181     public void initZenMode() {
    182         if (DEBUG) Log.d(TAG, "initZenMode");
    183         evaluateZenMode("init", true /*setRingerMode*/);
    184     }
    185 
    186     public void onSystemReady() {
    187         if (DEBUG) Log.d(TAG, "onSystemReady");
    188         mAudioManager = LocalServices.getService(AudioManagerInternal.class);
    189         if (mAudioManager != null) {
    190             mAudioManager.setRingerModeDelegate(mRingerModeDelegate);
    191         }
    192         mPm = mContext.getPackageManager();
    193         mHandler.postMetricsTimer();
    194         cleanUpZenRules();
    195         evaluateZenMode("onSystemReady", true);
    196     }
    197 
    198     public void onUserSwitched(int user) {
    199         loadConfigForUser(user, "onUserSwitched");
    200     }
    201 
    202     public void onUserRemoved(int user) {
    203         if (user < UserHandle.USER_SYSTEM) return;
    204         if (DEBUG) Log.d(TAG, "onUserRemoved u=" + user);
    205         mConfigs.remove(user);
    206     }
    207 
    208     public void onUserUnlocked(int user) {
    209         loadConfigForUser(user, "onUserUnlocked");
    210     }
    211 
    212     private void loadConfigForUser(int user, String reason) {
    213         if (mUser == user || user < UserHandle.USER_SYSTEM) return;
    214         mUser = user;
    215         if (DEBUG) Log.d(TAG, reason + " u=" + user);
    216         ZenModeConfig config = mConfigs.get(user);
    217         if (config == null) {
    218             if (DEBUG) Log.d(TAG, reason + " generating default config for user " + user);
    219             config = mDefaultConfig.copy();
    220             config.user = user;
    221         }
    222         synchronized (mConfig) {
    223             setConfigLocked(config, reason);
    224         }
    225         cleanUpZenRules();
    226     }
    227 
    228     public int getZenModeListenerInterruptionFilter() {
    229         return NotificationManager.zenModeToInterruptionFilter(mZenMode);
    230     }
    231 
    232     public void requestFromListener(ComponentName name, int filter) {
    233         final int newZen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
    234         if (newZen != -1) {
    235             setManualZenMode(newZen, null, name != null ? name.getPackageName() : null,
    236                     "listener:" + (name != null ? name.flattenToShortString() : null));
    237         }
    238     }
    239 
    240     public void setSuppressedEffects(long suppressedEffects) {
    241         if (mSuppressedEffects == suppressedEffects) return;
    242         mSuppressedEffects = suppressedEffects;
    243         applyRestrictions();
    244     }
    245 
    246     public long getSuppressedEffects() {
    247         return mSuppressedEffects;
    248     }
    249 
    250     public int getZenMode() {
    251         return mZenMode;
    252     }
    253 
    254     public List<ZenRule> getZenRules() {
    255         List<ZenRule> rules = new ArrayList<>();
    256         synchronized (mConfig) {
    257             if (mConfig == null) return rules;
    258             for (ZenRule rule : mConfig.automaticRules.values()) {
    259                 if (canManageAutomaticZenRule(rule)) {
    260                     rules.add(rule);
    261                 }
    262             }
    263         }
    264         return rules;
    265     }
    266 
    267     public AutomaticZenRule getAutomaticZenRule(String id) {
    268         ZenRule rule;
    269         synchronized (mConfig) {
    270             if (mConfig == null) return null;
    271              rule = mConfig.automaticRules.get(id);
    272         }
    273         if (rule == null) return null;
    274         if (canManageAutomaticZenRule(rule)) {
    275              return createAutomaticZenRule(rule);
    276         }
    277         return null;
    278     }
    279 
    280     public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) {
    281         if (!isSystemRule(automaticZenRule)) {
    282             ServiceInfo owner = getServiceInfo(automaticZenRule.getOwner());
    283             if (owner == null) {
    284                 throw new IllegalArgumentException("Owner is not a condition provider service");
    285             }
    286 
    287             int ruleInstanceLimit = -1;
    288             if (owner.metaData != null) {
    289                 ruleInstanceLimit = owner.metaData.getInt(
    290                         ConditionProviderService.META_DATA_RULE_INSTANCE_LIMIT, -1);
    291             }
    292             if (ruleInstanceLimit > 0 && ruleInstanceLimit
    293                     < (getCurrentInstanceCount(automaticZenRule.getOwner()) + 1)) {
    294                 throw new IllegalArgumentException("Rule instance limit exceeded");
    295             }
    296         }
    297 
    298         ZenModeConfig newConfig;
    299         synchronized (mConfig) {
    300             if (mConfig == null) {
    301                 throw new AndroidRuntimeException("Could not create rule");
    302             }
    303             if (DEBUG) {
    304                 Log.d(TAG, "addAutomaticZenRule rule= " + automaticZenRule + " reason=" + reason);
    305             }
    306             newConfig = mConfig.copy();
    307             ZenRule rule = new ZenRule();
    308             populateZenRule(automaticZenRule, rule, true);
    309             newConfig.automaticRules.put(rule.id, rule);
    310             if (setConfigLocked(newConfig, reason, true)) {
    311                 return rule.id;
    312             } else {
    313                 throw new AndroidRuntimeException("Could not create rule");
    314             }
    315         }
    316     }
    317 
    318     public boolean updateAutomaticZenRule(String ruleId, AutomaticZenRule automaticZenRule,
    319             String reason) {
    320         ZenModeConfig newConfig;
    321         synchronized (mConfig) {
    322             if (mConfig == null) return false;
    323             if (DEBUG) {
    324                 Log.d(TAG, "updateAutomaticZenRule zenRule=" + automaticZenRule
    325                         + " reason=" + reason);
    326             }
    327             newConfig = mConfig.copy();
    328             ZenModeConfig.ZenRule rule;
    329             if (ruleId == null) {
    330                 throw new IllegalArgumentException("Rule doesn't exist");
    331             } else {
    332                 rule = newConfig.automaticRules.get(ruleId);
    333                 if (rule == null || !canManageAutomaticZenRule(rule)) {
    334                     throw new SecurityException(
    335                             "Cannot update rules not owned by your condition provider");
    336                 }
    337             }
    338             populateZenRule(automaticZenRule, rule, false);
    339             newConfig.automaticRules.put(ruleId, rule);
    340             return setConfigLocked(newConfig, reason, true);
    341         }
    342     }
    343 
    344     public boolean removeAutomaticZenRule(String id, String reason) {
    345         ZenModeConfig newConfig;
    346         synchronized (mConfig) {
    347             if (mConfig == null) return false;
    348             newConfig = mConfig.copy();
    349             ZenRule rule = newConfig.automaticRules.get(id);
    350             if (rule == null) return false;
    351             if (canManageAutomaticZenRule(rule)) {
    352                 newConfig.automaticRules.remove(id);
    353                 if (DEBUG) Log.d(TAG, "removeZenRule zenRule=" + id + " reason=" + reason);
    354             } else {
    355                 throw new SecurityException(
    356                         "Cannot delete rules not owned by your condition provider");
    357             }
    358             return setConfigLocked(newConfig, reason, true);
    359         }
    360     }
    361 
    362     public boolean removeAutomaticZenRules(String packageName, String reason) {
    363         ZenModeConfig newConfig;
    364         synchronized (mConfig) {
    365             if (mConfig == null) return false;
    366             newConfig = mConfig.copy();
    367             for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
    368                 ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
    369                 if (rule.component.getPackageName().equals(packageName)
    370                         && canManageAutomaticZenRule(rule)) {
    371                     newConfig.automaticRules.removeAt(i);
    372                 }
    373             }
    374             return setConfigLocked(newConfig, reason, true);
    375         }
    376     }
    377 
    378     public int getCurrentInstanceCount(ComponentName owner) {
    379         int count = 0;
    380         synchronized (mConfig) {
    381             for (ZenRule rule : mConfig.automaticRules.values()) {
    382                 if (rule.component != null && rule.component.equals(owner)) {
    383                     count++;
    384                 }
    385             }
    386         }
    387         return count;
    388     }
    389 
    390     public boolean canManageAutomaticZenRule(ZenRule rule) {
    391         final int callingUid = Binder.getCallingUid();
    392         if (callingUid == 0 || callingUid == Process.SYSTEM_UID) {
    393             return true;
    394         } else if (mContext.checkCallingPermission(android.Manifest.permission.MANAGE_NOTIFICATIONS)
    395                 == PackageManager.PERMISSION_GRANTED) {
    396             return true;
    397         } else {
    398             String[] packages = mPm.getPackagesForUid(Binder.getCallingUid());
    399             if (packages != null) {
    400                 final int packageCount = packages.length;
    401                 for (int i = 0; i < packageCount; i++) {
    402                     if (packages[i].equals(rule.component.getPackageName())) {
    403                         return true;
    404                     }
    405                 }
    406             }
    407             return false;
    408         }
    409     }
    410 
    411     private boolean isSystemRule(AutomaticZenRule rule) {
    412         return ZenModeConfig.SYSTEM_AUTHORITY.equals(rule.getOwner().getPackageName());
    413     }
    414 
    415     private ServiceInfo getServiceInfo(ComponentName owner) {
    416         Intent queryIntent = new Intent();
    417         queryIntent.setComponent(owner);
    418         List<ResolveInfo> installedServices = mPm.queryIntentServicesAsUser(
    419                 queryIntent,
    420                 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
    421                 UserHandle.getCallingUserId());
    422         if (installedServices != null) {
    423             for (int i = 0, count = installedServices.size(); i < count; i++) {
    424                 ResolveInfo resolveInfo = installedServices.get(i);
    425                 ServiceInfo info = resolveInfo.serviceInfo;
    426                 if (mServiceConfig.bindPermission.equals(info.permission)) {
    427                     return info;
    428                 }
    429             }
    430         }
    431         return null;
    432     }
    433 
    434     private void populateZenRule(AutomaticZenRule automaticZenRule, ZenRule rule, boolean isNew) {
    435         if (isNew) {
    436             rule.id = ZenModeConfig.newRuleId();
    437             rule.creationTime = System.currentTimeMillis();
    438             rule.component = automaticZenRule.getOwner();
    439         }
    440 
    441         if (rule.enabled != automaticZenRule.isEnabled()) {
    442             rule.snoozing = false;
    443         }
    444         rule.name = automaticZenRule.getName();
    445         rule.condition = null;
    446         rule.conditionId = automaticZenRule.getConditionId();
    447         rule.enabled = automaticZenRule.isEnabled();
    448         rule.zenMode = NotificationManager.zenModeFromInterruptionFilter(
    449                 automaticZenRule.getInterruptionFilter(), Global.ZEN_MODE_OFF);
    450     }
    451 
    452     private AutomaticZenRule createAutomaticZenRule(ZenRule rule) {
    453         return new AutomaticZenRule(rule.name, rule.component, rule.conditionId,
    454                 NotificationManager.zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
    455                 rule.creationTime);
    456     }
    457 
    458     public void setManualZenMode(int zenMode, Uri conditionId, String caller, String reason) {
    459         setManualZenMode(zenMode, conditionId, reason, caller, true /*setRingerMode*/);
    460     }
    461 
    462     private void setManualZenMode(int zenMode, Uri conditionId, String reason, String caller,
    463             boolean setRingerMode) {
    464         ZenModeConfig newConfig;
    465         synchronized (mConfig) {
    466             if (mConfig == null) return;
    467             if (!Global.isValidZenMode(zenMode)) return;
    468             if (DEBUG) Log.d(TAG, "setManualZenMode " + Global.zenModeToString(zenMode)
    469                     + " conditionId=" + conditionId + " reason=" + reason
    470                     + " setRingerMode=" + setRingerMode);
    471             newConfig = mConfig.copy();
    472             if (zenMode == Global.ZEN_MODE_OFF) {
    473                 newConfig.manualRule = null;
    474                 for (ZenRule automaticRule : newConfig.automaticRules.values()) {
    475                     if (automaticRule.isAutomaticActive()) {
    476                         automaticRule.snoozing = true;
    477                     }
    478                 }
    479             } else {
    480                 final ZenRule newRule = new ZenRule();
    481                 newRule.enabled = true;
    482                 newRule.zenMode = zenMode;
    483                 newRule.conditionId = conditionId;
    484                 newRule.enabler = caller;
    485                 newConfig.manualRule = newRule;
    486             }
    487             setConfigLocked(newConfig, reason, setRingerMode);
    488         }
    489     }
    490 
    491     public void dump(PrintWriter pw, String prefix) {
    492         pw.print(prefix); pw.print("mZenMode=");
    493         pw.println(Global.zenModeToString(mZenMode));
    494         dump(pw, prefix, "mDefaultConfig", mDefaultConfig);
    495         final int N = mConfigs.size();
    496         for (int i = 0; i < N; i++) {
    497             dump(pw, prefix, "mConfigs[u=" + mConfigs.keyAt(i) + "]", mConfigs.valueAt(i));
    498         }
    499         pw.print(prefix); pw.print("mUser="); pw.println(mUser);
    500         synchronized (mConfig) {
    501             dump(pw, prefix, "mConfig", mConfig);
    502         }
    503 
    504         pw.print(prefix); pw.print("mSuppressedEffects="); pw.println(mSuppressedEffects);
    505         mFiltering.dump(pw, prefix);
    506         mConditions.dump(pw, prefix);
    507     }
    508 
    509     private static void dump(PrintWriter pw, String prefix, String var, ZenModeConfig config) {
    510         pw.print(prefix); pw.print(var); pw.print('=');
    511         if (config == null) {
    512             pw.println(config);
    513             return;
    514         }
    515         pw.printf("allow(calls=%s,callsFrom=%s,repeatCallers=%s,messages=%s,messagesFrom=%s,"
    516                 + "events=%s,reminders=%s,whenScreenOff,whenScreenOn=%s)\n",
    517                 config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom),
    518                 config.allowRepeatCallers, config.allowMessages,
    519                 ZenModeConfig.sourceToString(config.allowMessagesFrom),
    520                 config.allowEvents, config.allowReminders, config.allowWhenScreenOff,
    521                 config.allowWhenScreenOn);
    522         pw.print(prefix); pw.print("  manualRule="); pw.println(config.manualRule);
    523         if (config.automaticRules.isEmpty()) return;
    524         final int N = config.automaticRules.size();
    525         for (int i = 0; i < N; i++) {
    526             pw.print(prefix); pw.print(i == 0 ? "  automaticRules=" : "                 ");
    527             pw.println(config.automaticRules.valueAt(i));
    528         }
    529     }
    530 
    531     public void readXml(XmlPullParser parser, boolean forRestore)
    532             throws XmlPullParserException, IOException {
    533         final ZenModeConfig config = ZenModeConfig.readXml(parser, mConfigMigration);
    534         if (config != null) {
    535             if (forRestore) {
    536                 //TODO: http://b/22388012
    537                 if (config.user != UserHandle.USER_SYSTEM) {
    538                     return;
    539                 }
    540                 config.manualRule = null;  // don't restore the manual rule
    541                 long time = System.currentTimeMillis();
    542                 if (config.automaticRules != null) {
    543                     for (ZenRule automaticRule : config.automaticRules.values()) {
    544                         // don't restore transient state from restored automatic rules
    545                         automaticRule.snoozing = false;
    546                         automaticRule.condition = null;
    547                         automaticRule.creationTime = time;
    548                     }
    549                 }
    550             }
    551             if (DEBUG) Log.d(TAG, "readXml");
    552             synchronized (mConfig) {
    553                 setConfigLocked(config, "readXml");
    554             }
    555         }
    556     }
    557 
    558     public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
    559         final int N = mConfigs.size();
    560         for (int i = 0; i < N; i++) {
    561             //TODO: http://b/22388012
    562             if (forBackup && mConfigs.keyAt(i) != UserHandle.USER_SYSTEM) {
    563                 continue;
    564             }
    565             mConfigs.valueAt(i).writeXml(out);
    566         }
    567     }
    568 
    569     public Policy getNotificationPolicy() {
    570         return getNotificationPolicy(mConfig);
    571     }
    572 
    573     private static Policy getNotificationPolicy(ZenModeConfig config) {
    574         return config == null ? null : config.toNotificationPolicy();
    575     }
    576 
    577     public void setNotificationPolicy(Policy policy) {
    578         if (policy == null || mConfig == null) return;
    579         synchronized (mConfig) {
    580             final ZenModeConfig newConfig = mConfig.copy();
    581             newConfig.applyNotificationPolicy(policy);
    582             setConfigLocked(newConfig, "setNotificationPolicy");
    583         }
    584     }
    585 
    586     /**
    587      * Removes old rule instances whose owner is not installed.
    588      */
    589     private void cleanUpZenRules() {
    590         long currentTime = System.currentTimeMillis();
    591         synchronized (mConfig) {
    592             final ZenModeConfig newConfig = mConfig.copy();
    593             if (newConfig.automaticRules != null) {
    594                 for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
    595                     ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
    596                     if (RULE_INSTANCE_GRACE_PERIOD < (currentTime - rule.creationTime)) {
    597                         try {
    598                             mPm.getPackageInfo(rule.component.getPackageName(),
    599                                     PackageManager.MATCH_UNINSTALLED_PACKAGES);
    600                         } catch (PackageManager.NameNotFoundException e) {
    601                             newConfig.automaticRules.removeAt(i);
    602                         }
    603                     }
    604                 }
    605             }
    606             setConfigLocked(newConfig, "cleanUpZenRules");
    607         }
    608     }
    609 
    610     /**
    611      * @return a copy of the zen mode configuration
    612      */
    613     public ZenModeConfig getConfig() {
    614         synchronized (mConfig) {
    615             return mConfig.copy();
    616         }
    617     }
    618 
    619     public boolean setConfigLocked(ZenModeConfig config, String reason) {
    620         return setConfigLocked(config, reason, true /*setRingerMode*/);
    621     }
    622 
    623     public void setConfig(ZenModeConfig config, String reason) {
    624         synchronized (mConfig) {
    625             setConfigLocked(config, reason);
    626         }
    627     }
    628 
    629     private boolean setConfigLocked(ZenModeConfig config, String reason, boolean setRingerMode) {
    630         final long identity = Binder.clearCallingIdentity();
    631         try {
    632             if (config == null || !config.isValid()) {
    633                 Log.w(TAG, "Invalid config in setConfigLocked; " + config);
    634                 return false;
    635             }
    636             if (config.user != mUser) {
    637                 // simply store away for background users
    638                 mConfigs.put(config.user, config);
    639                 if (DEBUG) Log.d(TAG, "setConfigLocked: store config for user " + config.user);
    640                 return true;
    641             }
    642             mConditions.evaluateConfig(config, false /*processSubscriptions*/);  // may modify config
    643             mConfigs.put(config.user, config);
    644             if (DEBUG) Log.d(TAG, "setConfigLocked reason=" + reason, new Throwable());
    645             ZenLog.traceConfig(reason, mConfig, config);
    646             final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
    647                     getNotificationPolicy(config));
    648             if (!config.equals(mConfig)) {
    649                 dispatchOnConfigChanged();
    650             }
    651             if (policyChanged) {
    652                 dispatchOnPolicyChanged();
    653             }
    654             mConfig = config;
    655             mHandler.postApplyConfig(config, reason, setRingerMode);
    656             return true;
    657         } finally {
    658             Binder.restoreCallingIdentity(identity);
    659         }
    660     }
    661 
    662     private void applyConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
    663         final String val = Integer.toString(config.hashCode());
    664         Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
    665         if (!evaluateZenMode(reason, setRingerMode)) {
    666             applyRestrictions();  // evaluateZenMode will also apply restrictions if changed
    667         }
    668         mConditions.evaluateConfig(config, true /*processSubscriptions*/);
    669     }
    670 
    671     private int getZenModeSetting() {
    672         return Global.getInt(mContext.getContentResolver(), Global.ZEN_MODE, Global.ZEN_MODE_OFF);
    673     }
    674 
    675     private void setZenModeSetting(int zen) {
    676         Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zen);
    677     }
    678 
    679     private int getPreviousRingerModeSetting() {
    680         return Global.getInt(mContext.getContentResolver(),
    681                 Global.ZEN_MODE_RINGER_LEVEL, AudioManager.RINGER_MODE_NORMAL);
    682     }
    683 
    684     private void setPreviousRingerModeSetting(Integer previousRingerLevel) {
    685         Global.putString(
    686                 mContext.getContentResolver(), Global.ZEN_MODE_RINGER_LEVEL,
    687                 previousRingerLevel == null ? null : Integer.toString(previousRingerLevel));
    688     }
    689 
    690     private boolean evaluateZenMode(String reason, boolean setRingerMode) {
    691         if (DEBUG) Log.d(TAG, "evaluateZenMode");
    692         final int zenBefore = mZenMode;
    693         final int zen = computeZenMode();
    694         ZenLog.traceSetZenMode(zen, reason);
    695         mZenMode = zen;
    696         updateRingerModeAffectedStreams();
    697         setZenModeSetting(mZenMode);
    698         if (setRingerMode) {
    699             applyZenToRingerMode();
    700         }
    701         applyRestrictions();
    702         if (zen != zenBefore) {
    703             mHandler.postDispatchOnZenModeChanged();
    704         }
    705         return true;
    706     }
    707 
    708     private void updateRingerModeAffectedStreams() {
    709         if (mAudioManager != null) {
    710             mAudioManager.updateRingerModeAffectedStreamsInternal();
    711         }
    712     }
    713 
    714     private int computeZenMode() {
    715         synchronized (mConfig) {
    716             if (mConfig == null) return Global.ZEN_MODE_OFF;
    717             if (mConfig.manualRule != null) return mConfig.manualRule.zenMode;
    718             int zen = Global.ZEN_MODE_OFF;
    719             for (ZenRule automaticRule : mConfig.automaticRules.values()) {
    720                 if (automaticRule.isAutomaticActive()) {
    721                     if (zenSeverity(automaticRule.zenMode) > zenSeverity(zen)) {
    722                         zen = automaticRule.zenMode;
    723                     }
    724                 }
    725             }
    726             return zen;
    727         }
    728     }
    729 
    730     private void applyRestrictions() {
    731         final boolean zen = mZenMode != Global.ZEN_MODE_OFF;
    732 
    733         // notification restrictions
    734         final boolean muteNotifications =
    735                 (mSuppressedEffects & SUPPRESSED_EFFECT_NOTIFICATIONS) != 0;
    736         // call restrictions
    737         final boolean muteCalls = zen && !mConfig.allowCalls && !mConfig.allowRepeatCallers
    738                 || (mSuppressedEffects & SUPPRESSED_EFFECT_CALLS) != 0;
    739         // total silence restrictions
    740         final boolean muteEverything = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
    741 
    742         for (int usage : AudioAttributes.SDK_USAGES) {
    743             final int suppressionBehavior = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage);
    744             if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NOTIFICATION) {
    745                 applyRestrictions(muteNotifications || muteEverything, usage);
    746             } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_CALL) {
    747                 applyRestrictions(muteCalls || muteEverything, usage);
    748             } else {
    749                 applyRestrictions(muteEverything, usage);
    750             }
    751         }
    752     }
    753 
    754     private void applyRestrictions(boolean mute, int usage) {
    755         final String[] exceptionPackages = null; // none (for now)
    756         mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, usage,
    757                 mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
    758                 exceptionPackages);
    759         mAppOps.setRestriction(AppOpsManager.OP_PLAY_AUDIO, usage,
    760                 mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
    761                 exceptionPackages);
    762     }
    763 
    764     private void applyZenToRingerMode() {
    765         if (mAudioManager == null) return;
    766         // force the ringer mode into compliance
    767         final int ringerModeInternal = mAudioManager.getRingerModeInternal();
    768         int newRingerModeInternal = ringerModeInternal;
    769         switch (mZenMode) {
    770             case Global.ZEN_MODE_NO_INTERRUPTIONS:
    771             case Global.ZEN_MODE_ALARMS:
    772                 if (ringerModeInternal != AudioManager.RINGER_MODE_SILENT) {
    773                     setPreviousRingerModeSetting(ringerModeInternal);
    774                     newRingerModeInternal = AudioManager.RINGER_MODE_SILENT;
    775                 }
    776                 break;
    777             case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
    778             case Global.ZEN_MODE_OFF:
    779                 if (ringerModeInternal == AudioManager.RINGER_MODE_SILENT) {
    780                     newRingerModeInternal = getPreviousRingerModeSetting();
    781                     setPreviousRingerModeSetting(null);
    782                 }
    783                 break;
    784         }
    785         if (newRingerModeInternal != -1) {
    786             mAudioManager.setRingerModeInternal(newRingerModeInternal, TAG);
    787         }
    788     }
    789 
    790     private void dispatchOnConfigChanged() {
    791         for (Callback callback : mCallbacks) {
    792             callback.onConfigChanged();
    793         }
    794     }
    795 
    796     private void dispatchOnPolicyChanged() {
    797         for (Callback callback : mCallbacks) {
    798             callback.onPolicyChanged();
    799         }
    800     }
    801 
    802     private void dispatchOnZenModeChanged() {
    803         for (Callback callback : mCallbacks) {
    804             callback.onZenModeChanged();
    805         }
    806     }
    807 
    808     private ZenModeConfig readDefaultConfig(Resources resources) {
    809         XmlResourceParser parser = null;
    810         try {
    811             parser = resources.getXml(R.xml.default_zen_mode_config);
    812             while (parser.next() != XmlPullParser.END_DOCUMENT) {
    813                 final ZenModeConfig config = ZenModeConfig.readXml(parser, mConfigMigration);
    814                 if (config != null) return config;
    815             }
    816         } catch (Exception e) {
    817             Log.w(TAG, "Error reading default zen mode config from resource", e);
    818         } finally {
    819             IoUtils.closeQuietly(parser);
    820         }
    821         return new ZenModeConfig();
    822     }
    823 
    824     private void appendDefaultScheduleRules(ZenModeConfig config) {
    825         if (config == null) return;
    826 
    827         final ScheduleInfo weeknights = new ScheduleInfo();
    828         weeknights.days = ZenModeConfig.WEEKNIGHT_DAYS;
    829         weeknights.startHour = 22;
    830         weeknights.endHour = 7;
    831         final ZenRule rule1 = new ZenRule();
    832         rule1.enabled = false;
    833         rule1.name = mContext.getResources()
    834                 .getString(R.string.zen_mode_default_weeknights_name);
    835         rule1.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
    836         rule1.zenMode = Global.ZEN_MODE_ALARMS;
    837         rule1.component = ScheduleConditionProvider.COMPONENT;
    838         rule1.id = ZenModeConfig.newRuleId();
    839         rule1.creationTime = System.currentTimeMillis();
    840         config.automaticRules.put(rule1.id, rule1);
    841 
    842         final ScheduleInfo weekends = new ScheduleInfo();
    843         weekends.days = ZenModeConfig.WEEKEND_DAYS;
    844         weekends.startHour = 23;
    845         weekends.startMinute = 30;
    846         weekends.endHour = 10;
    847         final ZenRule rule2 = new ZenRule();
    848         rule2.enabled = false;
    849         rule2.name = mContext.getResources()
    850                 .getString(R.string.zen_mode_default_weekends_name);
    851         rule2.conditionId = ZenModeConfig.toScheduleConditionId(weekends);
    852         rule2.zenMode = Global.ZEN_MODE_ALARMS;
    853         rule2.component = ScheduleConditionProvider.COMPONENT;
    854         rule2.id = ZenModeConfig.newRuleId();
    855         rule2.creationTime = System.currentTimeMillis();
    856         config.automaticRules.put(rule2.id, rule2);
    857     }
    858 
    859     private void appendDefaultEventRules(ZenModeConfig config) {
    860         if (config == null) return;
    861 
    862         final EventInfo events = new EventInfo();
    863         events.calendar = null; // any calendar
    864         events.reply = EventInfo.REPLY_YES_OR_MAYBE;
    865         final ZenRule rule = new ZenRule();
    866         rule.enabled = false;
    867         rule.name = mContext.getResources().getString(R.string.zen_mode_default_events_name);
    868         rule.conditionId = ZenModeConfig.toEventConditionId(events);
    869         rule.zenMode = Global.ZEN_MODE_ALARMS;
    870         rule.component = EventConditionProvider.COMPONENT;
    871         rule.id = ZenModeConfig.newRuleId();
    872         rule.creationTime = System.currentTimeMillis();
    873         config.automaticRules.put(rule.id, rule);
    874     }
    875 
    876     private static int zenSeverity(int zen) {
    877         switch (zen) {
    878             case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return 1;
    879             case Global.ZEN_MODE_ALARMS: return 2;
    880             case Global.ZEN_MODE_NO_INTERRUPTIONS: return 3;
    881             default: return 0;
    882         }
    883     }
    884 
    885     private final ZenModeConfig.Migration mConfigMigration = new ZenModeConfig.Migration() {
    886         @Override
    887         public ZenModeConfig migrate(ZenModeConfig.XmlV1 v1) {
    888             if (v1 == null) return null;
    889             final ZenModeConfig rt = new ZenModeConfig();
    890             rt.allowCalls = v1.allowCalls;
    891             rt.allowEvents = v1.allowEvents;
    892             rt.allowCallsFrom = v1.allowFrom;
    893             rt.allowMessages = v1.allowMessages;
    894             rt.allowMessagesFrom = v1.allowFrom;
    895             rt.allowReminders = v1.allowReminders;
    896             // don't migrate current exit condition
    897             final int[] days = ZenModeConfig.XmlV1.tryParseDays(v1.sleepMode);
    898             if (days != null && days.length > 0) {
    899                 Log.i(TAG, "Migrating existing V1 downtime to single schedule");
    900                 final ScheduleInfo schedule = new ScheduleInfo();
    901                 schedule.days = days;
    902                 schedule.startHour = v1.sleepStartHour;
    903                 schedule.startMinute = v1.sleepStartMinute;
    904                 schedule.endHour = v1.sleepEndHour;
    905                 schedule.endMinute = v1.sleepEndMinute;
    906                 final ZenRule rule = new ZenRule();
    907                 rule.enabled = true;
    908                 rule.name = mContext.getResources()
    909                         .getString(R.string.zen_mode_downtime_feature_name);
    910                 rule.conditionId = ZenModeConfig.toScheduleConditionId(schedule);
    911                 rule.zenMode = v1.sleepNone ? Global.ZEN_MODE_NO_INTERRUPTIONS
    912                         : Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
    913                 rule.component = ScheduleConditionProvider.COMPONENT;
    914                 rt.automaticRules.put(ZenModeConfig.newRuleId(), rule);
    915             } else {
    916                 Log.i(TAG, "No existing V1 downtime found, generating default schedules");
    917                 appendDefaultScheduleRules(rt);
    918             }
    919             appendDefaultEventRules(rt);
    920             return rt;
    921         }
    922     };
    923 
    924     private final class RingerModeDelegate implements AudioManagerInternal.RingerModeDelegate {
    925         @Override
    926         public String toString() {
    927             return TAG;
    928         }
    929 
    930         @Override
    931         public int onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller,
    932                 int ringerModeExternal, VolumePolicy policy) {
    933             final boolean isChange = ringerModeOld != ringerModeNew;
    934 
    935             int ringerModeExternalOut = ringerModeNew;
    936 
    937             int newZen = -1;
    938             switch (ringerModeNew) {
    939                 case AudioManager.RINGER_MODE_SILENT:
    940                     if (isChange && policy.doNotDisturbWhenSilent) {
    941                         if (mZenMode != Global.ZEN_MODE_NO_INTERRUPTIONS
    942                                 && mZenMode != Global.ZEN_MODE_ALARMS) {
    943                             newZen = Global.ZEN_MODE_ALARMS;
    944                         }
    945                         setPreviousRingerModeSetting(ringerModeOld);
    946                     }
    947                     break;
    948                 case AudioManager.RINGER_MODE_VIBRATE:
    949                 case AudioManager.RINGER_MODE_NORMAL:
    950                     if (isChange && ringerModeOld == AudioManager.RINGER_MODE_SILENT
    951                             && (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS
    952                                     || mZenMode == Global.ZEN_MODE_ALARMS)) {
    953                         newZen = Global.ZEN_MODE_OFF;
    954                     } else if (mZenMode != Global.ZEN_MODE_OFF) {
    955                         ringerModeExternalOut = AudioManager.RINGER_MODE_SILENT;
    956                     }
    957                     break;
    958             }
    959             if (newZen != -1) {
    960                 setManualZenMode(newZen, null, "ringerModeInternal", null,
    961                         false /*setRingerMode*/);
    962             }
    963 
    964             if (isChange || newZen != -1 || ringerModeExternal != ringerModeExternalOut) {
    965                 ZenLog.traceSetRingerModeInternal(ringerModeOld, ringerModeNew, caller,
    966                         ringerModeExternal, ringerModeExternalOut);
    967             }
    968             return ringerModeExternalOut;
    969         }
    970 
    971         @Override
    972         public int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller,
    973                 int ringerModeInternal, VolumePolicy policy) {
    974             int ringerModeInternalOut = ringerModeNew;
    975             final boolean isChange = ringerModeOld != ringerModeNew;
    976             final boolean isVibrate = ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE;
    977 
    978             int newZen = -1;
    979             switch (ringerModeNew) {
    980                 case AudioManager.RINGER_MODE_SILENT:
    981                     if (isChange) {
    982                         if (mZenMode == Global.ZEN_MODE_OFF) {
    983                             newZen = Global.ZEN_MODE_ALARMS;
    984                         }
    985                         ringerModeInternalOut = isVibrate ? AudioManager.RINGER_MODE_VIBRATE
    986                                 : AudioManager.RINGER_MODE_SILENT;
    987                     } else {
    988                         ringerModeInternalOut = ringerModeInternal;
    989                     }
    990                     break;
    991                 case AudioManager.RINGER_MODE_VIBRATE:
    992                 case AudioManager.RINGER_MODE_NORMAL:
    993                     if (mZenMode != Global.ZEN_MODE_OFF) {
    994                         newZen = Global.ZEN_MODE_OFF;
    995                     }
    996                     break;
    997             }
    998             if (newZen != -1) {
    999                 setManualZenMode(newZen, null, "ringerModeExternal", caller,
   1000                         false /*setRingerMode*/);
   1001             }
   1002 
   1003             ZenLog.traceSetRingerModeExternal(ringerModeOld, ringerModeNew, caller,
   1004                     ringerModeInternal, ringerModeInternalOut);
   1005             return ringerModeInternalOut;
   1006         }
   1007 
   1008         @Override
   1009         public boolean canVolumeDownEnterSilent() {
   1010             return mZenMode == Global.ZEN_MODE_OFF;
   1011         }
   1012 
   1013         @Override
   1014         public int getRingerModeAffectedStreams(int streams) {
   1015             // ringtone, notification and system streams are always affected by ringer mode
   1016             streams |= (1 << AudioSystem.STREAM_RING) |
   1017                        (1 << AudioSystem.STREAM_NOTIFICATION) |
   1018                        (1 << AudioSystem.STREAM_SYSTEM);
   1019 
   1020             // alarm and music streams are only affected by ringer mode when in total silence
   1021             if (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
   1022                 streams |= (1 << AudioSystem.STREAM_ALARM) |
   1023                            (1 << AudioSystem.STREAM_MUSIC);
   1024             } else {
   1025                 streams &= ~((1 << AudioSystem.STREAM_ALARM) |
   1026                              (1 << AudioSystem.STREAM_MUSIC));
   1027             }
   1028             return streams;
   1029         }
   1030     }
   1031 
   1032     private final class SettingsObserver extends ContentObserver {
   1033         private final Uri ZEN_MODE = Global.getUriFor(Global.ZEN_MODE);
   1034 
   1035         public SettingsObserver(Handler handler) {
   1036             super(handler);
   1037         }
   1038 
   1039         public void observe() {
   1040             final ContentResolver resolver = mContext.getContentResolver();
   1041             resolver.registerContentObserver(ZEN_MODE, false /*notifyForDescendents*/, this);
   1042             update(null);
   1043         }
   1044 
   1045         @Override
   1046         public void onChange(boolean selfChange, Uri uri) {
   1047             update(uri);
   1048         }
   1049 
   1050         public void update(Uri uri) {
   1051             if (ZEN_MODE.equals(uri)) {
   1052                 if (mZenMode != getZenModeSetting()) {
   1053                     if (DEBUG) Log.d(TAG, "Fixing zen mode setting");
   1054                     setZenModeSetting(mZenMode);
   1055                 }
   1056             }
   1057         }
   1058     }
   1059 
   1060     private final class Metrics extends Callback {
   1061         private static final String COUNTER_PREFIX = "dnd_mode_";
   1062         private static final long MINIMUM_LOG_PERIOD_MS = 60 * 1000;
   1063 
   1064         private int mPreviousZenMode = -1;
   1065         private long mBeginningMs = 0L;
   1066 
   1067         @Override
   1068         void onZenModeChanged() {
   1069             emit();
   1070         }
   1071 
   1072         private void emit() {
   1073             mHandler.postMetricsTimer();
   1074             final long now = SystemClock.elapsedRealtime();
   1075             final long since = (now - mBeginningMs);
   1076             if (mPreviousZenMode != mZenMode || since > MINIMUM_LOG_PERIOD_MS) {
   1077                 if (mPreviousZenMode != -1) {
   1078                     MetricsLogger.count(mContext, COUNTER_PREFIX + mPreviousZenMode, (int) since);
   1079                 }
   1080                 mPreviousZenMode = mZenMode;
   1081                 mBeginningMs = now;
   1082             }
   1083         }
   1084     }
   1085 
   1086     private final class H extends Handler {
   1087         private static final int MSG_DISPATCH = 1;
   1088         private static final int MSG_METRICS = 2;
   1089         private static final int MSG_APPLY_CONFIG = 4;
   1090 
   1091         private final class ConfigMessageData {
   1092             public final ZenModeConfig config;
   1093             public final String reason;
   1094             public final boolean setRingerMode;
   1095 
   1096             ConfigMessageData(ZenModeConfig config, String reason, boolean setRingerMode) {
   1097                 this.config = config;
   1098                 this.reason = reason;
   1099                 this.setRingerMode = setRingerMode;
   1100             }
   1101         }
   1102 
   1103         private static final long METRICS_PERIOD_MS = 6 * 60 * 60 * 1000;
   1104 
   1105         private H(Looper looper) {
   1106             super(looper);
   1107         }
   1108 
   1109         private void postDispatchOnZenModeChanged() {
   1110             removeMessages(MSG_DISPATCH);
   1111             sendEmptyMessage(MSG_DISPATCH);
   1112         }
   1113 
   1114         private void postMetricsTimer() {
   1115             removeMessages(MSG_METRICS);
   1116             sendEmptyMessageDelayed(MSG_METRICS, METRICS_PERIOD_MS);
   1117         }
   1118 
   1119         private void postApplyConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
   1120             sendMessage(obtainMessage(MSG_APPLY_CONFIG,
   1121                     new ConfigMessageData(config, reason, setRingerMode)));
   1122         }
   1123 
   1124         @Override
   1125         public void handleMessage(Message msg) {
   1126             switch (msg.what) {
   1127                 case MSG_DISPATCH:
   1128                     dispatchOnZenModeChanged();
   1129                     break;
   1130                 case MSG_METRICS:
   1131                     mMetrics.emit();
   1132                     break;
   1133                 case MSG_APPLY_CONFIG:
   1134                     ConfigMessageData applyConfigData = (ConfigMessageData) msg.obj;
   1135                     applyConfig(applyConfigData.config, applyConfigData.reason,
   1136                             applyConfigData.setRingerMode);
   1137             }
   1138         }
   1139     }
   1140 
   1141     public static class Callback {
   1142         void onConfigChanged() {}
   1143         void onZenModeChanged() {}
   1144         void onPolicyChanged() {}
   1145     }
   1146 
   1147 }
   1148