• 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.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 
ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders)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 
getLooper()129     public Looper getLooper() {
130         return mHandler.getLooper();
131     }
132 
133     @Override
toString()134     public String toString() {
135         return TAG;
136     }
137 
matchesCallFilter(UserHandle userHandle, Bundle extras, ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity)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 
isCall(NotificationRecord record)146     public boolean isCall(NotificationRecord record) {
147         return mFiltering.isCall(record);
148     }
149 
recordCaller(NotificationRecord record)150     public void recordCaller(NotificationRecord record) {
151         mFiltering.recordCall(record);
152     }
153 
shouldIntercept(NotificationRecord record)154     public boolean shouldIntercept(NotificationRecord record) {
155         synchronized (mConfig) {
156             return mFiltering.shouldIntercept(mZenMode, mConfig, record);
157         }
158     }
159 
shouldSuppressWhenScreenOff()160     public boolean shouldSuppressWhenScreenOff() {
161         synchronized (mConfig) {
162             return !mConfig.allowWhenScreenOff;
163         }
164     }
165 
shouldSuppressWhenScreenOn()166     public boolean shouldSuppressWhenScreenOn() {
167         synchronized (mConfig) {
168             return !mConfig.allowWhenScreenOn;
169         }
170     }
171 
addCallback(Callback callback)172     public void addCallback(Callback callback) {
173         mCallbacks.add(callback);
174     }
175 
removeCallback(Callback callback)176     public void removeCallback(Callback callback) {
177         mCallbacks.remove(callback);
178     }
179 
initZenMode()180     public void initZenMode() {
181         if (DEBUG) Log.d(TAG, "initZenMode");
182         evaluateZenMode("init", true /*setRingerMode*/);
183     }
184 
onSystemReady()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 
onUserSwitched(int user)197     public void onUserSwitched(int user) {
198         loadConfigForUser(user, "onUserSwitched");
199     }
200 
onUserRemoved(int user)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 
onUserUnlocked(int user)207     public void onUserUnlocked(int user) {
208         loadConfigForUser(user, "onUserUnlocked");
209     }
210 
loadConfigForUser(int user, String reason)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 
getZenModeListenerInterruptionFilter()227     public int getZenModeListenerInterruptionFilter() {
228         return NotificationManager.zenModeToInterruptionFilter(mZenMode);
229     }
230 
requestFromListener(ComponentName name, int filter)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 
setSuppressedEffects(long suppressedEffects)239     public void setSuppressedEffects(long suppressedEffects) {
240         if (mSuppressedEffects == suppressedEffects) return;
241         mSuppressedEffects = suppressedEffects;
242         applyRestrictions();
243     }
244 
getSuppressedEffects()245     public long getSuppressedEffects() {
246         return mSuppressedEffects;
247     }
248 
getZenMode()249     public int getZenMode() {
250         return mZenMode;
251     }
252 
getZenRules()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 
getAutomaticZenRule(String id)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 
addAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason)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 
updateAutomaticZenRule(String ruleId, AutomaticZenRule automaticZenRule, String reason)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 
removeAutomaticZenRule(String id, String reason)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 
removeAutomaticZenRules(String packageName, String reason)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 
getCurrentInstanceCount(ComponentName owner)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 
canManageAutomaticZenRule(ZenRule rule)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 
isSystemRule(AutomaticZenRule rule)410     private boolean isSystemRule(AutomaticZenRule rule) {
411         return ZenModeConfig.SYSTEM_AUTHORITY.equals(rule.getOwner().getPackageName());
412     }
413 
getServiceInfo(ComponentName owner)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 
populateZenRule(AutomaticZenRule automaticZenRule, ZenRule rule, boolean isNew)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 
createAutomaticZenRule(ZenRule rule)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 
setManualZenMode(int zenMode, Uri conditionId, String caller, String reason)457     public void setManualZenMode(int zenMode, Uri conditionId, String caller, String reason) {
458         setManualZenMode(zenMode, conditionId, reason, caller, true /*setRingerMode*/);
459     }
460 
setManualZenMode(int zenMode, Uri conditionId, String reason, String caller, boolean setRingerMode)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 
dump(PrintWriter pw, String prefix)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 
dump(PrintWriter pw, String prefix, String var, ZenModeConfig config)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 
readXml(XmlPullParser parser, boolean forRestore)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 
writeXml(XmlSerializer out, boolean forBackup)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 
getNotificationPolicy()568     public Policy getNotificationPolicy() {
569         return getNotificationPolicy(mConfig);
570     }
571 
getNotificationPolicy(ZenModeConfig config)572     private static Policy getNotificationPolicy(ZenModeConfig config) {
573         return config == null ? null : config.toNotificationPolicy();
574     }
575 
setNotificationPolicy(Policy policy)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      */
cleanUpZenRules()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      */
getConfig()612     public ZenModeConfig getConfig() {
613         synchronized (mConfig) {
614             return mConfig.copy();
615         }
616     }
617 
setConfigLocked(ZenModeConfig config, String reason)618     public boolean setConfigLocked(ZenModeConfig config, String reason) {
619         return setConfigLocked(config, reason, true /*setRingerMode*/);
620     }
621 
setConfigAsync(ZenModeConfig config, String reason)622     public void setConfigAsync(ZenModeConfig config, String reason) {
623         mHandler.postSetConfig(config, reason);
624     }
625 
setConfigLocked(ZenModeConfig config, String reason, boolean setRingerMode)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 
applyConfig(ZenModeConfig config, String reason, boolean setRingerMode)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 
getZenModeSetting()668     private int getZenModeSetting() {
669         return Global.getInt(mContext.getContentResolver(), Global.ZEN_MODE, Global.ZEN_MODE_OFF);
670     }
671 
setZenModeSetting(int zen)672     private void setZenModeSetting(int zen) {
673         Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zen);
674     }
675 
getPreviousRingerModeSetting()676     private int getPreviousRingerModeSetting() {
677         return Global.getInt(mContext.getContentResolver(),
678                 Global.ZEN_MODE_RINGER_LEVEL, AudioManager.RINGER_MODE_NORMAL);
679     }
680 
setPreviousRingerModeSetting(Integer previousRingerLevel)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 
evaluateZenMode(String reason, boolean setRingerMode)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 
updateRingerModeAffectedStreams()705     private void updateRingerModeAffectedStreams() {
706         if (mAudioManager != null) {
707             mAudioManager.updateRingerModeAffectedStreamsInternal();
708         }
709     }
710 
computeZenMode()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 
applyRestrictions()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 
applyRestrictions(boolean mute, int usage)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 
applyZenToRingerMode()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 
dispatchOnConfigChanged()786     private void dispatchOnConfigChanged() {
787         for (Callback callback : mCallbacks) {
788             callback.onConfigChanged();
789         }
790     }
791 
dispatchOnPolicyChanged()792     private void dispatchOnPolicyChanged() {
793         for (Callback callback : mCallbacks) {
794             callback.onPolicyChanged();
795         }
796     }
797 
dispatchOnZenModeChanged()798     private void dispatchOnZenModeChanged() {
799         for (Callback callback : mCallbacks) {
800             callback.onZenModeChanged();
801         }
802     }
803 
readDefaultConfig(Resources resources)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 
appendDefaultScheduleRules(ZenModeConfig config)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 
appendDefaultEventRules(ZenModeConfig config)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 
zenSeverity(int zen)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
toString()922         public String toString() {
923             return TAG;
924         }
925 
926         @Override
onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller, int ringerModeExternal, VolumePolicy policy)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
onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller, int ringerModeInternal, VolumePolicy policy)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
canVolumeDownEnterSilent()1005         public boolean canVolumeDownEnterSilent() {
1006             return mZenMode == Global.ZEN_MODE_OFF;
1007         }
1008 
1009         @Override
getRingerModeAffectedStreams(int streams)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 
SettingsObserver(Handler handler)1031         public SettingsObserver(Handler handler) {
1032             super(handler);
1033         }
1034 
observe()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
onChange(boolean selfChange, Uri uri)1042         public void onChange(boolean selfChange, Uri uri) {
1043             update(uri);
1044         }
1045 
update(Uri uri)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
onZenModeChanged()1064         void onZenModeChanged() {
1065             emit();
1066         }
1067 
emit()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 
ConfigMessageData(ZenModeConfig config, String reason)1093             ConfigMessageData(ZenModeConfig config, String reason) {
1094                 this.config = config;
1095                 this.reason = reason;
1096                 this.setRingerMode = false;
1097             }
1098 
ConfigMessageData(ZenModeConfig config, String reason, boolean setRingerMode)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 
H(Looper looper)1108         private H(Looper looper) {
1109             super(looper);
1110         }
1111 
postDispatchOnZenModeChanged()1112         private void postDispatchOnZenModeChanged() {
1113             removeMessages(MSG_DISPATCH);
1114             sendEmptyMessage(MSG_DISPATCH);
1115         }
1116 
postMetricsTimer()1117         private void postMetricsTimer() {
1118             removeMessages(MSG_METRICS);
1119             sendEmptyMessageDelayed(MSG_METRICS, METRICS_PERIOD_MS);
1120         }
1121 
postSetConfig(ZenModeConfig config, String reason)1122         private void postSetConfig(ZenModeConfig config, String reason) {
1123             sendMessage(obtainMessage(MSG_SET_CONFIG, new ConfigMessageData(config, reason)));
1124         }
1125 
postApplyConfig(ZenModeConfig config, String reason, boolean setRingerMode)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
handleMessage(Message msg)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 {
onConfigChanged()1155         void onConfigChanged() {}
onZenModeChanged()1156         void onZenModeChanged() {}
onPolicyChanged()1157         void onPolicyChanged() {}
1158     }
1159 
1160 }
1161