blob: 669d5565534ded8f2d8736a36ae71e87a7e2dfd3 [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();
John Spurlockb2278d62015-04-07 12:47:12 -0400105 private 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) {
228 setConfigLocked(config, reason);
229 }
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 Reynolds43b70cd2016-01-14 15:05:34 -0500315 if (setConfigLocked(newConfig, reason, 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 Reynolds43b70cd2016-01-14 15:05:34 -0500345 return setConfigLocked(newConfig, reason, 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 Reynolds43b70cd2016-01-14 15:05:34 -0500363 return setConfigLocked(newConfig, reason, 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 Reynolds43b70cd2016-01-14 15:05:34 -0500379 return setConfigLocked(newConfig, reason, 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*/);
Beverly301e92a2018-04-27 09:43:05 -0400511 Settings.Global.putInt(mContext.getContentResolver(), Global.SHOW_ZEN_SETTINGS_SUGGESTION,
512 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 Reynolds43b70cd2016-01-14 15:05:34 -0500540 setConfigLocked(newConfig, reason, 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
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) {
John Spurlock995a7492015-05-28 22:13:03 -0400620 // don't restore transient state from restored automatic rules
621 automaticRule.snoozing = false;
622 automaticRule.condition = null;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500623 automaticRule.creationTime = time;
John Spurlock995a7492015-05-28 22:13:03 -0400624 }
Beverly4e2f76c2018-03-16 15:43:49 -0400625 resetToDefaultRules &= !automaticRule.enabled;
John Spurlock995a7492015-05-28 22:13:03 -0400626 }
John Spurlock35ef0a62015-05-28 11:24:10 -0400627 }
Beverly4e2f76c2018-03-16 15:43:49 -0400628
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 }
Beverly301e92a2018-04-27 09:43:05 -0400640 } else {
641 // devices not restoring/upgrading already have updated zen settings
642 Settings.Global.putInt(mContext.getContentResolver(),
643 Global.ZEN_SETTINGS_UPDATED, 1);
Beverly4e2f76c2018-03-16 15:43:49 -0400644 }
645 if (DEBUG) Log.d(TAG, reason);
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500646 synchronized (mConfig) {
Beverly4e2f76c2018-03-16 15:43:49 -0400647 setConfigLocked(config, reason);
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500648 }
John Spurlockb2278d62015-04-07 12:47:12 -0400649 }
650 }
651
Beverly4e2f76c2018-03-16 15:43:49 -0400652 public void writeXml(XmlSerializer out, boolean forBackup, Integer version) throws IOException {
John Spurlock21258a32015-05-27 18:22:55 -0400653 final int N = mConfigs.size();
654 for (int i = 0; i < N; i++) {
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700655 //TODO: http://b/22388012
656 if (forBackup && mConfigs.keyAt(i) != UserHandle.USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -0400657 continue;
658 }
Beverly4e2f76c2018-03-16 15:43:49 -0400659 mConfigs.valueAt(i).writeXml(out, version);
John Spurlock21258a32015-05-27 18:22:55 -0400660 }
John Spurlockb2278d62015-04-07 12:47:12 -0400661 }
662
John Spurlock1fc476d2015-04-14 16:05:20 -0400663 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;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500673 synchronized (mConfig) {
674 final ZenModeConfig newConfig = mConfig.copy();
675 newConfig.applyNotificationPolicy(policy);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500676 setConfigLocked(newConfig, "setNotificationPolicy");
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500677 }
John Spurlock1fc476d2015-04-14 16:05:20 -0400678 }
679
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500680 /**
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 {
Jeff Sharkeyc7bacab2016-02-09 15:56:11 -0700692 mPm.getPackageInfo(rule.component.getPackageName(),
Amith Yamasani0d1fd8d2016-10-12 14:21:51 -0700693 PackageManager.MATCH_ANY_USER);
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500694 } catch (PackageManager.NameNotFoundException e) {
695 newConfig.automaticRules.removeAt(i);
696 }
697 }
698 }
699 }
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500700 setConfigLocked(newConfig, "cleanUpZenRules");
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500701 }
702 }
703
704 /**
705 * @return a copy of the zen mode configuration
706 */
John Spurlockb2278d62015-04-07 12:47:12 -0400707 public ZenModeConfig getConfig() {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400708 synchronized (mConfig) {
709 return mConfig.copy();
710 }
John Spurlockb2278d62015-04-07 12:47:12 -0400711 }
712
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500713 public boolean setConfigLocked(ZenModeConfig config, String reason) {
714 return setConfigLocked(config, reason, true /*setRingerMode*/);
John Spurlockb2278d62015-04-07 12:47:12 -0400715 }
716
Julia Reynolds89aeab02016-09-15 11:07:50 -0400717 public void setConfig(ZenModeConfig config, String reason) {
718 synchronized (mConfig) {
719 setConfigLocked(config, reason);
720 }
Eric Laurente0ced4d2015-09-30 17:44:28 -0700721 }
722
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500723 private boolean setConfigLocked(ZenModeConfig config, String reason, boolean setRingerMode) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400724 final long identity = Binder.clearCallingIdentity();
725 try {
726 if (config == null || !config.isValid()) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500727 Log.w(TAG, "Invalid config in setConfigLocked; " + config);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400728 return false;
729 }
730 if (config.user != mUser) {
731 // simply store away for background users
732 mConfigs.put(config.user, config);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500733 if (DEBUG) Log.d(TAG, "setConfigLocked: store config for user " + config.user);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400734 return true;
735 }
736 mConditions.evaluateConfig(config, false /*processSubscriptions*/); // may modify config
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500737 mConfigs.put(config.user, config);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500738 if (DEBUG) Log.d(TAG, "setConfigLocked reason=" + reason, new Throwable());
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500739 ZenLog.traceConfig(reason, mConfig, config);
740 final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
741 getNotificationPolicy(config));
Julia Reynolds9a25da12016-01-06 16:19:28 -0500742 if (!config.equals(mConfig)) {
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500743 dispatchOnConfigChanged();
744 }
745 if (policyChanged) {
746 dispatchOnPolicyChanged();
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400747 }
Julia Reynolds9a25da12016-01-06 16:19:28 -0500748 mConfig = config;
Julia Reynoldsd82e9812016-04-19 13:27:41 -0400749 mHandler.postApplyConfig(config, reason, setRingerMode);
John Spurlock21258a32015-05-27 18:22:55 -0400750 return true;
Julia Reynoldscb507b82017-09-07 13:53:40 -0400751 } catch (SecurityException e) {
752 Log.wtf(TAG, "Invalid rule in config", e);
753 return false;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400754 } finally {
755 Binder.restoreCallingIdentity(identity);
John Spurlock21258a32015-05-27 18:22:55 -0400756 }
John Spurlockb2278d62015-04-07 12:47:12 -0400757 }
758
Julia Reynoldsd82e9812016-04-19 13:27:41 -0400759 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
John Spurlockb2278d62015-04-07 12:47:12 -0400768 private int getZenModeSetting() {
769 return Global.getInt(mContext.getContentResolver(), Global.ZEN_MODE, Global.ZEN_MODE_OFF);
770 }
771
Beverly3bae4e52018-02-07 12:32:02 -0500772 @VisibleForTesting
773 protected void setZenModeSetting(int zen) {
John Spurlockb2278d62015-04-07 12:47:12 -0400774 Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zen);
Beverly3bae4e52018-02-07 12:32:02 -0500775 showZenUpgradeNotification(zen);
John Spurlockb2278d62015-04-07 12:47:12 -0400776 }
777
Julia Reynolds9b11fdb2015-07-31 09:49:55 -0400778 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
Beverlye4ee1cc2018-03-06 17:21:08 -0500789 @VisibleForTesting
790 protected boolean evaluateZenMode(String reason, boolean setRingerMode) {
John Spurlockb2278d62015-04-07 12:47:12 -0400791 if (DEBUG) Log.d(TAG, "evaluateZenMode");
Jason Monka9927322015-12-13 16:22:37 -0500792 final int zenBefore = mZenMode;
Julia Reynolds8ac63032015-08-31 15:19:43 -0400793 final int zen = computeZenMode();
John Spurlockb2278d62015-04-07 12:47:12 -0400794 ZenLog.traceSetZenMode(zen, reason);
795 mZenMode = zen;
796 setZenModeSetting(mZenMode);
Beverlyd6964762018-02-16 14:07:03 -0500797 updateRingerModeAffectedStreams();
Beverlye4ee1cc2018-03-06 17:21:08 -0500798 if (setRingerMode && zen != zenBefore) {
John Spurlock57627792014-12-11 11:29:54 -0500799 applyZenToRingerMode();
800 }
801 applyRestrictions();
Jason Monka9927322015-12-13 16:22:37 -0500802 if (zen != zenBefore) {
Julia Reynolds8ac63032015-08-31 15:19:43 -0400803 mHandler.postDispatchOnZenModeChanged();
804 }
John Spurlockb2278d62015-04-07 12:47:12 -0400805 return true;
John Spurlock57627792014-12-11 11:29:54 -0500806 }
807
John Spurlock50ced3f2015-05-11 16:00:09 -0400808 private void updateRingerModeAffectedStreams() {
809 if (mAudioManager != null) {
810 mAudioManager.updateRingerModeAffectedStreamsInternal();
811 }
812 }
813
Julia Reynolds8ac63032015-08-31 15:19:43 -0400814 private int computeZenMode() {
Beverlye4ee1cc2018-03-06 17:21:08 -0500815 if (mConfig == null) return Global.ZEN_MODE_OFF;
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400816 synchronized (mConfig) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400817 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)) {
Beverly301e92a2018-04-27 09:43:05 -0400822 // 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 }
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400828 zen = automaticRule.zenMode;
829 }
John Spurlockb2278d62015-04-07 12:47:12 -0400830 }
831 }
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400832 return zen;
John Spurlockb2278d62015-04-07 12:47:12 -0400833 }
John Spurlock8403b752014-12-10 12:47:01 -0500834 }
835
Beverly30bfbca2017-10-17 14:38:20 -0400836 private void getDefaultRuleNames() {
837 // on locale-change, these values differ
Beverly26eba872017-12-04 16:30:11 -0500838 mDefaultRuleEveryNightName = mContext.getResources()
839 .getString(R.string.zen_mode_default_every_night_name);
Beverly30bfbca2017-10-17 14:38:20 -0400840 mDefaultRuleEventsName = mContext.getResources()
841 .getString(R.string.zen_mode_default_events_name);
842 }
843
Beverly04216872017-09-28 10:55:32 -0400844 @VisibleForTesting
845 protected void applyRestrictions() {
Beverlyd820bc22018-01-11 15:28:33 -0500846 final boolean zenPriorityOnly = mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
Beverly925cde82018-01-23 09:31:23 -0500847 final boolean zenSilence = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
Beverlyd820bc22018-01-11 15:28:33 -0500848 final boolean zenAlarmsOnly = mZenMode == Global.ZEN_MODE_ALARMS;
John Spurlock8403b752014-12-10 12:47:01 -0500849
850 // notification restrictions
Bryce Lee7219ada2016-04-08 10:54:23 -0700851 final boolean muteNotifications =
852 (mSuppressedEffects & SUPPRESSED_EFFECT_NOTIFICATIONS) != 0;
John Spurlock056c5192014-04-20 21:52:01 -0400853 // call restrictions
Beverlyd820bc22018-01-11 15:28:33 -0500854 final boolean muteCalls = zenAlarmsOnly
855 || (zenPriorityOnly && !mConfig.allowCalls && !mConfig.allowRepeatCallers)
Bryce Lee7219ada2016-04-08 10:54:23 -0700856 || (mSuppressedEffects & SUPPRESSED_EFFECT_CALLS) != 0;
Beverly04216872017-09-28 10:55:32 -0400857 // alarm restrictions
Beverlyd820bc22018-01-11 15:28:33 -0500858 final boolean muteAlarms = zenPriorityOnly && !mConfig.allowAlarms;
Beverlyd6964762018-02-16 14:07:03 -0500859 // media restrictions
860 final boolean muteMedia = zenPriorityOnly && !mConfig.allowMedia;
861 // system restrictions
862 final boolean muteSystem = zenAlarmsOnly || (zenPriorityOnly && !mConfig.allowSystem);
Julia Reynolds3fe81be2016-02-03 09:10:06 -0500863 // total silence restrictions
Beverlyd820bc22018-01-11 15:28:33 -0500864 final boolean muteEverything = zenSilence
Beverly925cde82018-01-23 09:31:23 -0500865 || (zenPriorityOnly && ZenModeConfig.areAllZenBehaviorSoundsMuted(mConfig));
John Spurlock25d01ee2015-06-03 12:17:46 -0400866
Jean-Michel Trivie743bda2016-09-09 11:56:48 -0700867 for (int usage : AudioAttributes.SDK_USAGES) {
868 final int suppressionBehavior = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage);
Jean-Michel Trivi7a84eae2017-06-20 14:58:18 -0700869 if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NEVER) {
870 applyRestrictions(false /*mute*/, usage);
871 } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NOTIFICATION) {
Jean-Michel Trivie743bda2016-09-09 11:56:48 -0700872 applyRestrictions(muteNotifications || muteEverything, usage);
873 } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_CALL) {
874 applyRestrictions(muteCalls || muteEverything, usage);
Beverly04216872017-09-28 10:55:32 -0400875 } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_ALARM) {
876 applyRestrictions(muteAlarms || muteEverything, usage);
Beverlyd6964762018-02-16 14:07:03 -0500877 } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_MEDIA) {
878 applyRestrictions(muteMedia || muteEverything, usage);
879 } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_SYSTEM) {
Beverly738bffd2018-03-12 10:46:17 -0400880 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 }
Julia Reynolds3fe81be2016-02-03 09:10:06 -0500888 } else {
Jean-Michel Trivie743bda2016-09-09 11:56:48 -0700889 applyRestrictions(muteEverything, usage);
Julia Reynolds3fe81be2016-02-03 09:10:06 -0500890 }
891 }
John Spurlock8403b752014-12-10 12:47:01 -0500892 }
John Spurlockae641c92014-06-30 18:11:40 -0400893
Beverlye2d9a232017-11-08 18:14:59 -0500894
Beverly04216872017-09-28 10:55:32 -0400895 @VisibleForTesting
Beverly738bffd2018-03-12 10:46:17 -0400896 protected void applyRestrictions(boolean mute, int usage, int code) {
John Spurlock8403b752014-12-10 12:47:01 -0500897 final String[] exceptionPackages = null; // none (for now)
Beverlye2d9a232017-11-08 18:14:59 -0500898
Dianne Hackbornbf1b57d2018-03-07 12:42:47 -0800899 // 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 }
John Spurlock056c5192014-04-20 21:52:01 -0400911 }
912
Beverly85f52412018-02-27 10:41:13 -0500913 @VisibleForTesting
Beverly738bffd2018-03-12 10:46:17 -0400914 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
Beverly85f52412018-02-27 10:41:13 -0500921 protected void applyZenToRingerMode() {
John Spurlock661f2cf2014-11-17 10:29:10 -0500922 if (mAudioManager == null) return;
John Spurlock661f2cf2014-11-17 10:29:10 -0500923 // force the ringer mode into compliance
924 final int ringerModeInternal = mAudioManager.getRingerModeInternal();
925 int newRingerModeInternal = ringerModeInternal;
John Spurlock57627792014-12-11 11:29:54 -0500926 switch (mZenMode) {
John Spurlock661f2cf2014-11-17 10:29:10 -0500927 case Global.ZEN_MODE_NO_INTERRUPTIONS:
John Spurlock4f1163c2015-04-02 17:41:21 -0400928 case Global.ZEN_MODE_ALARMS:
John Spurlock661f2cf2014-11-17 10:29:10 -0500929 if (ringerModeInternal != AudioManager.RINGER_MODE_SILENT) {
Julia Reynolds9b11fdb2015-07-31 09:49:55 -0400930 setPreviousRingerModeSetting(ringerModeInternal);
John Spurlock661f2cf2014-11-17 10:29:10 -0500931 newRingerModeInternal = AudioManager.RINGER_MODE_SILENT;
John Spurlock8c01d882014-07-28 13:37:13 -0400932 }
John Spurlock661f2cf2014-11-17 10:29:10 -0500933 break;
934 case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
Beverly9e4214d2018-03-26 11:10:10 -0400935 // do not apply zen to ringer, streams zen muted in AudioService
Beverly925cde82018-01-23 09:31:23 -0500936 break;
John Spurlock661f2cf2014-11-17 10:29:10 -0500937 case Global.ZEN_MODE_OFF:
938 if (ringerModeInternal == AudioManager.RINGER_MODE_SILENT) {
Julia Reynolds9b11fdb2015-07-31 09:49:55 -0400939 newRingerModeInternal = getPreviousRingerModeSetting();
940 setPreviousRingerModeSetting(null);
John Spurlock661f2cf2014-11-17 10:29:10 -0500941 }
942 break;
John Spurlock8c01d882014-07-28 13:37:13 -0400943 }
John Spurlock661f2cf2014-11-17 10:29:10 -0500944 if (newRingerModeInternal != -1) {
945 mAudioManager.setRingerModeInternal(newRingerModeInternal, TAG);
946 }
947 }
948
John Spurlock1c923a32014-04-27 16:42:29 -0400949 private void dispatchOnConfigChanged() {
950 for (Callback callback : mCallbacks) {
951 callback.onConfigChanged();
952 }
953 }
954
John Spurlock1fc476d2015-04-14 16:05:20 -0400955 private void dispatchOnPolicyChanged() {
956 for (Callback callback : mCallbacks) {
957 callback.onPolicyChanged();
958 }
959 }
960
John Spurlock1c923a32014-04-27 16:42:29 -0400961 private void dispatchOnZenModeChanged() {
962 for (Callback callback : mCallbacks) {
963 callback.onZenModeChanged();
964 }
965 }
966
John Spurlockb2278d62015-04-07 12:47:12 -0400967 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) {
Julia Reynolds206c7e92016-09-15 10:38:03 -0400972 final ZenModeConfig config = ZenModeConfig.readXml(parser);
John Spurlockb2278d62015-04-07 12:47:12 -0400973 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
Beverly26eba872017-12-04 16:30:11 -0500983 private void appendDefaultEveryNightRule(ZenModeConfig config) {
John Spurlockb2278d62015-04-07 12:47:12 -0400984 if (config == null) return;
985
986 final ScheduleInfo weeknights = new ScheduleInfo();
Beverly26eba872017-12-04 16:30:11 -0500987 weeknights.days = ZenModeConfig.ALL_DAYS;
John Spurlockb2278d62015-04-07 12:47:12 -0400988 weeknights.startHour = 22;
989 weeknights.endHour = 7;
Beverly30bfbca2017-10-17 14:38:20 -0400990 weeknights.exitAtAlarm = true;
Beverly26eba872017-12-04 16:30:11 -0500991 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);
John Spurlockb2278d62015-04-07 12:47:12 -04001000 }
1001
John Spurlockcb9aa202015-05-08 17:35:22 -04001002 private void appendDefaultEventRules(ZenModeConfig config) {
1003 if (config == null) return;
1004
1005 final EventInfo events = new EventInfo();
John Spurlock995a7492015-05-28 22:13:03 -04001006 events.calendar = null; // any calendar
John Spurlockcb9aa202015-05-08 17:35:22 -04001007 events.reply = EventInfo.REPLY_YES_OR_MAYBE;
1008 final ZenRule rule = new ZenRule();
1009 rule.enabled = false;
Beverlyd4f96492017-08-02 13:36:11 -04001010 rule.name = mDefaultRuleEventsName;
John Spurlockcb9aa202015-05-08 17:35:22 -04001011 rule.conditionId = ZenModeConfig.toEventConditionId(events);
Beverlybf16c142017-11-27 16:21:34 -05001012 rule.zenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001013 rule.component = EventConditionProvider.COMPONENT;
Beverly26eba872017-12-04 16:30:11 -05001014 rule.id = ZenModeConfig.EVENTS_DEFAULT_RULE_ID;
Julia Reynolds56106ff2015-09-30 14:42:53 -04001015 rule.creationTime = System.currentTimeMillis();
1016 config.automaticRules.put(rule.id, rule);
John Spurlockcb9aa202015-05-08 17:35:22 -04001017 }
1018
John Spurlockb2278d62015-04-07 12:47:12 -04001019 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
Beverly85f52412018-02-27 10:41:13 -05001028 @VisibleForTesting
1029 protected final class RingerModeDelegate implements AudioManagerInternal.RingerModeDelegate {
John Spurlockb2278d62015-04-07 12:47:12 -04001030 @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
Beverlye4ee1cc2018-03-06 17:21:08 -05001042 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 }
John Spurlockb2278d62015-04-07 12:47:12 -04001049 int newZen = -1;
1050 switch (ringerModeNew) {
1051 case AudioManager.RINGER_MODE_SILENT:
1052 if (isChange && policy.doNotDisturbWhenSilent) {
Beverly925cde82018-01-23 09:31:23 -05001053 if (mZenMode == Global.ZEN_MODE_OFF) {
Julia Reynoldsf3252be2018-01-17 09:26:21 -05001054 newZen = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
John Spurlockb2278d62015-04-07 12:47:12 -04001055 }
Julia Reynolds9b11fdb2015-07-31 09:49:55 -04001056 setPreviousRingerModeSetting(ringerModeOld);
John Spurlockb2278d62015-04-07 12:47:12 -04001057 }
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
Beverly925cde82018-01-23 09:31:23 -05001063 || mZenMode == Global.ZEN_MODE_ALARMS
1064 || (mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
1065 && ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(
Beverlyd6964762018-02-16 14:07:03 -05001066 mConfig)))) {
John Spurlockb2278d62015-04-07 12:47:12 -04001067 newZen = Global.ZEN_MODE_OFF;
1068 } else if (mZenMode != Global.ZEN_MODE_OFF) {
1069 ringerModeExternalOut = AudioManager.RINGER_MODE_SILENT;
1070 }
1071 break;
1072 }
Beverly85f52412018-02-27 10:41:13 -05001073
John Spurlockb2278d62015-04-07 12:47:12 -04001074 if (newZen != -1) {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04001075 setManualZenMode(newZen, null, "ringerModeInternal", null,
1076 false /*setRingerMode*/);
John Spurlockb2278d62015-04-07 12:47:12 -04001077 }
John Spurlockb2278d62015-04-07 12:47:12 -04001078 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) {
Julia Reynoldsf3252be2018-01-17 09:26:21 -05001097 newZen = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
John Spurlockb2278d62015-04-07 12:47:12 -04001098 }
1099 ringerModeInternalOut = isVibrate ? AudioManager.RINGER_MODE_VIBRATE
John Spurlock05715ec2015-05-13 11:19:19 -04001100 : AudioManager.RINGER_MODE_SILENT;
John Spurlockb2278d62015-04-07 12:47:12 -04001101 } 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) {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04001113 setManualZenMode(newZen, null, "ringerModeExternal", caller,
1114 false /*setRingerMode*/);
John Spurlockb2278d62015-04-07 12:47:12 -04001115 }
1116
1117 ZenLog.traceSetRingerModeExternal(ringerModeOld, ringerModeNew, caller,
1118 ringerModeInternal, ringerModeInternalOut);
1119 return ringerModeInternalOut;
1120 }
John Spurlockd9c75db2015-04-28 11:19:13 -04001121
1122 @Override
1123 public boolean canVolumeDownEnterSilent() {
1124 return mZenMode == Global.ZEN_MODE_OFF;
1125 }
John Spurlock50ced3f2015-05-11 16:00:09 -04001126
1127 @Override
1128 public int getRingerModeAffectedStreams(int streams) {
Beverlyd6964762018-02-16 14:07:03 -05001129 // ringtone and notification streams are always affected by ringer mode
1130 // system stream is affected by ringer mode when not in priority-only
John Spurlock50ced3f2015-05-11 16:00:09 -04001131 streams |= (1 << AudioSystem.STREAM_RING) |
Beverlyd6964762018-02-16 14:07:03 -05001132 (1 << AudioSystem.STREAM_NOTIFICATION) |
1133 (1 << AudioSystem.STREAM_SYSTEM);
John Spurlock50ced3f2015-05-11 16:00:09 -04001134
John Spurlock50ced3f2015-05-11 16:00:09 -04001135 if (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
Beverly925cde82018-01-23 09:31:23 -05001136 // alarm and music streams affected by ringer mode when in total silence
John Spurlock50ced3f2015-05-11 16:00:09 -04001137 streams |= (1 << AudioSystem.STREAM_ALARM) |
Beverlyd6964762018-02-16 14:07:03 -05001138 (1 << AudioSystem.STREAM_MUSIC);
John Spurlock50ced3f2015-05-11 16:00:09 -04001139 } else {
1140 streams &= ~((1 << AudioSystem.STREAM_ALARM) |
Beverlyd6964762018-02-16 14:07:03 -05001141 (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);
John Spurlock50ced3f2015-05-11 16:00:09 -04001151 }
1152 return streams;
1153 }
John Spurlockb2278d62015-04-07 12:47:12 -04001154 }
1155
1156 private final class SettingsObserver extends ContentObserver {
John Spurlock056c5192014-04-20 21:52:01 -04001157 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)) {
John Spurlockb2278d62015-04-07 12:47:12 -04001176 if (mZenMode != getZenModeSetting()) {
1177 if (DEBUG) Log.d(TAG, "Fixing zen mode setting");
1178 setZenModeSetting(mZenMode);
1179 }
John Spurlock056c5192014-04-20 21:52:01 -04001180 }
1181 }
1182 }
1183
Beverly3bae4e52018-02-07 12:32:02 -05001184 private void showZenUpgradeNotification(int zen) {
1185 final boolean showNotification = mIsBootComplete
Julia Reynolds76bfa602018-04-23 09:38:47 -04001186 && zen != Global.ZEN_MODE_OFF
Beverly3bae4e52018-02-07 12:32:02 -05001187 && 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() {
Beverly3bae4e52018-02-07 12:32:02 -05001200 final Bundle extras = new Bundle();
1201 extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
1202 mContext.getResources().getString(R.string.global_action_settings));
Julia Reynolds0b8455d2018-03-14 11:38:44 -04001203 int title = R.string.zen_upgrade_notification_title;
1204 int content = R.string.zen_upgrade_notification_content;
Julia Reynolds76bfa602018-04-23 09:38:47 -04001205 int drawable = R.drawable.ic_zen_24dp;
Julia Reynolds0b8455d2018-03-14 11:38:44 -04001206 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;
Julia Reynolds76bfa602018-04-23 09:38:47 -04001210 drawable = R.drawable.ic_dnd_block_notifications;
Julia Reynolds0b8455d2018-03-14 11:38:44 -04001211 }
Julia Reynolds76bfa602018-04-23 09:38:47 -04001212
Julia Reynolds9aa1c9e2018-04-09 11:31:15 -04001213 Intent onboardingIntent = new Intent(Settings.ZEN_MODE_ONBOARDING);
1214 onboardingIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
Julia Reynolds0b8455d2018-03-14 11:38:44 -04001215 return new Notification.Builder(mContext, SystemNotificationChannels.DO_NOT_DISTURB)
Julia Reynolds9aa1c9e2018-04-09 11:31:15 -04001216 .setAutoCancel(true)
Beverlyd8b15ee2018-02-13 14:37:38 -05001217 .setSmallIcon(R.drawable.ic_settings_24dp)
Julia Reynolds76bfa602018-04-23 09:38:47 -04001218 .setLargeIcon(Icon.createWithResource(mContext, drawable))
Julia Reynolds0b8455d2018-03-14 11:38:44 -04001219 .setContentTitle(mContext.getResources().getString(title))
1220 .setContentText(mContext.getResources().getString(content))
Julia Reynolds9aa1c9e2018-04-09 11:31:15 -04001221 .setContentIntent(PendingIntent.getActivity(mContext, 0, onboardingIntent,
1222 PendingIntent.FLAG_UPDATE_CURRENT))
Beverly3bae4e52018-02-07 12:32:02 -05001223 .setAutoCancel(true)
1224 .setLocalOnly(true)
1225 .addExtras(extras)
Julia Reynolds0b8455d2018-03-14 11:38:44 -04001226 .setStyle(new Notification.BigTextStyle())
Beverly3bae4e52018-02-07 12:32:02 -05001227 .build();
1228 }
1229
Chris Wren98d235b2015-05-27 18:25:17 -04001230 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
John Spurlockb2278d62015-04-07 12:47:12 -04001256 private final class H extends Handler {
John Spurlock57627792014-12-11 11:29:54 -05001257 private static final int MSG_DISPATCH = 1;
Chris Wren98d235b2015-05-27 18:25:17 -04001258 private static final int MSG_METRICS = 2;
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001259 private static final int MSG_APPLY_CONFIG = 4;
Eric Laurente0ced4d2015-09-30 17:44:28 -07001260
1261 private final class ConfigMessageData {
1262 public final ZenModeConfig config;
1263 public final String reason;
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001264 public final boolean setRingerMode;
Eric Laurente0ced4d2015-09-30 17:44:28 -07001265
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001266 ConfigMessageData(ZenModeConfig config, String reason, boolean setRingerMode) {
1267 this.config = config;
1268 this.reason = reason;
1269 this.setRingerMode = setRingerMode;
Eric Laurente0ced4d2015-09-30 17:44:28 -07001270 }
1271 }
Chris Wren98d235b2015-05-27 18:25:17 -04001272
1273 private static final long METRICS_PERIOD_MS = 6 * 60 * 60 * 1000;
John Spurlock661f2cf2014-11-17 10:29:10 -05001274
1275 private H(Looper looper) {
1276 super(looper);
John Spurlock056c5192014-04-20 21:52:01 -04001277 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001278
John Spurlock57627792014-12-11 11:29:54 -05001279 private void postDispatchOnZenModeChanged() {
1280 removeMessages(MSG_DISPATCH);
1281 sendEmptyMessage(MSG_DISPATCH);
John Spurlock661f2cf2014-11-17 10:29:10 -05001282 }
1283
Chris Wren98d235b2015-05-27 18:25:17 -04001284 private void postMetricsTimer() {
1285 removeMessages(MSG_METRICS);
1286 sendEmptyMessageDelayed(MSG_METRICS, METRICS_PERIOD_MS);
1287 }
1288
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001289 private void postApplyConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
1290 sendMessage(obtainMessage(MSG_APPLY_CONFIG,
1291 new ConfigMessageData(config, reason, setRingerMode)));
1292 }
1293
John Spurlock661f2cf2014-11-17 10:29:10 -05001294 @Override
1295 public void handleMessage(Message msg) {
John Spurlock57627792014-12-11 11:29:54 -05001296 switch (msg.what) {
1297 case MSG_DISPATCH:
1298 dispatchOnZenModeChanged();
John Spurlock661f2cf2014-11-17 10:29:10 -05001299 break;
Chris Wren98d235b2015-05-27 18:25:17 -04001300 case MSG_METRICS:
1301 mMetrics.emit();
1302 break;
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001303 case MSG_APPLY_CONFIG:
1304 ConfigMessageData applyConfigData = (ConfigMessageData) msg.obj;
1305 applyConfig(applyConfigData.config, applyConfigData.reason,
1306 applyConfigData.setRingerMode);
John Spurlock661f2cf2014-11-17 10:29:10 -05001307 }
1308 }
1309 }
John Spurlock056c5192014-04-20 21:52:01 -04001310
John Spurlock1c923a32014-04-27 16:42:29 -04001311 public static class Callback {
1312 void onConfigChanged() {}
1313 void onZenModeChanged() {}
John Spurlock1fc476d2015-04-14 16:05:20 -04001314 void onPolicyChanged() {}
John Spurlock056c5192014-04-20 21:52:01 -04001315 }
John Spurlockb2278d62015-04-07 12:47:12 -04001316
John Spurlock056c5192014-04-20 21:52:01 -04001317}