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