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