blob: 4393761f47748de5b83ce29c5419b8b448d67759 [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 Spurlock8403b752014-12-10 12:47:01 -050019import static android.media.AudioAttributes.USAGE_NOTIFICATION;
Jean-Michel Trivi89c3b292014-07-20 11:41:02 -070020import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
Julia Reynolds3fe81be2016-02-03 09:10:06 -050021import static android.media.AudioAttributes.USAGE_UNKNOWN;
22import static android.media.AudioAttributes.USAGE_VIRTUAL_SOURCE;
John Spurlock7b414672014-07-18 13:02:39 -040023
John Spurlock056c5192014-04-20 21:52:01 -040024import android.app.AppOpsManager;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040025import android.app.AutomaticZenRule;
John Spurlock80774932015-05-07 17:38:50 -040026import android.app.NotificationManager;
John Spurlock1fc476d2015-04-14 16:05:20 -040027import android.app.NotificationManager.Policy;
John Spurlock312d1d02014-07-08 10:24:57 -040028import android.content.ComponentName;
John Spurlock056c5192014-04-20 21:52:01 -040029import android.content.ContentResolver;
30import android.content.Context;
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -050031import android.content.Intent;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040032import android.content.pm.PackageManager;
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -050033import android.content.pm.ResolveInfo;
34import android.content.pm.ServiceInfo;
John Spurlock056c5192014-04-20 21:52:01 -040035import android.content.res.Resources;
36import android.content.res.XmlResourceParser;
37import android.database.ContentObserver;
38import android.media.AudioManager;
John Spurlock661f2cf2014-11-17 10:29:10 -050039import android.media.AudioManagerInternal;
John Spurlock50ced3f2015-05-11 16:00:09 -040040import android.media.AudioSystem;
John Spurlocka48d7792015-03-03 17:35:57 -050041import android.media.VolumePolicy;
John Spurlock056c5192014-04-20 21:52:01 -040042import android.net.Uri;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040043import android.os.Binder;
John Spurlock2b122f42014-08-27 16:29:47 -040044import android.os.Bundle;
John Spurlock056c5192014-04-20 21:52:01 -040045import android.os.Handler;
John Spurlock661f2cf2014-11-17 10:29:10 -050046import android.os.Looper;
47import android.os.Message;
Julia Reynoldsc8e54e82015-11-30 16:43:05 -050048import android.os.Process;
Chris Wren98d235b2015-05-27 18:25:17 -040049import android.os.SystemClock;
John Spurlockb5e767b2014-07-27 11:53:20 -040050import android.os.UserHandle;
John Spurlock056c5192014-04-20 21:52:01 -040051import android.provider.Settings.Global;
Julia Reynolds43b70cd2016-01-14 15:05:34 -050052import android.service.notification.ConditionProviderService;
John Spurlock056c5192014-04-20 21:52:01 -040053import android.service.notification.ZenModeConfig;
John Spurlockcb9aa202015-05-08 17:35:22 -040054import android.service.notification.ZenModeConfig.EventInfo;
John Spurlockb2278d62015-04-07 12:47:12 -040055import android.service.notification.ZenModeConfig.ScheduleInfo;
56import android.service.notification.ZenModeConfig.ZenRule;
Julia Reynolds87c42772016-05-16 09:52:17 -040057import android.util.AndroidRuntimeException;
John Spurlock4db0d982014-08-13 09:19:03 -040058import android.util.Log;
John Spurlock21258a32015-05-27 18:22:55 -040059import android.util.SparseArray;
John Spurlock056c5192014-04-20 21:52:01 -040060
61import com.android.internal.R;
John Spurlock25d01ee2015-06-03 12:17:46 -040062import com.android.internal.logging.MetricsLogger;
John Spurlock661f2cf2014-11-17 10:29:10 -050063import com.android.server.LocalServices;
John Spurlock056c5192014-04-20 21:52:01 -040064
65import libcore.io.IoUtils;
66
67import org.xmlpull.v1.XmlPullParser;
68import org.xmlpull.v1.XmlPullParserException;
69import org.xmlpull.v1.XmlSerializer;
70
71import java.io.IOException;
72import java.io.PrintWriter;
John Spurlock1c923a32014-04-27 16:42:29 -040073import java.util.ArrayList;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040074import java.util.List;
John Spurlock1fc476d2015-04-14 16:05:20 -040075import java.util.Objects;
John Spurlock056c5192014-04-20 21:52:01 -040076
77/**
78 * NotificationManagerService helper for functionality related to zen mode.
79 */
John Spurlockb2278d62015-04-07 12:47:12 -040080public class ZenModeHelper {
81 static final String TAG = "ZenModeHelper";
82 static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
John Spurlock056c5192014-04-20 21:52:01 -040083
Julia Reynolds5a43aaa2015-12-15 13:54:41 -050084 // The amount of time rules instances can exist without their owning app being installed.
85 private static final int RULE_INSTANCE_GRACE_PERIOD = 1000 * 60 * 60 * 72;
86
John Spurlock056c5192014-04-20 21:52:01 -040087 private final Context mContext;
John Spurlock661f2cf2014-11-17 10:29:10 -050088 private final H mHandler;
John Spurlock056c5192014-04-20 21:52:01 -040089 private final SettingsObserver mSettingsObserver;
90 private final AppOpsManager mAppOps;
91 private final ZenModeConfig mDefaultConfig;
John Spurlock1c923a32014-04-27 16:42:29 -040092 private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
John Spurlockb2278d62015-04-07 12:47:12 -040093 private final ZenModeFiltering mFiltering;
94 private final RingerModeDelegate mRingerModeDelegate = new RingerModeDelegate();
95 private final ZenModeConditions mConditions;
John Spurlock21258a32015-05-27 18:22:55 -040096 private final SparseArray<ZenModeConfig> mConfigs = new SparseArray<>();
Chris Wren98d235b2015-05-27 18:25:17 -040097 private final Metrics mMetrics = new Metrics();
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -050098 private final ConditionProviders.Config mServiceConfig;
John Spurlock056c5192014-04-20 21:52:01 -040099
John Spurlock056c5192014-04-20 21:52:01 -0400100 private int mZenMode;
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700101 private int mUser = UserHandle.USER_SYSTEM;
John Spurlock056c5192014-04-20 21:52:01 -0400102 private ZenModeConfig mConfig;
John Spurlock661f2cf2014-11-17 10:29:10 -0500103 private AudioManagerInternal mAudioManager;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500104 private PackageManager mPm;
Bryce Lee7219ada2016-04-08 10:54:23 -0700105 private long mSuppressedEffects;
106
107 public static final long SUPPRESSED_EFFECT_NOTIFICATIONS = 1;
108 public static final long SUPPRESSED_EFFECT_CALLS = 1 << 1;
109 public static final long SUPPRESSED_EFFECT_ALL = SUPPRESSED_EFFECT_CALLS
110 | SUPPRESSED_EFFECT_NOTIFICATIONS;
John Spurlock056c5192014-04-20 21:52:01 -0400111
John Spurlockb2278d62015-04-07 12:47:12 -0400112 public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) {
John Spurlock056c5192014-04-20 21:52:01 -0400113 mContext = context;
John Spurlock661f2cf2014-11-17 10:29:10 -0500114 mHandler = new H(looper);
Chris Wren98d235b2015-05-27 18:25:17 -0400115 addCallback(mMetrics);
John Spurlock056c5192014-04-20 21:52:01 -0400116 mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
117 mDefaultConfig = readDefaultConfig(context.getResources());
John Spurlockb2278d62015-04-07 12:47:12 -0400118 appendDefaultScheduleRules(mDefaultConfig);
John Spurlockcb9aa202015-05-08 17:35:22 -0400119 appendDefaultEventRules(mDefaultConfig);
John Spurlock056c5192014-04-20 21:52:01 -0400120 mConfig = mDefaultConfig;
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700121 mConfigs.put(UserHandle.USER_SYSTEM, mConfig);
John Spurlock056c5192014-04-20 21:52:01 -0400122 mSettingsObserver = new SettingsObserver(mHandler);
123 mSettingsObserver.observe();
John Spurlockb2278d62015-04-07 12:47:12 -0400124 mFiltering = new ZenModeFiltering(mContext);
125 mConditions = new ZenModeConditions(this, conditionProviders);
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500126 mServiceConfig = conditionProviders.getConfig();
John Spurlock056c5192014-04-20 21:52:01 -0400127 }
128
John Spurlock1b8b22b2015-05-20 09:47:13 -0400129 public Looper getLooper() {
130 return mHandler.getLooper();
131 }
132
John Spurlockb2278d62015-04-07 12:47:12 -0400133 @Override
134 public String toString() {
135 return TAG;
136 }
137
138 public boolean matchesCallFilter(UserHandle userHandle, Bundle extras,
139 ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400140 synchronized (mConfig) {
141 return ZenModeFiltering.matchesCallFilter(mContext, mZenMode, mConfig, userHandle,
Julia Reynoldsc6b371b2016-06-14 08:31:03 -0400142 extras, validator, contactsTimeoutMs, timeoutAffinity);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400143 }
John Spurlockb2278d62015-04-07 12:47:12 -0400144 }
145
146 public boolean isCall(NotificationRecord record) {
147 return mFiltering.isCall(record);
148 }
149
Julia Reynoldsc6b371b2016-06-14 08:31:03 -0400150 public void recordCaller(NotificationRecord record) {
151 mFiltering.recordCall(record);
152 }
153
John Spurlockb2278d62015-04-07 12:47:12 -0400154 public boolean shouldIntercept(NotificationRecord record) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400155 synchronized (mConfig) {
156 return mFiltering.shouldIntercept(mZenMode, mConfig, record);
157 }
John Spurlock056c5192014-04-20 21:52:01 -0400158 }
159
Julia Reynoldsd5607292016-02-05 15:25:58 -0500160 public boolean shouldSuppressWhenScreenOff() {
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500161 synchronized (mConfig) {
Julia Reynoldsd5607292016-02-05 15:25:58 -0500162 return !mConfig.allowWhenScreenOff;
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500163 }
164 }
165
Julia Reynoldsd5607292016-02-05 15:25:58 -0500166 public boolean shouldSuppressWhenScreenOn() {
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500167 synchronized (mConfig) {
Julia Reynoldsd5607292016-02-05 15:25:58 -0500168 return !mConfig.allowWhenScreenOn;
Julia Reynolds61721582016-01-05 08:35:25 -0500169 }
170 }
171
John Spurlock1c923a32014-04-27 16:42:29 -0400172 public void addCallback(Callback callback) {
173 mCallbacks.add(callback);
John Spurlock056c5192014-04-20 21:52:01 -0400174 }
175
John Spurlock530052a2014-11-30 16:26:19 -0500176 public void removeCallback(Callback callback) {
177 mCallbacks.remove(callback);
178 }
179
John Spurlockb2278d62015-04-07 12:47:12 -0400180 public void initZenMode() {
181 if (DEBUG) Log.d(TAG, "initZenMode");
182 evaluateZenMode("init", true /*setRingerMode*/);
183 }
184
John Spurlock661f2cf2014-11-17 10:29:10 -0500185 public void onSystemReady() {
John Spurlockb2278d62015-04-07 12:47:12 -0400186 if (DEBUG) Log.d(TAG, "onSystemReady");
John Spurlock661f2cf2014-11-17 10:29:10 -0500187 mAudioManager = LocalServices.getService(AudioManagerInternal.class);
188 if (mAudioManager != null) {
John Spurlockb2278d62015-04-07 12:47:12 -0400189 mAudioManager.setRingerModeDelegate(mRingerModeDelegate);
John Spurlock661f2cf2014-11-17 10:29:10 -0500190 }
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500191 mPm = mContext.getPackageManager();
Chris Wren98d235b2015-05-27 18:25:17 -0400192 mHandler.postMetricsTimer();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500193 cleanUpZenRules();
Julia Reynolds8ac63032015-08-31 15:19:43 -0400194 evaluateZenMode("onSystemReady", true);
John Spurlockae641c92014-06-30 18:11:40 -0400195 }
196
John Spurlock21258a32015-05-27 18:22:55 -0400197 public void onUserSwitched(int user) {
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500198 loadConfigForUser(user, "onUserSwitched");
John Spurlock21258a32015-05-27 18:22:55 -0400199 }
200
201 public void onUserRemoved(int user) {
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700202 if (user < UserHandle.USER_SYSTEM) return;
John Spurlock21258a32015-05-27 18:22:55 -0400203 if (DEBUG) Log.d(TAG, "onUserRemoved u=" + user);
204 mConfigs.remove(user);
205 }
206
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500207 public void onUserUnlocked(int user) {
208 loadConfigForUser(user, "onUserUnlocked");
209 }
210
211 private void loadConfigForUser(int user, String reason) {
212 if (mUser == user || user < UserHandle.USER_SYSTEM) return;
213 mUser = user;
214 if (DEBUG) Log.d(TAG, reason + " u=" + user);
215 ZenModeConfig config = mConfigs.get(user);
216 if (config == null) {
217 if (DEBUG) Log.d(TAG, reason + " generating default config for user " + user);
218 config = mDefaultConfig.copy();
219 config.user = user;
220 }
221 synchronized (mConfig) {
222 setConfigLocked(config, reason);
223 }
224 cleanUpZenRules();
225 }
226
Christoph Studer85a384b2014-08-27 20:16:15 +0200227 public int getZenModeListenerInterruptionFilter() {
John Spurlock80774932015-05-07 17:38:50 -0400228 return NotificationManager.zenModeToInterruptionFilter(mZenMode);
John Spurlockd8afe3c2014-08-01 14:04:07 -0400229 }
230
John Spurlock80774932015-05-07 17:38:50 -0400231 public void requestFromListener(ComponentName name, int filter) {
232 final int newZen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
John Spurlockd8afe3c2014-08-01 14:04:07 -0400233 if (newZen != -1) {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -0400234 setManualZenMode(newZen, null, name != null ? name.getPackageName() : null,
John Spurlockb2278d62015-04-07 12:47:12 -0400235 "listener:" + (name != null ? name.flattenToShortString() : null));
John Spurlockd8afe3c2014-08-01 14:04:07 -0400236 }
237 }
238
Bryce Lee7219ada2016-04-08 10:54:23 -0700239 public void setSuppressedEffects(long suppressedEffects) {
240 if (mSuppressedEffects == suppressedEffects) return;
241 mSuppressedEffects = suppressedEffects;
John Spurlock8403b752014-12-10 12:47:01 -0500242 applyRestrictions();
243 }
244
Bryce Lee7219ada2016-04-08 10:54:23 -0700245 public long getSuppressedEffects() {
246 return mSuppressedEffects;
247 }
248
John Spurlock1c923a32014-04-27 16:42:29 -0400249 public int getZenMode() {
250 return mZenMode;
251 }
252
Julia Reynolds361e82d32016-02-26 18:19:49 -0500253 public List<ZenRule> getZenRules() {
254 List<ZenRule> rules = new ArrayList<>();
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400255 synchronized (mConfig) {
256 if (mConfig == null) return rules;
257 for (ZenRule rule : mConfig.automaticRules.values()) {
258 if (canManageAutomaticZenRule(rule)) {
Julia Reynolds361e82d32016-02-26 18:19:49 -0500259 rules.add(rule);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400260 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400261 }
262 }
263 return rules;
264 }
265
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400266 public AutomaticZenRule getAutomaticZenRule(String id) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400267 ZenRule rule;
268 synchronized (mConfig) {
269 if (mConfig == null) return null;
270 rule = mConfig.automaticRules.get(id);
271 }
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400272 if (rule == null) return null;
273 if (canManageAutomaticZenRule(rule)) {
274 return createAutomaticZenRule(rule);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400275 }
276 return null;
277 }
278
Julia Reynolds361e82d32016-02-26 18:19:49 -0500279 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500280 if (!isSystemRule(automaticZenRule)) {
281 ServiceInfo owner = getServiceInfo(automaticZenRule.getOwner());
282 if (owner == null) {
283 throw new IllegalArgumentException("Owner is not a condition provider service");
284 }
285
Julia Reynolds7f2f4412016-03-01 12:33:48 -0500286 int ruleInstanceLimit = -1;
287 if (owner.metaData != null) {
288 ruleInstanceLimit = owner.metaData.getInt(
289 ConditionProviderService.META_DATA_RULE_INSTANCE_LIMIT, -1);
290 }
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500291 if (ruleInstanceLimit > 0 && ruleInstanceLimit
292 < (getCurrentInstanceCount(automaticZenRule.getOwner()) + 1)) {
293 throw new IllegalArgumentException("Rule instance limit exceeded");
294 }
295 }
296
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400297 ZenModeConfig newConfig;
298 synchronized (mConfig) {
Julia Reynolds87c42772016-05-16 09:52:17 -0400299 if (mConfig == null) {
300 throw new AndroidRuntimeException("Could not create rule");
301 }
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400302 if (DEBUG) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500303 Log.d(TAG, "addAutomaticZenRule rule= " + automaticZenRule + " reason=" + reason);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400304 }
305 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500306 ZenRule rule = new ZenRule();
307 populateZenRule(automaticZenRule, rule, true);
308 newConfig.automaticRules.put(rule.id, rule);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500309 if (setConfigLocked(newConfig, reason, true)) {
Julia Reynolds361e82d32016-02-26 18:19:49 -0500310 return rule.id;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500311 } else {
Julia Reynolds87c42772016-05-16 09:52:17 -0400312 throw new AndroidRuntimeException("Could not create rule");
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500313 }
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400314 }
315 }
316
Julia Reynolds361e82d32016-02-26 18:19:49 -0500317 public boolean updateAutomaticZenRule(String ruleId, AutomaticZenRule automaticZenRule,
318 String reason) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400319 ZenModeConfig newConfig;
320 synchronized (mConfig) {
321 if (mConfig == null) return false;
322 if (DEBUG) {
323 Log.d(TAG, "updateAutomaticZenRule zenRule=" + automaticZenRule
324 + " reason=" + reason);
325 }
326 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500327 ZenModeConfig.ZenRule rule;
328 if (ruleId == null) {
329 throw new IllegalArgumentException("Rule doesn't exist");
330 } else {
331 rule = newConfig.automaticRules.get(ruleId);
332 if (rule == null || !canManageAutomaticZenRule(rule)) {
333 throw new SecurityException(
334 "Cannot update rules not owned by your condition provider");
335 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400336 }
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500337 populateZenRule(automaticZenRule, rule, false);
338 newConfig.automaticRules.put(ruleId, rule);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500339 return setConfigLocked(newConfig, reason, true);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400340 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400341 }
342
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400343 public boolean removeAutomaticZenRule(String id, String reason) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400344 ZenModeConfig newConfig;
345 synchronized (mConfig) {
346 if (mConfig == null) return false;
347 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500348 ZenRule rule = newConfig.automaticRules.get(id);
349 if (rule == null) return false;
350 if (canManageAutomaticZenRule(rule)) {
351 newConfig.automaticRules.remove(id);
352 if (DEBUG) Log.d(TAG, "removeZenRule zenRule=" + id + " reason=" + reason);
353 } else {
354 throw new SecurityException(
355 "Cannot delete rules not owned by your condition provider");
356 }
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500357 return setConfigLocked(newConfig, reason, true);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400358 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400359 }
360
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500361 public boolean removeAutomaticZenRules(String packageName, String reason) {
362 ZenModeConfig newConfig;
363 synchronized (mConfig) {
364 if (mConfig == null) return false;
365 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500366 for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
367 ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
368 if (rule.component.getPackageName().equals(packageName)
369 && canManageAutomaticZenRule(rule)) {
370 newConfig.automaticRules.removeAt(i);
371 }
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500372 }
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500373 return setConfigLocked(newConfig, reason, true);
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500374 }
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500375 }
376
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500377 public int getCurrentInstanceCount(ComponentName owner) {
378 int count = 0;
379 synchronized (mConfig) {
380 for (ZenRule rule : mConfig.automaticRules.values()) {
381 if (rule.component != null && rule.component.equals(owner)) {
382 count++;
383 }
384 }
385 }
386 return count;
387 }
388
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400389 public boolean canManageAutomaticZenRule(ZenRule rule) {
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500390 final int callingUid = Binder.getCallingUid();
391 if (callingUid == 0 || callingUid == Process.SYSTEM_UID) {
392 return true;
393 } else if (mContext.checkCallingPermission(android.Manifest.permission.MANAGE_NOTIFICATIONS)
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400394 == PackageManager.PERMISSION_GRANTED) {
395 return true;
396 } else {
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500397 String[] packages = mPm.getPackagesForUid(Binder.getCallingUid());
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400398 if (packages != null) {
399 final int packageCount = packages.length;
400 for (int i = 0; i < packageCount; i++) {
401 if (packages[i].equals(rule.component.getPackageName())) {
402 return true;
403 }
404 }
405 }
406 return false;
407 }
408 }
409
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500410 private boolean isSystemRule(AutomaticZenRule rule) {
411 return ZenModeConfig.SYSTEM_AUTHORITY.equals(rule.getOwner().getPackageName());
412 }
413
414 private ServiceInfo getServiceInfo(ComponentName owner) {
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500415 Intent queryIntent = new Intent();
416 queryIntent.setComponent(owner);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500417 List<ResolveInfo> installedServices = mPm.queryIntentServicesAsUser(
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500418 queryIntent,
419 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
420 UserHandle.getCallingUserId());
421 if (installedServices != null) {
422 for (int i = 0, count = installedServices.size(); i < count; i++) {
423 ResolveInfo resolveInfo = installedServices.get(i);
424 ServiceInfo info = resolveInfo.serviceInfo;
425 if (mServiceConfig.bindPermission.equals(info.permission)) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500426 return info;
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500427 }
428 }
429 }
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500430 return null;
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500431 }
432
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400433 private void populateZenRule(AutomaticZenRule automaticZenRule, ZenRule rule, boolean isNew) {
434 if (isNew) {
435 rule.id = ZenModeConfig.newRuleId();
436 rule.creationTime = System.currentTimeMillis();
437 rule.component = automaticZenRule.getOwner();
438 }
439
440 if (rule.enabled != automaticZenRule.isEnabled()) {
441 rule.snoozing = false;
442 }
443 rule.name = automaticZenRule.getName();
444 rule.condition = null;
445 rule.conditionId = automaticZenRule.getConditionId();
446 rule.enabled = automaticZenRule.isEnabled();
447 rule.zenMode = NotificationManager.zenModeFromInterruptionFilter(
448 automaticZenRule.getInterruptionFilter(), Global.ZEN_MODE_OFF);
449 }
450
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400451 private AutomaticZenRule createAutomaticZenRule(ZenRule rule) {
452 return new AutomaticZenRule(rule.name, rule.component, rule.conditionId,
Julia Reynolds56106ff2015-09-30 14:42:53 -0400453 NotificationManager.zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
Julia Reynolds361e82d32016-02-26 18:19:49 -0500454 rule.creationTime);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400455 }
456
Julia Reynolds44ad6ff2016-07-06 09:47:45 -0400457 public void setManualZenMode(int zenMode, Uri conditionId, String caller, String reason) {
458 setManualZenMode(zenMode, conditionId, reason, caller, true /*setRingerMode*/);
John Spurlocke77bb362014-04-26 10:24:59 -0400459 }
460
Julia Reynolds44ad6ff2016-07-06 09:47:45 -0400461 private void setManualZenMode(int zenMode, Uri conditionId, String reason, String caller,
John Spurlockb2278d62015-04-07 12:47:12 -0400462 boolean setRingerMode) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400463 ZenModeConfig newConfig;
464 synchronized (mConfig) {
465 if (mConfig == null) return;
466 if (!Global.isValidZenMode(zenMode)) return;
467 if (DEBUG) Log.d(TAG, "setManualZenMode " + Global.zenModeToString(zenMode)
468 + " conditionId=" + conditionId + " reason=" + reason
469 + " setRingerMode=" + setRingerMode);
470 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500471 if (zenMode == Global.ZEN_MODE_OFF) {
472 newConfig.manualRule = null;
473 for (ZenRule automaticRule : newConfig.automaticRules.values()) {
474 if (automaticRule.isAutomaticActive()) {
475 automaticRule.snoozing = true;
476 }
John Spurlockb2278d62015-04-07 12:47:12 -0400477 }
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500478 } else {
479 final ZenRule newRule = new ZenRule();
480 newRule.enabled = true;
481 newRule.zenMode = zenMode;
482 newRule.conditionId = conditionId;
Julia Reynolds44ad6ff2016-07-06 09:47:45 -0400483 newRule.enabler = caller;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500484 newConfig.manualRule = newRule;
John Spurlockb2278d62015-04-07 12:47:12 -0400485 }
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500486 setConfigLocked(newConfig, reason, setRingerMode);
John Spurlockb2278d62015-04-07 12:47:12 -0400487 }
John Spurlockb2278d62015-04-07 12:47:12 -0400488 }
489
490 public void dump(PrintWriter pw, String prefix) {
491 pw.print(prefix); pw.print("mZenMode=");
492 pw.println(Global.zenModeToString(mZenMode));
John Spurlockb2278d62015-04-07 12:47:12 -0400493 dump(pw, prefix, "mDefaultConfig", mDefaultConfig);
John Spurlock21258a32015-05-27 18:22:55 -0400494 final int N = mConfigs.size();
495 for (int i = 0; i < N; i++) {
496 dump(pw, prefix, "mConfigs[u=" + mConfigs.keyAt(i) + "]", mConfigs.valueAt(i));
497 }
498 pw.print(prefix); pw.print("mUser="); pw.println(mUser);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400499 synchronized (mConfig) {
500 dump(pw, prefix, "mConfig", mConfig);
501 }
Bryce Lee7219ada2016-04-08 10:54:23 -0700502
503 pw.print(prefix); pw.print("mSuppressedEffects="); pw.println(mSuppressedEffects);
John Spurlock1d7d2242015-04-10 08:10:22 -0400504 mFiltering.dump(pw, prefix);
John Spurlockb2278d62015-04-07 12:47:12 -0400505 mConditions.dump(pw, prefix);
506 }
507
508 private static void dump(PrintWriter pw, String prefix, String var, ZenModeConfig config) {
509 pw.print(prefix); pw.print(var); pw.print('=');
510 if (config == null) {
511 pw.println(config);
512 return;
513 }
Ian Rogersb0b995b2016-06-06 23:43:59 -0700514 pw.printf("allow(calls=%b,callsFrom=%s,repeatCallers=%b,messages=%b,messagesFrom=%s,"
515 + "events=%b,reminders=%b,whenScreenOff=%b,whenScreenOn=%b)\n",
Julia Reynolds6ee26172015-09-28 11:34:48 -0400516 config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom),
517 config.allowRepeatCallers, config.allowMessages,
518 ZenModeConfig.sourceToString(config.allowMessagesFrom),
Julia Reynoldsd5607292016-02-05 15:25:58 -0500519 config.allowEvents, config.allowReminders, config.allowWhenScreenOff,
520 config.allowWhenScreenOn);
John Spurlockb2278d62015-04-07 12:47:12 -0400521 pw.print(prefix); pw.print(" manualRule="); pw.println(config.manualRule);
522 if (config.automaticRules.isEmpty()) return;
523 final int N = config.automaticRules.size();
524 for (int i = 0; i < N; i++) {
525 pw.print(prefix); pw.print(i == 0 ? " automaticRules=" : " ");
526 pw.println(config.automaticRules.valueAt(i));
527 }
528 }
529
John Spurlock35ef0a62015-05-28 11:24:10 -0400530 public void readXml(XmlPullParser parser, boolean forRestore)
531 throws XmlPullParserException, IOException {
John Spurlockb2278d62015-04-07 12:47:12 -0400532 final ZenModeConfig config = ZenModeConfig.readXml(parser, mConfigMigration);
533 if (config != null) {
John Spurlock35ef0a62015-05-28 11:24:10 -0400534 if (forRestore) {
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700535 //TODO: http://b/22388012
536 if (config.user != UserHandle.USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -0400537 return;
538 }
539 config.manualRule = null; // don't restore the manual rule
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500540 long time = System.currentTimeMillis();
John Spurlock995a7492015-05-28 22:13:03 -0400541 if (config.automaticRules != null) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400542 for (ZenRule automaticRule : config.automaticRules.values()) {
John Spurlock995a7492015-05-28 22:13:03 -0400543 // don't restore transient state from restored automatic rules
544 automaticRule.snoozing = false;
545 automaticRule.condition = null;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500546 automaticRule.creationTime = time;
John Spurlock995a7492015-05-28 22:13:03 -0400547 }
548 }
John Spurlock35ef0a62015-05-28 11:24:10 -0400549 }
John Spurlockb2278d62015-04-07 12:47:12 -0400550 if (DEBUG) Log.d(TAG, "readXml");
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500551 synchronized (mConfig) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500552 setConfigLocked(config, "readXml");
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500553 }
John Spurlockb2278d62015-04-07 12:47:12 -0400554 }
555 }
556
John Spurlock35ef0a62015-05-28 11:24:10 -0400557 public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
John Spurlock21258a32015-05-27 18:22:55 -0400558 final int N = mConfigs.size();
559 for (int i = 0; i < N; i++) {
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700560 //TODO: http://b/22388012
561 if (forBackup && mConfigs.keyAt(i) != UserHandle.USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -0400562 continue;
563 }
John Spurlock21258a32015-05-27 18:22:55 -0400564 mConfigs.valueAt(i).writeXml(out);
565 }
John Spurlockb2278d62015-04-07 12:47:12 -0400566 }
567
John Spurlock1fc476d2015-04-14 16:05:20 -0400568 public Policy getNotificationPolicy() {
569 return getNotificationPolicy(mConfig);
570 }
571
572 private static Policy getNotificationPolicy(ZenModeConfig config) {
573 return config == null ? null : config.toNotificationPolicy();
574 }
575
576 public void setNotificationPolicy(Policy policy) {
577 if (policy == null || mConfig == null) return;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500578 synchronized (mConfig) {
579 final ZenModeConfig newConfig = mConfig.copy();
580 newConfig.applyNotificationPolicy(policy);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500581 setConfigLocked(newConfig, "setNotificationPolicy");
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500582 }
John Spurlock1fc476d2015-04-14 16:05:20 -0400583 }
584
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500585 /**
586 * Removes old rule instances whose owner is not installed.
587 */
588 private void cleanUpZenRules() {
589 long currentTime = System.currentTimeMillis();
590 synchronized (mConfig) {
591 final ZenModeConfig newConfig = mConfig.copy();
592 if (newConfig.automaticRules != null) {
593 for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
594 ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
595 if (RULE_INSTANCE_GRACE_PERIOD < (currentTime - rule.creationTime)) {
596 try {
Jeff Sharkeyc7bacab2016-02-09 15:56:11 -0700597 mPm.getPackageInfo(rule.component.getPackageName(),
598 PackageManager.MATCH_UNINSTALLED_PACKAGES);
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500599 } catch (PackageManager.NameNotFoundException e) {
600 newConfig.automaticRules.removeAt(i);
601 }
602 }
603 }
604 }
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500605 setConfigLocked(newConfig, "cleanUpZenRules");
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500606 }
607 }
608
609 /**
610 * @return a copy of the zen mode configuration
611 */
John Spurlockb2278d62015-04-07 12:47:12 -0400612 public ZenModeConfig getConfig() {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400613 synchronized (mConfig) {
614 return mConfig.copy();
615 }
John Spurlockb2278d62015-04-07 12:47:12 -0400616 }
617
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500618 public boolean setConfigLocked(ZenModeConfig config, String reason) {
619 return setConfigLocked(config, reason, true /*setRingerMode*/);
John Spurlockb2278d62015-04-07 12:47:12 -0400620 }
621
Eric Laurente0ced4d2015-09-30 17:44:28 -0700622 public void setConfigAsync(ZenModeConfig config, String reason) {
623 mHandler.postSetConfig(config, reason);
624 }
625
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500626 private boolean setConfigLocked(ZenModeConfig config, String reason, boolean setRingerMode) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400627 final long identity = Binder.clearCallingIdentity();
628 try {
629 if (config == null || !config.isValid()) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500630 Log.w(TAG, "Invalid config in setConfigLocked; " + config);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400631 return false;
632 }
633 if (config.user != mUser) {
634 // simply store away for background users
635 mConfigs.put(config.user, config);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500636 if (DEBUG) Log.d(TAG, "setConfigLocked: store config for user " + config.user);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400637 return true;
638 }
639 mConditions.evaluateConfig(config, false /*processSubscriptions*/); // may modify config
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500640 mConfigs.put(config.user, config);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500641 if (DEBUG) Log.d(TAG, "setConfigLocked reason=" + reason, new Throwable());
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500642 ZenLog.traceConfig(reason, mConfig, config);
643 final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
644 getNotificationPolicy(config));
Julia Reynolds9a25da12016-01-06 16:19:28 -0500645 if (!config.equals(mConfig)) {
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500646 dispatchOnConfigChanged();
647 }
648 if (policyChanged) {
649 dispatchOnPolicyChanged();
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400650 }
Julia Reynolds9a25da12016-01-06 16:19:28 -0500651 mConfig = config;
Julia Reynoldsd82e9812016-04-19 13:27:41 -0400652 mHandler.postApplyConfig(config, reason, setRingerMode);
John Spurlock21258a32015-05-27 18:22:55 -0400653 return true;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400654 } finally {
655 Binder.restoreCallingIdentity(identity);
John Spurlock21258a32015-05-27 18:22:55 -0400656 }
John Spurlockb2278d62015-04-07 12:47:12 -0400657 }
658
Julia Reynoldsd82e9812016-04-19 13:27:41 -0400659 private void applyConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
660 final String val = Integer.toString(config.hashCode());
661 Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
662 if (!evaluateZenMode(reason, setRingerMode)) {
663 applyRestrictions(); // evaluateZenMode will also apply restrictions if changed
664 }
665 mConditions.evaluateConfig(config, true /*processSubscriptions*/);
666 }
667
John Spurlockb2278d62015-04-07 12:47:12 -0400668 private int getZenModeSetting() {
669 return Global.getInt(mContext.getContentResolver(), Global.ZEN_MODE, Global.ZEN_MODE_OFF);
670 }
671
672 private void setZenModeSetting(int zen) {
673 Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zen);
674 }
675
Julia Reynolds9b11fdb2015-07-31 09:49:55 -0400676 private int getPreviousRingerModeSetting() {
677 return Global.getInt(mContext.getContentResolver(),
678 Global.ZEN_MODE_RINGER_LEVEL, AudioManager.RINGER_MODE_NORMAL);
679 }
680
681 private void setPreviousRingerModeSetting(Integer previousRingerLevel) {
682 Global.putString(
683 mContext.getContentResolver(), Global.ZEN_MODE_RINGER_LEVEL,
684 previousRingerLevel == null ? null : Integer.toString(previousRingerLevel));
685 }
686
John Spurlockb2278d62015-04-07 12:47:12 -0400687 private boolean evaluateZenMode(String reason, boolean setRingerMode) {
688 if (DEBUG) Log.d(TAG, "evaluateZenMode");
Jason Monka9927322015-12-13 16:22:37 -0500689 final int zenBefore = mZenMode;
Julia Reynolds8ac63032015-08-31 15:19:43 -0400690 final int zen = computeZenMode();
John Spurlockb2278d62015-04-07 12:47:12 -0400691 ZenLog.traceSetZenMode(zen, reason);
692 mZenMode = zen;
John Spurlock50ced3f2015-05-11 16:00:09 -0400693 updateRingerModeAffectedStreams();
John Spurlockb2278d62015-04-07 12:47:12 -0400694 setZenModeSetting(mZenMode);
John Spurlock57627792014-12-11 11:29:54 -0500695 if (setRingerMode) {
696 applyZenToRingerMode();
697 }
698 applyRestrictions();
Jason Monka9927322015-12-13 16:22:37 -0500699 if (zen != zenBefore) {
Julia Reynolds8ac63032015-08-31 15:19:43 -0400700 mHandler.postDispatchOnZenModeChanged();
701 }
John Spurlockb2278d62015-04-07 12:47:12 -0400702 return true;
John Spurlock57627792014-12-11 11:29:54 -0500703 }
704
John Spurlock50ced3f2015-05-11 16:00:09 -0400705 private void updateRingerModeAffectedStreams() {
706 if (mAudioManager != null) {
707 mAudioManager.updateRingerModeAffectedStreamsInternal();
708 }
709 }
710
Julia Reynolds8ac63032015-08-31 15:19:43 -0400711 private int computeZenMode() {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400712 synchronized (mConfig) {
713 if (mConfig == null) return Global.ZEN_MODE_OFF;
714 if (mConfig.manualRule != null) return mConfig.manualRule.zenMode;
715 int zen = Global.ZEN_MODE_OFF;
716 for (ZenRule automaticRule : mConfig.automaticRules.values()) {
717 if (automaticRule.isAutomaticActive()) {
718 if (zenSeverity(automaticRule.zenMode) > zenSeverity(zen)) {
719 zen = automaticRule.zenMode;
720 }
John Spurlockb2278d62015-04-07 12:47:12 -0400721 }
722 }
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400723 return zen;
John Spurlockb2278d62015-04-07 12:47:12 -0400724 }
John Spurlock8403b752014-12-10 12:47:01 -0500725 }
726
727 private void applyRestrictions() {
John Spurlock056c5192014-04-20 21:52:01 -0400728 final boolean zen = mZenMode != Global.ZEN_MODE_OFF;
John Spurlock8403b752014-12-10 12:47:01 -0500729
730 // notification restrictions
Bryce Lee7219ada2016-04-08 10:54:23 -0700731 final boolean muteNotifications =
732 (mSuppressedEffects & SUPPRESSED_EFFECT_NOTIFICATIONS) != 0;
John Spurlock056c5192014-04-20 21:52:01 -0400733 // call restrictions
Bryce Lee7219ada2016-04-08 10:54:23 -0700734 final boolean muteCalls = zen && !mConfig.allowCalls && !mConfig.allowRepeatCallers
735 || (mSuppressedEffects & SUPPRESSED_EFFECT_CALLS) != 0;
Julia Reynolds3fe81be2016-02-03 09:10:06 -0500736 // total silence restrictions
737 final boolean muteEverything = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
John Spurlock25d01ee2015-06-03 12:17:46 -0400738
Julia Reynolds3fe81be2016-02-03 09:10:06 -0500739 for (int i = USAGE_UNKNOWN; i <= USAGE_VIRTUAL_SOURCE; i++) {
740 if (i == USAGE_NOTIFICATION) {
741 applyRestrictions(muteNotifications || muteEverything, i);
742 } else if (i == USAGE_NOTIFICATION_RINGTONE) {
743 applyRestrictions(muteCalls || muteEverything, i);
744 } else {
745 applyRestrictions(muteEverything, i);
746 }
747 }
John Spurlock8403b752014-12-10 12:47:01 -0500748 }
John Spurlockae641c92014-06-30 18:11:40 -0400749
John Spurlock8403b752014-12-10 12:47:01 -0500750 private void applyRestrictions(boolean mute, int usage) {
751 final String[] exceptionPackages = null; // none (for now)
752 mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, usage,
753 mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
754 exceptionPackages);
755 mAppOps.setRestriction(AppOpsManager.OP_PLAY_AUDIO, usage,
756 mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
757 exceptionPackages);
John Spurlock056c5192014-04-20 21:52:01 -0400758 }
759
John Spurlock57627792014-12-11 11:29:54 -0500760 private void applyZenToRingerMode() {
John Spurlock661f2cf2014-11-17 10:29:10 -0500761 if (mAudioManager == null) return;
John Spurlock661f2cf2014-11-17 10:29:10 -0500762 // force the ringer mode into compliance
763 final int ringerModeInternal = mAudioManager.getRingerModeInternal();
764 int newRingerModeInternal = ringerModeInternal;
John Spurlock57627792014-12-11 11:29:54 -0500765 switch (mZenMode) {
John Spurlock661f2cf2014-11-17 10:29:10 -0500766 case Global.ZEN_MODE_NO_INTERRUPTIONS:
John Spurlock4f1163c2015-04-02 17:41:21 -0400767 case Global.ZEN_MODE_ALARMS:
John Spurlock661f2cf2014-11-17 10:29:10 -0500768 if (ringerModeInternal != AudioManager.RINGER_MODE_SILENT) {
Julia Reynolds9b11fdb2015-07-31 09:49:55 -0400769 setPreviousRingerModeSetting(ringerModeInternal);
John Spurlock661f2cf2014-11-17 10:29:10 -0500770 newRingerModeInternal = AudioManager.RINGER_MODE_SILENT;
John Spurlock8c01d882014-07-28 13:37:13 -0400771 }
John Spurlock661f2cf2014-11-17 10:29:10 -0500772 break;
773 case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
774 case Global.ZEN_MODE_OFF:
775 if (ringerModeInternal == AudioManager.RINGER_MODE_SILENT) {
Julia Reynolds9b11fdb2015-07-31 09:49:55 -0400776 newRingerModeInternal = getPreviousRingerModeSetting();
777 setPreviousRingerModeSetting(null);
John Spurlock661f2cf2014-11-17 10:29:10 -0500778 }
779 break;
John Spurlock8c01d882014-07-28 13:37:13 -0400780 }
John Spurlock661f2cf2014-11-17 10:29:10 -0500781 if (newRingerModeInternal != -1) {
782 mAudioManager.setRingerModeInternal(newRingerModeInternal, TAG);
783 }
784 }
785
John Spurlock1c923a32014-04-27 16:42:29 -0400786 private void dispatchOnConfigChanged() {
787 for (Callback callback : mCallbacks) {
788 callback.onConfigChanged();
789 }
790 }
791
John Spurlock1fc476d2015-04-14 16:05:20 -0400792 private void dispatchOnPolicyChanged() {
793 for (Callback callback : mCallbacks) {
794 callback.onPolicyChanged();
795 }
796 }
797
John Spurlock1c923a32014-04-27 16:42:29 -0400798 private void dispatchOnZenModeChanged() {
799 for (Callback callback : mCallbacks) {
800 callback.onZenModeChanged();
801 }
802 }
803
John Spurlockb2278d62015-04-07 12:47:12 -0400804 private ZenModeConfig readDefaultConfig(Resources resources) {
805 XmlResourceParser parser = null;
806 try {
807 parser = resources.getXml(R.xml.default_zen_mode_config);
808 while (parser.next() != XmlPullParser.END_DOCUMENT) {
809 final ZenModeConfig config = ZenModeConfig.readXml(parser, mConfigMigration);
810 if (config != null) return config;
811 }
812 } catch (Exception e) {
813 Log.w(TAG, "Error reading default zen mode config from resource", e);
814 } finally {
815 IoUtils.closeQuietly(parser);
816 }
817 return new ZenModeConfig();
818 }
819
820 private void appendDefaultScheduleRules(ZenModeConfig config) {
821 if (config == null) return;
822
823 final ScheduleInfo weeknights = new ScheduleInfo();
824 weeknights.days = ZenModeConfig.WEEKNIGHT_DAYS;
825 weeknights.startHour = 22;
826 weeknights.endHour = 7;
827 final ZenRule rule1 = new ZenRule();
828 rule1.enabled = false;
829 rule1.name = mContext.getResources()
830 .getString(R.string.zen_mode_default_weeknights_name);
831 rule1.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
832 rule1.zenMode = Global.ZEN_MODE_ALARMS;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400833 rule1.component = ScheduleConditionProvider.COMPONENT;
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400834 rule1.id = ZenModeConfig.newRuleId();
Julia Reynolds56106ff2015-09-30 14:42:53 -0400835 rule1.creationTime = System.currentTimeMillis();
836 config.automaticRules.put(rule1.id, rule1);
John Spurlockb2278d62015-04-07 12:47:12 -0400837
838 final ScheduleInfo weekends = new ScheduleInfo();
839 weekends.days = ZenModeConfig.WEEKEND_DAYS;
840 weekends.startHour = 23;
841 weekends.startMinute = 30;
842 weekends.endHour = 10;
843 final ZenRule rule2 = new ZenRule();
844 rule2.enabled = false;
845 rule2.name = mContext.getResources()
846 .getString(R.string.zen_mode_default_weekends_name);
847 rule2.conditionId = ZenModeConfig.toScheduleConditionId(weekends);
848 rule2.zenMode = Global.ZEN_MODE_ALARMS;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400849 rule2.component = ScheduleConditionProvider.COMPONENT;
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400850 rule2.id = ZenModeConfig.newRuleId();
Julia Reynolds56106ff2015-09-30 14:42:53 -0400851 rule2.creationTime = System.currentTimeMillis();
852 config.automaticRules.put(rule2.id, rule2);
John Spurlockb2278d62015-04-07 12:47:12 -0400853 }
854
John Spurlockcb9aa202015-05-08 17:35:22 -0400855 private void appendDefaultEventRules(ZenModeConfig config) {
856 if (config == null) return;
857
858 final EventInfo events = new EventInfo();
John Spurlock995a7492015-05-28 22:13:03 -0400859 events.calendar = null; // any calendar
John Spurlockcb9aa202015-05-08 17:35:22 -0400860 events.reply = EventInfo.REPLY_YES_OR_MAYBE;
861 final ZenRule rule = new ZenRule();
862 rule.enabled = false;
863 rule.name = mContext.getResources().getString(R.string.zen_mode_default_events_name);
864 rule.conditionId = ZenModeConfig.toEventConditionId(events);
865 rule.zenMode = Global.ZEN_MODE_ALARMS;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400866 rule.component = EventConditionProvider.COMPONENT;
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400867 rule.id = ZenModeConfig.newRuleId();
Julia Reynolds56106ff2015-09-30 14:42:53 -0400868 rule.creationTime = System.currentTimeMillis();
869 config.automaticRules.put(rule.id, rule);
John Spurlockcb9aa202015-05-08 17:35:22 -0400870 }
871
John Spurlockb2278d62015-04-07 12:47:12 -0400872 private static int zenSeverity(int zen) {
873 switch (zen) {
874 case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return 1;
875 case Global.ZEN_MODE_ALARMS: return 2;
876 case Global.ZEN_MODE_NO_INTERRUPTIONS: return 3;
877 default: return 0;
878 }
879 }
880
881 private final ZenModeConfig.Migration mConfigMigration = new ZenModeConfig.Migration() {
882 @Override
883 public ZenModeConfig migrate(ZenModeConfig.XmlV1 v1) {
884 if (v1 == null) return null;
885 final ZenModeConfig rt = new ZenModeConfig();
886 rt.allowCalls = v1.allowCalls;
887 rt.allowEvents = v1.allowEvents;
John Spurlocka492d1d2015-05-05 18:30:28 -0400888 rt.allowCallsFrom = v1.allowFrom;
John Spurlockb2278d62015-04-07 12:47:12 -0400889 rt.allowMessages = v1.allowMessages;
John Spurlocka492d1d2015-05-05 18:30:28 -0400890 rt.allowMessagesFrom = v1.allowFrom;
John Spurlockb2278d62015-04-07 12:47:12 -0400891 rt.allowReminders = v1.allowReminders;
892 // don't migrate current exit condition
893 final int[] days = ZenModeConfig.XmlV1.tryParseDays(v1.sleepMode);
894 if (days != null && days.length > 0) {
895 Log.i(TAG, "Migrating existing V1 downtime to single schedule");
896 final ScheduleInfo schedule = new ScheduleInfo();
897 schedule.days = days;
898 schedule.startHour = v1.sleepStartHour;
899 schedule.startMinute = v1.sleepStartMinute;
900 schedule.endHour = v1.sleepEndHour;
901 schedule.endMinute = v1.sleepEndMinute;
902 final ZenRule rule = new ZenRule();
903 rule.enabled = true;
904 rule.name = mContext.getResources()
905 .getString(R.string.zen_mode_downtime_feature_name);
906 rule.conditionId = ZenModeConfig.toScheduleConditionId(schedule);
907 rule.zenMode = v1.sleepNone ? Global.ZEN_MODE_NO_INTERRUPTIONS
908 : Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400909 rule.component = ScheduleConditionProvider.COMPONENT;
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400910 rt.automaticRules.put(ZenModeConfig.newRuleId(), rule);
John Spurlockb2278d62015-04-07 12:47:12 -0400911 } else {
912 Log.i(TAG, "No existing V1 downtime found, generating default schedules");
913 appendDefaultScheduleRules(rt);
914 }
John Spurlockcb9aa202015-05-08 17:35:22 -0400915 appendDefaultEventRules(rt);
John Spurlockb2278d62015-04-07 12:47:12 -0400916 return rt;
917 }
918 };
919
920 private final class RingerModeDelegate implements AudioManagerInternal.RingerModeDelegate {
921 @Override
922 public String toString() {
923 return TAG;
924 }
925
926 @Override
927 public int onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller,
928 int ringerModeExternal, VolumePolicy policy) {
929 final boolean isChange = ringerModeOld != ringerModeNew;
930
931 int ringerModeExternalOut = ringerModeNew;
932
933 int newZen = -1;
934 switch (ringerModeNew) {
935 case AudioManager.RINGER_MODE_SILENT:
936 if (isChange && policy.doNotDisturbWhenSilent) {
937 if (mZenMode != Global.ZEN_MODE_NO_INTERRUPTIONS
938 && mZenMode != Global.ZEN_MODE_ALARMS) {
John Spurlockb02c7442015-04-14 09:32:25 -0400939 newZen = Global.ZEN_MODE_ALARMS;
John Spurlockb2278d62015-04-07 12:47:12 -0400940 }
Julia Reynolds9b11fdb2015-07-31 09:49:55 -0400941 setPreviousRingerModeSetting(ringerModeOld);
John Spurlockb2278d62015-04-07 12:47:12 -0400942 }
943 break;
944 case AudioManager.RINGER_MODE_VIBRATE:
945 case AudioManager.RINGER_MODE_NORMAL:
946 if (isChange && ringerModeOld == AudioManager.RINGER_MODE_SILENT
947 && (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS
948 || mZenMode == Global.ZEN_MODE_ALARMS)) {
949 newZen = Global.ZEN_MODE_OFF;
950 } else if (mZenMode != Global.ZEN_MODE_OFF) {
951 ringerModeExternalOut = AudioManager.RINGER_MODE_SILENT;
952 }
953 break;
954 }
955 if (newZen != -1) {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -0400956 setManualZenMode(newZen, null, "ringerModeInternal", null,
957 false /*setRingerMode*/);
John Spurlockb2278d62015-04-07 12:47:12 -0400958 }
959
960 if (isChange || newZen != -1 || ringerModeExternal != ringerModeExternalOut) {
961 ZenLog.traceSetRingerModeInternal(ringerModeOld, ringerModeNew, caller,
962 ringerModeExternal, ringerModeExternalOut);
963 }
964 return ringerModeExternalOut;
965 }
966
967 @Override
968 public int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller,
969 int ringerModeInternal, VolumePolicy policy) {
970 int ringerModeInternalOut = ringerModeNew;
971 final boolean isChange = ringerModeOld != ringerModeNew;
972 final boolean isVibrate = ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE;
973
974 int newZen = -1;
975 switch (ringerModeNew) {
976 case AudioManager.RINGER_MODE_SILENT:
977 if (isChange) {
978 if (mZenMode == Global.ZEN_MODE_OFF) {
John Spurlock05715ec2015-05-13 11:19:19 -0400979 newZen = Global.ZEN_MODE_ALARMS;
John Spurlockb2278d62015-04-07 12:47:12 -0400980 }
981 ringerModeInternalOut = isVibrate ? AudioManager.RINGER_MODE_VIBRATE
John Spurlock05715ec2015-05-13 11:19:19 -0400982 : AudioManager.RINGER_MODE_SILENT;
John Spurlockb2278d62015-04-07 12:47:12 -0400983 } else {
984 ringerModeInternalOut = ringerModeInternal;
985 }
986 break;
987 case AudioManager.RINGER_MODE_VIBRATE:
988 case AudioManager.RINGER_MODE_NORMAL:
989 if (mZenMode != Global.ZEN_MODE_OFF) {
990 newZen = Global.ZEN_MODE_OFF;
991 }
992 break;
993 }
994 if (newZen != -1) {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -0400995 setManualZenMode(newZen, null, "ringerModeExternal", caller,
996 false /*setRingerMode*/);
John Spurlockb2278d62015-04-07 12:47:12 -0400997 }
998
999 ZenLog.traceSetRingerModeExternal(ringerModeOld, ringerModeNew, caller,
1000 ringerModeInternal, ringerModeInternalOut);
1001 return ringerModeInternalOut;
1002 }
John Spurlockd9c75db2015-04-28 11:19:13 -04001003
1004 @Override
1005 public boolean canVolumeDownEnterSilent() {
1006 return mZenMode == Global.ZEN_MODE_OFF;
1007 }
John Spurlock50ced3f2015-05-11 16:00:09 -04001008
1009 @Override
1010 public int getRingerModeAffectedStreams(int streams) {
1011 // ringtone, notification and system streams are always affected by ringer mode
1012 streams |= (1 << AudioSystem.STREAM_RING) |
1013 (1 << AudioSystem.STREAM_NOTIFICATION) |
1014 (1 << AudioSystem.STREAM_SYSTEM);
1015
1016 // alarm and music streams are only affected by ringer mode when in total silence
1017 if (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
1018 streams |= (1 << AudioSystem.STREAM_ALARM) |
1019 (1 << AudioSystem.STREAM_MUSIC);
1020 } else {
1021 streams &= ~((1 << AudioSystem.STREAM_ALARM) |
1022 (1 << AudioSystem.STREAM_MUSIC));
1023 }
1024 return streams;
1025 }
John Spurlockb2278d62015-04-07 12:47:12 -04001026 }
1027
1028 private final class SettingsObserver extends ContentObserver {
John Spurlock056c5192014-04-20 21:52:01 -04001029 private final Uri ZEN_MODE = Global.getUriFor(Global.ZEN_MODE);
1030
1031 public SettingsObserver(Handler handler) {
1032 super(handler);
1033 }
1034
1035 public void observe() {
1036 final ContentResolver resolver = mContext.getContentResolver();
1037 resolver.registerContentObserver(ZEN_MODE, false /*notifyForDescendents*/, this);
1038 update(null);
1039 }
1040
1041 @Override
1042 public void onChange(boolean selfChange, Uri uri) {
1043 update(uri);
1044 }
1045
1046 public void update(Uri uri) {
1047 if (ZEN_MODE.equals(uri)) {
John Spurlockb2278d62015-04-07 12:47:12 -04001048 if (mZenMode != getZenModeSetting()) {
1049 if (DEBUG) Log.d(TAG, "Fixing zen mode setting");
1050 setZenModeSetting(mZenMode);
1051 }
John Spurlock056c5192014-04-20 21:52:01 -04001052 }
1053 }
1054 }
1055
Chris Wren98d235b2015-05-27 18:25:17 -04001056 private final class Metrics extends Callback {
1057 private static final String COUNTER_PREFIX = "dnd_mode_";
1058 private static final long MINIMUM_LOG_PERIOD_MS = 60 * 1000;
1059
1060 private int mPreviousZenMode = -1;
1061 private long mBeginningMs = 0L;
1062
1063 @Override
1064 void onZenModeChanged() {
1065 emit();
1066 }
1067
1068 private void emit() {
1069 mHandler.postMetricsTimer();
1070 final long now = SystemClock.elapsedRealtime();
1071 final long since = (now - mBeginningMs);
1072 if (mPreviousZenMode != mZenMode || since > MINIMUM_LOG_PERIOD_MS) {
1073 if (mPreviousZenMode != -1) {
1074 MetricsLogger.count(mContext, COUNTER_PREFIX + mPreviousZenMode, (int) since);
1075 }
1076 mPreviousZenMode = mZenMode;
1077 mBeginningMs = now;
1078 }
1079 }
1080 }
1081
John Spurlockb2278d62015-04-07 12:47:12 -04001082 private final class H extends Handler {
John Spurlock57627792014-12-11 11:29:54 -05001083 private static final int MSG_DISPATCH = 1;
Chris Wren98d235b2015-05-27 18:25:17 -04001084 private static final int MSG_METRICS = 2;
Eric Laurente0ced4d2015-09-30 17:44:28 -07001085 private static final int MSG_SET_CONFIG = 3;
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001086 private static final int MSG_APPLY_CONFIG = 4;
Eric Laurente0ced4d2015-09-30 17:44:28 -07001087
1088 private final class ConfigMessageData {
1089 public final ZenModeConfig config;
1090 public final String reason;
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001091 public final boolean setRingerMode;
Eric Laurente0ced4d2015-09-30 17:44:28 -07001092
1093 ConfigMessageData(ZenModeConfig config, String reason) {
1094 this.config = config;
1095 this.reason = reason;
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001096 this.setRingerMode = false;
1097 }
1098
1099 ConfigMessageData(ZenModeConfig config, String reason, boolean setRingerMode) {
1100 this.config = config;
1101 this.reason = reason;
1102 this.setRingerMode = setRingerMode;
Eric Laurente0ced4d2015-09-30 17:44:28 -07001103 }
1104 }
Chris Wren98d235b2015-05-27 18:25:17 -04001105
1106 private static final long METRICS_PERIOD_MS = 6 * 60 * 60 * 1000;
John Spurlock661f2cf2014-11-17 10:29:10 -05001107
1108 private H(Looper looper) {
1109 super(looper);
John Spurlock056c5192014-04-20 21:52:01 -04001110 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001111
John Spurlock57627792014-12-11 11:29:54 -05001112 private void postDispatchOnZenModeChanged() {
1113 removeMessages(MSG_DISPATCH);
1114 sendEmptyMessage(MSG_DISPATCH);
John Spurlock661f2cf2014-11-17 10:29:10 -05001115 }
1116
Chris Wren98d235b2015-05-27 18:25:17 -04001117 private void postMetricsTimer() {
1118 removeMessages(MSG_METRICS);
1119 sendEmptyMessageDelayed(MSG_METRICS, METRICS_PERIOD_MS);
1120 }
1121
Eric Laurente0ced4d2015-09-30 17:44:28 -07001122 private void postSetConfig(ZenModeConfig config, String reason) {
1123 sendMessage(obtainMessage(MSG_SET_CONFIG, new ConfigMessageData(config, reason)));
1124 }
1125
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001126 private void postApplyConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
1127 sendMessage(obtainMessage(MSG_APPLY_CONFIG,
1128 new ConfigMessageData(config, reason, setRingerMode)));
1129 }
1130
John Spurlock661f2cf2014-11-17 10:29:10 -05001131 @Override
1132 public void handleMessage(Message msg) {
John Spurlock57627792014-12-11 11:29:54 -05001133 switch (msg.what) {
1134 case MSG_DISPATCH:
1135 dispatchOnZenModeChanged();
John Spurlock661f2cf2014-11-17 10:29:10 -05001136 break;
Chris Wren98d235b2015-05-27 18:25:17 -04001137 case MSG_METRICS:
1138 mMetrics.emit();
1139 break;
Eric Laurente0ced4d2015-09-30 17:44:28 -07001140 case MSG_SET_CONFIG:
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001141 ConfigMessageData configData = (ConfigMessageData) msg.obj;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -05001142 synchronized (mConfig) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -05001143 setConfigLocked(configData.config, configData.reason);
Julia Reynolds5a43aaa2015-12-15 13:54:41 -05001144 }
Eric Laurente0ced4d2015-09-30 17:44:28 -07001145 break;
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001146 case MSG_APPLY_CONFIG:
1147 ConfigMessageData applyConfigData = (ConfigMessageData) msg.obj;
1148 applyConfig(applyConfigData.config, applyConfigData.reason,
1149 applyConfigData.setRingerMode);
John Spurlock661f2cf2014-11-17 10:29:10 -05001150 }
1151 }
1152 }
John Spurlock056c5192014-04-20 21:52:01 -04001153
John Spurlock1c923a32014-04-27 16:42:29 -04001154 public static class Callback {
1155 void onConfigChanged() {}
1156 void onZenModeChanged() {}
John Spurlock1fc476d2015-04-14 16:05:20 -04001157 void onPolicyChanged() {}
John Spurlock056c5192014-04-20 21:52:01 -04001158 }
John Spurlockb2278d62015-04-07 12:47:12 -04001159
John Spurlock056c5192014-04-20 21:52:01 -04001160}