blob: 5c5c8f8541053c2205c89b90bfab21466bd438bf [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 Reynolds4fe98d62015-10-06 16:23:41 -040057import android.text.TextUtils;
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;
John Spurlock8403b752014-12-10 12:47:01 -0500105 private boolean mEffectsSuppressed;
John Spurlock056c5192014-04-20 21:52:01 -0400106
John Spurlockb2278d62015-04-07 12:47:12 -0400107 public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) {
John Spurlock056c5192014-04-20 21:52:01 -0400108 mContext = context;
John Spurlock661f2cf2014-11-17 10:29:10 -0500109 mHandler = new H(looper);
Chris Wren98d235b2015-05-27 18:25:17 -0400110 addCallback(mMetrics);
John Spurlock056c5192014-04-20 21:52:01 -0400111 mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
112 mDefaultConfig = readDefaultConfig(context.getResources());
John Spurlockb2278d62015-04-07 12:47:12 -0400113 appendDefaultScheduleRules(mDefaultConfig);
John Spurlockcb9aa202015-05-08 17:35:22 -0400114 appendDefaultEventRules(mDefaultConfig);
John Spurlock056c5192014-04-20 21:52:01 -0400115 mConfig = mDefaultConfig;
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700116 mConfigs.put(UserHandle.USER_SYSTEM, mConfig);
John Spurlock056c5192014-04-20 21:52:01 -0400117 mSettingsObserver = new SettingsObserver(mHandler);
118 mSettingsObserver.observe();
John Spurlockb2278d62015-04-07 12:47:12 -0400119 mFiltering = new ZenModeFiltering(mContext);
120 mConditions = new ZenModeConditions(this, conditionProviders);
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500121 mServiceConfig = conditionProviders.getConfig();
John Spurlock056c5192014-04-20 21:52:01 -0400122 }
123
John Spurlock1b8b22b2015-05-20 09:47:13 -0400124 public Looper getLooper() {
125 return mHandler.getLooper();
126 }
127
John Spurlockb2278d62015-04-07 12:47:12 -0400128 @Override
129 public String toString() {
130 return TAG;
131 }
132
133 public boolean matchesCallFilter(UserHandle userHandle, Bundle extras,
134 ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400135 synchronized (mConfig) {
136 return ZenModeFiltering.matchesCallFilter(mContext, mZenMode, mConfig, userHandle,
137 extras,
138 validator, contactsTimeoutMs, timeoutAffinity);
139 }
John Spurlockb2278d62015-04-07 12:47:12 -0400140 }
141
142 public boolean isCall(NotificationRecord record) {
143 return mFiltering.isCall(record);
144 }
145
146 public boolean shouldIntercept(NotificationRecord record) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400147 synchronized (mConfig) {
148 return mFiltering.shouldIntercept(mZenMode, mConfig, record);
149 }
John Spurlock056c5192014-04-20 21:52:01 -0400150 }
151
Julia Reynoldsd5607292016-02-05 15:25:58 -0500152 public boolean shouldSuppressWhenScreenOff() {
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500153 synchronized (mConfig) {
Julia Reynoldsd5607292016-02-05 15:25:58 -0500154 return !mConfig.allowWhenScreenOff;
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500155 }
156 }
157
Julia Reynoldsd5607292016-02-05 15:25:58 -0500158 public boolean shouldSuppressWhenScreenOn() {
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500159 synchronized (mConfig) {
Julia Reynoldsd5607292016-02-05 15:25:58 -0500160 return !mConfig.allowWhenScreenOn;
Julia Reynolds61721582016-01-05 08:35:25 -0500161 }
162 }
163
John Spurlock1c923a32014-04-27 16:42:29 -0400164 public void addCallback(Callback callback) {
165 mCallbacks.add(callback);
John Spurlock056c5192014-04-20 21:52:01 -0400166 }
167
John Spurlock530052a2014-11-30 16:26:19 -0500168 public void removeCallback(Callback callback) {
169 mCallbacks.remove(callback);
170 }
171
John Spurlockb2278d62015-04-07 12:47:12 -0400172 public void initZenMode() {
173 if (DEBUG) Log.d(TAG, "initZenMode");
174 evaluateZenMode("init", true /*setRingerMode*/);
175 }
176
John Spurlock661f2cf2014-11-17 10:29:10 -0500177 public void onSystemReady() {
John Spurlockb2278d62015-04-07 12:47:12 -0400178 if (DEBUG) Log.d(TAG, "onSystemReady");
John Spurlock661f2cf2014-11-17 10:29:10 -0500179 mAudioManager = LocalServices.getService(AudioManagerInternal.class);
180 if (mAudioManager != null) {
John Spurlockb2278d62015-04-07 12:47:12 -0400181 mAudioManager.setRingerModeDelegate(mRingerModeDelegate);
John Spurlock661f2cf2014-11-17 10:29:10 -0500182 }
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500183 mPm = mContext.getPackageManager();
Chris Wren98d235b2015-05-27 18:25:17 -0400184 mHandler.postMetricsTimer();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500185 cleanUpZenRules();
Julia Reynolds8ac63032015-08-31 15:19:43 -0400186 evaluateZenMode("onSystemReady", true);
John Spurlockae641c92014-06-30 18:11:40 -0400187 }
188
John Spurlock21258a32015-05-27 18:22:55 -0400189 public void onUserSwitched(int user) {
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500190 loadConfigForUser(user, "onUserSwitched");
John Spurlock21258a32015-05-27 18:22:55 -0400191 }
192
193 public void onUserRemoved(int user) {
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700194 if (user < UserHandle.USER_SYSTEM) return;
John Spurlock21258a32015-05-27 18:22:55 -0400195 if (DEBUG) Log.d(TAG, "onUserRemoved u=" + user);
196 mConfigs.remove(user);
197 }
198
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500199 public void onUserUnlocked(int user) {
200 loadConfigForUser(user, "onUserUnlocked");
201 }
202
203 private void loadConfigForUser(int user, String reason) {
204 if (mUser == user || user < UserHandle.USER_SYSTEM) return;
205 mUser = user;
206 if (DEBUG) Log.d(TAG, reason + " u=" + user);
207 ZenModeConfig config = mConfigs.get(user);
208 if (config == null) {
209 if (DEBUG) Log.d(TAG, reason + " generating default config for user " + user);
210 config = mDefaultConfig.copy();
211 config.user = user;
212 }
213 synchronized (mConfig) {
214 setConfigLocked(config, reason);
215 }
216 cleanUpZenRules();
217 }
218
Christoph Studer85a384b2014-08-27 20:16:15 +0200219 public int getZenModeListenerInterruptionFilter() {
John Spurlock80774932015-05-07 17:38:50 -0400220 return NotificationManager.zenModeToInterruptionFilter(mZenMode);
John Spurlockd8afe3c2014-08-01 14:04:07 -0400221 }
222
John Spurlock80774932015-05-07 17:38:50 -0400223 public void requestFromListener(ComponentName name, int filter) {
224 final int newZen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
John Spurlockd8afe3c2014-08-01 14:04:07 -0400225 if (newZen != -1) {
John Spurlockb2278d62015-04-07 12:47:12 -0400226 setManualZenMode(newZen, null,
227 "listener:" + (name != null ? name.flattenToShortString() : null));
John Spurlockd8afe3c2014-08-01 14:04:07 -0400228 }
229 }
230
John Spurlock8403b752014-12-10 12:47:01 -0500231 public void setEffectsSuppressed(boolean effectsSuppressed) {
232 if (mEffectsSuppressed == effectsSuppressed) return;
233 mEffectsSuppressed = effectsSuppressed;
234 applyRestrictions();
235 }
236
John Spurlock1c923a32014-04-27 16:42:29 -0400237 public int getZenMode() {
238 return mZenMode;
239 }
240
Julia Reynolds361e82d32016-02-26 18:19:49 -0500241 public List<ZenRule> getZenRules() {
242 List<ZenRule> rules = new ArrayList<>();
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400243 synchronized (mConfig) {
244 if (mConfig == null) return rules;
245 for (ZenRule rule : mConfig.automaticRules.values()) {
246 if (canManageAutomaticZenRule(rule)) {
Julia Reynolds361e82d32016-02-26 18:19:49 -0500247 rules.add(rule);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400248 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400249 }
250 }
251 return rules;
252 }
253
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400254 public AutomaticZenRule getAutomaticZenRule(String id) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400255 ZenRule rule;
256 synchronized (mConfig) {
257 if (mConfig == null) return null;
258 rule = mConfig.automaticRules.get(id);
259 }
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400260 if (rule == null) return null;
261 if (canManageAutomaticZenRule(rule)) {
262 return createAutomaticZenRule(rule);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400263 }
264 return null;
265 }
266
Julia Reynolds361e82d32016-02-26 18:19:49 -0500267 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500268 if (!isSystemRule(automaticZenRule)) {
269 ServiceInfo owner = getServiceInfo(automaticZenRule.getOwner());
270 if (owner == null) {
271 throw new IllegalArgumentException("Owner is not a condition provider service");
272 }
273
Julia Reynolds7f2f4412016-03-01 12:33:48 -0500274 int ruleInstanceLimit = -1;
275 if (owner.metaData != null) {
276 ruleInstanceLimit = owner.metaData.getInt(
277 ConditionProviderService.META_DATA_RULE_INSTANCE_LIMIT, -1);
278 }
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500279 if (ruleInstanceLimit > 0 && ruleInstanceLimit
280 < (getCurrentInstanceCount(automaticZenRule.getOwner()) + 1)) {
281 throw new IllegalArgumentException("Rule instance limit exceeded");
282 }
283 }
284
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400285 ZenModeConfig newConfig;
286 synchronized (mConfig) {
287 if (mConfig == null) return null;
288 if (DEBUG) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500289 Log.d(TAG, "addAutomaticZenRule rule= " + automaticZenRule + " reason=" + reason);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400290 }
291 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500292 ZenRule rule = new ZenRule();
293 populateZenRule(automaticZenRule, rule, true);
294 newConfig.automaticRules.put(rule.id, rule);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500295 if (setConfigLocked(newConfig, reason, true)) {
Julia Reynolds361e82d32016-02-26 18:19:49 -0500296 return rule.id;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500297 } else {
298 return null;
299 }
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400300 }
301 }
302
Julia Reynolds361e82d32016-02-26 18:19:49 -0500303 public boolean updateAutomaticZenRule(String ruleId, AutomaticZenRule automaticZenRule,
304 String reason) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400305 ZenModeConfig newConfig;
306 synchronized (mConfig) {
307 if (mConfig == null) return false;
308 if (DEBUG) {
309 Log.d(TAG, "updateAutomaticZenRule zenRule=" + automaticZenRule
310 + " reason=" + reason);
311 }
312 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500313 ZenModeConfig.ZenRule rule;
314 if (ruleId == null) {
315 throw new IllegalArgumentException("Rule doesn't exist");
316 } else {
317 rule = newConfig.automaticRules.get(ruleId);
318 if (rule == null || !canManageAutomaticZenRule(rule)) {
319 throw new SecurityException(
320 "Cannot update rules not owned by your condition provider");
321 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400322 }
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500323 populateZenRule(automaticZenRule, rule, false);
324 newConfig.automaticRules.put(ruleId, rule);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500325 return setConfigLocked(newConfig, reason, true);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400326 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400327 }
328
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400329 public boolean removeAutomaticZenRule(String id, String reason) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400330 ZenModeConfig newConfig;
331 synchronized (mConfig) {
332 if (mConfig == null) return false;
333 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500334 ZenRule rule = newConfig.automaticRules.get(id);
335 if (rule == null) return false;
336 if (canManageAutomaticZenRule(rule)) {
337 newConfig.automaticRules.remove(id);
338 if (DEBUG) Log.d(TAG, "removeZenRule zenRule=" + id + " reason=" + reason);
339 } else {
340 throw new SecurityException(
341 "Cannot delete rules not owned by your condition provider");
342 }
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500343 return setConfigLocked(newConfig, reason, true);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400344 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400345 }
346
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500347 public boolean removeAutomaticZenRules(String packageName, String reason) {
348 ZenModeConfig newConfig;
349 synchronized (mConfig) {
350 if (mConfig == null) return false;
351 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500352 for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
353 ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
354 if (rule.component.getPackageName().equals(packageName)
355 && canManageAutomaticZenRule(rule)) {
356 newConfig.automaticRules.removeAt(i);
357 }
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500358 }
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500359 return setConfigLocked(newConfig, reason, true);
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500360 }
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500361 }
362
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500363 public int getCurrentInstanceCount(ComponentName owner) {
364 int count = 0;
365 synchronized (mConfig) {
366 for (ZenRule rule : mConfig.automaticRules.values()) {
367 if (rule.component != null && rule.component.equals(owner)) {
368 count++;
369 }
370 }
371 }
372 return count;
373 }
374
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400375 public boolean canManageAutomaticZenRule(ZenRule rule) {
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500376 final int callingUid = Binder.getCallingUid();
377 if (callingUid == 0 || callingUid == Process.SYSTEM_UID) {
378 return true;
379 } else if (mContext.checkCallingPermission(android.Manifest.permission.MANAGE_NOTIFICATIONS)
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400380 == PackageManager.PERMISSION_GRANTED) {
381 return true;
382 } else {
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500383 String[] packages = mPm.getPackagesForUid(Binder.getCallingUid());
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400384 if (packages != null) {
385 final int packageCount = packages.length;
386 for (int i = 0; i < packageCount; i++) {
387 if (packages[i].equals(rule.component.getPackageName())) {
388 return true;
389 }
390 }
391 }
392 return false;
393 }
394 }
395
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500396 private boolean isSystemRule(AutomaticZenRule rule) {
397 return ZenModeConfig.SYSTEM_AUTHORITY.equals(rule.getOwner().getPackageName());
398 }
399
400 private ServiceInfo getServiceInfo(ComponentName owner) {
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500401 Intent queryIntent = new Intent();
402 queryIntent.setComponent(owner);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500403 List<ResolveInfo> installedServices = mPm.queryIntentServicesAsUser(
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500404 queryIntent,
405 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
406 UserHandle.getCallingUserId());
407 if (installedServices != null) {
408 for (int i = 0, count = installedServices.size(); i < count; i++) {
409 ResolveInfo resolveInfo = installedServices.get(i);
410 ServiceInfo info = resolveInfo.serviceInfo;
411 if (mServiceConfig.bindPermission.equals(info.permission)) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500412 return info;
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500413 }
414 }
415 }
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500416 return null;
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500417 }
418
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400419 private void populateZenRule(AutomaticZenRule automaticZenRule, ZenRule rule, boolean isNew) {
420 if (isNew) {
421 rule.id = ZenModeConfig.newRuleId();
422 rule.creationTime = System.currentTimeMillis();
423 rule.component = automaticZenRule.getOwner();
424 }
425
426 if (rule.enabled != automaticZenRule.isEnabled()) {
427 rule.snoozing = false;
428 }
429 rule.name = automaticZenRule.getName();
430 rule.condition = null;
431 rule.conditionId = automaticZenRule.getConditionId();
432 rule.enabled = automaticZenRule.isEnabled();
433 rule.zenMode = NotificationManager.zenModeFromInterruptionFilter(
434 automaticZenRule.getInterruptionFilter(), Global.ZEN_MODE_OFF);
435 }
436
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400437 private AutomaticZenRule createAutomaticZenRule(ZenRule rule) {
438 return new AutomaticZenRule(rule.name, rule.component, rule.conditionId,
Julia Reynolds56106ff2015-09-30 14:42:53 -0400439 NotificationManager.zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
Julia Reynolds361e82d32016-02-26 18:19:49 -0500440 rule.creationTime);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400441 }
442
John Spurlockb2278d62015-04-07 12:47:12 -0400443 public void setManualZenMode(int zenMode, Uri conditionId, String reason) {
444 setManualZenMode(zenMode, conditionId, reason, true /*setRingerMode*/);
John Spurlocke77bb362014-04-26 10:24:59 -0400445 }
446
John Spurlockb2278d62015-04-07 12:47:12 -0400447 private void setManualZenMode(int zenMode, Uri conditionId, String reason,
448 boolean setRingerMode) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400449 ZenModeConfig newConfig;
450 synchronized (mConfig) {
451 if (mConfig == null) return;
452 if (!Global.isValidZenMode(zenMode)) return;
453 if (DEBUG) Log.d(TAG, "setManualZenMode " + Global.zenModeToString(zenMode)
454 + " conditionId=" + conditionId + " reason=" + reason
455 + " setRingerMode=" + setRingerMode);
456 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500457 if (zenMode == Global.ZEN_MODE_OFF) {
458 newConfig.manualRule = null;
459 for (ZenRule automaticRule : newConfig.automaticRules.values()) {
460 if (automaticRule.isAutomaticActive()) {
461 automaticRule.snoozing = true;
462 }
John Spurlockb2278d62015-04-07 12:47:12 -0400463 }
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500464 } else {
465 final ZenRule newRule = new ZenRule();
466 newRule.enabled = true;
467 newRule.zenMode = zenMode;
468 newRule.conditionId = conditionId;
469 newConfig.manualRule = newRule;
John Spurlockb2278d62015-04-07 12:47:12 -0400470 }
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500471 setConfigLocked(newConfig, reason, setRingerMode);
John Spurlockb2278d62015-04-07 12:47:12 -0400472 }
John Spurlockb2278d62015-04-07 12:47:12 -0400473 }
474
475 public void dump(PrintWriter pw, String prefix) {
476 pw.print(prefix); pw.print("mZenMode=");
477 pw.println(Global.zenModeToString(mZenMode));
John Spurlockb2278d62015-04-07 12:47:12 -0400478 dump(pw, prefix, "mDefaultConfig", mDefaultConfig);
John Spurlock21258a32015-05-27 18:22:55 -0400479 final int N = mConfigs.size();
480 for (int i = 0; i < N; i++) {
481 dump(pw, prefix, "mConfigs[u=" + mConfigs.keyAt(i) + "]", mConfigs.valueAt(i));
482 }
483 pw.print(prefix); pw.print("mUser="); pw.println(mUser);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400484 synchronized (mConfig) {
485 dump(pw, prefix, "mConfig", mConfig);
486 }
John Spurlockb2278d62015-04-07 12:47:12 -0400487 pw.print(prefix); pw.print("mEffectsSuppressed="); pw.println(mEffectsSuppressed);
John Spurlock1d7d2242015-04-10 08:10:22 -0400488 mFiltering.dump(pw, prefix);
John Spurlockb2278d62015-04-07 12:47:12 -0400489 mConditions.dump(pw, prefix);
490 }
491
492 private static void dump(PrintWriter pw, String prefix, String var, ZenModeConfig config) {
493 pw.print(prefix); pw.print(var); pw.print('=');
494 if (config == null) {
495 pw.println(config);
496 return;
497 }
John Spurlocka492d1d2015-05-05 18:30:28 -0400498 pw.printf("allow(calls=%s,callsFrom=%s,repeatCallers=%s,messages=%s,messagesFrom=%s,"
Julia Reynoldsd5607292016-02-05 15:25:58 -0500499 + "events=%s,reminders=%s,whenScreenOff,whenScreenOn=%s)\n",
Julia Reynolds6ee26172015-09-28 11:34:48 -0400500 config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom),
501 config.allowRepeatCallers, config.allowMessages,
502 ZenModeConfig.sourceToString(config.allowMessagesFrom),
Julia Reynoldsd5607292016-02-05 15:25:58 -0500503 config.allowEvents, config.allowReminders, config.allowWhenScreenOff,
504 config.allowWhenScreenOn);
John Spurlockb2278d62015-04-07 12:47:12 -0400505 pw.print(prefix); pw.print(" manualRule="); pw.println(config.manualRule);
506 if (config.automaticRules.isEmpty()) return;
507 final int N = config.automaticRules.size();
508 for (int i = 0; i < N; i++) {
509 pw.print(prefix); pw.print(i == 0 ? " automaticRules=" : " ");
510 pw.println(config.automaticRules.valueAt(i));
511 }
512 }
513
John Spurlock35ef0a62015-05-28 11:24:10 -0400514 public void readXml(XmlPullParser parser, boolean forRestore)
515 throws XmlPullParserException, IOException {
John Spurlockb2278d62015-04-07 12:47:12 -0400516 final ZenModeConfig config = ZenModeConfig.readXml(parser, mConfigMigration);
517 if (config != null) {
John Spurlock35ef0a62015-05-28 11:24:10 -0400518 if (forRestore) {
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700519 //TODO: http://b/22388012
520 if (config.user != UserHandle.USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -0400521 return;
522 }
523 config.manualRule = null; // don't restore the manual rule
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500524 long time = System.currentTimeMillis();
John Spurlock995a7492015-05-28 22:13:03 -0400525 if (config.automaticRules != null) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400526 for (ZenRule automaticRule : config.automaticRules.values()) {
John Spurlock995a7492015-05-28 22:13:03 -0400527 // don't restore transient state from restored automatic rules
528 automaticRule.snoozing = false;
529 automaticRule.condition = null;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500530 automaticRule.creationTime = time;
John Spurlock995a7492015-05-28 22:13:03 -0400531 }
532 }
John Spurlock35ef0a62015-05-28 11:24:10 -0400533 }
John Spurlockb2278d62015-04-07 12:47:12 -0400534 if (DEBUG) Log.d(TAG, "readXml");
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500535 synchronized (mConfig) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500536 setConfigLocked(config, "readXml");
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500537 }
John Spurlockb2278d62015-04-07 12:47:12 -0400538 }
539 }
540
John Spurlock35ef0a62015-05-28 11:24:10 -0400541 public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
John Spurlock21258a32015-05-27 18:22:55 -0400542 final int N = mConfigs.size();
543 for (int i = 0; i < N; i++) {
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700544 //TODO: http://b/22388012
545 if (forBackup && mConfigs.keyAt(i) != UserHandle.USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -0400546 continue;
547 }
John Spurlock21258a32015-05-27 18:22:55 -0400548 mConfigs.valueAt(i).writeXml(out);
549 }
John Spurlockb2278d62015-04-07 12:47:12 -0400550 }
551
John Spurlock1fc476d2015-04-14 16:05:20 -0400552 public Policy getNotificationPolicy() {
553 return getNotificationPolicy(mConfig);
554 }
555
556 private static Policy getNotificationPolicy(ZenModeConfig config) {
557 return config == null ? null : config.toNotificationPolicy();
558 }
559
560 public void setNotificationPolicy(Policy policy) {
561 if (policy == null || mConfig == null) return;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500562 synchronized (mConfig) {
563 final ZenModeConfig newConfig = mConfig.copy();
564 newConfig.applyNotificationPolicy(policy);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500565 setConfigLocked(newConfig, "setNotificationPolicy");
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500566 }
John Spurlock1fc476d2015-04-14 16:05:20 -0400567 }
568
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500569 /**
570 * Removes old rule instances whose owner is not installed.
571 */
572 private void cleanUpZenRules() {
573 long currentTime = System.currentTimeMillis();
574 synchronized (mConfig) {
575 final ZenModeConfig newConfig = mConfig.copy();
576 if (newConfig.automaticRules != null) {
577 for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
578 ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
579 if (RULE_INSTANCE_GRACE_PERIOD < (currentTime - rule.creationTime)) {
580 try {
Jeff Sharkeyc7bacab2016-02-09 15:56:11 -0700581 mPm.getPackageInfo(rule.component.getPackageName(),
582 PackageManager.MATCH_UNINSTALLED_PACKAGES);
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500583 } catch (PackageManager.NameNotFoundException e) {
584 newConfig.automaticRules.removeAt(i);
585 }
586 }
587 }
588 }
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500589 setConfigLocked(newConfig, "cleanUpZenRules");
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500590 }
591 }
592
593 /**
594 * @return a copy of the zen mode configuration
595 */
John Spurlockb2278d62015-04-07 12:47:12 -0400596 public ZenModeConfig getConfig() {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400597 synchronized (mConfig) {
598 return mConfig.copy();
599 }
John Spurlockb2278d62015-04-07 12:47:12 -0400600 }
601
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500602 public boolean setConfigLocked(ZenModeConfig config, String reason) {
603 return setConfigLocked(config, reason, true /*setRingerMode*/);
John Spurlockb2278d62015-04-07 12:47:12 -0400604 }
605
Eric Laurente0ced4d2015-09-30 17:44:28 -0700606 public void setConfigAsync(ZenModeConfig config, String reason) {
607 mHandler.postSetConfig(config, reason);
608 }
609
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500610 private boolean setConfigLocked(ZenModeConfig config, String reason, boolean setRingerMode) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400611 final long identity = Binder.clearCallingIdentity();
612 try {
613 if (config == null || !config.isValid()) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500614 Log.w(TAG, "Invalid config in setConfigLocked; " + config);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400615 return false;
616 }
617 if (config.user != mUser) {
618 // simply store away for background users
619 mConfigs.put(config.user, config);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500620 if (DEBUG) Log.d(TAG, "setConfigLocked: store config for user " + config.user);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400621 return true;
622 }
623 mConditions.evaluateConfig(config, false /*processSubscriptions*/); // may modify config
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500624 mConfigs.put(config.user, config);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500625 if (DEBUG) Log.d(TAG, "setConfigLocked reason=" + reason, new Throwable());
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500626 ZenLog.traceConfig(reason, mConfig, config);
627 final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
628 getNotificationPolicy(config));
Julia Reynolds9a25da12016-01-06 16:19:28 -0500629 if (!config.equals(mConfig)) {
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500630 dispatchOnConfigChanged();
631 }
632 if (policyChanged) {
633 dispatchOnPolicyChanged();
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400634 }
Julia Reynolds9a25da12016-01-06 16:19:28 -0500635 mConfig = config;
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400636 final String val = Integer.toString(config.hashCode());
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400637 Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
638 if (!evaluateZenMode(reason, setRingerMode)) {
639 applyRestrictions(); // evaluateZenMode will also apply restrictions if changed
640 }
641 mConditions.evaluateConfig(config, true /*processSubscriptions*/);
John Spurlock21258a32015-05-27 18:22:55 -0400642 return true;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400643 } finally {
644 Binder.restoreCallingIdentity(identity);
John Spurlock21258a32015-05-27 18:22:55 -0400645 }
John Spurlockb2278d62015-04-07 12:47:12 -0400646 }
647
648 private int getZenModeSetting() {
649 return Global.getInt(mContext.getContentResolver(), Global.ZEN_MODE, Global.ZEN_MODE_OFF);
650 }
651
652 private void setZenModeSetting(int zen) {
653 Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zen);
654 }
655
Julia Reynolds9b11fdb2015-07-31 09:49:55 -0400656 private int getPreviousRingerModeSetting() {
657 return Global.getInt(mContext.getContentResolver(),
658 Global.ZEN_MODE_RINGER_LEVEL, AudioManager.RINGER_MODE_NORMAL);
659 }
660
661 private void setPreviousRingerModeSetting(Integer previousRingerLevel) {
662 Global.putString(
663 mContext.getContentResolver(), Global.ZEN_MODE_RINGER_LEVEL,
664 previousRingerLevel == null ? null : Integer.toString(previousRingerLevel));
665 }
666
John Spurlockb2278d62015-04-07 12:47:12 -0400667 private boolean evaluateZenMode(String reason, boolean setRingerMode) {
668 if (DEBUG) Log.d(TAG, "evaluateZenMode");
Jason Monka9927322015-12-13 16:22:37 -0500669 final int zenBefore = mZenMode;
Julia Reynolds8ac63032015-08-31 15:19:43 -0400670 final int zen = computeZenMode();
John Spurlockb2278d62015-04-07 12:47:12 -0400671 ZenLog.traceSetZenMode(zen, reason);
672 mZenMode = zen;
John Spurlock50ced3f2015-05-11 16:00:09 -0400673 updateRingerModeAffectedStreams();
John Spurlockb2278d62015-04-07 12:47:12 -0400674 setZenModeSetting(mZenMode);
John Spurlock57627792014-12-11 11:29:54 -0500675 if (setRingerMode) {
676 applyZenToRingerMode();
677 }
678 applyRestrictions();
Jason Monka9927322015-12-13 16:22:37 -0500679 if (zen != zenBefore) {
Julia Reynolds8ac63032015-08-31 15:19:43 -0400680 mHandler.postDispatchOnZenModeChanged();
681 }
John Spurlockb2278d62015-04-07 12:47:12 -0400682 return true;
John Spurlock57627792014-12-11 11:29:54 -0500683 }
684
John Spurlock50ced3f2015-05-11 16:00:09 -0400685 private void updateRingerModeAffectedStreams() {
686 if (mAudioManager != null) {
687 mAudioManager.updateRingerModeAffectedStreamsInternal();
688 }
689 }
690
Julia Reynolds8ac63032015-08-31 15:19:43 -0400691 private int computeZenMode() {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400692 synchronized (mConfig) {
693 if (mConfig == null) return Global.ZEN_MODE_OFF;
694 if (mConfig.manualRule != null) return mConfig.manualRule.zenMode;
695 int zen = Global.ZEN_MODE_OFF;
696 for (ZenRule automaticRule : mConfig.automaticRules.values()) {
697 if (automaticRule.isAutomaticActive()) {
698 if (zenSeverity(automaticRule.zenMode) > zenSeverity(zen)) {
699 zen = automaticRule.zenMode;
700 }
John Spurlockb2278d62015-04-07 12:47:12 -0400701 }
702 }
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400703 return zen;
John Spurlockb2278d62015-04-07 12:47:12 -0400704 }
John Spurlock8403b752014-12-10 12:47:01 -0500705 }
706
707 private void applyRestrictions() {
John Spurlock056c5192014-04-20 21:52:01 -0400708 final boolean zen = mZenMode != Global.ZEN_MODE_OFF;
John Spurlock8403b752014-12-10 12:47:01 -0500709
710 // notification restrictions
711 final boolean muteNotifications = mEffectsSuppressed;
John Spurlock056c5192014-04-20 21:52:01 -0400712 // call restrictions
Zach Johnsonf1b48142015-08-24 15:38:27 -0700713 final boolean muteCalls = zen && !mConfig.allowCalls && !mConfig.allowRepeatCallers;
Julia Reynolds3fe81be2016-02-03 09:10:06 -0500714 // total silence restrictions
715 final boolean muteEverything = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
John Spurlock25d01ee2015-06-03 12:17:46 -0400716
Julia Reynolds3fe81be2016-02-03 09:10:06 -0500717 for (int i = USAGE_UNKNOWN; i <= USAGE_VIRTUAL_SOURCE; i++) {
718 if (i == USAGE_NOTIFICATION) {
719 applyRestrictions(muteNotifications || muteEverything, i);
720 } else if (i == USAGE_NOTIFICATION_RINGTONE) {
721 applyRestrictions(muteCalls || muteEverything, i);
722 } else {
723 applyRestrictions(muteEverything, i);
724 }
725 }
John Spurlock8403b752014-12-10 12:47:01 -0500726 }
John Spurlockae641c92014-06-30 18:11:40 -0400727
John Spurlock8403b752014-12-10 12:47:01 -0500728 private void applyRestrictions(boolean mute, int usage) {
729 final String[] exceptionPackages = null; // none (for now)
730 mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, usage,
731 mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
732 exceptionPackages);
733 mAppOps.setRestriction(AppOpsManager.OP_PLAY_AUDIO, usage,
734 mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
735 exceptionPackages);
John Spurlock056c5192014-04-20 21:52:01 -0400736 }
737
John Spurlock57627792014-12-11 11:29:54 -0500738 private void applyZenToRingerMode() {
John Spurlock661f2cf2014-11-17 10:29:10 -0500739 if (mAudioManager == null) return;
John Spurlock661f2cf2014-11-17 10:29:10 -0500740 // force the ringer mode into compliance
741 final int ringerModeInternal = mAudioManager.getRingerModeInternal();
742 int newRingerModeInternal = ringerModeInternal;
John Spurlock57627792014-12-11 11:29:54 -0500743 switch (mZenMode) {
John Spurlock661f2cf2014-11-17 10:29:10 -0500744 case Global.ZEN_MODE_NO_INTERRUPTIONS:
John Spurlock4f1163c2015-04-02 17:41:21 -0400745 case Global.ZEN_MODE_ALARMS:
John Spurlock661f2cf2014-11-17 10:29:10 -0500746 if (ringerModeInternal != AudioManager.RINGER_MODE_SILENT) {
Julia Reynolds9b11fdb2015-07-31 09:49:55 -0400747 setPreviousRingerModeSetting(ringerModeInternal);
John Spurlock661f2cf2014-11-17 10:29:10 -0500748 newRingerModeInternal = AudioManager.RINGER_MODE_SILENT;
John Spurlock8c01d882014-07-28 13:37:13 -0400749 }
John Spurlock661f2cf2014-11-17 10:29:10 -0500750 break;
751 case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
752 case Global.ZEN_MODE_OFF:
753 if (ringerModeInternal == AudioManager.RINGER_MODE_SILENT) {
Julia Reynolds9b11fdb2015-07-31 09:49:55 -0400754 newRingerModeInternal = getPreviousRingerModeSetting();
755 setPreviousRingerModeSetting(null);
John Spurlock661f2cf2014-11-17 10:29:10 -0500756 }
757 break;
John Spurlock8c01d882014-07-28 13:37:13 -0400758 }
John Spurlock661f2cf2014-11-17 10:29:10 -0500759 if (newRingerModeInternal != -1) {
760 mAudioManager.setRingerModeInternal(newRingerModeInternal, TAG);
761 }
762 }
763
John Spurlock1c923a32014-04-27 16:42:29 -0400764 private void dispatchOnConfigChanged() {
765 for (Callback callback : mCallbacks) {
766 callback.onConfigChanged();
767 }
768 }
769
John Spurlock1fc476d2015-04-14 16:05:20 -0400770 private void dispatchOnPolicyChanged() {
771 for (Callback callback : mCallbacks) {
772 callback.onPolicyChanged();
773 }
774 }
775
John Spurlock1c923a32014-04-27 16:42:29 -0400776 private void dispatchOnZenModeChanged() {
777 for (Callback callback : mCallbacks) {
778 callback.onZenModeChanged();
779 }
780 }
781
John Spurlockb2278d62015-04-07 12:47:12 -0400782 private ZenModeConfig readDefaultConfig(Resources resources) {
783 XmlResourceParser parser = null;
784 try {
785 parser = resources.getXml(R.xml.default_zen_mode_config);
786 while (parser.next() != XmlPullParser.END_DOCUMENT) {
787 final ZenModeConfig config = ZenModeConfig.readXml(parser, mConfigMigration);
788 if (config != null) return config;
789 }
790 } catch (Exception e) {
791 Log.w(TAG, "Error reading default zen mode config from resource", e);
792 } finally {
793 IoUtils.closeQuietly(parser);
794 }
795 return new ZenModeConfig();
796 }
797
798 private void appendDefaultScheduleRules(ZenModeConfig config) {
799 if (config == null) return;
800
801 final ScheduleInfo weeknights = new ScheduleInfo();
802 weeknights.days = ZenModeConfig.WEEKNIGHT_DAYS;
803 weeknights.startHour = 22;
804 weeknights.endHour = 7;
805 final ZenRule rule1 = new ZenRule();
806 rule1.enabled = false;
807 rule1.name = mContext.getResources()
808 .getString(R.string.zen_mode_default_weeknights_name);
809 rule1.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
810 rule1.zenMode = Global.ZEN_MODE_ALARMS;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400811 rule1.component = ScheduleConditionProvider.COMPONENT;
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400812 rule1.id = ZenModeConfig.newRuleId();
Julia Reynolds56106ff2015-09-30 14:42:53 -0400813 rule1.creationTime = System.currentTimeMillis();
814 config.automaticRules.put(rule1.id, rule1);
John Spurlockb2278d62015-04-07 12:47:12 -0400815
816 final ScheduleInfo weekends = new ScheduleInfo();
817 weekends.days = ZenModeConfig.WEEKEND_DAYS;
818 weekends.startHour = 23;
819 weekends.startMinute = 30;
820 weekends.endHour = 10;
821 final ZenRule rule2 = new ZenRule();
822 rule2.enabled = false;
823 rule2.name = mContext.getResources()
824 .getString(R.string.zen_mode_default_weekends_name);
825 rule2.conditionId = ZenModeConfig.toScheduleConditionId(weekends);
826 rule2.zenMode = Global.ZEN_MODE_ALARMS;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400827 rule2.component = ScheduleConditionProvider.COMPONENT;
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400828 rule2.id = ZenModeConfig.newRuleId();
Julia Reynolds56106ff2015-09-30 14:42:53 -0400829 rule2.creationTime = System.currentTimeMillis();
830 config.automaticRules.put(rule2.id, rule2);
John Spurlockb2278d62015-04-07 12:47:12 -0400831 }
832
John Spurlockcb9aa202015-05-08 17:35:22 -0400833 private void appendDefaultEventRules(ZenModeConfig config) {
834 if (config == null) return;
835
836 final EventInfo events = new EventInfo();
John Spurlock995a7492015-05-28 22:13:03 -0400837 events.calendar = null; // any calendar
John Spurlockcb9aa202015-05-08 17:35:22 -0400838 events.reply = EventInfo.REPLY_YES_OR_MAYBE;
839 final ZenRule rule = new ZenRule();
840 rule.enabled = false;
841 rule.name = mContext.getResources().getString(R.string.zen_mode_default_events_name);
842 rule.conditionId = ZenModeConfig.toEventConditionId(events);
843 rule.zenMode = Global.ZEN_MODE_ALARMS;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400844 rule.component = EventConditionProvider.COMPONENT;
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400845 rule.id = ZenModeConfig.newRuleId();
Julia Reynolds56106ff2015-09-30 14:42:53 -0400846 rule.creationTime = System.currentTimeMillis();
847 config.automaticRules.put(rule.id, rule);
John Spurlockcb9aa202015-05-08 17:35:22 -0400848 }
849
John Spurlockb2278d62015-04-07 12:47:12 -0400850 private static int zenSeverity(int zen) {
851 switch (zen) {
852 case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return 1;
853 case Global.ZEN_MODE_ALARMS: return 2;
854 case Global.ZEN_MODE_NO_INTERRUPTIONS: return 3;
855 default: return 0;
856 }
857 }
858
859 private final ZenModeConfig.Migration mConfigMigration = new ZenModeConfig.Migration() {
860 @Override
861 public ZenModeConfig migrate(ZenModeConfig.XmlV1 v1) {
862 if (v1 == null) return null;
863 final ZenModeConfig rt = new ZenModeConfig();
864 rt.allowCalls = v1.allowCalls;
865 rt.allowEvents = v1.allowEvents;
John Spurlocka492d1d2015-05-05 18:30:28 -0400866 rt.allowCallsFrom = v1.allowFrom;
John Spurlockb2278d62015-04-07 12:47:12 -0400867 rt.allowMessages = v1.allowMessages;
John Spurlocka492d1d2015-05-05 18:30:28 -0400868 rt.allowMessagesFrom = v1.allowFrom;
John Spurlockb2278d62015-04-07 12:47:12 -0400869 rt.allowReminders = v1.allowReminders;
870 // don't migrate current exit condition
871 final int[] days = ZenModeConfig.XmlV1.tryParseDays(v1.sleepMode);
872 if (days != null && days.length > 0) {
873 Log.i(TAG, "Migrating existing V1 downtime to single schedule");
874 final ScheduleInfo schedule = new ScheduleInfo();
875 schedule.days = days;
876 schedule.startHour = v1.sleepStartHour;
877 schedule.startMinute = v1.sleepStartMinute;
878 schedule.endHour = v1.sleepEndHour;
879 schedule.endMinute = v1.sleepEndMinute;
880 final ZenRule rule = new ZenRule();
881 rule.enabled = true;
882 rule.name = mContext.getResources()
883 .getString(R.string.zen_mode_downtime_feature_name);
884 rule.conditionId = ZenModeConfig.toScheduleConditionId(schedule);
885 rule.zenMode = v1.sleepNone ? Global.ZEN_MODE_NO_INTERRUPTIONS
886 : Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400887 rule.component = ScheduleConditionProvider.COMPONENT;
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400888 rt.automaticRules.put(ZenModeConfig.newRuleId(), rule);
John Spurlockb2278d62015-04-07 12:47:12 -0400889 } else {
890 Log.i(TAG, "No existing V1 downtime found, generating default schedules");
891 appendDefaultScheduleRules(rt);
892 }
John Spurlockcb9aa202015-05-08 17:35:22 -0400893 appendDefaultEventRules(rt);
John Spurlockb2278d62015-04-07 12:47:12 -0400894 return rt;
895 }
896 };
897
898 private final class RingerModeDelegate implements AudioManagerInternal.RingerModeDelegate {
899 @Override
900 public String toString() {
901 return TAG;
902 }
903
904 @Override
905 public int onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller,
906 int ringerModeExternal, VolumePolicy policy) {
907 final boolean isChange = ringerModeOld != ringerModeNew;
908
909 int ringerModeExternalOut = ringerModeNew;
910
911 int newZen = -1;
912 switch (ringerModeNew) {
913 case AudioManager.RINGER_MODE_SILENT:
914 if (isChange && policy.doNotDisturbWhenSilent) {
915 if (mZenMode != Global.ZEN_MODE_NO_INTERRUPTIONS
916 && mZenMode != Global.ZEN_MODE_ALARMS) {
John Spurlockb02c7442015-04-14 09:32:25 -0400917 newZen = Global.ZEN_MODE_ALARMS;
John Spurlockb2278d62015-04-07 12:47:12 -0400918 }
Julia Reynolds9b11fdb2015-07-31 09:49:55 -0400919 setPreviousRingerModeSetting(ringerModeOld);
John Spurlockb2278d62015-04-07 12:47:12 -0400920 }
921 break;
922 case AudioManager.RINGER_MODE_VIBRATE:
923 case AudioManager.RINGER_MODE_NORMAL:
924 if (isChange && ringerModeOld == AudioManager.RINGER_MODE_SILENT
925 && (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS
926 || mZenMode == Global.ZEN_MODE_ALARMS)) {
927 newZen = Global.ZEN_MODE_OFF;
928 } else if (mZenMode != Global.ZEN_MODE_OFF) {
929 ringerModeExternalOut = AudioManager.RINGER_MODE_SILENT;
930 }
931 break;
932 }
933 if (newZen != -1) {
934 setManualZenMode(newZen, null, "ringerModeInternal", false /*setRingerMode*/);
935 }
936
937 if (isChange || newZen != -1 || ringerModeExternal != ringerModeExternalOut) {
938 ZenLog.traceSetRingerModeInternal(ringerModeOld, ringerModeNew, caller,
939 ringerModeExternal, ringerModeExternalOut);
940 }
941 return ringerModeExternalOut;
942 }
943
944 @Override
945 public int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller,
946 int ringerModeInternal, VolumePolicy policy) {
947 int ringerModeInternalOut = ringerModeNew;
948 final boolean isChange = ringerModeOld != ringerModeNew;
949 final boolean isVibrate = ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE;
950
951 int newZen = -1;
952 switch (ringerModeNew) {
953 case AudioManager.RINGER_MODE_SILENT:
954 if (isChange) {
955 if (mZenMode == Global.ZEN_MODE_OFF) {
John Spurlock05715ec2015-05-13 11:19:19 -0400956 newZen = Global.ZEN_MODE_ALARMS;
John Spurlockb2278d62015-04-07 12:47:12 -0400957 }
958 ringerModeInternalOut = isVibrate ? AudioManager.RINGER_MODE_VIBRATE
John Spurlock05715ec2015-05-13 11:19:19 -0400959 : AudioManager.RINGER_MODE_SILENT;
John Spurlockb2278d62015-04-07 12:47:12 -0400960 } else {
961 ringerModeInternalOut = ringerModeInternal;
962 }
963 break;
964 case AudioManager.RINGER_MODE_VIBRATE:
965 case AudioManager.RINGER_MODE_NORMAL:
966 if (mZenMode != Global.ZEN_MODE_OFF) {
967 newZen = Global.ZEN_MODE_OFF;
968 }
969 break;
970 }
971 if (newZen != -1) {
972 setManualZenMode(newZen, null, "ringerModeExternal", false /*setRingerMode*/);
973 }
974
975 ZenLog.traceSetRingerModeExternal(ringerModeOld, ringerModeNew, caller,
976 ringerModeInternal, ringerModeInternalOut);
977 return ringerModeInternalOut;
978 }
John Spurlockd9c75db2015-04-28 11:19:13 -0400979
980 @Override
981 public boolean canVolumeDownEnterSilent() {
982 return mZenMode == Global.ZEN_MODE_OFF;
983 }
John Spurlock50ced3f2015-05-11 16:00:09 -0400984
985 @Override
986 public int getRingerModeAffectedStreams(int streams) {
987 // ringtone, notification and system streams are always affected by ringer mode
988 streams |= (1 << AudioSystem.STREAM_RING) |
989 (1 << AudioSystem.STREAM_NOTIFICATION) |
990 (1 << AudioSystem.STREAM_SYSTEM);
991
992 // alarm and music streams are only affected by ringer mode when in total silence
993 if (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
994 streams |= (1 << AudioSystem.STREAM_ALARM) |
995 (1 << AudioSystem.STREAM_MUSIC);
996 } else {
997 streams &= ~((1 << AudioSystem.STREAM_ALARM) |
998 (1 << AudioSystem.STREAM_MUSIC));
999 }
1000 return streams;
1001 }
John Spurlockb2278d62015-04-07 12:47:12 -04001002 }
1003
1004 private final class SettingsObserver extends ContentObserver {
John Spurlock056c5192014-04-20 21:52:01 -04001005 private final Uri ZEN_MODE = Global.getUriFor(Global.ZEN_MODE);
1006
1007 public SettingsObserver(Handler handler) {
1008 super(handler);
1009 }
1010
1011 public void observe() {
1012 final ContentResolver resolver = mContext.getContentResolver();
1013 resolver.registerContentObserver(ZEN_MODE, false /*notifyForDescendents*/, this);
1014 update(null);
1015 }
1016
1017 @Override
1018 public void onChange(boolean selfChange, Uri uri) {
1019 update(uri);
1020 }
1021
1022 public void update(Uri uri) {
1023 if (ZEN_MODE.equals(uri)) {
John Spurlockb2278d62015-04-07 12:47:12 -04001024 if (mZenMode != getZenModeSetting()) {
1025 if (DEBUG) Log.d(TAG, "Fixing zen mode setting");
1026 setZenModeSetting(mZenMode);
1027 }
John Spurlock056c5192014-04-20 21:52:01 -04001028 }
1029 }
1030 }
1031
Chris Wren98d235b2015-05-27 18:25:17 -04001032 private final class Metrics extends Callback {
1033 private static final String COUNTER_PREFIX = "dnd_mode_";
1034 private static final long MINIMUM_LOG_PERIOD_MS = 60 * 1000;
1035
1036 private int mPreviousZenMode = -1;
1037 private long mBeginningMs = 0L;
1038
1039 @Override
1040 void onZenModeChanged() {
1041 emit();
1042 }
1043
1044 private void emit() {
1045 mHandler.postMetricsTimer();
1046 final long now = SystemClock.elapsedRealtime();
1047 final long since = (now - mBeginningMs);
1048 if (mPreviousZenMode != mZenMode || since > MINIMUM_LOG_PERIOD_MS) {
1049 if (mPreviousZenMode != -1) {
1050 MetricsLogger.count(mContext, COUNTER_PREFIX + mPreviousZenMode, (int) since);
1051 }
1052 mPreviousZenMode = mZenMode;
1053 mBeginningMs = now;
1054 }
1055 }
1056 }
1057
John Spurlockb2278d62015-04-07 12:47:12 -04001058 private final class H extends Handler {
John Spurlock57627792014-12-11 11:29:54 -05001059 private static final int MSG_DISPATCH = 1;
Chris Wren98d235b2015-05-27 18:25:17 -04001060 private static final int MSG_METRICS = 2;
Eric Laurente0ced4d2015-09-30 17:44:28 -07001061 private static final int MSG_SET_CONFIG = 3;
1062
1063 private final class ConfigMessageData {
1064 public final ZenModeConfig config;
1065 public final String reason;
1066
1067 ConfigMessageData(ZenModeConfig config, String reason) {
1068 this.config = config;
1069 this.reason = reason;
1070 }
1071 }
Chris Wren98d235b2015-05-27 18:25:17 -04001072
1073 private static final long METRICS_PERIOD_MS = 6 * 60 * 60 * 1000;
John Spurlock661f2cf2014-11-17 10:29:10 -05001074
1075 private H(Looper looper) {
1076 super(looper);
John Spurlock056c5192014-04-20 21:52:01 -04001077 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001078
John Spurlock57627792014-12-11 11:29:54 -05001079 private void postDispatchOnZenModeChanged() {
1080 removeMessages(MSG_DISPATCH);
1081 sendEmptyMessage(MSG_DISPATCH);
John Spurlock661f2cf2014-11-17 10:29:10 -05001082 }
1083
Chris Wren98d235b2015-05-27 18:25:17 -04001084 private void postMetricsTimer() {
1085 removeMessages(MSG_METRICS);
1086 sendEmptyMessageDelayed(MSG_METRICS, METRICS_PERIOD_MS);
1087 }
1088
Eric Laurente0ced4d2015-09-30 17:44:28 -07001089 private void postSetConfig(ZenModeConfig config, String reason) {
1090 sendMessage(obtainMessage(MSG_SET_CONFIG, new ConfigMessageData(config, reason)));
1091 }
1092
John Spurlock661f2cf2014-11-17 10:29:10 -05001093 @Override
1094 public void handleMessage(Message msg) {
John Spurlock57627792014-12-11 11:29:54 -05001095 switch (msg.what) {
1096 case MSG_DISPATCH:
1097 dispatchOnZenModeChanged();
John Spurlock661f2cf2014-11-17 10:29:10 -05001098 break;
Chris Wren98d235b2015-05-27 18:25:17 -04001099 case MSG_METRICS:
1100 mMetrics.emit();
1101 break;
Eric Laurente0ced4d2015-09-30 17:44:28 -07001102 case MSG_SET_CONFIG:
1103 ConfigMessageData configData = (ConfigMessageData)msg.obj;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -05001104 synchronized (mConfig) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -05001105 setConfigLocked(configData.config, configData.reason);
Julia Reynolds5a43aaa2015-12-15 13:54:41 -05001106 }
Eric Laurente0ced4d2015-09-30 17:44:28 -07001107 break;
John Spurlock661f2cf2014-11-17 10:29:10 -05001108 }
1109 }
1110 }
John Spurlock056c5192014-04-20 21:52:01 -04001111
John Spurlock1c923a32014-04-27 16:42:29 -04001112 public static class Callback {
1113 void onConfigChanged() {}
1114 void onZenModeChanged() {}
John Spurlock1fc476d2015-04-14 16:05:20 -04001115 void onPolicyChanged() {}
John Spurlock056c5192014-04-20 21:52:01 -04001116 }
John Spurlockb2278d62015-04-07 12:47:12 -04001117
John Spurlock056c5192014-04-20 21:52:01 -04001118}