blob: 6ac72d3ae167ff13dd11baef30bc564b14221da6 [file] [log] [blame]
John Spurlock056c5192014-04-20 21:52:01 -04001/**
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
17package com.android.server.notification;
18
John Spurlock056c5192014-04-20 21:52:01 -040019import android.app.AppOpsManager;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040020import android.app.AutomaticZenRule;
Beverly3bae4e52018-02-07 12:32:02 -050021import android.app.Notification;
John Spurlock80774932015-05-07 17:38:50 -040022import android.app.NotificationManager;
John Spurlock1fc476d2015-04-14 16:05:20 -040023import android.app.NotificationManager.Policy;
Beverly3bae4e52018-02-07 12:32:02 -050024import android.app.PendingIntent;
John Spurlock312d1d02014-07-08 10:24:57 -040025import android.content.ComponentName;
John Spurlock056c5192014-04-20 21:52:01 -040026import android.content.ContentResolver;
27import android.content.Context;
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -050028import android.content.Intent;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040029import android.content.pm.PackageManager;
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -050030import android.content.pm.ResolveInfo;
31import android.content.pm.ServiceInfo;
John Spurlock056c5192014-04-20 21:52:01 -040032import android.content.res.Resources;
33import android.content.res.XmlResourceParser;
34import android.database.ContentObserver;
Julia Reynolds9aa1c9e2018-04-09 11:31:15 -040035import android.graphics.drawable.Icon;
Jean-Michel Trivie743bda2016-09-09 11:56:48 -070036import android.media.AudioAttributes;
John Spurlock056c5192014-04-20 21:52:01 -040037import android.media.AudioManager;
John Spurlock661f2cf2014-11-17 10:29:10 -050038import android.media.AudioManagerInternal;
John Spurlock50ced3f2015-05-11 16:00:09 -040039import android.media.AudioSystem;
John Spurlocka48d7792015-03-03 17:35:57 -050040import android.media.VolumePolicy;
John Spurlock056c5192014-04-20 21:52:01 -040041import android.net.Uri;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040042import android.os.Binder;
John Spurlock2b122f42014-08-27 16:29:47 -040043import android.os.Bundle;
John Spurlock056c5192014-04-20 21:52:01 -040044import android.os.Handler;
John Spurlock661f2cf2014-11-17 10:29:10 -050045import android.os.Looper;
46import android.os.Message;
Julia Reynoldsc8e54e82015-11-30 16:43:05 -050047import android.os.Process;
Chris Wren98d235b2015-05-27 18:25:17 -040048import android.os.SystemClock;
John Spurlockb5e767b2014-07-27 11:53:20 -040049import android.os.UserHandle;
Beverly3bae4e52018-02-07 12:32:02 -050050import android.provider.Settings;
John Spurlock056c5192014-04-20 21:52:01 -040051import android.provider.Settings.Global;
Julia Reynolds520df6e2017-02-13 09:05:10 -050052import android.service.notification.Condition;
Julia Reynolds43b70cd2016-01-14 15:05:34 -050053import android.service.notification.ConditionProviderService;
John Spurlock056c5192014-04-20 21:52:01 -040054import android.service.notification.ZenModeConfig;
John Spurlockcb9aa202015-05-08 17:35:22 -040055import android.service.notification.ZenModeConfig.EventInfo;
John Spurlockb2278d62015-04-07 12:47:12 -040056import android.service.notification.ZenModeConfig.ScheduleInfo;
57import android.service.notification.ZenModeConfig.ZenRule;
Julia Reynolds520df6e2017-02-13 09:05:10 -050058import android.service.notification.ZenModeProto;
Julia Reynolds87c42772016-05-16 09:52:17 -040059import android.util.AndroidRuntimeException;
Beverly4e2f76c2018-03-16 15:43:49 -040060import android.util.ArrayMap;
John Spurlock4db0d982014-08-13 09:19:03 -040061import android.util.Log;
Beverlyd4f96492017-08-02 13:36:11 -040062import android.util.Slog;
John Spurlock21258a32015-05-27 18:22:55 -040063import android.util.SparseArray;
Julia Reynolds520df6e2017-02-13 09:05:10 -050064import android.util.proto.ProtoOutputStream;
John Spurlock056c5192014-04-20 21:52:01 -040065
66import com.android.internal.R;
Beverly04216872017-09-28 10:55:32 -040067import com.android.internal.annotations.VisibleForTesting;
John Spurlock25d01ee2015-06-03 12:17:46 -040068import com.android.internal.logging.MetricsLogger;
Beverly3bae4e52018-02-07 12:32:02 -050069import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
70import com.android.internal.notification.SystemNotificationChannels;
John Spurlock661f2cf2014-11-17 10:29:10 -050071import com.android.server.LocalServices;
John Spurlock056c5192014-04-20 21:52:01 -040072
73import libcore.io.IoUtils;
74
75import org.xmlpull.v1.XmlPullParser;
76import org.xmlpull.v1.XmlPullParserException;
77import org.xmlpull.v1.XmlSerializer;
78
79import java.io.IOException;
80import java.io.PrintWriter;
John Spurlock1c923a32014-04-27 16:42:29 -040081import java.util.ArrayList;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040082import java.util.List;
John Spurlock1fc476d2015-04-14 16:05:20 -040083import java.util.Objects;
John Spurlock056c5192014-04-20 21:52:01 -040084
85/**
86 * NotificationManagerService helper for functionality related to zen mode.
87 */
John Spurlockb2278d62015-04-07 12:47:12 -040088public class ZenModeHelper {
89 static final String TAG = "ZenModeHelper";
90 static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
John Spurlock056c5192014-04-20 21:52:01 -040091
Julia Reynolds5a43aaa2015-12-15 13:54:41 -050092 // 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
John Spurlock056c5192014-04-20 21:52:01 -040095 private final Context mContext;
John Spurlock661f2cf2014-11-17 10:29:10 -050096 private final H mHandler;
John Spurlock056c5192014-04-20 21:52:01 -040097 private final SettingsObserver mSettingsObserver;
Beverly04216872017-09-28 10:55:32 -040098 @VisibleForTesting protected final AppOpsManager mAppOps;
Beverly3bae4e52018-02-07 12:32:02 -050099 @VisibleForTesting protected final NotificationManager mNotificationManager;
Beverlyd4f96492017-08-02 13:36:11 -0400100 protected ZenModeConfig mDefaultConfig;
John Spurlock1c923a32014-04-27 16:42:29 -0400101 private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
John Spurlockb2278d62015-04-07 12:47:12 -0400102 private final ZenModeFiltering mFiltering;
Beverlyd6964762018-02-16 14:07:03 -0500103 protected final RingerModeDelegate mRingerModeDelegate = new
104 RingerModeDelegate();
Beverly2f43b642018-08-14 09:43:11 -0400105 @VisibleForTesting protected final ZenModeConditions mConditions;
John Spurlock21258a32015-05-27 18:22:55 -0400106 private final SparseArray<ZenModeConfig> mConfigs = new SparseArray<>();
Chris Wren98d235b2015-05-27 18:25:17 -0400107 private final Metrics mMetrics = new Metrics();
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500108 private final ConditionProviders.Config mServiceConfig;
John Spurlock056c5192014-04-20 21:52:01 -0400109
Beverly04216872017-09-28 10:55:32 -0400110 @VisibleForTesting protected int mZenMode;
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700111 private int mUser = UserHandle.USER_SYSTEM;
Beverly04216872017-09-28 10:55:32 -0400112 @VisibleForTesting protected ZenModeConfig mConfig;
Beverly85f52412018-02-27 10:41:13 -0500113 @VisibleForTesting protected AudioManagerInternal mAudioManager;
Beverlyd4f96492017-08-02 13:36:11 -0400114 protected PackageManager mPm;
Bryce Lee7219ada2016-04-08 10:54:23 -0700115 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;
John Spurlock056c5192014-04-20 21:52:01 -0400121
Beverly26eba872017-12-04 16:30:11 -0500122 protected String mDefaultRuleEveryNightName;
Beverlyd4f96492017-08-02 13:36:11 -0400123 protected String mDefaultRuleEventsName;
Beverly3bae4e52018-02-07 12:32:02 -0500124 @VisibleForTesting protected boolean mIsBootComplete;
Beverlyd4f96492017-08-02 13:36:11 -0400125
John Spurlockb2278d62015-04-07 12:47:12 -0400126 public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) {
John Spurlock056c5192014-04-20 21:52:01 -0400127 mContext = context;
John Spurlock661f2cf2014-11-17 10:29:10 -0500128 mHandler = new H(looper);
Chris Wren98d235b2015-05-27 18:25:17 -0400129 addCallback(mMetrics);
John Spurlock056c5192014-04-20 21:52:01 -0400130 mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
Beverly3bae4e52018-02-07 12:32:02 -0500131 mNotificationManager = context.getSystemService(NotificationManager.class);
Beverlyd4f96492017-08-02 13:36:11 -0400132
133 mDefaultConfig = new ZenModeConfig();
Beverlyd4f96492017-08-02 13:36:11 -0400134 setDefaultZenRules(mContext);
John Spurlock056c5192014-04-20 21:52:01 -0400135 mConfig = mDefaultConfig;
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700136 mConfigs.put(UserHandle.USER_SYSTEM, mConfig);
Beverlyd4f96492017-08-02 13:36:11 -0400137
John Spurlock056c5192014-04-20 21:52:01 -0400138 mSettingsObserver = new SettingsObserver(mHandler);
139 mSettingsObserver.observe();
John Spurlockb2278d62015-04-07 12:47:12 -0400140 mFiltering = new ZenModeFiltering(mContext);
141 mConditions = new ZenModeConditions(this, conditionProviders);
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500142 mServiceConfig = conditionProviders.getConfig();
John Spurlock056c5192014-04-20 21:52:01 -0400143 }
144
John Spurlock1b8b22b2015-05-20 09:47:13 -0400145 public Looper getLooper() {
146 return mHandler.getLooper();
147 }
148
John Spurlockb2278d62015-04-07 12:47:12 -0400149 @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) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400156 synchronized (mConfig) {
157 return ZenModeFiltering.matchesCallFilter(mContext, mZenMode, mConfig, userHandle,
Julia Reynoldsc6b371b2016-06-14 08:31:03 -0400158 extras, validator, contactsTimeoutMs, timeoutAffinity);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400159 }
John Spurlockb2278d62015-04-07 12:47:12 -0400160 }
161
162 public boolean isCall(NotificationRecord record) {
163 return mFiltering.isCall(record);
164 }
165
Julia Reynoldsc6b371b2016-06-14 08:31:03 -0400166 public void recordCaller(NotificationRecord record) {
167 mFiltering.recordCall(record);
168 }
169
John Spurlockb2278d62015-04-07 12:47:12 -0400170 public boolean shouldIntercept(NotificationRecord record) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400171 synchronized (mConfig) {
172 return mFiltering.shouldIntercept(mZenMode, mConfig, record);
173 }
John Spurlock056c5192014-04-20 21:52:01 -0400174 }
175
John Spurlock1c923a32014-04-27 16:42:29 -0400176 public void addCallback(Callback callback) {
177 mCallbacks.add(callback);
John Spurlock056c5192014-04-20 21:52:01 -0400178 }
179
John Spurlock530052a2014-11-30 16:26:19 -0500180 public void removeCallback(Callback callback) {
181 mCallbacks.remove(callback);
182 }
183
John Spurlockb2278d62015-04-07 12:47:12 -0400184 public void initZenMode() {
185 if (DEBUG) Log.d(TAG, "initZenMode");
186 evaluateZenMode("init", true /*setRingerMode*/);
187 }
188
John Spurlock661f2cf2014-11-17 10:29:10 -0500189 public void onSystemReady() {
John Spurlockb2278d62015-04-07 12:47:12 -0400190 if (DEBUG) Log.d(TAG, "onSystemReady");
John Spurlock661f2cf2014-11-17 10:29:10 -0500191 mAudioManager = LocalServices.getService(AudioManagerInternal.class);
192 if (mAudioManager != null) {
John Spurlockb2278d62015-04-07 12:47:12 -0400193 mAudioManager.setRingerModeDelegate(mRingerModeDelegate);
John Spurlock661f2cf2014-11-17 10:29:10 -0500194 }
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500195 mPm = mContext.getPackageManager();
Chris Wren98d235b2015-05-27 18:25:17 -0400196 mHandler.postMetricsTimer();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500197 cleanUpZenRules();
Julia Reynolds8ac63032015-08-31 15:19:43 -0400198 evaluateZenMode("onSystemReady", true);
Beverly3bae4e52018-02-07 12:32:02 -0500199 mIsBootComplete = true;
200 showZenUpgradeNotification(mZenMode);
John Spurlockae641c92014-06-30 18:11:40 -0400201 }
202
John Spurlock21258a32015-05-27 18:22:55 -0400203 public void onUserSwitched(int user) {
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500204 loadConfigForUser(user, "onUserSwitched");
John Spurlock21258a32015-05-27 18:22:55 -0400205 }
206
207 public void onUserRemoved(int user) {
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700208 if (user < UserHandle.USER_SYSTEM) return;
John Spurlock21258a32015-05-27 18:22:55 -0400209 if (DEBUG) Log.d(TAG, "onUserRemoved u=" + user);
210 mConfigs.remove(user);
211 }
212
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500213 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) {
Julia Reynolds8f056002018-07-13 15:12:29 -0400228 setConfigLocked(config, null, reason);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500229 }
230 cleanUpZenRules();
231 }
232
Christoph Studer85a384b2014-08-27 20:16:15 +0200233 public int getZenModeListenerInterruptionFilter() {
John Spurlock80774932015-05-07 17:38:50 -0400234 return NotificationManager.zenModeToInterruptionFilter(mZenMode);
John Spurlockd8afe3c2014-08-01 14:04:07 -0400235 }
236
John Spurlock80774932015-05-07 17:38:50 -0400237 public void requestFromListener(ComponentName name, int filter) {
238 final int newZen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
John Spurlockd8afe3c2014-08-01 14:04:07 -0400239 if (newZen != -1) {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -0400240 setManualZenMode(newZen, null, name != null ? name.getPackageName() : null,
John Spurlockb2278d62015-04-07 12:47:12 -0400241 "listener:" + (name != null ? name.flattenToShortString() : null));
John Spurlockd8afe3c2014-08-01 14:04:07 -0400242 }
243 }
244
Bryce Lee7219ada2016-04-08 10:54:23 -0700245 public void setSuppressedEffects(long suppressedEffects) {
246 if (mSuppressedEffects == suppressedEffects) return;
247 mSuppressedEffects = suppressedEffects;
John Spurlock8403b752014-12-10 12:47:01 -0500248 applyRestrictions();
249 }
250
Bryce Lee7219ada2016-04-08 10:54:23 -0700251 public long getSuppressedEffects() {
252 return mSuppressedEffects;
253 }
254
John Spurlock1c923a32014-04-27 16:42:29 -0400255 public int getZenMode() {
256 return mZenMode;
257 }
258
Julia Reynolds361e82d32016-02-26 18:19:49 -0500259 public List<ZenRule> getZenRules() {
260 List<ZenRule> rules = new ArrayList<>();
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400261 synchronized (mConfig) {
262 if (mConfig == null) return rules;
263 for (ZenRule rule : mConfig.automaticRules.values()) {
264 if (canManageAutomaticZenRule(rule)) {
Julia Reynolds361e82d32016-02-26 18:19:49 -0500265 rules.add(rule);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400266 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400267 }
268 }
269 return rules;
270 }
271
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400272 public AutomaticZenRule getAutomaticZenRule(String id) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400273 ZenRule rule;
274 synchronized (mConfig) {
275 if (mConfig == null) return null;
276 rule = mConfig.automaticRules.get(id);
277 }
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400278 if (rule == null) return null;
279 if (canManageAutomaticZenRule(rule)) {
280 return createAutomaticZenRule(rule);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400281 }
282 return null;
283 }
284
Julia Reynolds361e82d32016-02-26 18:19:49 -0500285 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500286 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
Julia Reynolds7f2f4412016-03-01 12:33:48 -0500292 int ruleInstanceLimit = -1;
293 if (owner.metaData != null) {
294 ruleInstanceLimit = owner.metaData.getInt(
295 ConditionProviderService.META_DATA_RULE_INSTANCE_LIMIT, -1);
296 }
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500297 if (ruleInstanceLimit > 0 && ruleInstanceLimit
298 < (getCurrentInstanceCount(automaticZenRule.getOwner()) + 1)) {
299 throw new IllegalArgumentException("Rule instance limit exceeded");
300 }
301 }
302
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400303 ZenModeConfig newConfig;
304 synchronized (mConfig) {
Julia Reynolds87c42772016-05-16 09:52:17 -0400305 if (mConfig == null) {
306 throw new AndroidRuntimeException("Could not create rule");
307 }
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400308 if (DEBUG) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500309 Log.d(TAG, "addAutomaticZenRule rule= " + automaticZenRule + " reason=" + reason);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400310 }
311 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500312 ZenRule rule = new ZenRule();
313 populateZenRule(automaticZenRule, rule, true);
314 newConfig.automaticRules.put(rule.id, rule);
Julia Reynolds8f056002018-07-13 15:12:29 -0400315 if (setConfigLocked(newConfig, reason, rule.component, true)) {
Julia Reynolds361e82d32016-02-26 18:19:49 -0500316 return rule.id;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500317 } else {
Julia Reynolds87c42772016-05-16 09:52:17 -0400318 throw new AndroidRuntimeException("Could not create rule");
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500319 }
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400320 }
321 }
322
Julia Reynolds361e82d32016-02-26 18:19:49 -0500323 public boolean updateAutomaticZenRule(String ruleId, AutomaticZenRule automaticZenRule,
324 String reason) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400325 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();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500333 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 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400342 }
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500343 populateZenRule(automaticZenRule, rule, false);
344 newConfig.automaticRules.put(ruleId, rule);
Julia Reynolds8f056002018-07-13 15:12:29 -0400345 return setConfigLocked(newConfig, reason, rule.component, true);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400346 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400347 }
348
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400349 public boolean removeAutomaticZenRule(String id, String reason) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400350 ZenModeConfig newConfig;
351 synchronized (mConfig) {
352 if (mConfig == null) return false;
353 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500354 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 }
Julia Reynolds8f056002018-07-13 15:12:29 -0400363 return setConfigLocked(newConfig, reason, null, true);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400364 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400365 }
366
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500367 public boolean removeAutomaticZenRules(String packageName, String reason) {
368 ZenModeConfig newConfig;
369 synchronized (mConfig) {
370 if (mConfig == null) return false;
371 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500372 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 }
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500378 }
Julia Reynolds8f056002018-07-13 15:12:29 -0400379 return setConfigLocked(newConfig, reason, null, true);
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500380 }
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500381 }
382
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500383 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
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400395 public boolean canManageAutomaticZenRule(ZenRule rule) {
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500396 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)
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400400 == PackageManager.PERMISSION_GRANTED) {
401 return true;
402 } else {
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500403 String[] packages = mPm.getPackagesForUid(Binder.getCallingUid());
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400404 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
Beverlyd4f96492017-08-02 13:36:11 -0400416 public void setDefaultZenRules(Context context) {
417 mDefaultConfig = readDefaultConfig(context.getResources());
Beverlyd4f96492017-08-02 13:36:11 -0400418 appendDefaultRules(mDefaultConfig);
419 }
420
421 private void appendDefaultRules (ZenModeConfig config) {
Beverly30bfbca2017-10-17 14:38:20 -0400422 getDefaultRuleNames();
Beverly26eba872017-12-04 16:30:11 -0500423 appendDefaultEveryNightRule(config);
Beverlyd4f96492017-08-02 13:36:11 -0400424 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
Beverly26eba872017-12-04 16:30:11 -0500442 for (String ruleId : ZenModeConfig.DEFAULT_RULE_IDS) {
Beverlyd4f96492017-08-02 13:36:11 -0400443 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);
Beverly83639442017-09-06 10:36:04 -0400453 // ensure enabled state is carried over from current rule
454 defaultAutoRule.setEnabled(currRule.isEnabled());
Beverlyd4f96492017-08-02 13:36:11 -0400455 updateAutomaticZenRule(ruleId, defaultAutoRule,
456 "locale changed");
457 }
458 }
459 }
460 }
461
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500462 private boolean isSystemRule(AutomaticZenRule rule) {
463 return ZenModeConfig.SYSTEM_AUTHORITY.equals(rule.getOwner().getPackageName());
464 }
465
466 private ServiceInfo getServiceInfo(ComponentName owner) {
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500467 Intent queryIntent = new Intent();
468 queryIntent.setComponent(owner);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500469 List<ResolveInfo> installedServices = mPm.queryIntentServicesAsUser(
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500470 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)) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500478 return info;
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500479 }
480 }
481 }
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500482 return null;
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500483 }
484
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400485 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
Beverlyd4f96492017-08-02 13:36:11 -0400503 protected AutomaticZenRule createAutomaticZenRule(ZenRule rule) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400504 return new AutomaticZenRule(rule.name, rule.component, rule.conditionId,
Julia Reynolds56106ff2015-09-30 14:42:53 -0400505 NotificationManager.zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
Julia Reynolds361e82d32016-02-26 18:19:49 -0500506 rule.creationTime);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400507 }
508
Julia Reynolds44ad6ff2016-07-06 09:47:45 -0400509 public void setManualZenMode(int zenMode, Uri conditionId, String caller, String reason) {
510 setManualZenMode(zenMode, conditionId, reason, caller, true /*setRingerMode*/);
Beverly91d0a632018-07-02 16:45:00 -0400511 Settings.Secure.putInt(mContext.getContentResolver(),
512 Settings.Secure.SHOW_ZEN_SETTINGS_SUGGESTION, 0);
John Spurlocke77bb362014-04-26 10:24:59 -0400513 }
514
Julia Reynolds44ad6ff2016-07-06 09:47:45 -0400515 private void setManualZenMode(int zenMode, Uri conditionId, String reason, String caller,
John Spurlockb2278d62015-04-07 12:47:12 -0400516 boolean setRingerMode) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400517 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();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500525 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 }
John Spurlockb2278d62015-04-07 12:47:12 -0400531 }
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500532 } else {
533 final ZenRule newRule = new ZenRule();
534 newRule.enabled = true;
535 newRule.zenMode = zenMode;
536 newRule.conditionId = conditionId;
Julia Reynolds44ad6ff2016-07-06 09:47:45 -0400537 newRule.enabler = caller;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500538 newConfig.manualRule = newRule;
John Spurlockb2278d62015-04-07 12:47:12 -0400539 }
Julia Reynolds8f056002018-07-13 15:12:29 -0400540 setConfigLocked(newConfig, reason, null, setRingerMode);
John Spurlockb2278d62015-04-07 12:47:12 -0400541 }
John Spurlockb2278d62015-04-07 12:47:12 -0400542 }
543
Julia Reynolds520df6e2017-02-13 09:05:10 -0500544 void dump(ProtoOutputStream proto) {
Julia Reynolds520df6e2017-02-13 09:05:10 -0500545 proto.write(ZenModeProto.ZEN_MODE, mZenMode);
546 synchronized (mConfig) {
547 if (mConfig.manualRule != null) {
Kweku Adams99546332018-01-24 17:03:50 -0800548 mConfig.manualRule.writeToProto(proto, ZenModeProto.ENABLED_ACTIVE_CONDITIONS);
Julia Reynolds520df6e2017-02-13 09:05:10 -0500549 }
550 for (ZenRule rule : mConfig.automaticRules.values()) {
551 if (rule.enabled && rule.condition.state == Condition.STATE_TRUE
552 && !rule.snoozing) {
Kweku Adams99546332018-01-24 17:03:50 -0800553 rule.writeToProto(proto, ZenModeProto.ENABLED_ACTIVE_CONDITIONS);
Julia Reynolds520df6e2017-02-13 09:05:10 -0500554 }
555 }
Kweku Adamsbc84aec2018-01-23 13:33:12 -0800556 mConfig.toNotificationPolicy().writeToProto(proto, ZenModeProto.POLICY);
Julia Reynolds520df6e2017-02-13 09:05:10 -0500557 proto.write(ZenModeProto.SUPPRESSED_EFFECTS, mSuppressedEffects);
558 }
559 }
560
John Spurlockb2278d62015-04-07 12:47:12 -0400561 public void dump(PrintWriter pw, String prefix) {
562 pw.print(prefix); pw.print("mZenMode=");
563 pw.println(Global.zenModeToString(mZenMode));
John Spurlock21258a32015-05-27 18:22:55 -0400564 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);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400569 synchronized (mConfig) {
570 dump(pw, prefix, "mConfig", mConfig);
571 }
Bryce Lee7219ada2016-04-08 10:54:23 -0700572
573 pw.print(prefix); pw.print("mSuppressedEffects="); pw.println(mSuppressedEffects);
John Spurlock1d7d2242015-04-10 08:10:22 -0400574 mFiltering.dump(pw, prefix);
John Spurlockb2278d62015-04-07 12:47:12 -0400575 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 }
Julia Reynoldsccc6ae62018-03-01 16:24:49 -0500584 pw.printf("allow(alarms=%b,media=%b,system=%b,calls=%b,callsFrom=%s,repeatCallers=%b,"
Julia Reynolds1f580572018-04-27 14:48:36 -0400585 + "messages=%b,messagesFrom=%s,events=%b,reminders=%b)\n",
Beverlyd6964762018-02-16 14:07:03 -0500586 config.allowAlarms, config.allowMedia, config.allowSystem,
Julia Reynolds6ee26172015-09-28 11:34:48 -0400587 config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom),
588 config.allowRepeatCallers, config.allowMessages,
589 ZenModeConfig.sourceToString(config.allowMessagesFrom),
Julia Reynolds1f580572018-04-27 14:48:36 -0400590 config.allowEvents, config.allowReminders);
Julia Reynoldsccc6ae62018-03-01 16:24:49 -0500591 pw.printf(" disallow(visualEffects=%s)\n", config.suppressedVisualEffects);
John Spurlockb2278d62015-04-07 12:47:12 -0400592 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
John Spurlock35ef0a62015-05-28 11:24:10 -0400601 public void readXml(XmlPullParser parser, boolean forRestore)
602 throws XmlPullParserException, IOException {
Beverly4e2f76c2018-03-16 15:43:49 -0400603 ZenModeConfig config = ZenModeConfig.readXml(parser);
604 String reason = "readXml";
605
John Spurlockb2278d62015-04-07 12:47:12 -0400606 if (config != null) {
John Spurlock35ef0a62015-05-28 11:24:10 -0400607 if (forRestore) {
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700608 //TODO: http://b/22388012
609 if (config.user != UserHandle.USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -0400610 return;
611 }
612 config.manualRule = null; // don't restore the manual rule
Beverly4e2f76c2018-03-16 15:43:49 -0400613 }
614
Beverlyad3841a2018-07-31 11:23:35 -0400615 // booleans to determine whether to reset the rules to the default rules
616 boolean allRulesDisabled = true;
617 boolean hasDefaultRules = config.automaticRules.containsAll(
618 ZenModeConfig.DEFAULT_RULE_IDS);
619
Beverly4e2f76c2018-03-16 15:43:49 -0400620 long time = System.currentTimeMillis();
621 if (config.automaticRules != null && config.automaticRules.size() > 0) {
622 for (ZenRule automaticRule : config.automaticRules.values()) {
623 if (forRestore) {
John Spurlock995a7492015-05-28 22:13:03 -0400624 // don't restore transient state from restored automatic rules
625 automaticRule.snoozing = false;
626 automaticRule.condition = null;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500627 automaticRule.creationTime = time;
John Spurlock995a7492015-05-28 22:13:03 -0400628 }
Beverlyad3841a2018-07-31 11:23:35 -0400629
630 allRulesDisabled &= !automaticRule.enabled;
John Spurlock995a7492015-05-28 22:13:03 -0400631 }
John Spurlock35ef0a62015-05-28 11:24:10 -0400632 }
Beverly4e2f76c2018-03-16 15:43:49 -0400633
Beverlyad3841a2018-07-31 11:23:35 -0400634 if (!hasDefaultRules && allRulesDisabled
635 && (forRestore || config.version < ZenModeConfig.XML_VERSION)) {
636 // reset zen automatic rules to default on restore or upgrade if:
637 // - doesn't already have default rules and
638 // - all previous automatic rules were disabled
639 config.automaticRules = new ArrayMap<>();
640 appendDefaultRules(config);
641 reason += ", reset to default rules";
642 }
643
644 if (config.version < ZenModeConfig.XML_VERSION) {
Beverly91d0a632018-07-02 16:45:00 -0400645 Settings.Secure.putInt(mContext.getContentResolver(),
646 Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 1);
Beverly301e92a2018-04-27 09:43:05 -0400647 } else {
648 // devices not restoring/upgrading already have updated zen settings
Beverly91d0a632018-07-02 16:45:00 -0400649 Settings.Secure.putInt(mContext.getContentResolver(),
650 Settings.Secure.ZEN_SETTINGS_UPDATED, 1);
Beverly4e2f76c2018-03-16 15:43:49 -0400651 }
652 if (DEBUG) Log.d(TAG, reason);
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500653 synchronized (mConfig) {
Julia Reynolds8f056002018-07-13 15:12:29 -0400654 setConfigLocked(config, null, reason);
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500655 }
John Spurlockb2278d62015-04-07 12:47:12 -0400656 }
657 }
658
Beverly4e2f76c2018-03-16 15:43:49 -0400659 public void writeXml(XmlSerializer out, boolean forBackup, Integer version) throws IOException {
John Spurlock21258a32015-05-27 18:22:55 -0400660 final int N = mConfigs.size();
661 for (int i = 0; i < N; i++) {
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700662 //TODO: http://b/22388012
663 if (forBackup && mConfigs.keyAt(i) != UserHandle.USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -0400664 continue;
665 }
Beverly4e2f76c2018-03-16 15:43:49 -0400666 mConfigs.valueAt(i).writeXml(out, version);
John Spurlock21258a32015-05-27 18:22:55 -0400667 }
John Spurlockb2278d62015-04-07 12:47:12 -0400668 }
669
John Spurlock1fc476d2015-04-14 16:05:20 -0400670 public Policy getNotificationPolicy() {
671 return getNotificationPolicy(mConfig);
672 }
673
674 private static Policy getNotificationPolicy(ZenModeConfig config) {
675 return config == null ? null : config.toNotificationPolicy();
676 }
677
678 public void setNotificationPolicy(Policy policy) {
679 if (policy == null || mConfig == null) return;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500680 synchronized (mConfig) {
681 final ZenModeConfig newConfig = mConfig.copy();
682 newConfig.applyNotificationPolicy(policy);
Julia Reynolds8f056002018-07-13 15:12:29 -0400683 setConfigLocked(newConfig, null, "setNotificationPolicy");
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500684 }
John Spurlock1fc476d2015-04-14 16:05:20 -0400685 }
686
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500687 /**
688 * Removes old rule instances whose owner is not installed.
689 */
690 private void cleanUpZenRules() {
691 long currentTime = System.currentTimeMillis();
692 synchronized (mConfig) {
693 final ZenModeConfig newConfig = mConfig.copy();
694 if (newConfig.automaticRules != null) {
695 for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
696 ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
697 if (RULE_INSTANCE_GRACE_PERIOD < (currentTime - rule.creationTime)) {
698 try {
Jeff Sharkeyc7bacab2016-02-09 15:56:11 -0700699 mPm.getPackageInfo(rule.component.getPackageName(),
Amith Yamasani0d1fd8d2016-10-12 14:21:51 -0700700 PackageManager.MATCH_ANY_USER);
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500701 } catch (PackageManager.NameNotFoundException e) {
702 newConfig.automaticRules.removeAt(i);
703 }
704 }
705 }
706 }
Julia Reynolds8f056002018-07-13 15:12:29 -0400707 setConfigLocked(newConfig, null, "cleanUpZenRules");
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500708 }
709 }
710
711 /**
712 * @return a copy of the zen mode configuration
713 */
John Spurlockb2278d62015-04-07 12:47:12 -0400714 public ZenModeConfig getConfig() {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400715 synchronized (mConfig) {
716 return mConfig.copy();
717 }
John Spurlockb2278d62015-04-07 12:47:12 -0400718 }
719
Julia Reynolds8f056002018-07-13 15:12:29 -0400720 public boolean setConfigLocked(ZenModeConfig config, ComponentName triggeringComponent,
721 String reason) {
722 return setConfigLocked(config, reason, triggeringComponent, true /*setRingerMode*/);
John Spurlockb2278d62015-04-07 12:47:12 -0400723 }
724
Julia Reynolds8f056002018-07-13 15:12:29 -0400725 public void setConfig(ZenModeConfig config, ComponentName triggeringComponent, String reason) {
Julia Reynolds89aeab02016-09-15 11:07:50 -0400726 synchronized (mConfig) {
Julia Reynolds8f056002018-07-13 15:12:29 -0400727 setConfigLocked(config, triggeringComponent, reason);
Julia Reynolds89aeab02016-09-15 11:07:50 -0400728 }
Eric Laurente0ced4d2015-09-30 17:44:28 -0700729 }
730
Julia Reynolds8f056002018-07-13 15:12:29 -0400731 private boolean setConfigLocked(ZenModeConfig config, String reason,
732 ComponentName triggeringComponent, boolean setRingerMode) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400733 final long identity = Binder.clearCallingIdentity();
734 try {
735 if (config == null || !config.isValid()) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500736 Log.w(TAG, "Invalid config in setConfigLocked; " + config);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400737 return false;
738 }
739 if (config.user != mUser) {
740 // simply store away for background users
741 mConfigs.put(config.user, config);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500742 if (DEBUG) Log.d(TAG, "setConfigLocked: store config for user " + config.user);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400743 return true;
744 }
Julia Reynolds8f056002018-07-13 15:12:29 -0400745 // may modify config
746 mConditions.evaluateConfig(config, null, false /*processSubscriptions*/);
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500747 mConfigs.put(config.user, config);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500748 if (DEBUG) Log.d(TAG, "setConfigLocked reason=" + reason, new Throwable());
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500749 ZenLog.traceConfig(reason, mConfig, config);
750 final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
751 getNotificationPolicy(config));
Julia Reynolds9a25da12016-01-06 16:19:28 -0500752 if (!config.equals(mConfig)) {
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500753 dispatchOnConfigChanged();
754 }
755 if (policyChanged) {
756 dispatchOnPolicyChanged();
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400757 }
Julia Reynolds9a25da12016-01-06 16:19:28 -0500758 mConfig = config;
Julia Reynolds8f056002018-07-13 15:12:29 -0400759 mHandler.postApplyConfig(config, reason, triggeringComponent, setRingerMode);
John Spurlock21258a32015-05-27 18:22:55 -0400760 return true;
Julia Reynoldscb507b82017-09-07 13:53:40 -0400761 } catch (SecurityException e) {
762 Log.wtf(TAG, "Invalid rule in config", e);
763 return false;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400764 } finally {
765 Binder.restoreCallingIdentity(identity);
John Spurlock21258a32015-05-27 18:22:55 -0400766 }
John Spurlockb2278d62015-04-07 12:47:12 -0400767 }
768
Julia Reynolds8f056002018-07-13 15:12:29 -0400769 private void applyConfig(ZenModeConfig config, String reason,
770 ComponentName triggeringComponent, boolean setRingerMode) {
Julia Reynoldsd82e9812016-04-19 13:27:41 -0400771 final String val = Integer.toString(config.hashCode());
772 Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
773 if (!evaluateZenMode(reason, setRingerMode)) {
774 applyRestrictions(); // evaluateZenMode will also apply restrictions if changed
775 }
Julia Reynolds8f056002018-07-13 15:12:29 -0400776 mConditions.evaluateConfig(config, triggeringComponent, true /*processSubscriptions*/);
Julia Reynoldsd82e9812016-04-19 13:27:41 -0400777 }
778
John Spurlockb2278d62015-04-07 12:47:12 -0400779 private int getZenModeSetting() {
780 return Global.getInt(mContext.getContentResolver(), Global.ZEN_MODE, Global.ZEN_MODE_OFF);
781 }
782
Beverly3bae4e52018-02-07 12:32:02 -0500783 @VisibleForTesting
784 protected void setZenModeSetting(int zen) {
John Spurlockb2278d62015-04-07 12:47:12 -0400785 Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zen);
Beverly3bae4e52018-02-07 12:32:02 -0500786 showZenUpgradeNotification(zen);
John Spurlockb2278d62015-04-07 12:47:12 -0400787 }
788
Julia Reynolds9b11fdb2015-07-31 09:49:55 -0400789 private int getPreviousRingerModeSetting() {
790 return Global.getInt(mContext.getContentResolver(),
791 Global.ZEN_MODE_RINGER_LEVEL, AudioManager.RINGER_MODE_NORMAL);
792 }
793
794 private void setPreviousRingerModeSetting(Integer previousRingerLevel) {
795 Global.putString(
796 mContext.getContentResolver(), Global.ZEN_MODE_RINGER_LEVEL,
797 previousRingerLevel == null ? null : Integer.toString(previousRingerLevel));
798 }
799
Beverlye4ee1cc2018-03-06 17:21:08 -0500800 @VisibleForTesting
801 protected boolean evaluateZenMode(String reason, boolean setRingerMode) {
John Spurlockb2278d62015-04-07 12:47:12 -0400802 if (DEBUG) Log.d(TAG, "evaluateZenMode");
Jason Monka9927322015-12-13 16:22:37 -0500803 final int zenBefore = mZenMode;
Julia Reynolds8ac63032015-08-31 15:19:43 -0400804 final int zen = computeZenMode();
John Spurlockb2278d62015-04-07 12:47:12 -0400805 ZenLog.traceSetZenMode(zen, reason);
806 mZenMode = zen;
807 setZenModeSetting(mZenMode);
Beverlyd6964762018-02-16 14:07:03 -0500808 updateRingerModeAffectedStreams();
Beverlye4ee1cc2018-03-06 17:21:08 -0500809 if (setRingerMode && zen != zenBefore) {
John Spurlock57627792014-12-11 11:29:54 -0500810 applyZenToRingerMode();
811 }
812 applyRestrictions();
Jason Monka9927322015-12-13 16:22:37 -0500813 if (zen != zenBefore) {
Julia Reynolds8ac63032015-08-31 15:19:43 -0400814 mHandler.postDispatchOnZenModeChanged();
815 }
John Spurlockb2278d62015-04-07 12:47:12 -0400816 return true;
John Spurlock57627792014-12-11 11:29:54 -0500817 }
818
John Spurlock50ced3f2015-05-11 16:00:09 -0400819 private void updateRingerModeAffectedStreams() {
820 if (mAudioManager != null) {
821 mAudioManager.updateRingerModeAffectedStreamsInternal();
822 }
823 }
824
Julia Reynolds8ac63032015-08-31 15:19:43 -0400825 private int computeZenMode() {
Beverlye4ee1cc2018-03-06 17:21:08 -0500826 if (mConfig == null) return Global.ZEN_MODE_OFF;
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400827 synchronized (mConfig) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400828 if (mConfig.manualRule != null) return mConfig.manualRule.zenMode;
829 int zen = Global.ZEN_MODE_OFF;
830 for (ZenRule automaticRule : mConfig.automaticRules.values()) {
831 if (automaticRule.isAutomaticActive()) {
832 if (zenSeverity(automaticRule.zenMode) > zenSeverity(zen)) {
Beverly301e92a2018-04-27 09:43:05 -0400833 // automatic rule triggered dnd and user hasn't seen update dnd dialog
Beverly91d0a632018-07-02 16:45:00 -0400834 if (Settings.Secure.getInt(mContext.getContentResolver(),
835 Settings.Secure.ZEN_SETTINGS_SUGGESTION_VIEWED, 1) == 0) {
836 Settings.Secure.putInt(mContext.getContentResolver(),
837 Settings.Secure.SHOW_ZEN_SETTINGS_SUGGESTION, 1);
Beverly301e92a2018-04-27 09:43:05 -0400838 }
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400839 zen = automaticRule.zenMode;
840 }
John Spurlockb2278d62015-04-07 12:47:12 -0400841 }
842 }
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400843 return zen;
John Spurlockb2278d62015-04-07 12:47:12 -0400844 }
John Spurlock8403b752014-12-10 12:47:01 -0500845 }
846
Beverly30bfbca2017-10-17 14:38:20 -0400847 private void getDefaultRuleNames() {
848 // on locale-change, these values differ
Beverly26eba872017-12-04 16:30:11 -0500849 mDefaultRuleEveryNightName = mContext.getResources()
850 .getString(R.string.zen_mode_default_every_night_name);
Beverly30bfbca2017-10-17 14:38:20 -0400851 mDefaultRuleEventsName = mContext.getResources()
852 .getString(R.string.zen_mode_default_events_name);
853 }
854
Beverly04216872017-09-28 10:55:32 -0400855 @VisibleForTesting
856 protected void applyRestrictions() {
Beverlyd820bc22018-01-11 15:28:33 -0500857 final boolean zenPriorityOnly = mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
Beverly925cde82018-01-23 09:31:23 -0500858 final boolean zenSilence = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
Beverlyd820bc22018-01-11 15:28:33 -0500859 final boolean zenAlarmsOnly = mZenMode == Global.ZEN_MODE_ALARMS;
John Spurlock8403b752014-12-10 12:47:01 -0500860
861 // notification restrictions
Bryce Lee7219ada2016-04-08 10:54:23 -0700862 final boolean muteNotifications =
863 (mSuppressedEffects & SUPPRESSED_EFFECT_NOTIFICATIONS) != 0;
John Spurlock056c5192014-04-20 21:52:01 -0400864 // call restrictions
Beverlyd820bc22018-01-11 15:28:33 -0500865 final boolean muteCalls = zenAlarmsOnly
866 || (zenPriorityOnly && !mConfig.allowCalls && !mConfig.allowRepeatCallers)
Bryce Lee7219ada2016-04-08 10:54:23 -0700867 || (mSuppressedEffects & SUPPRESSED_EFFECT_CALLS) != 0;
Beverly04216872017-09-28 10:55:32 -0400868 // alarm restrictions
Beverlyd820bc22018-01-11 15:28:33 -0500869 final boolean muteAlarms = zenPriorityOnly && !mConfig.allowAlarms;
Beverlyd6964762018-02-16 14:07:03 -0500870 // media restrictions
871 final boolean muteMedia = zenPriorityOnly && !mConfig.allowMedia;
872 // system restrictions
873 final boolean muteSystem = zenAlarmsOnly || (zenPriorityOnly && !mConfig.allowSystem);
Julia Reynolds3fe81be2016-02-03 09:10:06 -0500874 // total silence restrictions
Beverlyd820bc22018-01-11 15:28:33 -0500875 final boolean muteEverything = zenSilence
Beverly925cde82018-01-23 09:31:23 -0500876 || (zenPriorityOnly && ZenModeConfig.areAllZenBehaviorSoundsMuted(mConfig));
John Spurlock25d01ee2015-06-03 12:17:46 -0400877
Jean-Michel Trivie743bda2016-09-09 11:56:48 -0700878 for (int usage : AudioAttributes.SDK_USAGES) {
879 final int suppressionBehavior = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage);
Jean-Michel Trivi7a84eae2017-06-20 14:58:18 -0700880 if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NEVER) {
881 applyRestrictions(false /*mute*/, usage);
882 } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NOTIFICATION) {
Jean-Michel Trivie743bda2016-09-09 11:56:48 -0700883 applyRestrictions(muteNotifications || muteEverything, usage);
884 } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_CALL) {
885 applyRestrictions(muteCalls || muteEverything, usage);
Beverly04216872017-09-28 10:55:32 -0400886 } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_ALARM) {
887 applyRestrictions(muteAlarms || muteEverything, usage);
Beverlyd6964762018-02-16 14:07:03 -0500888 } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_MEDIA) {
889 applyRestrictions(muteMedia || muteEverything, usage);
890 } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_SYSTEM) {
Beverly738bffd2018-03-12 10:46:17 -0400891 if (usage == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) {
892 // normally DND will only restrict touch sounds, not haptic feedback/vibrations
893 applyRestrictions(muteSystem || muteEverything, usage,
894 AppOpsManager.OP_PLAY_AUDIO);
895 applyRestrictions(false, usage, AppOpsManager.OP_VIBRATE);
896 } else {
897 applyRestrictions(muteSystem || muteEverything, usage);
898 }
Julia Reynolds3fe81be2016-02-03 09:10:06 -0500899 } else {
Jean-Michel Trivie743bda2016-09-09 11:56:48 -0700900 applyRestrictions(muteEverything, usage);
Julia Reynolds3fe81be2016-02-03 09:10:06 -0500901 }
902 }
John Spurlock8403b752014-12-10 12:47:01 -0500903 }
John Spurlockae641c92014-06-30 18:11:40 -0400904
Beverlye2d9a232017-11-08 18:14:59 -0500905
Beverly04216872017-09-28 10:55:32 -0400906 @VisibleForTesting
Beverly738bffd2018-03-12 10:46:17 -0400907 protected void applyRestrictions(boolean mute, int usage, int code) {
John Spurlock8403b752014-12-10 12:47:01 -0500908 final String[] exceptionPackages = null; // none (for now)
Beverlye2d9a232017-11-08 18:14:59 -0500909
Dianne Hackbornbf1b57d2018-03-07 12:42:47 -0800910 // Only do this if we are executing within the system process... otherwise
911 // we are running as test code, so don't have access to the protected call.
912 if (Process.myUid() == Process.SYSTEM_UID) {
913 final long ident = Binder.clearCallingIdentity();
914 try {
915 mAppOps.setRestriction(code, usage,
916 mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
917 exceptionPackages);
918 } finally {
919 Binder.restoreCallingIdentity(ident);
920 }
921 }
John Spurlock056c5192014-04-20 21:52:01 -0400922 }
923
Beverly85f52412018-02-27 10:41:13 -0500924 @VisibleForTesting
Beverly738bffd2018-03-12 10:46:17 -0400925 protected void applyRestrictions(boolean mute, int usage) {
926 applyRestrictions(mute, usage, AppOpsManager.OP_VIBRATE);
927 applyRestrictions(mute, usage, AppOpsManager.OP_PLAY_AUDIO);
928 }
929
930
931 @VisibleForTesting
Beverly85f52412018-02-27 10:41:13 -0500932 protected void applyZenToRingerMode() {
John Spurlock661f2cf2014-11-17 10:29:10 -0500933 if (mAudioManager == null) return;
John Spurlock661f2cf2014-11-17 10:29:10 -0500934 // force the ringer mode into compliance
935 final int ringerModeInternal = mAudioManager.getRingerModeInternal();
936 int newRingerModeInternal = ringerModeInternal;
John Spurlock57627792014-12-11 11:29:54 -0500937 switch (mZenMode) {
John Spurlock661f2cf2014-11-17 10:29:10 -0500938 case Global.ZEN_MODE_NO_INTERRUPTIONS:
John Spurlock4f1163c2015-04-02 17:41:21 -0400939 case Global.ZEN_MODE_ALARMS:
John Spurlock661f2cf2014-11-17 10:29:10 -0500940 if (ringerModeInternal != AudioManager.RINGER_MODE_SILENT) {
Julia Reynolds9b11fdb2015-07-31 09:49:55 -0400941 setPreviousRingerModeSetting(ringerModeInternal);
John Spurlock661f2cf2014-11-17 10:29:10 -0500942 newRingerModeInternal = AudioManager.RINGER_MODE_SILENT;
John Spurlock8c01d882014-07-28 13:37:13 -0400943 }
John Spurlock661f2cf2014-11-17 10:29:10 -0500944 break;
945 case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
Beverly9e4214d2018-03-26 11:10:10 -0400946 // do not apply zen to ringer, streams zen muted in AudioService
Beverly925cde82018-01-23 09:31:23 -0500947 break;
John Spurlock661f2cf2014-11-17 10:29:10 -0500948 case Global.ZEN_MODE_OFF:
949 if (ringerModeInternal == AudioManager.RINGER_MODE_SILENT) {
Julia Reynolds9b11fdb2015-07-31 09:49:55 -0400950 newRingerModeInternal = getPreviousRingerModeSetting();
951 setPreviousRingerModeSetting(null);
John Spurlock661f2cf2014-11-17 10:29:10 -0500952 }
953 break;
John Spurlock8c01d882014-07-28 13:37:13 -0400954 }
John Spurlock661f2cf2014-11-17 10:29:10 -0500955 if (newRingerModeInternal != -1) {
956 mAudioManager.setRingerModeInternal(newRingerModeInternal, TAG);
957 }
958 }
959
John Spurlock1c923a32014-04-27 16:42:29 -0400960 private void dispatchOnConfigChanged() {
961 for (Callback callback : mCallbacks) {
962 callback.onConfigChanged();
963 }
964 }
965
John Spurlock1fc476d2015-04-14 16:05:20 -0400966 private void dispatchOnPolicyChanged() {
967 for (Callback callback : mCallbacks) {
968 callback.onPolicyChanged();
969 }
970 }
971
John Spurlock1c923a32014-04-27 16:42:29 -0400972 private void dispatchOnZenModeChanged() {
973 for (Callback callback : mCallbacks) {
974 callback.onZenModeChanged();
975 }
976 }
977
John Spurlockb2278d62015-04-07 12:47:12 -0400978 private ZenModeConfig readDefaultConfig(Resources resources) {
979 XmlResourceParser parser = null;
980 try {
981 parser = resources.getXml(R.xml.default_zen_mode_config);
982 while (parser.next() != XmlPullParser.END_DOCUMENT) {
Julia Reynolds206c7e92016-09-15 10:38:03 -0400983 final ZenModeConfig config = ZenModeConfig.readXml(parser);
John Spurlockb2278d62015-04-07 12:47:12 -0400984 if (config != null) return config;
985 }
986 } catch (Exception e) {
987 Log.w(TAG, "Error reading default zen mode config from resource", e);
988 } finally {
989 IoUtils.closeQuietly(parser);
990 }
991 return new ZenModeConfig();
992 }
993
Beverly26eba872017-12-04 16:30:11 -0500994 private void appendDefaultEveryNightRule(ZenModeConfig config) {
John Spurlockb2278d62015-04-07 12:47:12 -0400995 if (config == null) return;
996
997 final ScheduleInfo weeknights = new ScheduleInfo();
Beverly26eba872017-12-04 16:30:11 -0500998 weeknights.days = ZenModeConfig.ALL_DAYS;
John Spurlockb2278d62015-04-07 12:47:12 -0400999 weeknights.startHour = 22;
1000 weeknights.endHour = 7;
Beverly30bfbca2017-10-17 14:38:20 -04001001 weeknights.exitAtAlarm = true;
Beverly26eba872017-12-04 16:30:11 -05001002 final ZenRule rule = new ZenRule();
1003 rule.enabled = false;
1004 rule.name = mDefaultRuleEveryNightName;
1005 rule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
1006 rule.zenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
1007 rule.component = ScheduleConditionProvider.COMPONENT;
1008 rule.id = ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID;
1009 rule.creationTime = System.currentTimeMillis();
1010 config.automaticRules.put(rule.id, rule);
John Spurlockb2278d62015-04-07 12:47:12 -04001011 }
1012
John Spurlockcb9aa202015-05-08 17:35:22 -04001013 private void appendDefaultEventRules(ZenModeConfig config) {
1014 if (config == null) return;
1015
1016 final EventInfo events = new EventInfo();
John Spurlock995a7492015-05-28 22:13:03 -04001017 events.calendar = null; // any calendar
John Spurlockcb9aa202015-05-08 17:35:22 -04001018 events.reply = EventInfo.REPLY_YES_OR_MAYBE;
1019 final ZenRule rule = new ZenRule();
1020 rule.enabled = false;
Beverlyd4f96492017-08-02 13:36:11 -04001021 rule.name = mDefaultRuleEventsName;
John Spurlockcb9aa202015-05-08 17:35:22 -04001022 rule.conditionId = ZenModeConfig.toEventConditionId(events);
Beverlybf16c142017-11-27 16:21:34 -05001023 rule.zenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001024 rule.component = EventConditionProvider.COMPONENT;
Beverly26eba872017-12-04 16:30:11 -05001025 rule.id = ZenModeConfig.EVENTS_DEFAULT_RULE_ID;
Julia Reynolds56106ff2015-09-30 14:42:53 -04001026 rule.creationTime = System.currentTimeMillis();
1027 config.automaticRules.put(rule.id, rule);
John Spurlockcb9aa202015-05-08 17:35:22 -04001028 }
1029
John Spurlockb2278d62015-04-07 12:47:12 -04001030 private static int zenSeverity(int zen) {
1031 switch (zen) {
1032 case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return 1;
1033 case Global.ZEN_MODE_ALARMS: return 2;
1034 case Global.ZEN_MODE_NO_INTERRUPTIONS: return 3;
1035 default: return 0;
1036 }
1037 }
1038
Beverly85f52412018-02-27 10:41:13 -05001039 @VisibleForTesting
1040 protected final class RingerModeDelegate implements AudioManagerInternal.RingerModeDelegate {
John Spurlockb2278d62015-04-07 12:47:12 -04001041 @Override
1042 public String toString() {
1043 return TAG;
1044 }
1045
1046 @Override
1047 public int onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller,
1048 int ringerModeExternal, VolumePolicy policy) {
1049 final boolean isChange = ringerModeOld != ringerModeNew;
1050
1051 int ringerModeExternalOut = ringerModeNew;
1052
Beverlye4ee1cc2018-03-06 17:21:08 -05001053 if (mZenMode == Global.ZEN_MODE_OFF
1054 || (mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
1055 && !ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(mConfig))) {
1056 // in priority only with ringer not muted, save ringer mode changes
1057 // in dnd off, save ringer mode changes
1058 setPreviousRingerModeSetting(ringerModeNew);
1059 }
John Spurlockb2278d62015-04-07 12:47:12 -04001060 int newZen = -1;
1061 switch (ringerModeNew) {
1062 case AudioManager.RINGER_MODE_SILENT:
1063 if (isChange && policy.doNotDisturbWhenSilent) {
Beverly925cde82018-01-23 09:31:23 -05001064 if (mZenMode == Global.ZEN_MODE_OFF) {
Julia Reynoldsf3252be2018-01-17 09:26:21 -05001065 newZen = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
John Spurlockb2278d62015-04-07 12:47:12 -04001066 }
Julia Reynolds9b11fdb2015-07-31 09:49:55 -04001067 setPreviousRingerModeSetting(ringerModeOld);
John Spurlockb2278d62015-04-07 12:47:12 -04001068 }
1069 break;
1070 case AudioManager.RINGER_MODE_VIBRATE:
1071 case AudioManager.RINGER_MODE_NORMAL:
1072 if (isChange && ringerModeOld == AudioManager.RINGER_MODE_SILENT
1073 && (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS
Beverly925cde82018-01-23 09:31:23 -05001074 || mZenMode == Global.ZEN_MODE_ALARMS
1075 || (mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
1076 && ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(
Beverlyd6964762018-02-16 14:07:03 -05001077 mConfig)))) {
John Spurlockb2278d62015-04-07 12:47:12 -04001078 newZen = Global.ZEN_MODE_OFF;
1079 } else if (mZenMode != Global.ZEN_MODE_OFF) {
1080 ringerModeExternalOut = AudioManager.RINGER_MODE_SILENT;
1081 }
1082 break;
1083 }
Beverly85f52412018-02-27 10:41:13 -05001084
John Spurlockb2278d62015-04-07 12:47:12 -04001085 if (newZen != -1) {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04001086 setManualZenMode(newZen, null, "ringerModeInternal", null,
1087 false /*setRingerMode*/);
John Spurlockb2278d62015-04-07 12:47:12 -04001088 }
John Spurlockb2278d62015-04-07 12:47:12 -04001089 if (isChange || newZen != -1 || ringerModeExternal != ringerModeExternalOut) {
1090 ZenLog.traceSetRingerModeInternal(ringerModeOld, ringerModeNew, caller,
1091 ringerModeExternal, ringerModeExternalOut);
1092 }
1093 return ringerModeExternalOut;
1094 }
1095
1096 @Override
1097 public int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller,
1098 int ringerModeInternal, VolumePolicy policy) {
1099 int ringerModeInternalOut = ringerModeNew;
1100 final boolean isChange = ringerModeOld != ringerModeNew;
1101 final boolean isVibrate = ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE;
1102
1103 int newZen = -1;
1104 switch (ringerModeNew) {
1105 case AudioManager.RINGER_MODE_SILENT:
1106 if (isChange) {
1107 if (mZenMode == Global.ZEN_MODE_OFF) {
Julia Reynoldsf3252be2018-01-17 09:26:21 -05001108 newZen = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
John Spurlockb2278d62015-04-07 12:47:12 -04001109 }
1110 ringerModeInternalOut = isVibrate ? AudioManager.RINGER_MODE_VIBRATE
John Spurlock05715ec2015-05-13 11:19:19 -04001111 : AudioManager.RINGER_MODE_SILENT;
John Spurlockb2278d62015-04-07 12:47:12 -04001112 } else {
1113 ringerModeInternalOut = ringerModeInternal;
1114 }
1115 break;
1116 case AudioManager.RINGER_MODE_VIBRATE:
1117 case AudioManager.RINGER_MODE_NORMAL:
1118 if (mZenMode != Global.ZEN_MODE_OFF) {
1119 newZen = Global.ZEN_MODE_OFF;
1120 }
1121 break;
1122 }
1123 if (newZen != -1) {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04001124 setManualZenMode(newZen, null, "ringerModeExternal", caller,
1125 false /*setRingerMode*/);
John Spurlockb2278d62015-04-07 12:47:12 -04001126 }
1127
1128 ZenLog.traceSetRingerModeExternal(ringerModeOld, ringerModeNew, caller,
1129 ringerModeInternal, ringerModeInternalOut);
1130 return ringerModeInternalOut;
1131 }
John Spurlockd9c75db2015-04-28 11:19:13 -04001132
1133 @Override
1134 public boolean canVolumeDownEnterSilent() {
1135 return mZenMode == Global.ZEN_MODE_OFF;
1136 }
John Spurlock50ced3f2015-05-11 16:00:09 -04001137
1138 @Override
1139 public int getRingerModeAffectedStreams(int streams) {
Beverlyd6964762018-02-16 14:07:03 -05001140 // ringtone and notification streams are always affected by ringer mode
1141 // system stream is affected by ringer mode when not in priority-only
John Spurlock50ced3f2015-05-11 16:00:09 -04001142 streams |= (1 << AudioSystem.STREAM_RING) |
Beverlyd6964762018-02-16 14:07:03 -05001143 (1 << AudioSystem.STREAM_NOTIFICATION) |
1144 (1 << AudioSystem.STREAM_SYSTEM);
John Spurlock50ced3f2015-05-11 16:00:09 -04001145
John Spurlock50ced3f2015-05-11 16:00:09 -04001146 if (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
Beverly925cde82018-01-23 09:31:23 -05001147 // alarm and music streams affected by ringer mode when in total silence
John Spurlock50ced3f2015-05-11 16:00:09 -04001148 streams |= (1 << AudioSystem.STREAM_ALARM) |
Beverlyd6964762018-02-16 14:07:03 -05001149 (1 << AudioSystem.STREAM_MUSIC);
John Spurlock50ced3f2015-05-11 16:00:09 -04001150 } else {
1151 streams &= ~((1 << AudioSystem.STREAM_ALARM) |
Beverlyd6964762018-02-16 14:07:03 -05001152 (1 << AudioSystem.STREAM_MUSIC));
1153 }
1154
1155 if (mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
1156 && ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(mConfig)) {
1157 // system stream is not affected by ringer mode in priority only when the ringer
1158 // is zen muted (all other notification categories are muted)
1159 streams &= ~(1 << AudioSystem.STREAM_SYSTEM);
1160 } else {
1161 streams |= (1 << AudioSystem.STREAM_SYSTEM);
John Spurlock50ced3f2015-05-11 16:00:09 -04001162 }
1163 return streams;
1164 }
John Spurlockb2278d62015-04-07 12:47:12 -04001165 }
1166
1167 private final class SettingsObserver extends ContentObserver {
John Spurlock056c5192014-04-20 21:52:01 -04001168 private final Uri ZEN_MODE = Global.getUriFor(Global.ZEN_MODE);
1169
1170 public SettingsObserver(Handler handler) {
1171 super(handler);
1172 }
1173
1174 public void observe() {
1175 final ContentResolver resolver = mContext.getContentResolver();
1176 resolver.registerContentObserver(ZEN_MODE, false /*notifyForDescendents*/, this);
1177 update(null);
1178 }
1179
1180 @Override
1181 public void onChange(boolean selfChange, Uri uri) {
1182 update(uri);
1183 }
1184
1185 public void update(Uri uri) {
1186 if (ZEN_MODE.equals(uri)) {
John Spurlockb2278d62015-04-07 12:47:12 -04001187 if (mZenMode != getZenModeSetting()) {
1188 if (DEBUG) Log.d(TAG, "Fixing zen mode setting");
1189 setZenModeSetting(mZenMode);
1190 }
John Spurlock056c5192014-04-20 21:52:01 -04001191 }
1192 }
1193 }
1194
Beverly3bae4e52018-02-07 12:32:02 -05001195 private void showZenUpgradeNotification(int zen) {
Nicka485ec62018-07-03 11:32:39 -07001196 final boolean isWatch = mContext.getPackageManager().hasSystemFeature(
1197 PackageManager.FEATURE_WATCH);
Beverly3bae4e52018-02-07 12:32:02 -05001198 final boolean showNotification = mIsBootComplete
Julia Reynolds76bfa602018-04-23 09:38:47 -04001199 && zen != Global.ZEN_MODE_OFF
Nicka485ec62018-07-03 11:32:39 -07001200 && !isWatch
Beverly3bae4e52018-02-07 12:32:02 -05001201 && Settings.Global.getInt(mContext.getContentResolver(),
Beverly6c60b902018-08-17 10:10:46 -04001202 Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0) != 0
1203 && Settings.Global.getInt(mContext.getContentResolver(),
1204 Settings.Secure.ZEN_SETTINGS_UPDATED, 0) != 1;
Beverly3bae4e52018-02-07 12:32:02 -05001205
Nicka485ec62018-07-03 11:32:39 -07001206 if (isWatch) {
1207 Settings.Global.putInt(mContext.getContentResolver(),
Beverly91d0a632018-07-02 16:45:00 -04001208 Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0);
Nicka485ec62018-07-03 11:32:39 -07001209 }
1210
Beverly3bae4e52018-02-07 12:32:02 -05001211 if (showNotification) {
1212 mNotificationManager.notify(TAG, SystemMessage.NOTE_ZEN_UPGRADE,
1213 createZenUpgradeNotification());
Beverly91d0a632018-07-02 16:45:00 -04001214 Settings.Secure.putInt(mContext.getContentResolver(),
1215 Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0);
Beverly3bae4e52018-02-07 12:32:02 -05001216 }
1217 }
1218
1219 @VisibleForTesting
1220 protected Notification createZenUpgradeNotification() {
Beverly3bae4e52018-02-07 12:32:02 -05001221 final Bundle extras = new Bundle();
1222 extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
1223 mContext.getResources().getString(R.string.global_action_settings));
Julia Reynolds0b8455d2018-03-14 11:38:44 -04001224 int title = R.string.zen_upgrade_notification_title;
1225 int content = R.string.zen_upgrade_notification_content;
Julia Reynolds76bfa602018-04-23 09:38:47 -04001226 int drawable = R.drawable.ic_zen_24dp;
Julia Reynolds0b8455d2018-03-14 11:38:44 -04001227 if (NotificationManager.Policy.areAllVisualEffectsSuppressed(
1228 getNotificationPolicy().suppressedVisualEffects)) {
1229 title = R.string.zen_upgrade_notification_visd_title;
1230 content = R.string.zen_upgrade_notification_visd_content;
Julia Reynolds76bfa602018-04-23 09:38:47 -04001231 drawable = R.drawable.ic_dnd_block_notifications;
Julia Reynolds0b8455d2018-03-14 11:38:44 -04001232 }
Julia Reynolds76bfa602018-04-23 09:38:47 -04001233
Julia Reynolds9aa1c9e2018-04-09 11:31:15 -04001234 Intent onboardingIntent = new Intent(Settings.ZEN_MODE_ONBOARDING);
1235 onboardingIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
Julia Reynolds0b8455d2018-03-14 11:38:44 -04001236 return new Notification.Builder(mContext, SystemNotificationChannels.DO_NOT_DISTURB)
Julia Reynolds9aa1c9e2018-04-09 11:31:15 -04001237 .setAutoCancel(true)
Beverlyd8b15ee2018-02-13 14:37:38 -05001238 .setSmallIcon(R.drawable.ic_settings_24dp)
Julia Reynolds76bfa602018-04-23 09:38:47 -04001239 .setLargeIcon(Icon.createWithResource(mContext, drawable))
Julia Reynolds0b8455d2018-03-14 11:38:44 -04001240 .setContentTitle(mContext.getResources().getString(title))
1241 .setContentText(mContext.getResources().getString(content))
Julia Reynolds9aa1c9e2018-04-09 11:31:15 -04001242 .setContentIntent(PendingIntent.getActivity(mContext, 0, onboardingIntent,
1243 PendingIntent.FLAG_UPDATE_CURRENT))
Beverly3bae4e52018-02-07 12:32:02 -05001244 .setAutoCancel(true)
1245 .setLocalOnly(true)
1246 .addExtras(extras)
Julia Reynolds0b8455d2018-03-14 11:38:44 -04001247 .setStyle(new Notification.BigTextStyle())
Beverly3bae4e52018-02-07 12:32:02 -05001248 .build();
1249 }
1250
Chris Wren98d235b2015-05-27 18:25:17 -04001251 private final class Metrics extends Callback {
1252 private static final String COUNTER_PREFIX = "dnd_mode_";
1253 private static final long MINIMUM_LOG_PERIOD_MS = 60 * 1000;
1254
1255 private int mPreviousZenMode = -1;
1256 private long mBeginningMs = 0L;
1257
1258 @Override
1259 void onZenModeChanged() {
1260 emit();
1261 }
1262
1263 private void emit() {
1264 mHandler.postMetricsTimer();
1265 final long now = SystemClock.elapsedRealtime();
1266 final long since = (now - mBeginningMs);
1267 if (mPreviousZenMode != mZenMode || since > MINIMUM_LOG_PERIOD_MS) {
1268 if (mPreviousZenMode != -1) {
1269 MetricsLogger.count(mContext, COUNTER_PREFIX + mPreviousZenMode, (int) since);
1270 }
1271 mPreviousZenMode = mZenMode;
1272 mBeginningMs = now;
1273 }
1274 }
1275 }
1276
John Spurlockb2278d62015-04-07 12:47:12 -04001277 private final class H extends Handler {
John Spurlock57627792014-12-11 11:29:54 -05001278 private static final int MSG_DISPATCH = 1;
Chris Wren98d235b2015-05-27 18:25:17 -04001279 private static final int MSG_METRICS = 2;
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001280 private static final int MSG_APPLY_CONFIG = 4;
Eric Laurente0ced4d2015-09-30 17:44:28 -07001281
1282 private final class ConfigMessageData {
1283 public final ZenModeConfig config;
Julia Reynolds8f056002018-07-13 15:12:29 -04001284 public ComponentName triggeringComponent;
Eric Laurente0ced4d2015-09-30 17:44:28 -07001285 public final String reason;
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001286 public final boolean setRingerMode;
Eric Laurente0ced4d2015-09-30 17:44:28 -07001287
Julia Reynolds8f056002018-07-13 15:12:29 -04001288 ConfigMessageData(ZenModeConfig config, String reason,
1289 ComponentName triggeringComponent, boolean setRingerMode) {
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001290 this.config = config;
1291 this.reason = reason;
1292 this.setRingerMode = setRingerMode;
Julia Reynolds8f056002018-07-13 15:12:29 -04001293 this.triggeringComponent = triggeringComponent;
Eric Laurente0ced4d2015-09-30 17:44:28 -07001294 }
1295 }
Chris Wren98d235b2015-05-27 18:25:17 -04001296
1297 private static final long METRICS_PERIOD_MS = 6 * 60 * 60 * 1000;
John Spurlock661f2cf2014-11-17 10:29:10 -05001298
1299 private H(Looper looper) {
1300 super(looper);
John Spurlock056c5192014-04-20 21:52:01 -04001301 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001302
John Spurlock57627792014-12-11 11:29:54 -05001303 private void postDispatchOnZenModeChanged() {
1304 removeMessages(MSG_DISPATCH);
1305 sendEmptyMessage(MSG_DISPATCH);
John Spurlock661f2cf2014-11-17 10:29:10 -05001306 }
1307
Chris Wren98d235b2015-05-27 18:25:17 -04001308 private void postMetricsTimer() {
1309 removeMessages(MSG_METRICS);
1310 sendEmptyMessageDelayed(MSG_METRICS, METRICS_PERIOD_MS);
1311 }
1312
Julia Reynolds8f056002018-07-13 15:12:29 -04001313 private void postApplyConfig(ZenModeConfig config, String reason,
1314 ComponentName triggeringComponent, boolean setRingerMode) {
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001315 sendMessage(obtainMessage(MSG_APPLY_CONFIG,
Julia Reynolds8f056002018-07-13 15:12:29 -04001316 new ConfigMessageData(config, reason, triggeringComponent, setRingerMode)));
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001317 }
1318
John Spurlock661f2cf2014-11-17 10:29:10 -05001319 @Override
1320 public void handleMessage(Message msg) {
John Spurlock57627792014-12-11 11:29:54 -05001321 switch (msg.what) {
1322 case MSG_DISPATCH:
1323 dispatchOnZenModeChanged();
John Spurlock661f2cf2014-11-17 10:29:10 -05001324 break;
Chris Wren98d235b2015-05-27 18:25:17 -04001325 case MSG_METRICS:
1326 mMetrics.emit();
1327 break;
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001328 case MSG_APPLY_CONFIG:
1329 ConfigMessageData applyConfigData = (ConfigMessageData) msg.obj;
1330 applyConfig(applyConfigData.config, applyConfigData.reason,
Julia Reynolds8f056002018-07-13 15:12:29 -04001331 applyConfigData.triggeringComponent, applyConfigData.setRingerMode);
John Spurlock661f2cf2014-11-17 10:29:10 -05001332 }
1333 }
1334 }
John Spurlock056c5192014-04-20 21:52:01 -04001335
John Spurlock1c923a32014-04-27 16:42:29 -04001336 public static class Callback {
1337 void onConfigChanged() {}
1338 void onZenModeChanged() {}
John Spurlock1fc476d2015-04-14 16:05:20 -04001339 void onPolicyChanged() {}
John Spurlock056c5192014-04-20 21:52:01 -04001340 }
John Spurlockb2278d62015-04-07 12:47:12 -04001341
John Spurlock056c5192014-04-20 21:52:01 -04001342}