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