blob: 29fa7540f36ea8d3e306db0a726d1cb0abfc75c3 [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;
Jean-Michel Trivie743bda2016-09-09 11:56:48 -070038import android.media.AudioAttributes;
John Spurlock056c5192014-04-20 21:52:01 -040039import android.media.AudioManager;
John Spurlock661f2cf2014-11-17 10:29:10 -050040import android.media.AudioManagerInternal;
John Spurlock50ced3f2015-05-11 16:00:09 -040041import android.media.AudioSystem;
John Spurlocka48d7792015-03-03 17:35:57 -050042import android.media.VolumePolicy;
John Spurlock056c5192014-04-20 21:52:01 -040043import android.net.Uri;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040044import android.os.Binder;
John Spurlock2b122f42014-08-27 16:29:47 -040045import android.os.Bundle;
John Spurlock056c5192014-04-20 21:52:01 -040046import android.os.Handler;
John Spurlock661f2cf2014-11-17 10:29:10 -050047import android.os.Looper;
48import android.os.Message;
Julia Reynoldsc8e54e82015-11-30 16:43:05 -050049import android.os.Process;
Chris Wren98d235b2015-05-27 18:25:17 -040050import android.os.SystemClock;
John Spurlockb5e767b2014-07-27 11:53:20 -040051import android.os.UserHandle;
John Spurlock056c5192014-04-20 21:52:01 -040052import android.provider.Settings.Global;
Julia Reynolds43b70cd2016-01-14 15:05:34 -050053import android.service.notification.ConditionProviderService;
John Spurlock056c5192014-04-20 21:52:01 -040054import android.service.notification.ZenModeConfig;
John Spurlockcb9aa202015-05-08 17:35:22 -040055import android.service.notification.ZenModeConfig.EventInfo;
John Spurlockb2278d62015-04-07 12:47:12 -040056import android.service.notification.ZenModeConfig.ScheduleInfo;
57import android.service.notification.ZenModeConfig.ZenRule;
Julia Reynolds87c42772016-05-16 09:52:17 -040058import android.util.AndroidRuntimeException;
John Spurlock4db0d982014-08-13 09:19:03 -040059import android.util.Log;
John Spurlock21258a32015-05-27 18:22:55 -040060import android.util.SparseArray;
John Spurlock056c5192014-04-20 21:52:01 -040061
62import com.android.internal.R;
John Spurlock25d01ee2015-06-03 12:17:46 -040063import com.android.internal.logging.MetricsLogger;
John Spurlock661f2cf2014-11-17 10:29:10 -050064import com.android.server.LocalServices;
John Spurlock056c5192014-04-20 21:52:01 -040065
66import libcore.io.IoUtils;
67
68import org.xmlpull.v1.XmlPullParser;
69import org.xmlpull.v1.XmlPullParserException;
70import org.xmlpull.v1.XmlSerializer;
71
72import java.io.IOException;
73import java.io.PrintWriter;
John Spurlock1c923a32014-04-27 16:42:29 -040074import java.util.ArrayList;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040075import java.util.List;
John Spurlock1fc476d2015-04-14 16:05:20 -040076import java.util.Objects;
John Spurlock056c5192014-04-20 21:52:01 -040077
78/**
79 * NotificationManagerService helper for functionality related to zen mode.
80 */
John Spurlockb2278d62015-04-07 12:47:12 -040081public class ZenModeHelper {
82 static final String TAG = "ZenModeHelper";
83 static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
John Spurlock056c5192014-04-20 21:52:01 -040084
Julia Reynolds5a43aaa2015-12-15 13:54:41 -050085 // The amount of time rules instances can exist without their owning app being installed.
86 private static final int RULE_INSTANCE_GRACE_PERIOD = 1000 * 60 * 60 * 72;
87
John Spurlock056c5192014-04-20 21:52:01 -040088 private final Context mContext;
John Spurlock661f2cf2014-11-17 10:29:10 -050089 private final H mHandler;
John Spurlock056c5192014-04-20 21:52:01 -040090 private final SettingsObserver mSettingsObserver;
91 private final AppOpsManager mAppOps;
92 private final ZenModeConfig mDefaultConfig;
John Spurlock1c923a32014-04-27 16:42:29 -040093 private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
John Spurlockb2278d62015-04-07 12:47:12 -040094 private final ZenModeFiltering mFiltering;
95 private final RingerModeDelegate mRingerModeDelegate = new RingerModeDelegate();
96 private final ZenModeConditions mConditions;
John Spurlock21258a32015-05-27 18:22:55 -040097 private final SparseArray<ZenModeConfig> mConfigs = new SparseArray<>();
Chris Wren98d235b2015-05-27 18:25:17 -040098 private final Metrics mMetrics = new Metrics();
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -050099 private final ConditionProviders.Config mServiceConfig;
John Spurlock056c5192014-04-20 21:52:01 -0400100
John Spurlock056c5192014-04-20 21:52:01 -0400101 private int mZenMode;
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700102 private int mUser = UserHandle.USER_SYSTEM;
John Spurlock056c5192014-04-20 21:52:01 -0400103 private ZenModeConfig mConfig;
John Spurlock661f2cf2014-11-17 10:29:10 -0500104 private AudioManagerInternal mAudioManager;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500105 private PackageManager mPm;
Bryce Lee7219ada2016-04-08 10:54:23 -0700106 private long mSuppressedEffects;
107
108 public static final long SUPPRESSED_EFFECT_NOTIFICATIONS = 1;
109 public static final long SUPPRESSED_EFFECT_CALLS = 1 << 1;
110 public static final long SUPPRESSED_EFFECT_ALL = SUPPRESSED_EFFECT_CALLS
111 | SUPPRESSED_EFFECT_NOTIFICATIONS;
John Spurlock056c5192014-04-20 21:52:01 -0400112
John Spurlockb2278d62015-04-07 12:47:12 -0400113 public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) {
John Spurlock056c5192014-04-20 21:52:01 -0400114 mContext = context;
John Spurlock661f2cf2014-11-17 10:29:10 -0500115 mHandler = new H(looper);
Chris Wren98d235b2015-05-27 18:25:17 -0400116 addCallback(mMetrics);
John Spurlock056c5192014-04-20 21:52:01 -0400117 mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
118 mDefaultConfig = readDefaultConfig(context.getResources());
John Spurlockb2278d62015-04-07 12:47:12 -0400119 appendDefaultScheduleRules(mDefaultConfig);
John Spurlockcb9aa202015-05-08 17:35:22 -0400120 appendDefaultEventRules(mDefaultConfig);
John Spurlock056c5192014-04-20 21:52:01 -0400121 mConfig = mDefaultConfig;
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700122 mConfigs.put(UserHandle.USER_SYSTEM, mConfig);
John Spurlock056c5192014-04-20 21:52:01 -0400123 mSettingsObserver = new SettingsObserver(mHandler);
124 mSettingsObserver.observe();
John Spurlockb2278d62015-04-07 12:47:12 -0400125 mFiltering = new ZenModeFiltering(mContext);
126 mConditions = new ZenModeConditions(this, conditionProviders);
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500127 mServiceConfig = conditionProviders.getConfig();
John Spurlock056c5192014-04-20 21:52:01 -0400128 }
129
John Spurlock1b8b22b2015-05-20 09:47:13 -0400130 public Looper getLooper() {
131 return mHandler.getLooper();
132 }
133
John Spurlockb2278d62015-04-07 12:47:12 -0400134 @Override
135 public String toString() {
136 return TAG;
137 }
138
139 public boolean matchesCallFilter(UserHandle userHandle, Bundle extras,
140 ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400141 synchronized (mConfig) {
142 return ZenModeFiltering.matchesCallFilter(mContext, mZenMode, mConfig, userHandle,
Julia Reynoldsc6b371b2016-06-14 08:31:03 -0400143 extras, validator, contactsTimeoutMs, timeoutAffinity);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400144 }
John Spurlockb2278d62015-04-07 12:47:12 -0400145 }
146
147 public boolean isCall(NotificationRecord record) {
148 return mFiltering.isCall(record);
149 }
150
Julia Reynoldsc6b371b2016-06-14 08:31:03 -0400151 public void recordCaller(NotificationRecord record) {
152 mFiltering.recordCall(record);
153 }
154
John Spurlockb2278d62015-04-07 12:47:12 -0400155 public boolean shouldIntercept(NotificationRecord record) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400156 synchronized (mConfig) {
157 return mFiltering.shouldIntercept(mZenMode, mConfig, record);
158 }
John Spurlock056c5192014-04-20 21:52:01 -0400159 }
160
Julia Reynoldsd5607292016-02-05 15:25:58 -0500161 public boolean shouldSuppressWhenScreenOff() {
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500162 synchronized (mConfig) {
Julia Reynoldsd5607292016-02-05 15:25:58 -0500163 return !mConfig.allowWhenScreenOff;
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500164 }
165 }
166
Julia Reynoldsd5607292016-02-05 15:25:58 -0500167 public boolean shouldSuppressWhenScreenOn() {
Julia Reynoldsf612869ae2015-11-05 16:48:55 -0500168 synchronized (mConfig) {
Julia Reynoldsd5607292016-02-05 15:25:58 -0500169 return !mConfig.allowWhenScreenOn;
Julia Reynolds61721582016-01-05 08:35:25 -0500170 }
171 }
172
John Spurlock1c923a32014-04-27 16:42:29 -0400173 public void addCallback(Callback callback) {
174 mCallbacks.add(callback);
John Spurlock056c5192014-04-20 21:52:01 -0400175 }
176
John Spurlock530052a2014-11-30 16:26:19 -0500177 public void removeCallback(Callback callback) {
178 mCallbacks.remove(callback);
179 }
180
John Spurlockb2278d62015-04-07 12:47:12 -0400181 public void initZenMode() {
182 if (DEBUG) Log.d(TAG, "initZenMode");
183 evaluateZenMode("init", true /*setRingerMode*/);
184 }
185
John Spurlock661f2cf2014-11-17 10:29:10 -0500186 public void onSystemReady() {
John Spurlockb2278d62015-04-07 12:47:12 -0400187 if (DEBUG) Log.d(TAG, "onSystemReady");
John Spurlock661f2cf2014-11-17 10:29:10 -0500188 mAudioManager = LocalServices.getService(AudioManagerInternal.class);
189 if (mAudioManager != null) {
John Spurlockb2278d62015-04-07 12:47:12 -0400190 mAudioManager.setRingerModeDelegate(mRingerModeDelegate);
John Spurlock661f2cf2014-11-17 10:29:10 -0500191 }
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500192 mPm = mContext.getPackageManager();
Chris Wren98d235b2015-05-27 18:25:17 -0400193 mHandler.postMetricsTimer();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500194 cleanUpZenRules();
Julia Reynolds8ac63032015-08-31 15:19:43 -0400195 evaluateZenMode("onSystemReady", true);
John Spurlockae641c92014-06-30 18:11:40 -0400196 }
197
John Spurlock21258a32015-05-27 18:22:55 -0400198 public void onUserSwitched(int user) {
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500199 loadConfigForUser(user, "onUserSwitched");
John Spurlock21258a32015-05-27 18:22:55 -0400200 }
201
202 public void onUserRemoved(int user) {
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700203 if (user < UserHandle.USER_SYSTEM) return;
John Spurlock21258a32015-05-27 18:22:55 -0400204 if (DEBUG) Log.d(TAG, "onUserRemoved u=" + user);
205 mConfigs.remove(user);
206 }
207
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500208 public void onUserUnlocked(int user) {
209 loadConfigForUser(user, "onUserUnlocked");
210 }
211
212 private void loadConfigForUser(int user, String reason) {
213 if (mUser == user || user < UserHandle.USER_SYSTEM) return;
214 mUser = user;
215 if (DEBUG) Log.d(TAG, reason + " u=" + user);
216 ZenModeConfig config = mConfigs.get(user);
217 if (config == null) {
218 if (DEBUG) Log.d(TAG, reason + " generating default config for user " + user);
219 config = mDefaultConfig.copy();
220 config.user = user;
221 }
222 synchronized (mConfig) {
223 setConfigLocked(config, reason);
224 }
225 cleanUpZenRules();
226 }
227
Christoph Studer85a384b2014-08-27 20:16:15 +0200228 public int getZenModeListenerInterruptionFilter() {
John Spurlock80774932015-05-07 17:38:50 -0400229 return NotificationManager.zenModeToInterruptionFilter(mZenMode);
John Spurlockd8afe3c2014-08-01 14:04:07 -0400230 }
231
John Spurlock80774932015-05-07 17:38:50 -0400232 public void requestFromListener(ComponentName name, int filter) {
233 final int newZen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
John Spurlockd8afe3c2014-08-01 14:04:07 -0400234 if (newZen != -1) {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -0400235 setManualZenMode(newZen, null, name != null ? name.getPackageName() : null,
John Spurlockb2278d62015-04-07 12:47:12 -0400236 "listener:" + (name != null ? name.flattenToShortString() : null));
John Spurlockd8afe3c2014-08-01 14:04:07 -0400237 }
238 }
239
Bryce Lee7219ada2016-04-08 10:54:23 -0700240 public void setSuppressedEffects(long suppressedEffects) {
241 if (mSuppressedEffects == suppressedEffects) return;
242 mSuppressedEffects = suppressedEffects;
John Spurlock8403b752014-12-10 12:47:01 -0500243 applyRestrictions();
244 }
245
Bryce Lee7219ada2016-04-08 10:54:23 -0700246 public long getSuppressedEffects() {
247 return mSuppressedEffects;
248 }
249
John Spurlock1c923a32014-04-27 16:42:29 -0400250 public int getZenMode() {
251 return mZenMode;
252 }
253
Julia Reynolds361e82d32016-02-26 18:19:49 -0500254 public List<ZenRule> getZenRules() {
255 List<ZenRule> rules = new ArrayList<>();
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400256 synchronized (mConfig) {
257 if (mConfig == null) return rules;
258 for (ZenRule rule : mConfig.automaticRules.values()) {
259 if (canManageAutomaticZenRule(rule)) {
Julia Reynolds361e82d32016-02-26 18:19:49 -0500260 rules.add(rule);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400261 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400262 }
263 }
264 return rules;
265 }
266
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400267 public AutomaticZenRule getAutomaticZenRule(String id) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400268 ZenRule rule;
269 synchronized (mConfig) {
270 if (mConfig == null) return null;
271 rule = mConfig.automaticRules.get(id);
272 }
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400273 if (rule == null) return null;
274 if (canManageAutomaticZenRule(rule)) {
275 return createAutomaticZenRule(rule);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400276 }
277 return null;
278 }
279
Julia Reynolds361e82d32016-02-26 18:19:49 -0500280 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500281 if (!isSystemRule(automaticZenRule)) {
282 ServiceInfo owner = getServiceInfo(automaticZenRule.getOwner());
283 if (owner == null) {
284 throw new IllegalArgumentException("Owner is not a condition provider service");
285 }
286
Julia Reynolds7f2f4412016-03-01 12:33:48 -0500287 int ruleInstanceLimit = -1;
288 if (owner.metaData != null) {
289 ruleInstanceLimit = owner.metaData.getInt(
290 ConditionProviderService.META_DATA_RULE_INSTANCE_LIMIT, -1);
291 }
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500292 if (ruleInstanceLimit > 0 && ruleInstanceLimit
293 < (getCurrentInstanceCount(automaticZenRule.getOwner()) + 1)) {
294 throw new IllegalArgumentException("Rule instance limit exceeded");
295 }
296 }
297
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400298 ZenModeConfig newConfig;
299 synchronized (mConfig) {
Julia Reynolds87c42772016-05-16 09:52:17 -0400300 if (mConfig == null) {
301 throw new AndroidRuntimeException("Could not create rule");
302 }
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400303 if (DEBUG) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500304 Log.d(TAG, "addAutomaticZenRule rule= " + automaticZenRule + " reason=" + reason);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400305 }
306 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500307 ZenRule rule = new ZenRule();
308 populateZenRule(automaticZenRule, rule, true);
309 newConfig.automaticRules.put(rule.id, rule);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500310 if (setConfigLocked(newConfig, reason, true)) {
Julia Reynolds361e82d32016-02-26 18:19:49 -0500311 return rule.id;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500312 } else {
Julia Reynolds87c42772016-05-16 09:52:17 -0400313 throw new AndroidRuntimeException("Could not create rule");
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500314 }
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400315 }
316 }
317
Julia Reynolds361e82d32016-02-26 18:19:49 -0500318 public boolean updateAutomaticZenRule(String ruleId, AutomaticZenRule automaticZenRule,
319 String reason) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400320 ZenModeConfig newConfig;
321 synchronized (mConfig) {
322 if (mConfig == null) return false;
323 if (DEBUG) {
324 Log.d(TAG, "updateAutomaticZenRule zenRule=" + automaticZenRule
325 + " reason=" + reason);
326 }
327 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500328 ZenModeConfig.ZenRule rule;
329 if (ruleId == null) {
330 throw new IllegalArgumentException("Rule doesn't exist");
331 } else {
332 rule = newConfig.automaticRules.get(ruleId);
333 if (rule == null || !canManageAutomaticZenRule(rule)) {
334 throw new SecurityException(
335 "Cannot update rules not owned by your condition provider");
336 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400337 }
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500338 populateZenRule(automaticZenRule, rule, false);
339 newConfig.automaticRules.put(ruleId, rule);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500340 return setConfigLocked(newConfig, reason, true);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400341 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400342 }
343
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400344 public boolean removeAutomaticZenRule(String id, String reason) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400345 ZenModeConfig newConfig;
346 synchronized (mConfig) {
347 if (mConfig == null) return false;
348 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500349 ZenRule rule = newConfig.automaticRules.get(id);
350 if (rule == null) return false;
351 if (canManageAutomaticZenRule(rule)) {
352 newConfig.automaticRules.remove(id);
353 if (DEBUG) Log.d(TAG, "removeZenRule zenRule=" + id + " reason=" + reason);
354 } else {
355 throw new SecurityException(
356 "Cannot delete rules not owned by your condition provider");
357 }
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500358 return setConfigLocked(newConfig, reason, true);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400359 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400360 }
361
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500362 public boolean removeAutomaticZenRules(String packageName, String reason) {
363 ZenModeConfig newConfig;
364 synchronized (mConfig) {
365 if (mConfig == null) return false;
366 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500367 for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
368 ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
369 if (rule.component.getPackageName().equals(packageName)
370 && canManageAutomaticZenRule(rule)) {
371 newConfig.automaticRules.removeAt(i);
372 }
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500373 }
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500374 return setConfigLocked(newConfig, reason, true);
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500375 }
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500376 }
377
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500378 public int getCurrentInstanceCount(ComponentName owner) {
379 int count = 0;
380 synchronized (mConfig) {
381 for (ZenRule rule : mConfig.automaticRules.values()) {
382 if (rule.component != null && rule.component.equals(owner)) {
383 count++;
384 }
385 }
386 }
387 return count;
388 }
389
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400390 public boolean canManageAutomaticZenRule(ZenRule rule) {
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500391 final int callingUid = Binder.getCallingUid();
392 if (callingUid == 0 || callingUid == Process.SYSTEM_UID) {
393 return true;
394 } else if (mContext.checkCallingPermission(android.Manifest.permission.MANAGE_NOTIFICATIONS)
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400395 == PackageManager.PERMISSION_GRANTED) {
396 return true;
397 } else {
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500398 String[] packages = mPm.getPackagesForUid(Binder.getCallingUid());
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400399 if (packages != null) {
400 final int packageCount = packages.length;
401 for (int i = 0; i < packageCount; i++) {
402 if (packages[i].equals(rule.component.getPackageName())) {
403 return true;
404 }
405 }
406 }
407 return false;
408 }
409 }
410
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500411 private boolean isSystemRule(AutomaticZenRule rule) {
412 return ZenModeConfig.SYSTEM_AUTHORITY.equals(rule.getOwner().getPackageName());
413 }
414
415 private ServiceInfo getServiceInfo(ComponentName owner) {
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500416 Intent queryIntent = new Intent();
417 queryIntent.setComponent(owner);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500418 List<ResolveInfo> installedServices = mPm.queryIntentServicesAsUser(
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500419 queryIntent,
420 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
421 UserHandle.getCallingUserId());
422 if (installedServices != null) {
423 for (int i = 0, count = installedServices.size(); i < count; i++) {
424 ResolveInfo resolveInfo = installedServices.get(i);
425 ServiceInfo info = resolveInfo.serviceInfo;
426 if (mServiceConfig.bindPermission.equals(info.permission)) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500427 return info;
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500428 }
429 }
430 }
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500431 return null;
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500432 }
433
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400434 private void populateZenRule(AutomaticZenRule automaticZenRule, ZenRule rule, boolean isNew) {
435 if (isNew) {
436 rule.id = ZenModeConfig.newRuleId();
437 rule.creationTime = System.currentTimeMillis();
438 rule.component = automaticZenRule.getOwner();
439 }
440
441 if (rule.enabled != automaticZenRule.isEnabled()) {
442 rule.snoozing = false;
443 }
444 rule.name = automaticZenRule.getName();
445 rule.condition = null;
446 rule.conditionId = automaticZenRule.getConditionId();
447 rule.enabled = automaticZenRule.isEnabled();
448 rule.zenMode = NotificationManager.zenModeFromInterruptionFilter(
449 automaticZenRule.getInterruptionFilter(), Global.ZEN_MODE_OFF);
450 }
451
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400452 private AutomaticZenRule createAutomaticZenRule(ZenRule rule) {
453 return new AutomaticZenRule(rule.name, rule.component, rule.conditionId,
Julia Reynolds56106ff2015-09-30 14:42:53 -0400454 NotificationManager.zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
Julia Reynolds361e82d32016-02-26 18:19:49 -0500455 rule.creationTime);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400456 }
457
Julia Reynolds44ad6ff2016-07-06 09:47:45 -0400458 public void setManualZenMode(int zenMode, Uri conditionId, String caller, String reason) {
459 setManualZenMode(zenMode, conditionId, reason, caller, true /*setRingerMode*/);
John Spurlocke77bb362014-04-26 10:24:59 -0400460 }
461
Julia Reynolds44ad6ff2016-07-06 09:47:45 -0400462 private void setManualZenMode(int zenMode, Uri conditionId, String reason, String caller,
John Spurlockb2278d62015-04-07 12:47:12 -0400463 boolean setRingerMode) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400464 ZenModeConfig newConfig;
465 synchronized (mConfig) {
466 if (mConfig == null) return;
467 if (!Global.isValidZenMode(zenMode)) return;
468 if (DEBUG) Log.d(TAG, "setManualZenMode " + Global.zenModeToString(zenMode)
469 + " conditionId=" + conditionId + " reason=" + reason
470 + " setRingerMode=" + setRingerMode);
471 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500472 if (zenMode == Global.ZEN_MODE_OFF) {
473 newConfig.manualRule = null;
474 for (ZenRule automaticRule : newConfig.automaticRules.values()) {
475 if (automaticRule.isAutomaticActive()) {
476 automaticRule.snoozing = true;
477 }
John Spurlockb2278d62015-04-07 12:47:12 -0400478 }
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500479 } else {
480 final ZenRule newRule = new ZenRule();
481 newRule.enabled = true;
482 newRule.zenMode = zenMode;
483 newRule.conditionId = conditionId;
Julia Reynolds44ad6ff2016-07-06 09:47:45 -0400484 newRule.enabler = caller;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500485 newConfig.manualRule = newRule;
John Spurlockb2278d62015-04-07 12:47:12 -0400486 }
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500487 setConfigLocked(newConfig, reason, setRingerMode);
John Spurlockb2278d62015-04-07 12:47:12 -0400488 }
John Spurlockb2278d62015-04-07 12:47:12 -0400489 }
490
491 public void dump(PrintWriter pw, String prefix) {
492 pw.print(prefix); pw.print("mZenMode=");
493 pw.println(Global.zenModeToString(mZenMode));
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 {
Julia Reynolds206c7e92016-09-15 10:38:03 -0400532 final ZenModeConfig config = ZenModeConfig.readXml(parser);
John Spurlockb2278d62015-04-07 12:47:12 -0400533 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
Julia Reynolds89aeab02016-09-15 11:07:50 -0400622 public void setConfig(ZenModeConfig config, String reason) {
623 synchronized (mConfig) {
624 setConfigLocked(config, reason);
625 }
Eric Laurente0ced4d2015-09-30 17:44:28 -0700626 }
627
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500628 private boolean setConfigLocked(ZenModeConfig config, String reason, boolean setRingerMode) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400629 final long identity = Binder.clearCallingIdentity();
630 try {
631 if (config == null || !config.isValid()) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500632 Log.w(TAG, "Invalid config in setConfigLocked; " + config);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400633 return false;
634 }
635 if (config.user != mUser) {
636 // simply store away for background users
637 mConfigs.put(config.user, config);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500638 if (DEBUG) Log.d(TAG, "setConfigLocked: store config for user " + config.user);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400639 return true;
640 }
641 mConditions.evaluateConfig(config, false /*processSubscriptions*/); // may modify config
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500642 mConfigs.put(config.user, config);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500643 if (DEBUG) Log.d(TAG, "setConfigLocked reason=" + reason, new Throwable());
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500644 ZenLog.traceConfig(reason, mConfig, config);
645 final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
646 getNotificationPolicy(config));
Julia Reynolds9a25da12016-01-06 16:19:28 -0500647 if (!config.equals(mConfig)) {
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500648 dispatchOnConfigChanged();
649 }
650 if (policyChanged) {
651 dispatchOnPolicyChanged();
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400652 }
Julia Reynolds9a25da12016-01-06 16:19:28 -0500653 mConfig = config;
Julia Reynoldsd82e9812016-04-19 13:27:41 -0400654 mHandler.postApplyConfig(config, reason, setRingerMode);
John Spurlock21258a32015-05-27 18:22:55 -0400655 return true;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400656 } finally {
657 Binder.restoreCallingIdentity(identity);
John Spurlock21258a32015-05-27 18:22:55 -0400658 }
John Spurlockb2278d62015-04-07 12:47:12 -0400659 }
660
Julia Reynoldsd82e9812016-04-19 13:27:41 -0400661 private void applyConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
662 final String val = Integer.toString(config.hashCode());
663 Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
664 if (!evaluateZenMode(reason, setRingerMode)) {
665 applyRestrictions(); // evaluateZenMode will also apply restrictions if changed
666 }
667 mConditions.evaluateConfig(config, true /*processSubscriptions*/);
668 }
669
John Spurlockb2278d62015-04-07 12:47:12 -0400670 private int getZenModeSetting() {
671 return Global.getInt(mContext.getContentResolver(), Global.ZEN_MODE, Global.ZEN_MODE_OFF);
672 }
673
674 private void setZenModeSetting(int zen) {
675 Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zen);
676 }
677
Julia Reynolds9b11fdb2015-07-31 09:49:55 -0400678 private int getPreviousRingerModeSetting() {
679 return Global.getInt(mContext.getContentResolver(),
680 Global.ZEN_MODE_RINGER_LEVEL, AudioManager.RINGER_MODE_NORMAL);
681 }
682
683 private void setPreviousRingerModeSetting(Integer previousRingerLevel) {
684 Global.putString(
685 mContext.getContentResolver(), Global.ZEN_MODE_RINGER_LEVEL,
686 previousRingerLevel == null ? null : Integer.toString(previousRingerLevel));
687 }
688
John Spurlockb2278d62015-04-07 12:47:12 -0400689 private boolean evaluateZenMode(String reason, boolean setRingerMode) {
690 if (DEBUG) Log.d(TAG, "evaluateZenMode");
Jason Monka9927322015-12-13 16:22:37 -0500691 final int zenBefore = mZenMode;
Julia Reynolds8ac63032015-08-31 15:19:43 -0400692 final int zen = computeZenMode();
John Spurlockb2278d62015-04-07 12:47:12 -0400693 ZenLog.traceSetZenMode(zen, reason);
694 mZenMode = zen;
John Spurlock50ced3f2015-05-11 16:00:09 -0400695 updateRingerModeAffectedStreams();
John Spurlockb2278d62015-04-07 12:47:12 -0400696 setZenModeSetting(mZenMode);
John Spurlock57627792014-12-11 11:29:54 -0500697 if (setRingerMode) {
698 applyZenToRingerMode();
699 }
700 applyRestrictions();
Jason Monka9927322015-12-13 16:22:37 -0500701 if (zen != zenBefore) {
Julia Reynolds8ac63032015-08-31 15:19:43 -0400702 mHandler.postDispatchOnZenModeChanged();
703 }
John Spurlockb2278d62015-04-07 12:47:12 -0400704 return true;
John Spurlock57627792014-12-11 11:29:54 -0500705 }
706
John Spurlock50ced3f2015-05-11 16:00:09 -0400707 private void updateRingerModeAffectedStreams() {
708 if (mAudioManager != null) {
709 mAudioManager.updateRingerModeAffectedStreamsInternal();
710 }
711 }
712
Julia Reynolds8ac63032015-08-31 15:19:43 -0400713 private int computeZenMode() {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400714 synchronized (mConfig) {
715 if (mConfig == null) return Global.ZEN_MODE_OFF;
716 if (mConfig.manualRule != null) return mConfig.manualRule.zenMode;
717 int zen = Global.ZEN_MODE_OFF;
718 for (ZenRule automaticRule : mConfig.automaticRules.values()) {
719 if (automaticRule.isAutomaticActive()) {
720 if (zenSeverity(automaticRule.zenMode) > zenSeverity(zen)) {
721 zen = automaticRule.zenMode;
722 }
John Spurlockb2278d62015-04-07 12:47:12 -0400723 }
724 }
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400725 return zen;
John Spurlockb2278d62015-04-07 12:47:12 -0400726 }
John Spurlock8403b752014-12-10 12:47:01 -0500727 }
728
729 private void applyRestrictions() {
John Spurlock056c5192014-04-20 21:52:01 -0400730 final boolean zen = mZenMode != Global.ZEN_MODE_OFF;
John Spurlock8403b752014-12-10 12:47:01 -0500731
732 // notification restrictions
Bryce Lee7219ada2016-04-08 10:54:23 -0700733 final boolean muteNotifications =
734 (mSuppressedEffects & SUPPRESSED_EFFECT_NOTIFICATIONS) != 0;
John Spurlock056c5192014-04-20 21:52:01 -0400735 // call restrictions
Bryce Lee7219ada2016-04-08 10:54:23 -0700736 final boolean muteCalls = zen && !mConfig.allowCalls && !mConfig.allowRepeatCallers
737 || (mSuppressedEffects & SUPPRESSED_EFFECT_CALLS) != 0;
Julia Reynolds3fe81be2016-02-03 09:10:06 -0500738 // total silence restrictions
739 final boolean muteEverything = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
John Spurlock25d01ee2015-06-03 12:17:46 -0400740
Jean-Michel Trivie743bda2016-09-09 11:56:48 -0700741 for (int usage : AudioAttributes.SDK_USAGES) {
742 final int suppressionBehavior = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage);
743 if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NOTIFICATION) {
744 applyRestrictions(muteNotifications || muteEverything, usage);
745 } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_CALL) {
746 applyRestrictions(muteCalls || muteEverything, usage);
Julia Reynolds3fe81be2016-02-03 09:10:06 -0500747 } else {
Jean-Michel Trivie743bda2016-09-09 11:56:48 -0700748 applyRestrictions(muteEverything, usage);
Julia Reynolds3fe81be2016-02-03 09:10:06 -0500749 }
750 }
John Spurlock8403b752014-12-10 12:47:01 -0500751 }
John Spurlockae641c92014-06-30 18:11:40 -0400752
John Spurlock8403b752014-12-10 12:47:01 -0500753 private void applyRestrictions(boolean mute, int usage) {
754 final String[] exceptionPackages = null; // none (for now)
755 mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, usage,
756 mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
757 exceptionPackages);
758 mAppOps.setRestriction(AppOpsManager.OP_PLAY_AUDIO, usage,
759 mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
760 exceptionPackages);
John Spurlock056c5192014-04-20 21:52:01 -0400761 }
762
John Spurlock57627792014-12-11 11:29:54 -0500763 private void applyZenToRingerMode() {
John Spurlock661f2cf2014-11-17 10:29:10 -0500764 if (mAudioManager == null) return;
John Spurlock661f2cf2014-11-17 10:29:10 -0500765 // force the ringer mode into compliance
766 final int ringerModeInternal = mAudioManager.getRingerModeInternal();
767 int newRingerModeInternal = ringerModeInternal;
John Spurlock57627792014-12-11 11:29:54 -0500768 switch (mZenMode) {
John Spurlock661f2cf2014-11-17 10:29:10 -0500769 case Global.ZEN_MODE_NO_INTERRUPTIONS:
John Spurlock4f1163c2015-04-02 17:41:21 -0400770 case Global.ZEN_MODE_ALARMS:
John Spurlock661f2cf2014-11-17 10:29:10 -0500771 if (ringerModeInternal != AudioManager.RINGER_MODE_SILENT) {
Julia Reynolds9b11fdb2015-07-31 09:49:55 -0400772 setPreviousRingerModeSetting(ringerModeInternal);
John Spurlock661f2cf2014-11-17 10:29:10 -0500773 newRingerModeInternal = AudioManager.RINGER_MODE_SILENT;
John Spurlock8c01d882014-07-28 13:37:13 -0400774 }
John Spurlock661f2cf2014-11-17 10:29:10 -0500775 break;
776 case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
777 case Global.ZEN_MODE_OFF:
778 if (ringerModeInternal == AudioManager.RINGER_MODE_SILENT) {
Julia Reynolds9b11fdb2015-07-31 09:49:55 -0400779 newRingerModeInternal = getPreviousRingerModeSetting();
780 setPreviousRingerModeSetting(null);
John Spurlock661f2cf2014-11-17 10:29:10 -0500781 }
782 break;
John Spurlock8c01d882014-07-28 13:37:13 -0400783 }
John Spurlock661f2cf2014-11-17 10:29:10 -0500784 if (newRingerModeInternal != -1) {
785 mAudioManager.setRingerModeInternal(newRingerModeInternal, TAG);
786 }
787 }
788
John Spurlock1c923a32014-04-27 16:42:29 -0400789 private void dispatchOnConfigChanged() {
790 for (Callback callback : mCallbacks) {
791 callback.onConfigChanged();
792 }
793 }
794
John Spurlock1fc476d2015-04-14 16:05:20 -0400795 private void dispatchOnPolicyChanged() {
796 for (Callback callback : mCallbacks) {
797 callback.onPolicyChanged();
798 }
799 }
800
John Spurlock1c923a32014-04-27 16:42:29 -0400801 private void dispatchOnZenModeChanged() {
802 for (Callback callback : mCallbacks) {
803 callback.onZenModeChanged();
804 }
805 }
806
John Spurlockb2278d62015-04-07 12:47:12 -0400807 private ZenModeConfig readDefaultConfig(Resources resources) {
808 XmlResourceParser parser = null;
809 try {
810 parser = resources.getXml(R.xml.default_zen_mode_config);
811 while (parser.next() != XmlPullParser.END_DOCUMENT) {
Julia Reynolds206c7e92016-09-15 10:38:03 -0400812 final ZenModeConfig config = ZenModeConfig.readXml(parser);
John Spurlockb2278d62015-04-07 12:47:12 -0400813 if (config != null) return config;
814 }
815 } catch (Exception e) {
816 Log.w(TAG, "Error reading default zen mode config from resource", e);
817 } finally {
818 IoUtils.closeQuietly(parser);
819 }
820 return new ZenModeConfig();
821 }
822
823 private void appendDefaultScheduleRules(ZenModeConfig config) {
824 if (config == null) return;
825
826 final ScheduleInfo weeknights = new ScheduleInfo();
827 weeknights.days = ZenModeConfig.WEEKNIGHT_DAYS;
828 weeknights.startHour = 22;
829 weeknights.endHour = 7;
830 final ZenRule rule1 = new ZenRule();
831 rule1.enabled = false;
832 rule1.name = mContext.getResources()
833 .getString(R.string.zen_mode_default_weeknights_name);
834 rule1.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
835 rule1.zenMode = Global.ZEN_MODE_ALARMS;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400836 rule1.component = ScheduleConditionProvider.COMPONENT;
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400837 rule1.id = ZenModeConfig.newRuleId();
Julia Reynolds56106ff2015-09-30 14:42:53 -0400838 rule1.creationTime = System.currentTimeMillis();
839 config.automaticRules.put(rule1.id, rule1);
John Spurlockb2278d62015-04-07 12:47:12 -0400840
841 final ScheduleInfo weekends = new ScheduleInfo();
842 weekends.days = ZenModeConfig.WEEKEND_DAYS;
843 weekends.startHour = 23;
844 weekends.startMinute = 30;
845 weekends.endHour = 10;
846 final ZenRule rule2 = new ZenRule();
847 rule2.enabled = false;
848 rule2.name = mContext.getResources()
849 .getString(R.string.zen_mode_default_weekends_name);
850 rule2.conditionId = ZenModeConfig.toScheduleConditionId(weekends);
851 rule2.zenMode = Global.ZEN_MODE_ALARMS;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400852 rule2.component = ScheduleConditionProvider.COMPONENT;
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400853 rule2.id = ZenModeConfig.newRuleId();
Julia Reynolds56106ff2015-09-30 14:42:53 -0400854 rule2.creationTime = System.currentTimeMillis();
855 config.automaticRules.put(rule2.id, rule2);
John Spurlockb2278d62015-04-07 12:47:12 -0400856 }
857
John Spurlockcb9aa202015-05-08 17:35:22 -0400858 private void appendDefaultEventRules(ZenModeConfig config) {
859 if (config == null) return;
860
861 final EventInfo events = new EventInfo();
John Spurlock995a7492015-05-28 22:13:03 -0400862 events.calendar = null; // any calendar
John Spurlockcb9aa202015-05-08 17:35:22 -0400863 events.reply = EventInfo.REPLY_YES_OR_MAYBE;
864 final ZenRule rule = new ZenRule();
865 rule.enabled = false;
866 rule.name = mContext.getResources().getString(R.string.zen_mode_default_events_name);
867 rule.conditionId = ZenModeConfig.toEventConditionId(events);
868 rule.zenMode = Global.ZEN_MODE_ALARMS;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400869 rule.component = EventConditionProvider.COMPONENT;
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400870 rule.id = ZenModeConfig.newRuleId();
Julia Reynolds56106ff2015-09-30 14:42:53 -0400871 rule.creationTime = System.currentTimeMillis();
872 config.automaticRules.put(rule.id, rule);
John Spurlockcb9aa202015-05-08 17:35:22 -0400873 }
874
John Spurlockb2278d62015-04-07 12:47:12 -0400875 private static int zenSeverity(int zen) {
876 switch (zen) {
877 case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return 1;
878 case Global.ZEN_MODE_ALARMS: return 2;
879 case Global.ZEN_MODE_NO_INTERRUPTIONS: return 3;
880 default: return 0;
881 }
882 }
883
John Spurlockb2278d62015-04-07 12:47:12 -0400884 private final class RingerModeDelegate implements AudioManagerInternal.RingerModeDelegate {
885 @Override
886 public String toString() {
887 return TAG;
888 }
889
890 @Override
891 public int onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller,
892 int ringerModeExternal, VolumePolicy policy) {
893 final boolean isChange = ringerModeOld != ringerModeNew;
894
895 int ringerModeExternalOut = ringerModeNew;
896
897 int newZen = -1;
898 switch (ringerModeNew) {
899 case AudioManager.RINGER_MODE_SILENT:
900 if (isChange && policy.doNotDisturbWhenSilent) {
901 if (mZenMode != Global.ZEN_MODE_NO_INTERRUPTIONS
902 && mZenMode != Global.ZEN_MODE_ALARMS) {
John Spurlockb02c7442015-04-14 09:32:25 -0400903 newZen = Global.ZEN_MODE_ALARMS;
John Spurlockb2278d62015-04-07 12:47:12 -0400904 }
Julia Reynolds9b11fdb2015-07-31 09:49:55 -0400905 setPreviousRingerModeSetting(ringerModeOld);
John Spurlockb2278d62015-04-07 12:47:12 -0400906 }
907 break;
908 case AudioManager.RINGER_MODE_VIBRATE:
909 case AudioManager.RINGER_MODE_NORMAL:
910 if (isChange && ringerModeOld == AudioManager.RINGER_MODE_SILENT
911 && (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS
912 || mZenMode == Global.ZEN_MODE_ALARMS)) {
913 newZen = Global.ZEN_MODE_OFF;
914 } else if (mZenMode != Global.ZEN_MODE_OFF) {
915 ringerModeExternalOut = AudioManager.RINGER_MODE_SILENT;
916 }
917 break;
918 }
919 if (newZen != -1) {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -0400920 setManualZenMode(newZen, null, "ringerModeInternal", null,
921 false /*setRingerMode*/);
John Spurlockb2278d62015-04-07 12:47:12 -0400922 }
923
924 if (isChange || newZen != -1 || ringerModeExternal != ringerModeExternalOut) {
925 ZenLog.traceSetRingerModeInternal(ringerModeOld, ringerModeNew, caller,
926 ringerModeExternal, ringerModeExternalOut);
927 }
928 return ringerModeExternalOut;
929 }
930
931 @Override
932 public int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller,
933 int ringerModeInternal, VolumePolicy policy) {
934 int ringerModeInternalOut = ringerModeNew;
935 final boolean isChange = ringerModeOld != ringerModeNew;
936 final boolean isVibrate = ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE;
937
938 int newZen = -1;
939 switch (ringerModeNew) {
940 case AudioManager.RINGER_MODE_SILENT:
941 if (isChange) {
942 if (mZenMode == Global.ZEN_MODE_OFF) {
John Spurlock05715ec2015-05-13 11:19:19 -0400943 newZen = Global.ZEN_MODE_ALARMS;
John Spurlockb2278d62015-04-07 12:47:12 -0400944 }
945 ringerModeInternalOut = isVibrate ? AudioManager.RINGER_MODE_VIBRATE
John Spurlock05715ec2015-05-13 11:19:19 -0400946 : AudioManager.RINGER_MODE_SILENT;
John Spurlockb2278d62015-04-07 12:47:12 -0400947 } else {
948 ringerModeInternalOut = ringerModeInternal;
949 }
950 break;
951 case AudioManager.RINGER_MODE_VIBRATE:
952 case AudioManager.RINGER_MODE_NORMAL:
953 if (mZenMode != Global.ZEN_MODE_OFF) {
954 newZen = Global.ZEN_MODE_OFF;
955 }
956 break;
957 }
958 if (newZen != -1) {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -0400959 setManualZenMode(newZen, null, "ringerModeExternal", caller,
960 false /*setRingerMode*/);
John Spurlockb2278d62015-04-07 12:47:12 -0400961 }
962
963 ZenLog.traceSetRingerModeExternal(ringerModeOld, ringerModeNew, caller,
964 ringerModeInternal, ringerModeInternalOut);
965 return ringerModeInternalOut;
966 }
John Spurlockd9c75db2015-04-28 11:19:13 -0400967
968 @Override
969 public boolean canVolumeDownEnterSilent() {
970 return mZenMode == Global.ZEN_MODE_OFF;
971 }
John Spurlock50ced3f2015-05-11 16:00:09 -0400972
973 @Override
974 public int getRingerModeAffectedStreams(int streams) {
975 // ringtone, notification and system streams are always affected by ringer mode
976 streams |= (1 << AudioSystem.STREAM_RING) |
977 (1 << AudioSystem.STREAM_NOTIFICATION) |
978 (1 << AudioSystem.STREAM_SYSTEM);
979
980 // alarm and music streams are only affected by ringer mode when in total silence
981 if (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
982 streams |= (1 << AudioSystem.STREAM_ALARM) |
983 (1 << AudioSystem.STREAM_MUSIC);
984 } else {
985 streams &= ~((1 << AudioSystem.STREAM_ALARM) |
986 (1 << AudioSystem.STREAM_MUSIC));
987 }
988 return streams;
989 }
John Spurlockb2278d62015-04-07 12:47:12 -0400990 }
991
992 private final class SettingsObserver extends ContentObserver {
John Spurlock056c5192014-04-20 21:52:01 -0400993 private final Uri ZEN_MODE = Global.getUriFor(Global.ZEN_MODE);
994
995 public SettingsObserver(Handler handler) {
996 super(handler);
997 }
998
999 public void observe() {
1000 final ContentResolver resolver = mContext.getContentResolver();
1001 resolver.registerContentObserver(ZEN_MODE, false /*notifyForDescendents*/, this);
1002 update(null);
1003 }
1004
1005 @Override
1006 public void onChange(boolean selfChange, Uri uri) {
1007 update(uri);
1008 }
1009
1010 public void update(Uri uri) {
1011 if (ZEN_MODE.equals(uri)) {
John Spurlockb2278d62015-04-07 12:47:12 -04001012 if (mZenMode != getZenModeSetting()) {
1013 if (DEBUG) Log.d(TAG, "Fixing zen mode setting");
1014 setZenModeSetting(mZenMode);
1015 }
John Spurlock056c5192014-04-20 21:52:01 -04001016 }
1017 }
1018 }
1019
Chris Wren98d235b2015-05-27 18:25:17 -04001020 private final class Metrics extends Callback {
1021 private static final String COUNTER_PREFIX = "dnd_mode_";
1022 private static final long MINIMUM_LOG_PERIOD_MS = 60 * 1000;
1023
1024 private int mPreviousZenMode = -1;
1025 private long mBeginningMs = 0L;
1026
1027 @Override
1028 void onZenModeChanged() {
1029 emit();
1030 }
1031
1032 private void emit() {
1033 mHandler.postMetricsTimer();
1034 final long now = SystemClock.elapsedRealtime();
1035 final long since = (now - mBeginningMs);
1036 if (mPreviousZenMode != mZenMode || since > MINIMUM_LOG_PERIOD_MS) {
1037 if (mPreviousZenMode != -1) {
1038 MetricsLogger.count(mContext, COUNTER_PREFIX + mPreviousZenMode, (int) since);
1039 }
1040 mPreviousZenMode = mZenMode;
1041 mBeginningMs = now;
1042 }
1043 }
1044 }
1045
John Spurlockb2278d62015-04-07 12:47:12 -04001046 private final class H extends Handler {
John Spurlock57627792014-12-11 11:29:54 -05001047 private static final int MSG_DISPATCH = 1;
Chris Wren98d235b2015-05-27 18:25:17 -04001048 private static final int MSG_METRICS = 2;
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001049 private static final int MSG_APPLY_CONFIG = 4;
Eric Laurente0ced4d2015-09-30 17:44:28 -07001050
1051 private final class ConfigMessageData {
1052 public final ZenModeConfig config;
1053 public final String reason;
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001054 public final boolean setRingerMode;
Eric Laurente0ced4d2015-09-30 17:44:28 -07001055
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001056 ConfigMessageData(ZenModeConfig config, String reason, boolean setRingerMode) {
1057 this.config = config;
1058 this.reason = reason;
1059 this.setRingerMode = setRingerMode;
Eric Laurente0ced4d2015-09-30 17:44:28 -07001060 }
1061 }
Chris Wren98d235b2015-05-27 18:25:17 -04001062
1063 private static final long METRICS_PERIOD_MS = 6 * 60 * 60 * 1000;
John Spurlock661f2cf2014-11-17 10:29:10 -05001064
1065 private H(Looper looper) {
1066 super(looper);
John Spurlock056c5192014-04-20 21:52:01 -04001067 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001068
John Spurlock57627792014-12-11 11:29:54 -05001069 private void postDispatchOnZenModeChanged() {
1070 removeMessages(MSG_DISPATCH);
1071 sendEmptyMessage(MSG_DISPATCH);
John Spurlock661f2cf2014-11-17 10:29:10 -05001072 }
1073
Chris Wren98d235b2015-05-27 18:25:17 -04001074 private void postMetricsTimer() {
1075 removeMessages(MSG_METRICS);
1076 sendEmptyMessageDelayed(MSG_METRICS, METRICS_PERIOD_MS);
1077 }
1078
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001079 private void postApplyConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
1080 sendMessage(obtainMessage(MSG_APPLY_CONFIG,
1081 new ConfigMessageData(config, reason, setRingerMode)));
1082 }
1083
John Spurlock661f2cf2014-11-17 10:29:10 -05001084 @Override
1085 public void handleMessage(Message msg) {
John Spurlock57627792014-12-11 11:29:54 -05001086 switch (msg.what) {
1087 case MSG_DISPATCH:
1088 dispatchOnZenModeChanged();
John Spurlock661f2cf2014-11-17 10:29:10 -05001089 break;
Chris Wren98d235b2015-05-27 18:25:17 -04001090 case MSG_METRICS:
1091 mMetrics.emit();
1092 break;
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001093 case MSG_APPLY_CONFIG:
1094 ConfigMessageData applyConfigData = (ConfigMessageData) msg.obj;
1095 applyConfig(applyConfigData.config, applyConfigData.reason,
1096 applyConfigData.setRingerMode);
John Spurlock661f2cf2014-11-17 10:29:10 -05001097 }
1098 }
1099 }
John Spurlock056c5192014-04-20 21:52:01 -04001100
John Spurlock1c923a32014-04-27 16:42:29 -04001101 public static class Callback {
1102 void onConfigChanged() {}
1103 void onZenModeChanged() {}
John Spurlock1fc476d2015-04-14 16:05:20 -04001104 void onPolicyChanged() {}
John Spurlock056c5192014-04-20 21:52:01 -04001105 }
John Spurlockb2278d62015-04-07 12:47:12 -04001106
John Spurlock056c5192014-04-20 21:52:01 -04001107}