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