• 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.app.NotificationManager.AUTOMATIC_RULE_STATUS_DISABLED;
20 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ENABLED;
21 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_REMOVED;
22 import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_ANY;
23 import static android.service.notification.DNDModeProto.ROOT_CONFIG;
24 import static android.util.StatsLog.ANNOTATION_ID_IS_UID;
25 
26 import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
27 
28 import android.app.AppOpsManager;
29 import android.app.AutomaticZenRule;
30 import android.app.Notification;
31 import android.app.NotificationManager;
32 import android.app.NotificationManager.Policy;
33 import android.app.PendingIntent;
34 import android.content.ComponentName;
35 import android.content.ContentResolver;
36 import android.content.Context;
37 import android.content.Intent;
38 import android.content.pm.ActivityInfo;
39 import android.content.pm.PackageItemInfo;
40 import android.content.pm.PackageManager;
41 import android.content.pm.ResolveInfo;
42 import android.content.pm.ServiceInfo;
43 import android.content.res.Resources;
44 import android.content.res.XmlResourceParser;
45 import android.database.ContentObserver;
46 import android.graphics.drawable.Icon;
47 import android.media.AudioAttributes;
48 import android.media.AudioManager;
49 import android.media.AudioManagerInternal;
50 import android.media.AudioSystem;
51 import android.media.VolumePolicy;
52 import android.net.Uri;
53 import android.os.Binder;
54 import android.os.Bundle;
55 import android.os.Handler;
56 import android.os.Looper;
57 import android.os.Message;
58 import android.os.Process;
59 import android.os.SystemClock;
60 import android.os.UserHandle;
61 import android.provider.Settings;
62 import android.provider.Settings.Global;
63 import android.service.notification.Condition;
64 import android.service.notification.ConditionProviderService;
65 import android.service.notification.ZenModeConfig;
66 import android.service.notification.ZenModeConfig.ZenRule;
67 import android.service.notification.ZenModeProto;
68 import android.service.notification.ZenPolicy;
69 import android.util.AndroidRuntimeException;
70 import android.util.ArrayMap;
71 import android.util.Log;
72 import android.util.Slog;
73 import android.util.SparseArray;
74 import android.util.StatsEvent;
75 import android.util.TypedXmlPullParser;
76 import android.util.TypedXmlSerializer;
77 import android.util.proto.ProtoOutputStream;
78 
79 import com.android.internal.R;
80 import com.android.internal.annotations.VisibleForTesting;
81 import com.android.internal.logging.MetricsLogger;
82 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
83 import com.android.internal.notification.SystemNotificationChannels;
84 import com.android.internal.util.XmlUtils;
85 import com.android.server.LocalServices;
86 
87 import libcore.io.IoUtils;
88 
89 import org.xmlpull.v1.XmlPullParser;
90 import org.xmlpull.v1.XmlPullParserException;
91 
92 import java.io.IOException;
93 import java.io.PrintWriter;
94 import java.util.ArrayList;
95 import java.util.List;
96 import java.util.Objects;
97 
98 /**
99  * NotificationManagerService helper for functionality related to zen mode.
100  */
101 public class ZenModeHelper {
102     static final String TAG = "ZenModeHelper";
103     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
104 
105     // The amount of time rules instances can exist without their owning app being installed.
106     private static final int RULE_INSTANCE_GRACE_PERIOD = 1000 * 60 * 60 * 72;
107     static final int RULE_LIMIT_PER_PACKAGE = 100;
108 
109     // pkg|userId => uid
110     protected final ArrayMap<String, Integer> mRulesUidCache = new ArrayMap<>();
111 
112     private final Context mContext;
113     private final H mHandler;
114     private final SettingsObserver mSettingsObserver;
115     private final AppOpsManager mAppOps;
116     @VisibleForTesting protected final NotificationManager mNotificationManager;
117     private final SysUiStatsEvent.BuilderFactory mStatsEventBuilderFactory;
118     @VisibleForTesting protected ZenModeConfig mDefaultConfig;
119     private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
120     private final ZenModeFiltering mFiltering;
121     protected final RingerModeDelegate mRingerModeDelegate = new
122             RingerModeDelegate();
123     @VisibleForTesting protected final ZenModeConditions mConditions;
124     Object mConfigsLock = new Object();
125     @VisibleForTesting final SparseArray<ZenModeConfig> mConfigs = new SparseArray<>();
126     private final Metrics mMetrics = new Metrics();
127     private final ConditionProviders.Config mServiceConfig;
128 
129     @VisibleForTesting protected int mZenMode;
130     @VisibleForTesting protected NotificationManager.Policy mConsolidatedPolicy;
131     private int mUser = UserHandle.USER_SYSTEM;
132     @VisibleForTesting protected ZenModeConfig mConfig;
133     @VisibleForTesting protected AudioManagerInternal mAudioManager;
134     protected PackageManager mPm;
135     private long mSuppressedEffects;
136 
137     public static final long SUPPRESSED_EFFECT_NOTIFICATIONS = 1;
138     public static final long SUPPRESSED_EFFECT_CALLS = 1 << 1;
139     public static final long SUPPRESSED_EFFECT_ALL = SUPPRESSED_EFFECT_CALLS
140             | SUPPRESSED_EFFECT_NOTIFICATIONS;
141 
142     @VisibleForTesting protected boolean mIsBootComplete;
143 
144     private String[] mPriorityOnlyDndExemptPackages;
145 
ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders, SysUiStatsEvent.BuilderFactory statsEventBuilderFactory)146     public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders,
147             SysUiStatsEvent.BuilderFactory statsEventBuilderFactory) {
148         mContext = context;
149         mHandler = new H(looper);
150         addCallback(mMetrics);
151         mAppOps = context.getSystemService(AppOpsManager.class);
152         mNotificationManager = context.getSystemService(NotificationManager.class);
153 
154         mDefaultConfig = readDefaultConfig(mContext.getResources());
155         updateDefaultAutomaticRuleNames();
156         mConfig = mDefaultConfig.copy();
157         synchronized (mConfigsLock) {
158             mConfigs.put(UserHandle.USER_SYSTEM, mConfig);
159         }
160         mConsolidatedPolicy = mConfig.toNotificationPolicy();
161 
162         mSettingsObserver = new SettingsObserver(mHandler);
163         mSettingsObserver.observe();
164         mFiltering = new ZenModeFiltering(mContext);
165         mConditions = new ZenModeConditions(this, conditionProviders);
166         mServiceConfig = conditionProviders.getConfig();
167         mStatsEventBuilderFactory = statsEventBuilderFactory;
168     }
169 
getLooper()170     public Looper getLooper() {
171         return mHandler.getLooper();
172     }
173 
174     @Override
toString()175     public String toString() {
176         return TAG;
177     }
178 
matchesCallFilter(UserHandle userHandle, Bundle extras, ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity, int callingUid)179     public boolean matchesCallFilter(UserHandle userHandle, Bundle extras,
180             ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity,
181             int callingUid) {
182         synchronized (mConfig) {
183             return ZenModeFiltering.matchesCallFilter(mContext, mZenMode, mConsolidatedPolicy,
184                     userHandle, extras, validator, contactsTimeoutMs, timeoutAffinity,
185                     callingUid);
186         }
187     }
188 
isCall(NotificationRecord record)189     public boolean isCall(NotificationRecord record) {
190         return mFiltering.isCall(record);
191     }
192 
recordCaller(NotificationRecord record)193     public void recordCaller(NotificationRecord record) {
194         mFiltering.recordCall(record);
195     }
196 
cleanUpCallersAfter(long timeThreshold)197     protected void cleanUpCallersAfter(long timeThreshold) {
198         mFiltering.cleanUpCallersAfter(timeThreshold);
199     }
200 
shouldIntercept(NotificationRecord record)201     public boolean shouldIntercept(NotificationRecord record) {
202         synchronized (mConfig) {
203             return mFiltering.shouldIntercept(mZenMode, mConsolidatedPolicy, record);
204         }
205     }
206 
addCallback(Callback callback)207     public void addCallback(Callback callback) {
208         mCallbacks.add(callback);
209     }
210 
removeCallback(Callback callback)211     public void removeCallback(Callback callback) {
212         mCallbacks.remove(callback);
213     }
214 
initZenMode()215     public void initZenMode() {
216         if (DEBUG) Log.d(TAG, "initZenMode");
217         evaluateZenMode("init", true /*setRingerMode*/);
218     }
219 
onSystemReady()220     public void onSystemReady() {
221         if (DEBUG) Log.d(TAG, "onSystemReady");
222         mAudioManager = LocalServices.getService(AudioManagerInternal.class);
223         if (mAudioManager != null) {
224             mAudioManager.setRingerModeDelegate(mRingerModeDelegate);
225         }
226         mPm = mContext.getPackageManager();
227         mHandler.postMetricsTimer();
228         cleanUpZenRules();
229         evaluateZenMode("onSystemReady", true);
230         mIsBootComplete = true;
231         showZenUpgradeNotification(mZenMode);
232     }
233 
onUserSwitched(int user)234     public void onUserSwitched(int user) {
235         loadConfigForUser(user, "onUserSwitched");
236     }
237 
onUserRemoved(int user)238     public void onUserRemoved(int user) {
239         if (user < UserHandle.USER_SYSTEM) return;
240         if (DEBUG) Log.d(TAG, "onUserRemoved u=" + user);
241         synchronized (mConfigsLock) {
242             mConfigs.remove(user);
243         }
244     }
245 
onUserUnlocked(int user)246     public void onUserUnlocked(int user) {
247         loadConfigForUser(user, "onUserUnlocked");
248     }
249 
setPriorityOnlyDndExemptPackages(String[] packages)250     void setPriorityOnlyDndExemptPackages(String[] packages) {
251         mPriorityOnlyDndExemptPackages = packages;
252     }
253 
loadConfigForUser(int user, String reason)254     private void loadConfigForUser(int user, String reason) {
255         if (mUser == user || user < UserHandle.USER_SYSTEM) return;
256         mUser = user;
257         if (DEBUG) Log.d(TAG, reason + " u=" + user);
258         ZenModeConfig config = null;
259         synchronized (mConfigsLock) {
260             if (mConfigs.get(user) != null) {
261                 config = mConfigs.get(user).copy();
262             }
263         }
264         if (config == null) {
265             if (DEBUG) Log.d(TAG, reason + " generating default config for user " + user);
266             config = mDefaultConfig.copy();
267             config.user = user;
268         }
269         synchronized (mConfig) {
270             setConfigLocked(config, null, reason);
271         }
272         cleanUpZenRules();
273     }
274 
getZenModeListenerInterruptionFilter()275     public int getZenModeListenerInterruptionFilter() {
276         return NotificationManager.zenModeToInterruptionFilter(mZenMode);
277     }
278 
requestFromListener(ComponentName name, int filter)279     public void requestFromListener(ComponentName name, int filter) {
280         final int newZen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
281         if (newZen != -1) {
282             setManualZenMode(newZen, null, name != null ? name.getPackageName() : null,
283                     "listener:" + (name != null ? name.flattenToShortString() : null));
284         }
285     }
286 
setSuppressedEffects(long suppressedEffects)287     public void setSuppressedEffects(long suppressedEffects) {
288         if (mSuppressedEffects == suppressedEffects) return;
289         mSuppressedEffects = suppressedEffects;
290         applyRestrictions();
291     }
292 
getSuppressedEffects()293     public long getSuppressedEffects() {
294         return mSuppressedEffects;
295     }
296 
getZenMode()297     public int getZenMode() {
298         return mZenMode;
299     }
300 
getZenRules()301     public List<ZenRule> getZenRules() {
302         List<ZenRule> rules = new ArrayList<>();
303         synchronized (mConfig) {
304             if (mConfig == null) return rules;
305             for (ZenRule rule : mConfig.automaticRules.values()) {
306                 if (canManageAutomaticZenRule(rule)) {
307                     rules.add(rule);
308                 }
309             }
310         }
311         return rules;
312     }
313 
getAutomaticZenRule(String id)314     public AutomaticZenRule getAutomaticZenRule(String id) {
315         ZenRule rule;
316         synchronized (mConfig) {
317             if (mConfig == null) return null;
318              rule = mConfig.automaticRules.get(id);
319         }
320         if (rule == null) return null;
321         if (canManageAutomaticZenRule(rule)) {
322              return createAutomaticZenRule(rule);
323         }
324         return null;
325     }
326 
addAutomaticZenRule(String pkg, AutomaticZenRule automaticZenRule, String reason)327     public String addAutomaticZenRule(String pkg, AutomaticZenRule automaticZenRule,
328             String reason) {
329         if (!ZenModeConfig.SYSTEM_AUTHORITY.equals(pkg)) {
330             PackageItemInfo component = getServiceInfo(automaticZenRule.getOwner());
331             if (component == null) {
332                 component = getActivityInfo(automaticZenRule.getConfigurationActivity());
333             }
334             if (component == null) {
335                 throw new IllegalArgumentException("Lacking enabled CPS or config activity");
336             }
337             int ruleInstanceLimit = -1;
338             if (component.metaData != null) {
339                 ruleInstanceLimit = component.metaData.getInt(
340                         ConditionProviderService.META_DATA_RULE_INSTANCE_LIMIT, -1);
341             }
342             int newRuleInstanceCount = getCurrentInstanceCount(automaticZenRule.getOwner())
343                     + getCurrentInstanceCount(automaticZenRule.getConfigurationActivity())
344                     + 1;
345             int newPackageRuleCount = getPackageRuleCount(pkg) + 1;
346             if (newPackageRuleCount > RULE_LIMIT_PER_PACKAGE
347                     || (ruleInstanceLimit > 0 && ruleInstanceLimit < newRuleInstanceCount)) {
348                 throw new IllegalArgumentException("Rule instance limit exceeded");
349             }
350         }
351 
352         ZenModeConfig newConfig;
353         synchronized (mConfig) {
354             if (mConfig == null) {
355                 throw new AndroidRuntimeException("Could not create rule");
356             }
357             if (DEBUG) {
358                 Log.d(TAG, "addAutomaticZenRule rule= " + automaticZenRule + " reason=" + reason);
359             }
360             newConfig = mConfig.copy();
361             ZenRule rule = new ZenRule();
362             populateZenRule(pkg, automaticZenRule, rule, true);
363             newConfig.automaticRules.put(rule.id, rule);
364             if (setConfigLocked(newConfig, reason, rule.component, true)) {
365                 return rule.id;
366             } else {
367                 throw new AndroidRuntimeException("Could not create rule");
368             }
369         }
370     }
371 
updateAutomaticZenRule(String ruleId, AutomaticZenRule automaticZenRule, String reason)372     public boolean updateAutomaticZenRule(String ruleId, AutomaticZenRule automaticZenRule,
373             String reason) {
374         ZenModeConfig newConfig;
375         synchronized (mConfig) {
376             if (mConfig == null) return false;
377             if (DEBUG) {
378                 Log.d(TAG, "updateAutomaticZenRule zenRule=" + automaticZenRule
379                         + " reason=" + reason);
380             }
381             newConfig = mConfig.copy();
382             ZenModeConfig.ZenRule rule;
383             if (ruleId == null) {
384                 throw new IllegalArgumentException("Rule doesn't exist");
385             } else {
386                 rule = newConfig.automaticRules.get(ruleId);
387                 if (rule == null || !canManageAutomaticZenRule(rule)) {
388                     throw new SecurityException(
389                             "Cannot update rules not owned by your condition provider");
390                 }
391             }
392             if (rule.enabled != automaticZenRule.isEnabled()) {
393                 dispatchOnAutomaticRuleStatusChanged(mConfig.user, rule.getPkg(), ruleId,
394                         automaticZenRule.isEnabled()
395                                 ? AUTOMATIC_RULE_STATUS_ENABLED : AUTOMATIC_RULE_STATUS_DISABLED);
396             }
397 
398             populateZenRule(rule.pkg, automaticZenRule, rule, false);
399             return setConfigLocked(newConfig, reason, rule.component, true);
400         }
401     }
402 
removeAutomaticZenRule(String id, String reason)403     public boolean removeAutomaticZenRule(String id, String reason) {
404         ZenModeConfig newConfig;
405         synchronized (mConfig) {
406             if (mConfig == null) return false;
407             newConfig = mConfig.copy();
408             ZenRule ruleToRemove = newConfig.automaticRules.get(id);
409             if (ruleToRemove == null) return false;
410             if (canManageAutomaticZenRule(ruleToRemove)) {
411                 newConfig.automaticRules.remove(id);
412                 if (ruleToRemove.getPkg() != null && !"android".equals(ruleToRemove.getPkg())) {
413                     for (ZenRule currRule : newConfig.automaticRules.values()) {
414                         if (currRule.getPkg() != null
415                                 && currRule.getPkg().equals(ruleToRemove.getPkg())) {
416                             break; // no need to remove from cache
417                         }
418                     }
419                     mRulesUidCache.remove(getPackageUserKey(ruleToRemove.getPkg(), newConfig.user));
420                 }
421                 if (DEBUG) Log.d(TAG, "removeZenRule zenRule=" + id + " reason=" + reason);
422             } else {
423                 throw new SecurityException(
424                         "Cannot delete rules not owned by your condition provider");
425             }
426             dispatchOnAutomaticRuleStatusChanged(
427                     mConfig.user, ruleToRemove.getPkg(), id, AUTOMATIC_RULE_STATUS_REMOVED);
428             return setConfigLocked(newConfig, reason, null, true);
429         }
430     }
431 
removeAutomaticZenRules(String packageName, String reason)432     public boolean removeAutomaticZenRules(String packageName, String reason) {
433         ZenModeConfig newConfig;
434         synchronized (mConfig) {
435             if (mConfig == null) return false;
436             newConfig = mConfig.copy();
437             for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
438                 ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
439                 if (Objects.equals(rule.getPkg(), packageName) && canManageAutomaticZenRule(rule)) {
440                     newConfig.automaticRules.removeAt(i);
441                 }
442             }
443             return setConfigLocked(newConfig, reason, null, true);
444         }
445     }
446 
setAutomaticZenRuleState(String id, Condition condition)447     public void setAutomaticZenRuleState(String id, Condition condition) {
448         ZenModeConfig newConfig;
449         synchronized (mConfig) {
450             if (mConfig == null) return;
451 
452             newConfig = mConfig.copy();
453             ArrayList<ZenRule> rules = new ArrayList<>();
454             rules.add(newConfig.automaticRules.get(id));
455             setAutomaticZenRuleStateLocked(newConfig, rules, condition);
456         }
457     }
458 
setAutomaticZenRuleState(Uri ruleDefinition, Condition condition)459     public void setAutomaticZenRuleState(Uri ruleDefinition, Condition condition) {
460         ZenModeConfig newConfig;
461         synchronized (mConfig) {
462             if (mConfig == null) return;
463             newConfig = mConfig.copy();
464 
465             setAutomaticZenRuleStateLocked(newConfig,
466                     findMatchingRules(newConfig, ruleDefinition, condition),
467                     condition);
468         }
469     }
470 
setAutomaticZenRuleStateLocked(ZenModeConfig config, List<ZenRule> rules, Condition condition)471     private void setAutomaticZenRuleStateLocked(ZenModeConfig config, List<ZenRule> rules,
472             Condition condition) {
473         if (rules == null || rules.isEmpty()) return;
474 
475         for (ZenRule rule : rules) {
476             rule.condition = condition;
477             updateSnoozing(rule);
478             setConfigLocked(config, rule.component, "conditionChanged");
479         }
480     }
481 
findMatchingRules(ZenModeConfig config, Uri id, Condition condition)482     private List<ZenRule> findMatchingRules(ZenModeConfig config, Uri id, Condition condition) {
483         List<ZenRule> matchingRules= new ArrayList<>();
484         if (ruleMatches(id, condition, config.manualRule)) {
485             matchingRules.add(config.manualRule);
486         } else {
487             for (ZenRule automaticRule : config.automaticRules.values()) {
488                 if (ruleMatches(id, condition, automaticRule)) {
489                     matchingRules.add(automaticRule);
490                 }
491             }
492         }
493         return matchingRules;
494     }
495 
ruleMatches(Uri id, Condition condition, ZenRule rule)496     private boolean ruleMatches(Uri id, Condition condition, ZenRule rule) {
497         if (id == null || rule == null || rule.conditionId == null) return false;
498         if (!rule.conditionId.equals(id)) return false;
499         if (Objects.equals(condition, rule.condition)) return false;
500         return true;
501     }
502 
updateSnoozing(ZenRule rule)503     private boolean updateSnoozing(ZenRule rule) {
504         if (rule != null && rule.snoozing && !rule.isTrueOrUnknown()) {
505             rule.snoozing = false;
506             if (DEBUG) Log.d(TAG, "Snoozing reset for " + rule.conditionId);
507             return true;
508         }
509         return false;
510     }
511 
getCurrentInstanceCount(ComponentName cn)512     public int getCurrentInstanceCount(ComponentName cn) {
513         if (cn == null) {
514             return 0;
515         }
516         int count = 0;
517         synchronized (mConfig) {
518             for (ZenRule rule : mConfig.automaticRules.values()) {
519                 if (cn.equals(rule.component) || cn.equals(rule.configurationActivity)) {
520                     count++;
521                 }
522             }
523         }
524         return count;
525     }
526 
527     // Equivalent method to getCurrentInstanceCount, but for all rules associated with a specific
528     // package rather than a condition provider service or activity.
getPackageRuleCount(String pkg)529     private int getPackageRuleCount(String pkg) {
530         if (pkg == null) {
531             return 0;
532         }
533         int count = 0;
534         synchronized (mConfig) {
535             for (ZenRule rule : mConfig.automaticRules.values()) {
536                 if (pkg.equals(rule.getPkg())) {
537                     count++;
538                 }
539             }
540         }
541         return count;
542     }
543 
canManageAutomaticZenRule(ZenRule rule)544     public boolean canManageAutomaticZenRule(ZenRule rule) {
545         final int callingUid = Binder.getCallingUid();
546         if (callingUid == 0 || callingUid == Process.SYSTEM_UID) {
547             return true;
548         } else if (mContext.checkCallingPermission(android.Manifest.permission.MANAGE_NOTIFICATIONS)
549                 == PackageManager.PERMISSION_GRANTED) {
550             return true;
551         } else {
552             String[] packages = mPm.getPackagesForUid(Binder.getCallingUid());
553             if (packages != null) {
554                 final int packageCount = packages.length;
555                 for (int i = 0; i < packageCount; i++) {
556                     if (packages[i].equals(rule.getPkg())) {
557                         return true;
558                     }
559                 }
560             }
561             return false;
562         }
563     }
564 
updateDefaultZenRules()565     protected void updateDefaultZenRules() {
566         updateDefaultAutomaticRuleNames();
567         for (ZenRule defaultRule : mDefaultConfig.automaticRules.values()) {
568             ZenRule currRule = mConfig.automaticRules.get(defaultRule.id);
569             // if default rule wasn't user-modified nor enabled, use localized name
570             // instead of previous system name
571             if (currRule != null && !currRule.modified && !currRule.enabled
572                     && !defaultRule.name.equals(currRule.name)) {
573                 if (canManageAutomaticZenRule(currRule)) {
574                     if (DEBUG) Slog.d(TAG, "Locale change - updating default zen rule name "
575                             + "from " + currRule.name + " to " + defaultRule.name);
576                     // update default rule (if locale changed, name of rule will change)
577                     currRule.name = defaultRule.name;
578                     updateAutomaticZenRule(defaultRule.id, createAutomaticZenRule(currRule),
579                             "locale changed");
580                 }
581             }
582         }
583     }
584 
getServiceInfo(ComponentName owner)585     private ServiceInfo getServiceInfo(ComponentName owner) {
586         Intent queryIntent = new Intent();
587         queryIntent.setComponent(owner);
588         List<ResolveInfo> installedServices = mPm.queryIntentServicesAsUser(
589                 queryIntent,
590                 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
591                 UserHandle.getCallingUserId());
592         if (installedServices != null) {
593             for (int i = 0, count = installedServices.size(); i < count; i++) {
594                 ResolveInfo resolveInfo = installedServices.get(i);
595                 ServiceInfo info = resolveInfo.serviceInfo;
596                 if (mServiceConfig.bindPermission.equals(info.permission)) {
597                     return info;
598                 }
599             }
600         }
601         return null;
602     }
603 
getActivityInfo(ComponentName configActivity)604     private ActivityInfo getActivityInfo(ComponentName configActivity) {
605         Intent queryIntent = new Intent();
606         queryIntent.setComponent(configActivity);
607         List<ResolveInfo> installedComponents = mPm.queryIntentActivitiesAsUser(
608                 queryIntent,
609                 PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA,
610                 UserHandle.getCallingUserId());
611         if (installedComponents != null) {
612             for (int i = 0, count = installedComponents.size(); i < count; i++) {
613                 ResolveInfo resolveInfo = installedComponents.get(i);
614                 return resolveInfo.activityInfo;
615             }
616         }
617         return null;
618     }
619 
populateZenRule(String pkg, AutomaticZenRule automaticZenRule, ZenRule rule, boolean isNew)620     private void populateZenRule(String pkg, AutomaticZenRule automaticZenRule, ZenRule rule,
621             boolean isNew) {
622         rule.name = automaticZenRule.getName();
623         rule.condition = null;
624         rule.conditionId = automaticZenRule.getConditionId();
625         rule.enabled = automaticZenRule.isEnabled();
626         rule.modified = automaticZenRule.isModified();
627         rule.zenPolicy = automaticZenRule.getZenPolicy();
628         rule.zenMode = NotificationManager.zenModeFromInterruptionFilter(
629                 automaticZenRule.getInterruptionFilter(), Global.ZEN_MODE_OFF);
630         rule.configurationActivity = automaticZenRule.getConfigurationActivity();
631 
632         if (isNew) {
633             rule.id = ZenModeConfig.newRuleId();
634             rule.creationTime = System.currentTimeMillis();
635             rule.component = automaticZenRule.getOwner();
636             rule.pkg = pkg;
637         }
638 
639         if (rule.enabled != automaticZenRule.isEnabled()) {
640             rule.snoozing = false;
641         }
642     }
643 
createAutomaticZenRule(ZenRule rule)644     protected AutomaticZenRule createAutomaticZenRule(ZenRule rule) {
645         AutomaticZenRule azr =  new AutomaticZenRule(rule.name, rule.component,
646                 rule.configurationActivity,
647                 rule.conditionId, rule.zenPolicy,
648                 NotificationManager.zenModeToInterruptionFilter(rule.zenMode),
649                 rule.enabled, rule.creationTime);
650         azr.setPackageName(rule.pkg);
651         return azr;
652     }
653 
setManualZenMode(int zenMode, Uri conditionId, String caller, String reason)654     public void setManualZenMode(int zenMode, Uri conditionId, String caller, String reason) {
655         setManualZenMode(zenMode, conditionId, reason, caller, true /*setRingerMode*/);
656         Settings.Secure.putInt(mContext.getContentResolver(),
657                 Settings.Secure.SHOW_ZEN_SETTINGS_SUGGESTION, 0);
658     }
659 
setManualZenMode(int zenMode, Uri conditionId, String reason, String caller, boolean setRingerMode)660     private void setManualZenMode(int zenMode, Uri conditionId, String reason, String caller,
661             boolean setRingerMode) {
662         ZenModeConfig newConfig;
663         synchronized (mConfig) {
664             if (mConfig == null) return;
665             if (!Global.isValidZenMode(zenMode)) return;
666             if (DEBUG) Log.d(TAG, "setManualZenMode " + Global.zenModeToString(zenMode)
667                     + " conditionId=" + conditionId + " reason=" + reason
668                     + " setRingerMode=" + setRingerMode);
669             newConfig = mConfig.copy();
670             if (zenMode == Global.ZEN_MODE_OFF) {
671                 newConfig.manualRule = null;
672                 for (ZenRule automaticRule : newConfig.automaticRules.values()) {
673                     if (automaticRule.isAutomaticActive()) {
674                         automaticRule.snoozing = true;
675                     }
676                 }
677             } else {
678                 final ZenRule newRule = new ZenRule();
679                 newRule.enabled = true;
680                 newRule.zenMode = zenMode;
681                 newRule.conditionId = conditionId;
682                 newRule.enabler = caller;
683                 newConfig.manualRule = newRule;
684             }
685             setConfigLocked(newConfig, reason, null, setRingerMode);
686         }
687     }
688 
dump(ProtoOutputStream proto)689     void dump(ProtoOutputStream proto) {
690         proto.write(ZenModeProto.ZEN_MODE, mZenMode);
691         synchronized (mConfig) {
692             if (mConfig.manualRule != null) {
693                 mConfig.manualRule.dumpDebug(proto, ZenModeProto.ENABLED_ACTIVE_CONDITIONS);
694             }
695             for (ZenRule rule : mConfig.automaticRules.values()) {
696                 if (rule.enabled && rule.condition != null
697                         && rule.condition.state == Condition.STATE_TRUE
698                         && !rule.snoozing) {
699                     rule.dumpDebug(proto, ZenModeProto.ENABLED_ACTIVE_CONDITIONS);
700                 }
701             }
702             mConfig.toNotificationPolicy().dumpDebug(proto, ZenModeProto.POLICY);
703             proto.write(ZenModeProto.SUPPRESSED_EFFECTS, mSuppressedEffects);
704         }
705     }
706 
dump(PrintWriter pw, String prefix)707     public void dump(PrintWriter pw, String prefix) {
708         pw.print(prefix);
709         pw.print("mZenMode=");
710         pw.println(Global.zenModeToString(mZenMode));
711         pw.print(prefix);
712         pw.println("mConsolidatedPolicy=" + mConsolidatedPolicy.toString());
713         synchronized(mConfigsLock) {
714             final int N = mConfigs.size();
715             for (int i = 0; i < N; i++) {
716                 dump(pw, prefix, "mConfigs[u=" + mConfigs.keyAt(i) + "]", mConfigs.valueAt(i));
717             }
718         }
719         pw.print(prefix); pw.print("mUser="); pw.println(mUser);
720         synchronized (mConfig) {
721             dump(pw, prefix, "mConfig", mConfig);
722         }
723 
724         pw.print(prefix); pw.print("mSuppressedEffects="); pw.println(mSuppressedEffects);
725         mFiltering.dump(pw, prefix);
726         mConditions.dump(pw, prefix);
727     }
728 
dump(PrintWriter pw, String prefix, String var, ZenModeConfig config)729     private static void dump(PrintWriter pw, String prefix, String var, ZenModeConfig config) {
730         pw.print(prefix); pw.print(var); pw.print('=');
731         if (config == null) {
732             pw.println(config);
733             return;
734         }
735         pw.printf("allow(alarms=%b,media=%b,system=%b,calls=%b,callsFrom=%s,repeatCallers=%b,"
736                 + "messages=%b,messagesFrom=%s,conversations=%b,conversationsFrom=%s,"
737                         + "events=%b,reminders=%b)\n",
738                 config.allowAlarms, config.allowMedia, config.allowSystem,
739                 config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom),
740                 config.allowRepeatCallers, config.allowMessages,
741                 ZenModeConfig.sourceToString(config.allowMessagesFrom),
742                 config.allowConversations,
743                 ZenPolicy.conversationTypeToString(config.allowConversationsFrom),
744                 config.allowEvents, config.allowReminders);
745         pw.print(prefix);
746         pw.printf("  disallow(visualEffects=%s)\n", config.suppressedVisualEffects);
747         pw.print(prefix); pw.print("  manualRule="); pw.println(config.manualRule);
748         if (config.automaticRules.isEmpty()) return;
749         final int N = config.automaticRules.size();
750         for (int i = 0; i < N; i++) {
751             pw.print(prefix); pw.print(i == 0 ? "  automaticRules=" : "                 ");
752             pw.println(config.automaticRules.valueAt(i));
753         }
754     }
755 
readXml(TypedXmlPullParser parser, boolean forRestore, int userId)756     public void readXml(TypedXmlPullParser parser, boolean forRestore, int userId)
757             throws XmlPullParserException, IOException {
758         ZenModeConfig config = ZenModeConfig.readXml(parser);
759         String reason = "readXml";
760 
761         if (config != null) {
762             if (forRestore) {
763                 config.user = userId;
764                 config.manualRule = null;  // don't restore the manual rule
765             }
766 
767             // booleans to determine whether to reset the rules to the default rules
768             boolean allRulesDisabled = true;
769             boolean hasDefaultRules = config.automaticRules.containsAll(
770                     ZenModeConfig.DEFAULT_RULE_IDS);
771 
772             long time = System.currentTimeMillis();
773             if (config.automaticRules != null && config.automaticRules.size() > 0) {
774                 for (ZenRule automaticRule : config.automaticRules.values()) {
775                     if (forRestore) {
776                         // don't restore transient state from restored automatic rules
777                         automaticRule.snoozing = false;
778                         automaticRule.condition = null;
779                         automaticRule.creationTime = time;
780                     }
781 
782                     allRulesDisabled &= !automaticRule.enabled;
783                 }
784             }
785 
786             if (!hasDefaultRules && allRulesDisabled
787                     && (forRestore || config.version < ZenModeConfig.XML_VERSION)) {
788                 // reset zen automatic rules to default on restore or upgrade if:
789                 // - doesn't already have default rules and
790                 // - all previous automatic rules were disabled
791                 config.automaticRules = new ArrayMap<>();
792                 for (ZenRule rule : mDefaultConfig.automaticRules.values()) {
793                     config.automaticRules.put(rule.id, rule);
794                 }
795                 reason += ", reset to default rules";
796             }
797 
798             // Resolve user id for settings.
799             userId = userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId;
800             if (config.version < ZenModeConfig.XML_VERSION) {
801                 Settings.Secure.putIntForUser(mContext.getContentResolver(),
802                         Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 1, userId);
803             } else {
804                 // devices not restoring/upgrading already have updated zen settings
805                 Settings.Secure.putIntForUser(mContext.getContentResolver(),
806                         Settings.Secure.ZEN_SETTINGS_UPDATED, 1, userId);
807             }
808             if (DEBUG) Log.d(TAG, reason);
809             synchronized (mConfig) {
810                 setConfigLocked(config, null, reason);
811             }
812         }
813     }
814 
writeXml(TypedXmlSerializer out, boolean forBackup, Integer version, int userId)815     public void writeXml(TypedXmlSerializer out, boolean forBackup, Integer version, int userId)
816             throws IOException {
817         synchronized (mConfigsLock) {
818             final int n = mConfigs.size();
819             for (int i = 0; i < n; i++) {
820                 if (forBackup && mConfigs.keyAt(i) != userId) {
821                     continue;
822                 }
823                 mConfigs.valueAt(i).writeXml(out, version);
824             }
825         }
826     }
827 
828     /**
829      * @return user-specified default notification policy for priority only do not disturb
830      */
getNotificationPolicy()831     public Policy getNotificationPolicy() {
832         return getNotificationPolicy(mConfig);
833     }
834 
getNotificationPolicy(ZenModeConfig config)835     private static Policy getNotificationPolicy(ZenModeConfig config) {
836         return config == null ? null : config.toNotificationPolicy();
837     }
838 
839     /**
840      * Sets the global notification policy used for priority only do not disturb
841      */
setNotificationPolicy(Policy policy)842     public void setNotificationPolicy(Policy policy) {
843         if (policy == null || mConfig == null) return;
844         synchronized (mConfig) {
845             final ZenModeConfig newConfig = mConfig.copy();
846             newConfig.applyNotificationPolicy(policy);
847             setConfigLocked(newConfig, null, "setNotificationPolicy");
848         }
849     }
850 
851     /**
852      * Removes old rule instances whose owner is not installed.
853      */
cleanUpZenRules()854     private void cleanUpZenRules() {
855         long currentTime = System.currentTimeMillis();
856         synchronized (mConfig) {
857             final ZenModeConfig newConfig = mConfig.copy();
858             if (newConfig.automaticRules != null) {
859                 for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
860                     ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
861                     if (RULE_INSTANCE_GRACE_PERIOD < (currentTime - rule.creationTime)) {
862                         try {
863                             if (rule.getPkg() != null) {
864                                 mPm.getPackageInfo(rule.getPkg(), PackageManager.MATCH_ANY_USER);
865                             }
866                         } catch (PackageManager.NameNotFoundException e) {
867                             newConfig.automaticRules.removeAt(i);
868                         }
869                     }
870                 }
871             }
872             setConfigLocked(newConfig, null, "cleanUpZenRules");
873         }
874     }
875 
876     /**
877      * @return a copy of the zen mode configuration
878      */
getConfig()879     public ZenModeConfig getConfig() {
880         synchronized (mConfig) {
881             return mConfig.copy();
882         }
883     }
884 
885     /**
886      * @return a copy of the zen mode consolidated policy
887      */
getConsolidatedNotificationPolicy()888     public Policy getConsolidatedNotificationPolicy() {
889         return mConsolidatedPolicy.copy();
890     }
891 
setConfigLocked(ZenModeConfig config, ComponentName triggeringComponent, String reason)892     public boolean setConfigLocked(ZenModeConfig config, ComponentName triggeringComponent,
893             String reason) {
894         return setConfigLocked(config, reason, triggeringComponent, true /*setRingerMode*/);
895     }
896 
setConfig(ZenModeConfig config, ComponentName triggeringComponent, String reason)897     public void setConfig(ZenModeConfig config, ComponentName triggeringComponent, String reason) {
898         synchronized (mConfig) {
899             setConfigLocked(config, triggeringComponent, reason);
900         }
901     }
902 
setConfigLocked(ZenModeConfig config, String reason, ComponentName triggeringComponent, boolean setRingerMode)903     private boolean setConfigLocked(ZenModeConfig config, String reason,
904             ComponentName triggeringComponent, boolean setRingerMode) {
905         final long identity = Binder.clearCallingIdentity();
906         try {
907             if (config == null || !config.isValid()) {
908                 Log.w(TAG, "Invalid config in setConfigLocked; " + config);
909                 return false;
910             }
911             if (config.user != mUser) {
912                 // simply store away for background users
913                 synchronized (mConfigsLock) {
914                     mConfigs.put(config.user, config);
915                 }
916                 if (DEBUG) Log.d(TAG, "setConfigLocked: store config for user " + config.user);
917                 return true;
918             }
919             // handle CPS backed conditions - danger! may modify config
920             mConditions.evaluateConfig(config, null, false /*processSubscriptions*/);
921 
922             synchronized (mConfigsLock) {
923                 mConfigs.put(config.user, config);
924             }
925             if (DEBUG) Log.d(TAG, "setConfigLocked reason=" + reason, new Throwable());
926             ZenLog.traceConfig(reason, mConfig, config);
927 
928             // send some broadcasts
929             final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
930                     getNotificationPolicy(config));
931             if (!config.equals(mConfig)) {
932                 mConfig = config;
933                 dispatchOnConfigChanged();
934                 updateConsolidatedPolicy(reason);
935             }
936             if (policyChanged) {
937                 dispatchOnPolicyChanged();
938             }
939             mHandler.postApplyConfig(config, reason, triggeringComponent, setRingerMode);
940             return true;
941         } catch (SecurityException e) {
942             Log.wtf(TAG, "Invalid rule in config", e);
943             return false;
944         } finally {
945             Binder.restoreCallingIdentity(identity);
946         }
947     }
948 
applyConfig(ZenModeConfig config, String reason, ComponentName triggeringComponent, boolean setRingerMode)949     private void applyConfig(ZenModeConfig config, String reason,
950             ComponentName triggeringComponent, boolean setRingerMode) {
951         final String val = Integer.toString(config.hashCode());
952         Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
953         evaluateZenMode(reason, setRingerMode);
954         mConditions.evaluateConfig(config, triggeringComponent, true /*processSubscriptions*/);
955     }
956 
getZenModeSetting()957     private int getZenModeSetting() {
958         return Global.getInt(mContext.getContentResolver(), Global.ZEN_MODE, Global.ZEN_MODE_OFF);
959     }
960 
961     @VisibleForTesting
setZenModeSetting(int zen)962     protected void setZenModeSetting(int zen) {
963         Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zen);
964         showZenUpgradeNotification(zen);
965     }
966 
getPreviousRingerModeSetting()967     private int getPreviousRingerModeSetting() {
968         return Global.getInt(mContext.getContentResolver(),
969                 Global.ZEN_MODE_RINGER_LEVEL, AudioManager.RINGER_MODE_NORMAL);
970     }
971 
setPreviousRingerModeSetting(Integer previousRingerLevel)972     private void setPreviousRingerModeSetting(Integer previousRingerLevel) {
973         Global.putString(
974                 mContext.getContentResolver(), Global.ZEN_MODE_RINGER_LEVEL,
975                 previousRingerLevel == null ? null : Integer.toString(previousRingerLevel));
976     }
977 
978     @VisibleForTesting
evaluateZenMode(String reason, boolean setRingerMode)979     protected void evaluateZenMode(String reason, boolean setRingerMode) {
980         if (DEBUG) Log.d(TAG, "evaluateZenMode");
981         if (mConfig == null) return;
982         final int policyHashBefore = mConsolidatedPolicy == null ? 0
983                 : mConsolidatedPolicy.hashCode();
984         final int zenBefore = mZenMode;
985         final int zen = computeZenMode();
986         ZenLog.traceSetZenMode(zen, reason);
987         mZenMode = zen;
988         setZenModeSetting(mZenMode);
989         updateConsolidatedPolicy(reason);
990         updateRingerModeAffectedStreams();
991         if (setRingerMode && (zen != zenBefore || (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
992                 && policyHashBefore != mConsolidatedPolicy.hashCode()))) {
993             applyZenToRingerMode();
994         }
995         applyRestrictions();
996         if (zen != zenBefore) {
997             mHandler.postDispatchOnZenModeChanged();
998         }
999     }
1000 
updateRingerModeAffectedStreams()1001     private void updateRingerModeAffectedStreams() {
1002         if (mAudioManager != null) {
1003             mAudioManager.updateRingerModeAffectedStreamsInternal();
1004         }
1005     }
1006 
computeZenMode()1007     private int computeZenMode() {
1008         if (mConfig == null) return Global.ZEN_MODE_OFF;
1009         synchronized (mConfig) {
1010             if (mConfig.manualRule != null) return mConfig.manualRule.zenMode;
1011             int zen = Global.ZEN_MODE_OFF;
1012             for (ZenRule automaticRule : mConfig.automaticRules.values()) {
1013                 if (automaticRule.isAutomaticActive()) {
1014                     if (zenSeverity(automaticRule.zenMode) > zenSeverity(zen)) {
1015                         // automatic rule triggered dnd and user hasn't seen update dnd dialog
1016                         if (Settings.Secure.getInt(mContext.getContentResolver(),
1017                                 Settings.Secure.ZEN_SETTINGS_SUGGESTION_VIEWED, 1) == 0) {
1018                             Settings.Secure.putInt(mContext.getContentResolver(),
1019                                     Settings.Secure.SHOW_ZEN_SETTINGS_SUGGESTION, 1);
1020                         }
1021                         zen = automaticRule.zenMode;
1022                     }
1023                 }
1024             }
1025             return zen;
1026         }
1027     }
1028 
applyCustomPolicy(ZenPolicy policy, ZenRule rule)1029     private void applyCustomPolicy(ZenPolicy policy, ZenRule rule) {
1030         if (rule.zenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
1031             policy.apply(new ZenPolicy.Builder()
1032                     .disallowAllSounds()
1033                     .build());
1034         } else if (rule.zenMode == Global.ZEN_MODE_ALARMS) {
1035             policy.apply(new ZenPolicy.Builder()
1036                     .disallowAllSounds()
1037                     .allowAlarms(true)
1038                     .allowMedia(true)
1039                     .build());
1040         } else {
1041             policy.apply(rule.zenPolicy);
1042         }
1043     }
1044 
updateConsolidatedPolicy(String reason)1045     private void updateConsolidatedPolicy(String reason) {
1046         if (mConfig == null) return;
1047         synchronized (mConfig) {
1048             ZenPolicy policy = new ZenPolicy();
1049             if (mConfig.manualRule != null) {
1050                 applyCustomPolicy(policy, mConfig.manualRule);
1051             }
1052 
1053             for (ZenRule automaticRule : mConfig.automaticRules.values()) {
1054                 if (automaticRule.isAutomaticActive()) {
1055                     applyCustomPolicy(policy, automaticRule);
1056                 }
1057             }
1058             Policy newPolicy = mConfig.toNotificationPolicy(policy);
1059             if (!Objects.equals(mConsolidatedPolicy, newPolicy)) {
1060                 mConsolidatedPolicy = newPolicy;
1061                 dispatchOnConsolidatedPolicyChanged();
1062                 ZenLog.traceSetConsolidatedZenPolicy(mConsolidatedPolicy, reason);
1063             }
1064         }
1065     }
1066 
updateDefaultAutomaticRuleNames()1067     private void updateDefaultAutomaticRuleNames() {
1068         for (ZenRule rule : mDefaultConfig.automaticRules.values()) {
1069             if (ZenModeConfig.EVENTS_DEFAULT_RULE_ID.equals(rule.id)) {
1070                 rule.name = mContext.getResources()
1071                         .getString(R.string.zen_mode_default_events_name);
1072             } else if (ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID.equals(rule.id)) {
1073                 rule.name = mContext.getResources()
1074                         .getString(R.string.zen_mode_default_every_night_name);
1075             }
1076         }
1077     }
1078 
1079     @VisibleForTesting
applyRestrictions()1080     protected void applyRestrictions() {
1081         final boolean zenOn = mZenMode != Global.ZEN_MODE_OFF;
1082         final boolean zenPriorityOnly = mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
1083         final boolean zenSilence = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
1084         final boolean zenAlarmsOnly = mZenMode == Global.ZEN_MODE_ALARMS;
1085         final boolean allowCalls = mConsolidatedPolicy.allowCalls()
1086                 && mConsolidatedPolicy.allowCallsFrom() == PRIORITY_SENDERS_ANY;
1087         final boolean allowRepeatCallers = mConsolidatedPolicy.allowRepeatCallers();
1088         final boolean allowSystem = mConsolidatedPolicy.allowSystem();
1089         final boolean allowMedia = mConsolidatedPolicy.allowMedia();
1090         final boolean allowAlarms = mConsolidatedPolicy.allowAlarms();
1091 
1092         // notification restrictions
1093         final boolean muteNotifications = zenOn
1094                 || (mSuppressedEffects & SUPPRESSED_EFFECT_NOTIFICATIONS) != 0;
1095         // call restrictions
1096         final boolean muteCalls = zenAlarmsOnly
1097                 || (zenPriorityOnly && !(allowCalls || allowRepeatCallers))
1098                 || (mSuppressedEffects & SUPPRESSED_EFFECT_CALLS) != 0;
1099         // alarm restrictions
1100         final boolean muteAlarms = zenPriorityOnly && !allowAlarms;
1101         // media restrictions
1102         final boolean muteMedia = zenPriorityOnly && !allowMedia;
1103         // system restrictions
1104         final boolean muteSystem = zenAlarmsOnly || (zenPriorityOnly && !allowSystem);
1105         // total silence restrictions
1106         final boolean muteEverything = zenSilence || (zenPriorityOnly
1107                 && ZenModeConfig.areAllZenBehaviorSoundsMuted(mConsolidatedPolicy));
1108 
1109         for (int usage : AudioAttributes.SDK_USAGES) {
1110             final int suppressionBehavior = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage);
1111             if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NEVER) {
1112                 applyRestrictions(zenPriorityOnly, false /*mute*/, usage);
1113             } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NOTIFICATION) {
1114                 applyRestrictions(zenPriorityOnly, muteNotifications || muteEverything, usage);
1115             } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_CALL) {
1116                 applyRestrictions(zenPriorityOnly, muteCalls || muteEverything, usage);
1117             } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_ALARM) {
1118                 applyRestrictions(zenPriorityOnly, muteAlarms || muteEverything, usage);
1119             } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_MEDIA) {
1120                 applyRestrictions(zenPriorityOnly, muteMedia || muteEverything, usage);
1121             } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_SYSTEM) {
1122                 if (usage == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) {
1123                     // normally DND will only restrict touch sounds, not haptic feedback/vibrations
1124                     applyRestrictions(zenPriorityOnly, muteSystem || muteEverything, usage,
1125                             AppOpsManager.OP_PLAY_AUDIO);
1126                     applyRestrictions(zenPriorityOnly, false, usage, AppOpsManager.OP_VIBRATE);
1127                 } else {
1128                     applyRestrictions(zenPriorityOnly, muteSystem || muteEverything, usage);
1129                 }
1130             } else {
1131                 applyRestrictions(zenPriorityOnly, muteEverything, usage);
1132             }
1133         }
1134     }
1135 
1136 
1137     @VisibleForTesting
applyRestrictions(boolean zenPriorityOnly, boolean mute, int usage, int code)1138     protected void applyRestrictions(boolean zenPriorityOnly, boolean mute, int usage, int code) {
1139         final long ident = Binder.clearCallingIdentity();
1140         try {
1141             mAppOps.setRestriction(code, usage,
1142                     mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
1143                     zenPriorityOnly ? mPriorityOnlyDndExemptPackages : null);
1144         } finally {
1145             Binder.restoreCallingIdentity(ident);
1146         }
1147     }
1148 
1149     @VisibleForTesting
applyRestrictions(boolean zenPriorityOnly, boolean mute, int usage)1150     protected void applyRestrictions(boolean zenPriorityOnly, boolean mute, int usage) {
1151         applyRestrictions(zenPriorityOnly, mute, usage, AppOpsManager.OP_VIBRATE);
1152         applyRestrictions(zenPriorityOnly, mute, usage, AppOpsManager.OP_PLAY_AUDIO);
1153     }
1154 
1155 
1156     @VisibleForTesting
applyZenToRingerMode()1157     protected void applyZenToRingerMode() {
1158         if (mAudioManager == null) return;
1159         // force the ringer mode into compliance
1160         final int ringerModeInternal = mAudioManager.getRingerModeInternal();
1161         int newRingerModeInternal = ringerModeInternal;
1162         switch (mZenMode) {
1163             case Global.ZEN_MODE_NO_INTERRUPTIONS:
1164             case Global.ZEN_MODE_ALARMS:
1165                 if (ringerModeInternal != AudioManager.RINGER_MODE_SILENT) {
1166                     setPreviousRingerModeSetting(ringerModeInternal);
1167                     newRingerModeInternal = AudioManager.RINGER_MODE_SILENT;
1168                 }
1169                 break;
1170             case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
1171                 // do not apply zen to ringer, streams zen muted in AudioService
1172                 break;
1173             case Global.ZEN_MODE_OFF:
1174                 if (ringerModeInternal == AudioManager.RINGER_MODE_SILENT) {
1175                     newRingerModeInternal = getPreviousRingerModeSetting();
1176                     setPreviousRingerModeSetting(null);
1177                 }
1178                 break;
1179         }
1180         if (newRingerModeInternal != -1) {
1181             mAudioManager.setRingerModeInternal(newRingerModeInternal, TAG);
1182         }
1183     }
1184 
dispatchOnConfigChanged()1185     private void dispatchOnConfigChanged() {
1186         for (Callback callback : mCallbacks) {
1187             callback.onConfigChanged();
1188         }
1189     }
1190 
dispatchOnPolicyChanged()1191     private void dispatchOnPolicyChanged() {
1192         for (Callback callback : mCallbacks) {
1193             callback.onPolicyChanged();
1194         }
1195     }
1196 
dispatchOnConsolidatedPolicyChanged()1197     private void dispatchOnConsolidatedPolicyChanged() {
1198         for (Callback callback : mCallbacks) {
1199             callback.onConsolidatedPolicyChanged();
1200         }
1201     }
1202 
dispatchOnZenModeChanged()1203     private void dispatchOnZenModeChanged() {
1204         for (Callback callback : mCallbacks) {
1205             callback.onZenModeChanged();
1206         }
1207     }
1208 
dispatchOnAutomaticRuleStatusChanged(int userId, String pkg, String id, int status)1209     private void dispatchOnAutomaticRuleStatusChanged(int userId, String pkg, String id,
1210             int status) {
1211         for (Callback callback : mCallbacks) {
1212             callback.onAutomaticRuleStatusChanged(userId, pkg, id, status);
1213         }
1214     }
1215 
readDefaultConfig(Resources resources)1216     private ZenModeConfig readDefaultConfig(Resources resources) {
1217         XmlResourceParser parser = null;
1218         try {
1219             parser = resources.getXml(R.xml.default_zen_mode_config);
1220             while (parser.next() != XmlPullParser.END_DOCUMENT) {
1221                 final ZenModeConfig config = ZenModeConfig.readXml(XmlUtils.makeTyped(parser));
1222                 if (config != null) return config;
1223             }
1224         } catch (Exception e) {
1225             Log.w(TAG, "Error reading default zen mode config from resource", e);
1226         } finally {
1227             IoUtils.closeQuietly(parser);
1228         }
1229         return new ZenModeConfig();
1230     }
1231 
zenSeverity(int zen)1232     private static int zenSeverity(int zen) {
1233         switch (zen) {
1234             case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return 1;
1235             case Global.ZEN_MODE_ALARMS: return 2;
1236             case Global.ZEN_MODE_NO_INTERRUPTIONS: return 3;
1237             default: return 0;
1238         }
1239     }
1240 
1241     /**
1242      * Generate pulled atoms about do not disturb configurations.
1243      */
pullRules(List<StatsEvent> events)1244     public void pullRules(List<StatsEvent> events) {
1245         synchronized (mConfigsLock) {
1246             final int numConfigs = mConfigs.size();
1247             for (int i = 0; i < numConfigs; i++) {
1248                 final int user = mConfigs.keyAt(i);
1249                 final ZenModeConfig config = mConfigs.valueAt(i);
1250                 SysUiStatsEvent.Builder data = mStatsEventBuilderFactory.newBuilder()
1251                         .setAtomId(DND_MODE_RULE)
1252                         .writeInt(user)
1253                         .writeBoolean(config.manualRule != null) // enabled
1254                         .writeBoolean(config.areChannelsBypassingDnd)
1255                         .writeInt(ROOT_CONFIG)
1256                         .writeString("") // name, empty for root config
1257                         .writeInt(Process.SYSTEM_UID) // system owns root config
1258                         .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
1259                         .writeByteArray(config.toZenPolicy().toProto());
1260                 events.add(data.build());
1261                 if (config.manualRule != null && config.manualRule.enabler != null) {
1262                     ruleToProtoLocked(user, config.manualRule, events);
1263                 }
1264                 for (ZenRule rule : config.automaticRules.values()) {
1265                     ruleToProtoLocked(user, rule, events);
1266                 }
1267             }
1268         }
1269     }
1270 
ruleToProtoLocked(int user, ZenRule rule, List<StatsEvent> events)1271     private void ruleToProtoLocked(int user, ZenRule rule, List<StatsEvent> events) {
1272         // Make the ID safe.
1273         String id = rule.id == null ? "" : rule.id;
1274         if (!ZenModeConfig.DEFAULT_RULE_IDS.contains(id)) {
1275             id = "";
1276         }
1277 
1278         // Look for packages and enablers, enablers get priority.
1279         String pkg = rule.getPkg() == null ? "" : rule.getPkg();
1280         if (rule.enabler != null) {
1281             pkg = rule.enabler;
1282             id = ZenModeConfig.MANUAL_RULE_ID;
1283         }
1284 
1285         SysUiStatsEvent.Builder data;
1286         data = mStatsEventBuilderFactory.newBuilder()
1287                 .setAtomId(DND_MODE_RULE)
1288                 .writeInt(user)
1289                 .writeBoolean(rule.enabled)
1290                 .writeBoolean(false) // channels_bypassing unused for rules
1291                 .writeInt(rule.zenMode)
1292                 .writeString(id)
1293                 .writeInt(getPackageUid(pkg, user))
1294                 .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
1295         byte[] policyProto = new byte[]{};
1296         if (rule.zenPolicy != null) {
1297             policyProto = rule.zenPolicy.toProto();
1298         }
1299         data.writeByteArray(policyProto);
1300         events.add(data.build());
1301     }
1302 
getPackageUid(String pkg, int user)1303     private int getPackageUid(String pkg, int user) {
1304         if ("android".equals(pkg)) {
1305             return Process.SYSTEM_UID;
1306         }
1307         final String key = getPackageUserKey(pkg, user);
1308         if (mRulesUidCache.get(key) == null) {
1309             try {
1310                 mRulesUidCache.put(key, mPm.getPackageUidAsUser(pkg, user));
1311             } catch (PackageManager.NameNotFoundException e) {
1312             }
1313         }
1314         return mRulesUidCache.getOrDefault(key, -1);
1315     }
1316 
getPackageUserKey(String pkg, int user)1317     private static String getPackageUserKey(String pkg, int user) {
1318         return pkg + "|" + user;
1319     }
1320 
1321     @VisibleForTesting
1322     protected final class RingerModeDelegate implements AudioManagerInternal.RingerModeDelegate {
1323         @Override
toString()1324         public String toString() {
1325             return TAG;
1326         }
1327 
1328         @Override
onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller, int ringerModeExternal, VolumePolicy policy)1329         public int onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller,
1330                 int ringerModeExternal, VolumePolicy policy) {
1331             final boolean isChange = ringerModeOld != ringerModeNew;
1332 
1333             int ringerModeExternalOut = ringerModeNew;
1334 
1335             if (mZenMode == Global.ZEN_MODE_OFF
1336                     || (mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
1337                     && !ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(mConfig))) {
1338                 // in priority only with ringer not muted, save ringer mode changes
1339                 // in dnd off, save ringer mode changes
1340                 setPreviousRingerModeSetting(ringerModeNew);
1341             }
1342             int newZen = -1;
1343             switch (ringerModeNew) {
1344                 case AudioManager.RINGER_MODE_SILENT:
1345                     if (isChange && policy.doNotDisturbWhenSilent) {
1346                         if (mZenMode == Global.ZEN_MODE_OFF) {
1347                             newZen = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
1348                         }
1349                         setPreviousRingerModeSetting(ringerModeOld);
1350                     }
1351                     break;
1352                 case AudioManager.RINGER_MODE_VIBRATE:
1353                 case AudioManager.RINGER_MODE_NORMAL:
1354                     if (isChange && ringerModeOld == AudioManager.RINGER_MODE_SILENT
1355                             && (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS
1356                             || mZenMode == Global.ZEN_MODE_ALARMS
1357                             || (mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
1358                             && ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(
1359                             mConfig)))) {
1360                         newZen = Global.ZEN_MODE_OFF;
1361                     } else if (mZenMode != Global.ZEN_MODE_OFF) {
1362                         ringerModeExternalOut = AudioManager.RINGER_MODE_SILENT;
1363                     }
1364                     break;
1365             }
1366 
1367             if (newZen != -1) {
1368                 setManualZenMode(newZen, null, "ringerModeInternal", null,
1369                         false /*setRingerMode*/);
1370             }
1371             if (isChange || newZen != -1 || ringerModeExternal != ringerModeExternalOut) {
1372                 ZenLog.traceSetRingerModeInternal(ringerModeOld, ringerModeNew, caller,
1373                         ringerModeExternal, ringerModeExternalOut);
1374             }
1375             return ringerModeExternalOut;
1376         }
1377 
1378         @Override
onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller, int ringerModeInternal, VolumePolicy policy)1379         public int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller,
1380                 int ringerModeInternal, VolumePolicy policy) {
1381             int ringerModeInternalOut = ringerModeNew;
1382             final boolean isChange = ringerModeOld != ringerModeNew;
1383             final boolean isVibrate = ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE;
1384 
1385             int newZen = -1;
1386             switch (ringerModeNew) {
1387                 case AudioManager.RINGER_MODE_SILENT:
1388                     if (isChange) {
1389                         if (mZenMode == Global.ZEN_MODE_OFF) {
1390                             newZen = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
1391                         }
1392                         ringerModeInternalOut = isVibrate ? AudioManager.RINGER_MODE_VIBRATE
1393                                 : AudioManager.RINGER_MODE_SILENT;
1394                     } else {
1395                         ringerModeInternalOut = ringerModeInternal;
1396                     }
1397                     break;
1398                 case AudioManager.RINGER_MODE_VIBRATE:
1399                 case AudioManager.RINGER_MODE_NORMAL:
1400                     if (mZenMode != Global.ZEN_MODE_OFF) {
1401                         newZen = Global.ZEN_MODE_OFF;
1402                     }
1403                     break;
1404             }
1405             if (newZen != -1) {
1406                 setManualZenMode(newZen, null, "ringerModeExternal", caller,
1407                         false /*setRingerMode*/);
1408             }
1409 
1410             ZenLog.traceSetRingerModeExternal(ringerModeOld, ringerModeNew, caller,
1411                     ringerModeInternal, ringerModeInternalOut);
1412             return ringerModeInternalOut;
1413         }
1414 
1415         @Override
canVolumeDownEnterSilent()1416         public boolean canVolumeDownEnterSilent() {
1417             return mZenMode == Global.ZEN_MODE_OFF;
1418         }
1419 
1420         @Override
getRingerModeAffectedStreams(int streams)1421         public int getRingerModeAffectedStreams(int streams) {
1422             // ringtone, notification and system streams are always affected by ringer mode
1423             // zen muting is handled in AudioService.java's mZenModeAffectedStreams
1424             streams |= (1 << AudioSystem.STREAM_RING) |
1425                     (1 << AudioSystem.STREAM_NOTIFICATION) |
1426                     (1 << AudioSystem.STREAM_SYSTEM);
1427 
1428             if (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
1429                 // alarm and music and streams affected by ringer mode (cannot be adjusted) when in
1430                 // total silence
1431                 streams |= (1 << AudioSystem.STREAM_ALARM) |
1432                         (1 << AudioSystem.STREAM_MUSIC) |
1433                         (1 << AudioSystem.STREAM_ASSISTANT);
1434             } else {
1435                 streams &= ~((1 << AudioSystem.STREAM_ALARM) |
1436                         (1 << AudioSystem.STREAM_MUSIC) |
1437                         (1 << AudioSystem.STREAM_ASSISTANT)
1438                 );
1439             }
1440             return streams;
1441         }
1442     }
1443 
1444     private final class SettingsObserver extends ContentObserver {
1445         private final Uri ZEN_MODE = Global.getUriFor(Global.ZEN_MODE);
1446 
SettingsObserver(Handler handler)1447         public SettingsObserver(Handler handler) {
1448             super(handler);
1449         }
1450 
observe()1451         public void observe() {
1452             final ContentResolver resolver = mContext.getContentResolver();
1453             resolver.registerContentObserver(ZEN_MODE, false /*notifyForDescendents*/, this);
1454             update(null);
1455         }
1456 
1457         @Override
onChange(boolean selfChange, Uri uri)1458         public void onChange(boolean selfChange, Uri uri) {
1459             update(uri);
1460         }
1461 
update(Uri uri)1462         public void update(Uri uri) {
1463             if (ZEN_MODE.equals(uri)) {
1464                 if (mZenMode != getZenModeSetting()) {
1465                     if (DEBUG) Log.d(TAG, "Fixing zen mode setting");
1466                     setZenModeSetting(mZenMode);
1467                 }
1468             }
1469         }
1470     }
1471 
showZenUpgradeNotification(int zen)1472     private void showZenUpgradeNotification(int zen) {
1473         final boolean isWatch = mContext.getPackageManager().hasSystemFeature(
1474             PackageManager.FEATURE_WATCH);
1475         final boolean showNotification = mIsBootComplete
1476                 && zen != Global.ZEN_MODE_OFF
1477                 && !isWatch
1478                 && Settings.Secure.getInt(mContext.getContentResolver(),
1479                 Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0) != 0
1480                 && Settings.Secure.getInt(mContext.getContentResolver(),
1481                 Settings.Secure.ZEN_SETTINGS_UPDATED, 0) != 1;
1482 
1483         if (isWatch) {
1484             Settings.Secure.putInt(mContext.getContentResolver(),
1485                     Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0);
1486         }
1487 
1488         if (showNotification) {
1489             mNotificationManager.notify(TAG, SystemMessage.NOTE_ZEN_UPGRADE,
1490                     createZenUpgradeNotification());
1491             Settings.Secure.putInt(mContext.getContentResolver(),
1492                     Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0);
1493         }
1494     }
1495 
1496     @VisibleForTesting
createZenUpgradeNotification()1497     protected Notification createZenUpgradeNotification() {
1498         final Bundle extras = new Bundle();
1499         extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
1500                 mContext.getResources().getString(R.string.global_action_settings));
1501         int title = R.string.zen_upgrade_notification_title;
1502         int content = R.string.zen_upgrade_notification_content;
1503         int drawable = R.drawable.ic_zen_24dp;
1504         if (NotificationManager.Policy.areAllVisualEffectsSuppressed(
1505                 getConsolidatedNotificationPolicy().suppressedVisualEffects)) {
1506             title = R.string.zen_upgrade_notification_visd_title;
1507             content = R.string.zen_upgrade_notification_visd_content;
1508             drawable = R.drawable.ic_dnd_block_notifications;
1509         }
1510 
1511         Intent onboardingIntent = new Intent(Settings.ZEN_MODE_ONBOARDING);
1512         onboardingIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
1513         return new Notification.Builder(mContext, SystemNotificationChannels.DO_NOT_DISTURB)
1514                 .setAutoCancel(true)
1515                 .setSmallIcon(R.drawable.ic_settings_24dp)
1516                 .setLargeIcon(Icon.createWithResource(mContext, drawable))
1517                 .setContentTitle(mContext.getResources().getString(title))
1518                 .setContentText(mContext.getResources().getString(content))
1519                 .setContentIntent(PendingIntent.getActivity(mContext, 0, onboardingIntent,
1520                         PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
1521                 .setAutoCancel(true)
1522                 .setLocalOnly(true)
1523                 .addExtras(extras)
1524                 .setStyle(new Notification.BigTextStyle())
1525                 .build();
1526     }
1527 
1528     private final class Metrics extends Callback {
1529         private static final String COUNTER_MODE_PREFIX = "dnd_mode_";
1530         private static final String COUNTER_TYPE_PREFIX = "dnd_type_";
1531         private static final int DND_OFF = 0;
1532         private static final int DND_ON_MANUAL = 1;
1533         private static final int DND_ON_AUTOMATIC = 2;
1534         private static final String COUNTER_RULE = "dnd_rule_count";
1535         private static final long MINIMUM_LOG_PERIOD_MS = 60 * 1000;
1536 
1537         // Total silence, alarms only, priority only
1538         private int mPreviousZenMode = -1;
1539         private long mModeLogTimeMs = 0L;
1540 
1541         private int mNumZenRules = -1;
1542         private long mRuleCountLogTime = 0L;
1543 
1544         // automatic (1) vs manual (0) vs dnd off (2)
1545         private int mPreviousZenType = -1;
1546         private long mTypeLogTimeMs = 0L;
1547 
1548         @Override
onZenModeChanged()1549         void onZenModeChanged() {
1550             emit();
1551         }
1552 
1553         @Override
onConfigChanged()1554         void onConfigChanged() {
1555             emit();
1556         }
1557 
emit()1558         private void emit() {
1559             mHandler.postMetricsTimer();
1560             emitZenMode();
1561             emitRules();
1562             emitDndType();
1563         }
1564 
emitZenMode()1565         private void emitZenMode() {
1566             final long now = SystemClock.elapsedRealtime();
1567             final long since = (now - mModeLogTimeMs);
1568             if (mPreviousZenMode != mZenMode || since > MINIMUM_LOG_PERIOD_MS) {
1569                 if (mPreviousZenMode != -1) {
1570                     MetricsLogger.count(
1571                             mContext, COUNTER_MODE_PREFIX + mPreviousZenMode, (int) since);
1572                 }
1573                 mPreviousZenMode = mZenMode;
1574                 mModeLogTimeMs = now;
1575             }
1576         }
1577 
emitRules()1578         private void emitRules() {
1579             final long now = SystemClock.elapsedRealtime();
1580             final long since = (now - mRuleCountLogTime);
1581             synchronized (mConfig) {
1582                 int numZenRules = mConfig.automaticRules.size();
1583                 if (mNumZenRules != numZenRules
1584                         || since > MINIMUM_LOG_PERIOD_MS) {
1585                     if (mNumZenRules != -1) {
1586                         MetricsLogger.count(mContext, COUNTER_RULE,
1587                                 numZenRules - mNumZenRules);
1588                     }
1589                     mNumZenRules = numZenRules;
1590 
1591                     mRuleCountLogTime = since;
1592                 }
1593             }
1594         }
1595 
emitDndType()1596         private void emitDndType() {
1597             final long now = SystemClock.elapsedRealtime();
1598             final long since = (now - mTypeLogTimeMs);
1599             synchronized (mConfig) {
1600                 boolean dndOn = mZenMode != Global.ZEN_MODE_OFF;
1601                 int zenType = !dndOn ? DND_OFF
1602                         : (mConfig.manualRule != null) ? DND_ON_MANUAL : DND_ON_AUTOMATIC;
1603                 if (zenType != mPreviousZenType
1604                         || since > MINIMUM_LOG_PERIOD_MS) {
1605                     if (mPreviousZenType != -1) {
1606                         MetricsLogger.count(
1607                                 mContext, COUNTER_TYPE_PREFIX + mPreviousZenType, (int) since);
1608                     }
1609                     mTypeLogTimeMs = now;
1610                     mPreviousZenType = zenType;
1611                 }
1612             }
1613         }
1614     }
1615 
1616     private final class H extends Handler {
1617         private static final int MSG_DISPATCH = 1;
1618         private static final int MSG_METRICS = 2;
1619         private static final int MSG_APPLY_CONFIG = 4;
1620 
1621         private final class ConfigMessageData {
1622             public final ZenModeConfig config;
1623             public ComponentName triggeringComponent;
1624             public final String reason;
1625             public final boolean setRingerMode;
1626 
ConfigMessageData(ZenModeConfig config, String reason, ComponentName triggeringComponent, boolean setRingerMode)1627             ConfigMessageData(ZenModeConfig config, String reason,
1628                     ComponentName triggeringComponent, boolean setRingerMode) {
1629                 this.config = config;
1630                 this.reason = reason;
1631                 this.setRingerMode = setRingerMode;
1632                 this.triggeringComponent = triggeringComponent;
1633             }
1634         }
1635 
1636         private static final long METRICS_PERIOD_MS = 6 * 60 * 60 * 1000;
1637 
H(Looper looper)1638         private H(Looper looper) {
1639             super(looper);
1640         }
1641 
postDispatchOnZenModeChanged()1642         private void postDispatchOnZenModeChanged() {
1643             removeMessages(MSG_DISPATCH);
1644             sendEmptyMessage(MSG_DISPATCH);
1645         }
1646 
postMetricsTimer()1647         private void postMetricsTimer() {
1648             removeMessages(MSG_METRICS);
1649             sendEmptyMessageDelayed(MSG_METRICS, METRICS_PERIOD_MS);
1650         }
1651 
postApplyConfig(ZenModeConfig config, String reason, ComponentName triggeringComponent, boolean setRingerMode)1652         private void postApplyConfig(ZenModeConfig config, String reason,
1653                 ComponentName triggeringComponent, boolean setRingerMode) {
1654             sendMessage(obtainMessage(MSG_APPLY_CONFIG,
1655                     new ConfigMessageData(config, reason, triggeringComponent, setRingerMode)));
1656         }
1657 
1658         @Override
handleMessage(Message msg)1659         public void handleMessage(Message msg) {
1660             switch (msg.what) {
1661                 case MSG_DISPATCH:
1662                     dispatchOnZenModeChanged();
1663                     break;
1664                 case MSG_METRICS:
1665                     mMetrics.emit();
1666                     break;
1667                 case MSG_APPLY_CONFIG:
1668                     ConfigMessageData applyConfigData = (ConfigMessageData) msg.obj;
1669                     applyConfig(applyConfigData.config, applyConfigData.reason,
1670                             applyConfigData.triggeringComponent, applyConfigData.setRingerMode);
1671             }
1672         }
1673     }
1674 
1675     public static class Callback {
onConfigChanged()1676         void onConfigChanged() {}
onZenModeChanged()1677         void onZenModeChanged() {}
onPolicyChanged()1678         void onPolicyChanged() {}
onConsolidatedPolicyChanged()1679         void onConsolidatedPolicyChanged() {}
onAutomaticRuleStatusChanged(int userId, String pkg, String id, int status)1680         void onAutomaticRuleStatusChanged(int userId, String pkg, String id, int status) {}
1681     }
1682 }
1683