blob: 8746486417fbd41348e71288fc948bd4040a2b6d [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
Julia Reynolds3ec93302019-07-11 15:27:31 -040019import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_DISABLED;
20import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ENABLED;
21import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_REMOVED;
Julia Reynolds8f5dabd2020-02-19 08:42:07 -050022import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_ANY;
Chris Wren93165692020-05-15 16:12:41 -040023import static android.service.notification.DNDModeProto.ROOT_CONFIG;
24
25import static com.android.internal.util.FrameworkStatsLog.ANNOTATION_ID_IS_UID;
26import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
Julia Reynolds3ec93302019-07-11 15:27:31 -040027
John Spurlock056c5192014-04-20 21:52:01 -040028import android.app.AppOpsManager;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040029import android.app.AutomaticZenRule;
Beverly3bae4e52018-02-07 12:32:02 -050030import android.app.Notification;
John Spurlock80774932015-05-07 17:38:50 -040031import android.app.NotificationManager;
John Spurlock1fc476d2015-04-14 16:05:20 -040032import android.app.NotificationManager.Policy;
Beverly3bae4e52018-02-07 12:32:02 -050033import android.app.PendingIntent;
John Spurlock312d1d02014-07-08 10:24:57 -040034import android.content.ComponentName;
John Spurlock056c5192014-04-20 21:52:01 -040035import android.content.ContentResolver;
36import android.content.Context;
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -050037import android.content.Intent;
Julia Reynolds68062072018-08-06 15:38:21 -040038import android.content.pm.ActivityInfo;
39import android.content.pm.PackageItemInfo;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040040import android.content.pm.PackageManager;
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -050041import android.content.pm.ResolveInfo;
42import android.content.pm.ServiceInfo;
John Spurlock056c5192014-04-20 21:52:01 -040043import android.content.res.Resources;
44import android.content.res.XmlResourceParser;
45import android.database.ContentObserver;
Julia Reynolds9aa1c9e2018-04-09 11:31:15 -040046import android.graphics.drawable.Icon;
Jean-Michel Trivie743bda2016-09-09 11:56:48 -070047import android.media.AudioAttributes;
John Spurlock056c5192014-04-20 21:52:01 -040048import android.media.AudioManager;
John Spurlock661f2cf2014-11-17 10:29:10 -050049import android.media.AudioManagerInternal;
John Spurlock50ced3f2015-05-11 16:00:09 -040050import android.media.AudioSystem;
John Spurlocka48d7792015-03-03 17:35:57 -050051import android.media.VolumePolicy;
John Spurlock056c5192014-04-20 21:52:01 -040052import android.net.Uri;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040053import android.os.Binder;
John Spurlock2b122f42014-08-27 16:29:47 -040054import android.os.Bundle;
John Spurlock056c5192014-04-20 21:52:01 -040055import android.os.Handler;
John Spurlock661f2cf2014-11-17 10:29:10 -050056import android.os.Looper;
57import android.os.Message;
Julia Reynoldsc8e54e82015-11-30 16:43:05 -050058import android.os.Process;
Chris Wren98d235b2015-05-27 18:25:17 -040059import android.os.SystemClock;
John Spurlockb5e767b2014-07-27 11:53:20 -040060import android.os.UserHandle;
Beverly3bae4e52018-02-07 12:32:02 -050061import android.provider.Settings;
John Spurlock056c5192014-04-20 21:52:01 -040062import android.provider.Settings.Global;
Julia Reynolds520df6e2017-02-13 09:05:10 -050063import android.service.notification.Condition;
Julia Reynolds43b70cd2016-01-14 15:05:34 -050064import android.service.notification.ConditionProviderService;
John Spurlock056c5192014-04-20 21:52:01 -040065import android.service.notification.ZenModeConfig;
John Spurlockb2278d62015-04-07 12:47:12 -040066import android.service.notification.ZenModeConfig.ZenRule;
Julia Reynolds520df6e2017-02-13 09:05:10 -050067import android.service.notification.ZenModeProto;
Beverlyff2df9b2018-10-10 16:54:10 -040068import android.service.notification.ZenPolicy;
Julia Reynolds87c42772016-05-16 09:52:17 -040069import android.util.AndroidRuntimeException;
Beverly4e2f76c2018-03-16 15:43:49 -040070import android.util.ArrayMap;
John Spurlock4db0d982014-08-13 09:19:03 -040071import android.util.Log;
Beverlyd4f96492017-08-02 13:36:11 -040072import android.util.Slog;
John Spurlock21258a32015-05-27 18:22:55 -040073import android.util.SparseArray;
Chris Wren93165692020-05-15 16:12:41 -040074import android.util.StatsEvent;
Julia Reynolds520df6e2017-02-13 09:05:10 -050075import android.util.proto.ProtoOutputStream;
John Spurlock056c5192014-04-20 21:52:01 -040076
77import com.android.internal.R;
Beverly04216872017-09-28 10:55:32 -040078import com.android.internal.annotations.VisibleForTesting;
John Spurlock25d01ee2015-06-03 12:17:46 -040079import com.android.internal.logging.MetricsLogger;
Beverly3bae4e52018-02-07 12:32:02 -050080import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
81import com.android.internal.notification.SystemNotificationChannels;
John Spurlock661f2cf2014-11-17 10:29:10 -050082import com.android.server.LocalServices;
John Spurlock056c5192014-04-20 21:52:01 -040083
84import libcore.io.IoUtils;
85
86import org.xmlpull.v1.XmlPullParser;
87import org.xmlpull.v1.XmlPullParserException;
88import org.xmlpull.v1.XmlSerializer;
89
90import java.io.IOException;
91import java.io.PrintWriter;
John Spurlock1c923a32014-04-27 16:42:29 -040092import java.util.ArrayList;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040093import java.util.List;
John Spurlock1fc476d2015-04-14 16:05:20 -040094import java.util.Objects;
John Spurlock056c5192014-04-20 21:52:01 -040095
96/**
97 * NotificationManagerService helper for functionality related to zen mode.
98 */
John Spurlockb2278d62015-04-07 12:47:12 -040099public class ZenModeHelper {
100 static final String TAG = "ZenModeHelper";
101 static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
John Spurlock056c5192014-04-20 21:52:01 -0400102
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500103 // The amount of time rules instances can exist without their owning app being installed.
104 private static final int RULE_INSTANCE_GRACE_PERIOD = 1000 * 60 * 60 * 72;
105
John Spurlock056c5192014-04-20 21:52:01 -0400106 private final Context mContext;
John Spurlock661f2cf2014-11-17 10:29:10 -0500107 private final H mHandler;
John Spurlock056c5192014-04-20 21:52:01 -0400108 private final SettingsObserver mSettingsObserver;
Julia Reynoldse99db5a2019-04-16 12:50:04 -0400109 private final AppOpsManager mAppOps;
Beverly3bae4e52018-02-07 12:32:02 -0500110 @VisibleForTesting protected final NotificationManager mNotificationManager;
Chris Wren93165692020-05-15 16:12:41 -0400111 private final SysUiStatsEvent.BuilderFactory mStatsEventBuilderFactory;
Beverly49ba9a62018-11-02 13:19:31 -0400112 @VisibleForTesting protected ZenModeConfig mDefaultConfig;
John Spurlock1c923a32014-04-27 16:42:29 -0400113 private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
John Spurlockb2278d62015-04-07 12:47:12 -0400114 private final ZenModeFiltering mFiltering;
Beverlyd6964762018-02-16 14:07:03 -0500115 protected final RingerModeDelegate mRingerModeDelegate = new
116 RingerModeDelegate();
Beverly2f43b642018-08-14 09:43:11 -0400117 @VisibleForTesting protected final ZenModeConditions mConditions;
Annie Meng8b646fd2019-02-01 18:46:42 +0000118 @VisibleForTesting final SparseArray<ZenModeConfig> mConfigs = new SparseArray<>();
Chris Wren98d235b2015-05-27 18:25:17 -0400119 private final Metrics mMetrics = new Metrics();
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500120 private final ConditionProviders.Config mServiceConfig;
John Spurlock056c5192014-04-20 21:52:01 -0400121
Beverly04216872017-09-28 10:55:32 -0400122 @VisibleForTesting protected int mZenMode;
Beverlyff2df9b2018-10-10 16:54:10 -0400123 @VisibleForTesting protected NotificationManager.Policy mConsolidatedPolicy;
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700124 private int mUser = UserHandle.USER_SYSTEM;
Beverly04216872017-09-28 10:55:32 -0400125 @VisibleForTesting protected ZenModeConfig mConfig;
Beverly85f52412018-02-27 10:41:13 -0500126 @VisibleForTesting protected AudioManagerInternal mAudioManager;
Beverlyd4f96492017-08-02 13:36:11 -0400127 protected PackageManager mPm;
Bryce Lee7219ada2016-04-08 10:54:23 -0700128 private long mSuppressedEffects;
129
130 public static final long SUPPRESSED_EFFECT_NOTIFICATIONS = 1;
131 public static final long SUPPRESSED_EFFECT_CALLS = 1 << 1;
132 public static final long SUPPRESSED_EFFECT_ALL = SUPPRESSED_EFFECT_CALLS
133 | SUPPRESSED_EFFECT_NOTIFICATIONS;
John Spurlock056c5192014-04-20 21:52:01 -0400134
Beverly3bae4e52018-02-07 12:32:02 -0500135 @VisibleForTesting protected boolean mIsBootComplete;
Beverlyd4f96492017-08-02 13:36:11 -0400136
Julia Reynoldse99db5a2019-04-16 12:50:04 -0400137 private String[] mPriorityOnlyDndExemptPackages;
138
Chris Wren93165692020-05-15 16:12:41 -0400139 public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders,
140 SysUiStatsEvent.BuilderFactory statsEventBuilderFactory) {
John Spurlock056c5192014-04-20 21:52:01 -0400141 mContext = context;
John Spurlock661f2cf2014-11-17 10:29:10 -0500142 mHandler = new H(looper);
Chris Wren98d235b2015-05-27 18:25:17 -0400143 addCallback(mMetrics);
Julia Reynoldse99db5a2019-04-16 12:50:04 -0400144 mAppOps = context.getSystemService(AppOpsManager.class);
Beverly3bae4e52018-02-07 12:32:02 -0500145 mNotificationManager = context.getSystemService(NotificationManager.class);
Beverlyd4f96492017-08-02 13:36:11 -0400146
Beverlyf3b92d22018-09-18 15:13:17 -0400147 mDefaultConfig = readDefaultConfig(mContext.getResources());
148 updateDefaultAutomaticRuleNames();
149 mConfig = mDefaultConfig.copy();
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700150 mConfigs.put(UserHandle.USER_SYSTEM, mConfig);
Beverly430b71a2020-03-16 14:17:31 -0400151 mConsolidatedPolicy = mConfig.toNotificationPolicy();
Beverlyd4f96492017-08-02 13:36:11 -0400152
John Spurlock056c5192014-04-20 21:52:01 -0400153 mSettingsObserver = new SettingsObserver(mHandler);
154 mSettingsObserver.observe();
John Spurlockb2278d62015-04-07 12:47:12 -0400155 mFiltering = new ZenModeFiltering(mContext);
156 mConditions = new ZenModeConditions(this, conditionProviders);
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500157 mServiceConfig = conditionProviders.getConfig();
Chris Wren93165692020-05-15 16:12:41 -0400158 mStatsEventBuilderFactory = statsEventBuilderFactory;
John Spurlock056c5192014-04-20 21:52:01 -0400159 }
160
John Spurlock1b8b22b2015-05-20 09:47:13 -0400161 public Looper getLooper() {
162 return mHandler.getLooper();
163 }
164
John Spurlockb2278d62015-04-07 12:47:12 -0400165 @Override
166 public String toString() {
167 return TAG;
168 }
169
170 public boolean matchesCallFilter(UserHandle userHandle, Bundle extras,
171 ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400172 synchronized (mConfig) {
Beverlyff2df9b2018-10-10 16:54:10 -0400173 return ZenModeFiltering.matchesCallFilter(mContext, mZenMode, mConsolidatedPolicy,
174 userHandle, extras, validator, contactsTimeoutMs, timeoutAffinity);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400175 }
John Spurlockb2278d62015-04-07 12:47:12 -0400176 }
177
178 public boolean isCall(NotificationRecord record) {
179 return mFiltering.isCall(record);
180 }
181
Julia Reynoldsc6b371b2016-06-14 08:31:03 -0400182 public void recordCaller(NotificationRecord record) {
183 mFiltering.recordCall(record);
184 }
185
John Spurlockb2278d62015-04-07 12:47:12 -0400186 public boolean shouldIntercept(NotificationRecord record) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400187 synchronized (mConfig) {
Beverlyff2df9b2018-10-10 16:54:10 -0400188 return mFiltering.shouldIntercept(mZenMode, mConsolidatedPolicy, record);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400189 }
John Spurlock056c5192014-04-20 21:52:01 -0400190 }
191
John Spurlock1c923a32014-04-27 16:42:29 -0400192 public void addCallback(Callback callback) {
193 mCallbacks.add(callback);
John Spurlock056c5192014-04-20 21:52:01 -0400194 }
195
John Spurlock530052a2014-11-30 16:26:19 -0500196 public void removeCallback(Callback callback) {
197 mCallbacks.remove(callback);
198 }
199
John Spurlockb2278d62015-04-07 12:47:12 -0400200 public void initZenMode() {
201 if (DEBUG) Log.d(TAG, "initZenMode");
202 evaluateZenMode("init", true /*setRingerMode*/);
203 }
204
John Spurlock661f2cf2014-11-17 10:29:10 -0500205 public void onSystemReady() {
John Spurlockb2278d62015-04-07 12:47:12 -0400206 if (DEBUG) Log.d(TAG, "onSystemReady");
John Spurlock661f2cf2014-11-17 10:29:10 -0500207 mAudioManager = LocalServices.getService(AudioManagerInternal.class);
208 if (mAudioManager != null) {
John Spurlockb2278d62015-04-07 12:47:12 -0400209 mAudioManager.setRingerModeDelegate(mRingerModeDelegate);
John Spurlock661f2cf2014-11-17 10:29:10 -0500210 }
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500211 mPm = mContext.getPackageManager();
Chris Wren98d235b2015-05-27 18:25:17 -0400212 mHandler.postMetricsTimer();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500213 cleanUpZenRules();
Julia Reynolds8ac63032015-08-31 15:19:43 -0400214 evaluateZenMode("onSystemReady", true);
Beverly3bae4e52018-02-07 12:32:02 -0500215 mIsBootComplete = true;
216 showZenUpgradeNotification(mZenMode);
John Spurlockae641c92014-06-30 18:11:40 -0400217 }
218
John Spurlock21258a32015-05-27 18:22:55 -0400219 public void onUserSwitched(int user) {
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500220 loadConfigForUser(user, "onUserSwitched");
John Spurlock21258a32015-05-27 18:22:55 -0400221 }
222
223 public void onUserRemoved(int user) {
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700224 if (user < UserHandle.USER_SYSTEM) return;
John Spurlock21258a32015-05-27 18:22:55 -0400225 if (DEBUG) Log.d(TAG, "onUserRemoved u=" + user);
226 mConfigs.remove(user);
227 }
228
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500229 public void onUserUnlocked(int user) {
230 loadConfigForUser(user, "onUserUnlocked");
231 }
232
Julia Reynoldse99db5a2019-04-16 12:50:04 -0400233 void setPriorityOnlyDndExemptPackages(String[] packages) {
234 mPriorityOnlyDndExemptPackages = packages;
235 }
236
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500237 private void loadConfigForUser(int user, String reason) {
238 if (mUser == user || user < UserHandle.USER_SYSTEM) return;
239 mUser = user;
240 if (DEBUG) Log.d(TAG, reason + " u=" + user);
241 ZenModeConfig config = mConfigs.get(user);
242 if (config == null) {
243 if (DEBUG) Log.d(TAG, reason + " generating default config for user " + user);
244 config = mDefaultConfig.copy();
245 config.user = user;
246 }
247 synchronized (mConfig) {
Julia Reynolds8f056002018-07-13 15:12:29 -0400248 setConfigLocked(config, null, reason);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500249 }
250 cleanUpZenRules();
251 }
252
Christoph Studer85a384b2014-08-27 20:16:15 +0200253 public int getZenModeListenerInterruptionFilter() {
John Spurlock80774932015-05-07 17:38:50 -0400254 return NotificationManager.zenModeToInterruptionFilter(mZenMode);
John Spurlockd8afe3c2014-08-01 14:04:07 -0400255 }
256
John Spurlock80774932015-05-07 17:38:50 -0400257 public void requestFromListener(ComponentName name, int filter) {
258 final int newZen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
John Spurlockd8afe3c2014-08-01 14:04:07 -0400259 if (newZen != -1) {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -0400260 setManualZenMode(newZen, null, name != null ? name.getPackageName() : null,
John Spurlockb2278d62015-04-07 12:47:12 -0400261 "listener:" + (name != null ? name.flattenToShortString() : null));
John Spurlockd8afe3c2014-08-01 14:04:07 -0400262 }
263 }
264
Bryce Lee7219ada2016-04-08 10:54:23 -0700265 public void setSuppressedEffects(long suppressedEffects) {
266 if (mSuppressedEffects == suppressedEffects) return;
267 mSuppressedEffects = suppressedEffects;
John Spurlock8403b752014-12-10 12:47:01 -0500268 applyRestrictions();
269 }
270
Bryce Lee7219ada2016-04-08 10:54:23 -0700271 public long getSuppressedEffects() {
272 return mSuppressedEffects;
273 }
274
John Spurlock1c923a32014-04-27 16:42:29 -0400275 public int getZenMode() {
276 return mZenMode;
277 }
278
Julia Reynolds361e82d32016-02-26 18:19:49 -0500279 public List<ZenRule> getZenRules() {
280 List<ZenRule> rules = new ArrayList<>();
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400281 synchronized (mConfig) {
282 if (mConfig == null) return rules;
283 for (ZenRule rule : mConfig.automaticRules.values()) {
284 if (canManageAutomaticZenRule(rule)) {
Julia Reynolds361e82d32016-02-26 18:19:49 -0500285 rules.add(rule);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400286 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400287 }
288 }
289 return rules;
290 }
291
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400292 public AutomaticZenRule getAutomaticZenRule(String id) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400293 ZenRule rule;
294 synchronized (mConfig) {
295 if (mConfig == null) return null;
296 rule = mConfig.automaticRules.get(id);
297 }
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400298 if (rule == null) return null;
299 if (canManageAutomaticZenRule(rule)) {
300 return createAutomaticZenRule(rule);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400301 }
302 return null;
303 }
304
Julia Reynolds361e82d32016-02-26 18:19:49 -0500305 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500306 if (!isSystemRule(automaticZenRule)) {
Julia Reynolds68062072018-08-06 15:38:21 -0400307 PackageItemInfo component = getServiceInfo(automaticZenRule.getOwner());
308 if (component == null) {
309 component = getActivityInfo(automaticZenRule.getConfigurationActivity());
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500310 }
Julia Reynolds68062072018-08-06 15:38:21 -0400311 if (component == null) {
312 throw new IllegalArgumentException("Lacking enabled CPS or config activity");
313 }
Julia Reynolds7f2f4412016-03-01 12:33:48 -0500314 int ruleInstanceLimit = -1;
Julia Reynolds68062072018-08-06 15:38:21 -0400315 if (component.metaData != null) {
316 ruleInstanceLimit = component.metaData.getInt(
Julia Reynolds7f2f4412016-03-01 12:33:48 -0500317 ConditionProviderService.META_DATA_RULE_INSTANCE_LIMIT, -1);
318 }
Julia Reynolds68062072018-08-06 15:38:21 -0400319 int newRuleInstanceCount = getCurrentInstanceCount(automaticZenRule.getOwner())
320 + getCurrentInstanceCount(automaticZenRule.getConfigurationActivity())
321 + 1;
322 if (ruleInstanceLimit > 0 && ruleInstanceLimit < newRuleInstanceCount) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500323 throw new IllegalArgumentException("Rule instance limit exceeded");
324 }
Julia Reynolds68062072018-08-06 15:38:21 -0400325
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500326 }
327
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400328 ZenModeConfig newConfig;
329 synchronized (mConfig) {
Julia Reynolds87c42772016-05-16 09:52:17 -0400330 if (mConfig == null) {
331 throw new AndroidRuntimeException("Could not create rule");
332 }
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400333 if (DEBUG) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500334 Log.d(TAG, "addAutomaticZenRule rule= " + automaticZenRule + " reason=" + reason);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400335 }
336 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500337 ZenRule rule = new ZenRule();
338 populateZenRule(automaticZenRule, rule, true);
Beverlya0d07ab2018-11-28 16:49:23 -0500339 newConfig.automaticRules.put(rule.id, rule);
Julia Reynolds8f056002018-07-13 15:12:29 -0400340 if (setConfigLocked(newConfig, reason, rule.component, true)) {
Julia Reynolds361e82d32016-02-26 18:19:49 -0500341 return rule.id;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500342 } else {
Julia Reynolds87c42772016-05-16 09:52:17 -0400343 throw new AndroidRuntimeException("Could not create rule");
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500344 }
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400345 }
346 }
347
Julia Reynolds361e82d32016-02-26 18:19:49 -0500348 public boolean updateAutomaticZenRule(String ruleId, AutomaticZenRule automaticZenRule,
349 String reason) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400350 ZenModeConfig newConfig;
351 synchronized (mConfig) {
352 if (mConfig == null) return false;
353 if (DEBUG) {
354 Log.d(TAG, "updateAutomaticZenRule zenRule=" + automaticZenRule
355 + " reason=" + reason);
356 }
357 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500358 ZenModeConfig.ZenRule rule;
359 if (ruleId == null) {
360 throw new IllegalArgumentException("Rule doesn't exist");
361 } else {
362 rule = newConfig.automaticRules.get(ruleId);
363 if (rule == null || !canManageAutomaticZenRule(rule)) {
364 throw new SecurityException(
365 "Cannot update rules not owned by your condition provider");
366 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400367 }
Julia Reynolds3ec93302019-07-11 15:27:31 -0400368 if (rule.enabled != automaticZenRule.isEnabled()) {
369 dispatchOnAutomaticRuleStatusChanged(mConfig.user, rule.pkg, ruleId,
370 automaticZenRule.isEnabled()
371 ? AUTOMATIC_RULE_STATUS_ENABLED : AUTOMATIC_RULE_STATUS_DISABLED);
372 }
373
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500374 populateZenRule(automaticZenRule, rule, false);
Julia Reynolds8f056002018-07-13 15:12:29 -0400375 return setConfigLocked(newConfig, reason, rule.component, true);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400376 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400377 }
378
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400379 public boolean removeAutomaticZenRule(String id, String reason) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400380 ZenModeConfig newConfig;
381 synchronized (mConfig) {
382 if (mConfig == null) return false;
383 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500384 ZenRule rule = newConfig.automaticRules.get(id);
385 if (rule == null) return false;
386 if (canManageAutomaticZenRule(rule)) {
387 newConfig.automaticRules.remove(id);
388 if (DEBUG) Log.d(TAG, "removeZenRule zenRule=" + id + " reason=" + reason);
389 } else {
390 throw new SecurityException(
391 "Cannot delete rules not owned by your condition provider");
392 }
Julia Reynolds3ec93302019-07-11 15:27:31 -0400393 dispatchOnAutomaticRuleStatusChanged(
394 mConfig.user, rule.pkg, id, AUTOMATIC_RULE_STATUS_REMOVED);
Julia Reynolds8f056002018-07-13 15:12:29 -0400395 return setConfigLocked(newConfig, reason, null, true);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400396 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400397 }
398
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500399 public boolean removeAutomaticZenRules(String packageName, String reason) {
400 ZenModeConfig newConfig;
401 synchronized (mConfig) {
402 if (mConfig == null) return false;
403 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500404 for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
405 ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
Julia Reynolds10e663b2019-01-07 10:15:12 -0500406 if (rule.pkg.equals(packageName) && canManageAutomaticZenRule(rule)) {
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500407 newConfig.automaticRules.removeAt(i);
408 }
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500409 }
Julia Reynolds8f056002018-07-13 15:12:29 -0400410 return setConfigLocked(newConfig, reason, null, true);
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500411 }
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500412 }
413
Julia Reynolds68062072018-08-06 15:38:21 -0400414 public void setAutomaticZenRuleState(String id, Condition condition) {
415 ZenModeConfig newConfig;
416 synchronized (mConfig) {
417 if (mConfig == null) return;
418
419 newConfig = mConfig.copy();
Julia Reynolds977a93e2019-04-10 16:18:13 -0400420 setAutomaticZenRuleStateLocked(newConfig, newConfig.automaticRules.get(id), condition);
Julia Reynolds68062072018-08-06 15:38:21 -0400421 }
Julia Reynolds68062072018-08-06 15:38:21 -0400422 }
423
424 public void setAutomaticZenRuleState(Uri ruleDefinition, Condition condition) {
425 ZenModeConfig newConfig;
426 synchronized (mConfig) {
427 if (mConfig == null) return;
428 newConfig = mConfig.copy();
Julia Reynolds68062072018-08-06 15:38:21 -0400429
Julia Reynolds977a93e2019-04-10 16:18:13 -0400430 setAutomaticZenRuleStateLocked(newConfig,
431 findMatchingRule(newConfig, ruleDefinition, condition),
432 condition);
433 }
Julia Reynolds68062072018-08-06 15:38:21 -0400434 }
435
Julia Reynolds977a93e2019-04-10 16:18:13 -0400436 private void setAutomaticZenRuleStateLocked(ZenModeConfig config, ZenRule rule,
437 Condition condition) {
Julia Reynolds68062072018-08-06 15:38:21 -0400438 if (rule == null) return;
439
440 rule.condition = condition;
441 updateSnoozing(rule);
442 setConfigLocked(config, rule.component, "conditionChanged");
443 }
444
445 private ZenRule findMatchingRule(ZenModeConfig config, Uri id, Condition condition) {
446 if (ruleMatches(id, condition, config.manualRule)) {
447 return config.manualRule;
448 } else {
449 for (ZenRule automaticRule : config.automaticRules.values()) {
450 if (ruleMatches(id, condition, automaticRule)) {
451 return automaticRule;
452 }
453 }
454 }
455 return null;
456 }
457
458 private boolean ruleMatches(Uri id, Condition condition, ZenRule rule) {
459 if (id == null || rule == null || rule.conditionId == null) return false;
460 if (!rule.conditionId.equals(id)) return false;
461 if (Objects.equals(condition, rule.condition)) return false;
462 return true;
463 }
464
465 private boolean updateSnoozing(ZenRule rule) {
466 if (rule != null && rule.snoozing && !rule.isTrueOrUnknown()) {
467 rule.snoozing = false;
468 if (DEBUG) Log.d(TAG, "Snoozing reset for " + rule.conditionId);
469 return true;
470 }
471 return false;
472 }
473
474 public int getCurrentInstanceCount(ComponentName cn) {
475 if (cn == null) {
476 return 0;
477 }
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500478 int count = 0;
479 synchronized (mConfig) {
480 for (ZenRule rule : mConfig.automaticRules.values()) {
Julia Reynolds68062072018-08-06 15:38:21 -0400481 if (cn.equals(rule.component) || cn.equals(rule.configurationActivity)) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500482 count++;
483 }
484 }
485 }
486 return count;
487 }
488
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400489 public boolean canManageAutomaticZenRule(ZenRule rule) {
Julia Reynoldsc8e54e82015-11-30 16:43:05 -0500490 final int callingUid = Binder.getCallingUid();
491 if (callingUid == 0 || callingUid == Process.SYSTEM_UID) {
492 return true;
493 } else if (mContext.checkCallingPermission(android.Manifest.permission.MANAGE_NOTIFICATIONS)
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400494 == PackageManager.PERMISSION_GRANTED) {
495 return true;
496 } else {
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500497 String[] packages = mPm.getPackagesForUid(Binder.getCallingUid());
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400498 if (packages != null) {
499 final int packageCount = packages.length;
500 for (int i = 0; i < packageCount; i++) {
Julia Reynolds68062072018-08-06 15:38:21 -0400501 if (packages[i].equals(rule.pkg)) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400502 return true;
503 }
504 }
505 }
506 return false;
507 }
508 }
509
Beverlyd4f96492017-08-02 13:36:11 -0400510 protected void updateDefaultZenRules() {
Beverlyf3b92d22018-09-18 15:13:17 -0400511 updateDefaultAutomaticRuleNames();
512 for (ZenRule defaultRule : mDefaultConfig.automaticRules.values()) {
513 ZenRule currRule = mConfig.automaticRules.get(defaultRule.id);
Beverly49ba9a62018-11-02 13:19:31 -0400514 // if default rule wasn't user-modified nor enabled, use localized name
515 // instead of previous system name
516 if (currRule != null && !currRule.modified && !currRule.enabled
517 && !defaultRule.name.equals(currRule.name)) {
518 if (canManageAutomaticZenRule(currRule)) {
Beverlyd4f96492017-08-02 13:36:11 -0400519 if (DEBUG) Slog.d(TAG, "Locale change - updating default zen rule name "
Beverlyf3b92d22018-09-18 15:13:17 -0400520 + "from " + currRule.name + " to " + defaultRule.name);
Beverlyd4f96492017-08-02 13:36:11 -0400521 // update default rule (if locale changed, name of rule will change)
Beverly49ba9a62018-11-02 13:19:31 -0400522 currRule.name = defaultRule.name;
523 updateAutomaticZenRule(defaultRule.id, createAutomaticZenRule(currRule),
Beverlyd4f96492017-08-02 13:36:11 -0400524 "locale changed");
525 }
526 }
527 }
528 }
529
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500530 private boolean isSystemRule(AutomaticZenRule rule) {
Julia Reynolds68062072018-08-06 15:38:21 -0400531 return rule.getOwner() != null
532 && ZenModeConfig.SYSTEM_AUTHORITY.equals(rule.getOwner().getPackageName());
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500533 }
534
535 private ServiceInfo getServiceInfo(ComponentName owner) {
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500536 Intent queryIntent = new Intent();
537 queryIntent.setComponent(owner);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500538 List<ResolveInfo> installedServices = mPm.queryIntentServicesAsUser(
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500539 queryIntent,
540 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
541 UserHandle.getCallingUserId());
542 if (installedServices != null) {
543 for (int i = 0, count = installedServices.size(); i < count; i++) {
544 ResolveInfo resolveInfo = installedServices.get(i);
545 ServiceInfo info = resolveInfo.serviceInfo;
546 if (mServiceConfig.bindPermission.equals(info.permission)) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500547 return info;
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500548 }
549 }
550 }
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500551 return null;
Julia Reynolds0ae2b0b2016-01-14 09:58:03 -0500552 }
553
Julia Reynolds68062072018-08-06 15:38:21 -0400554 private ActivityInfo getActivityInfo(ComponentName configActivity) {
555 Intent queryIntent = new Intent();
556 queryIntent.setComponent(configActivity);
557 List<ResolveInfo> installedComponents = mPm.queryIntentActivitiesAsUser(
558 queryIntent,
559 PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA,
560 UserHandle.getCallingUserId());
561 if (installedComponents != null) {
562 for (int i = 0, count = installedComponents.size(); i < count; i++) {
563 ResolveInfo resolveInfo = installedComponents.get(i);
564 return resolveInfo.activityInfo;
565 }
566 }
567 return null;
568 }
569
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400570 private void populateZenRule(AutomaticZenRule automaticZenRule, ZenRule rule, boolean isNew) {
571 if (isNew) {
572 rule.id = ZenModeConfig.newRuleId();
573 rule.creationTime = System.currentTimeMillis();
574 rule.component = automaticZenRule.getOwner();
Julia Reynolds68062072018-08-06 15:38:21 -0400575 rule.configurationActivity = automaticZenRule.getConfigurationActivity();
576 rule.pkg = (rule.component != null)
577 ? rule.component.getPackageName()
578 : rule.configurationActivity.getPackageName();
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400579 }
580
581 if (rule.enabled != automaticZenRule.isEnabled()) {
582 rule.snoozing = false;
583 }
584 rule.name = automaticZenRule.getName();
585 rule.condition = null;
586 rule.conditionId = automaticZenRule.getConditionId();
587 rule.enabled = automaticZenRule.isEnabled();
Beverly49ba9a62018-11-02 13:19:31 -0400588 rule.modified = automaticZenRule.isModified();
Beverly12196702018-12-12 15:05:51 -0500589 rule.zenPolicy = automaticZenRule.getZenPolicy();
Julia Reynolds4fe98d62015-10-06 16:23:41 -0400590 rule.zenMode = NotificationManager.zenModeFromInterruptionFilter(
591 automaticZenRule.getInterruptionFilter(), Global.ZEN_MODE_OFF);
592 }
593
Beverlyd4f96492017-08-02 13:36:11 -0400594 protected AutomaticZenRule createAutomaticZenRule(ZenRule rule) {
Julia Reynolds68062072018-08-06 15:38:21 -0400595 return new AutomaticZenRule(rule.name, rule.component, rule.configurationActivity,
596 rule.conditionId, rule.zenPolicy,
597 NotificationManager.zenModeToInterruptionFilter(rule.zenMode),
598 rule.enabled, rule.creationTime);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400599 }
600
Julia Reynolds44ad6ff2016-07-06 09:47:45 -0400601 public void setManualZenMode(int zenMode, Uri conditionId, String caller, String reason) {
602 setManualZenMode(zenMode, conditionId, reason, caller, true /*setRingerMode*/);
Beverly91d0a632018-07-02 16:45:00 -0400603 Settings.Secure.putInt(mContext.getContentResolver(),
604 Settings.Secure.SHOW_ZEN_SETTINGS_SUGGESTION, 0);
John Spurlocke77bb362014-04-26 10:24:59 -0400605 }
606
Julia Reynolds44ad6ff2016-07-06 09:47:45 -0400607 private void setManualZenMode(int zenMode, Uri conditionId, String reason, String caller,
John Spurlockb2278d62015-04-07 12:47:12 -0400608 boolean setRingerMode) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400609 ZenModeConfig newConfig;
610 synchronized (mConfig) {
611 if (mConfig == null) return;
612 if (!Global.isValidZenMode(zenMode)) return;
613 if (DEBUG) Log.d(TAG, "setManualZenMode " + Global.zenModeToString(zenMode)
614 + " conditionId=" + conditionId + " reason=" + reason
615 + " setRingerMode=" + setRingerMode);
616 newConfig = mConfig.copy();
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500617 if (zenMode == Global.ZEN_MODE_OFF) {
618 newConfig.manualRule = null;
619 for (ZenRule automaticRule : newConfig.automaticRules.values()) {
620 if (automaticRule.isAutomaticActive()) {
621 automaticRule.snoozing = true;
622 }
John Spurlockb2278d62015-04-07 12:47:12 -0400623 }
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500624 } else {
625 final ZenRule newRule = new ZenRule();
626 newRule.enabled = true;
627 newRule.zenMode = zenMode;
628 newRule.conditionId = conditionId;
Julia Reynolds44ad6ff2016-07-06 09:47:45 -0400629 newRule.enabler = caller;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500630 newConfig.manualRule = newRule;
John Spurlockb2278d62015-04-07 12:47:12 -0400631 }
Julia Reynolds8f056002018-07-13 15:12:29 -0400632 setConfigLocked(newConfig, reason, null, setRingerMode);
John Spurlockb2278d62015-04-07 12:47:12 -0400633 }
John Spurlockb2278d62015-04-07 12:47:12 -0400634 }
635
Julia Reynolds520df6e2017-02-13 09:05:10 -0500636 void dump(ProtoOutputStream proto) {
Julia Reynolds520df6e2017-02-13 09:05:10 -0500637 proto.write(ZenModeProto.ZEN_MODE, mZenMode);
638 synchronized (mConfig) {
639 if (mConfig.manualRule != null) {
Jeffrey Huangcb782852019-12-05 11:28:11 -0800640 mConfig.manualRule.dumpDebug(proto, ZenModeProto.ENABLED_ACTIVE_CONDITIONS);
Julia Reynolds520df6e2017-02-13 09:05:10 -0500641 }
642 for (ZenRule rule : mConfig.automaticRules.values()) {
643 if (rule.enabled && rule.condition.state == Condition.STATE_TRUE
644 && !rule.snoozing) {
Jeffrey Huangcb782852019-12-05 11:28:11 -0800645 rule.dumpDebug(proto, ZenModeProto.ENABLED_ACTIVE_CONDITIONS);
Julia Reynolds520df6e2017-02-13 09:05:10 -0500646 }
647 }
Jeffrey Huangcb782852019-12-05 11:28:11 -0800648 mConfig.toNotificationPolicy().dumpDebug(proto, ZenModeProto.POLICY);
Julia Reynolds520df6e2017-02-13 09:05:10 -0500649 proto.write(ZenModeProto.SUPPRESSED_EFFECTS, mSuppressedEffects);
650 }
651 }
652
John Spurlockb2278d62015-04-07 12:47:12 -0400653 public void dump(PrintWriter pw, String prefix) {
Julia Reynolds24edc002020-01-29 16:35:32 -0500654 pw.print(prefix);
655 pw.print("mZenMode=");
John Spurlockb2278d62015-04-07 12:47:12 -0400656 pw.println(Global.zenModeToString(mZenMode));
Julia Reynolds24edc002020-01-29 16:35:32 -0500657 pw.print(prefix);
658 pw.println("mConsolidatedPolicy=" + mConsolidatedPolicy.toString());
John Spurlock21258a32015-05-27 18:22:55 -0400659 final int N = mConfigs.size();
660 for (int i = 0; i < N; i++) {
661 dump(pw, prefix, "mConfigs[u=" + mConfigs.keyAt(i) + "]", mConfigs.valueAt(i));
662 }
663 pw.print(prefix); pw.print("mUser="); pw.println(mUser);
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400664 synchronized (mConfig) {
665 dump(pw, prefix, "mConfig", mConfig);
666 }
Bryce Lee7219ada2016-04-08 10:54:23 -0700667
668 pw.print(prefix); pw.print("mSuppressedEffects="); pw.println(mSuppressedEffects);
John Spurlock1d7d2242015-04-10 08:10:22 -0400669 mFiltering.dump(pw, prefix);
John Spurlockb2278d62015-04-07 12:47:12 -0400670 mConditions.dump(pw, prefix);
671 }
672
673 private static void dump(PrintWriter pw, String prefix, String var, ZenModeConfig config) {
674 pw.print(prefix); pw.print(var); pw.print('=');
675 if (config == null) {
676 pw.println(config);
677 return;
678 }
Julia Reynoldsccc6ae62018-03-01 16:24:49 -0500679 pw.printf("allow(alarms=%b,media=%b,system=%b,calls=%b,callsFrom=%s,repeatCallers=%b,"
Julia Reynolds24edc002020-01-29 16:35:32 -0500680 + "messages=%b,messagesFrom=%s,conversations=%b,conversationsFrom=%s,"
681 + "events=%b,reminders=%b)\n",
Beverlyd6964762018-02-16 14:07:03 -0500682 config.allowAlarms, config.allowMedia, config.allowSystem,
Julia Reynolds6ee26172015-09-28 11:34:48 -0400683 config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom),
684 config.allowRepeatCallers, config.allowMessages,
685 ZenModeConfig.sourceToString(config.allowMessagesFrom),
Julia Reynolds24edc002020-01-29 16:35:32 -0500686 config.allowConversations,
687 ZenPolicy.conversationTypeToString(config.allowConversationsFrom),
Julia Reynolds1f580572018-04-27 14:48:36 -0400688 config.allowEvents, config.allowReminders);
Julia Reynolds24edc002020-01-29 16:35:32 -0500689 pw.print(prefix);
690 pw.printf(" disallow(visualEffects=%s)\n", config.suppressedVisualEffects);
John Spurlockb2278d62015-04-07 12:47:12 -0400691 pw.print(prefix); pw.print(" manualRule="); pw.println(config.manualRule);
692 if (config.automaticRules.isEmpty()) return;
693 final int N = config.automaticRules.size();
694 for (int i = 0; i < N; i++) {
695 pw.print(prefix); pw.print(i == 0 ? " automaticRules=" : " ");
696 pw.println(config.automaticRules.valueAt(i));
697 }
698 }
699
Annie Meng8b646fd2019-02-01 18:46:42 +0000700 public void readXml(XmlPullParser parser, boolean forRestore, int userId)
John Spurlock35ef0a62015-05-28 11:24:10 -0400701 throws XmlPullParserException, IOException {
Beverly4e2f76c2018-03-16 15:43:49 -0400702 ZenModeConfig config = ZenModeConfig.readXml(parser);
703 String reason = "readXml";
704
John Spurlockb2278d62015-04-07 12:47:12 -0400705 if (config != null) {
John Spurlock35ef0a62015-05-28 11:24:10 -0400706 if (forRestore) {
Annie Meng8b646fd2019-02-01 18:46:42 +0000707 config.user = userId;
John Spurlock35ef0a62015-05-28 11:24:10 -0400708 config.manualRule = null; // don't restore the manual rule
Beverly4e2f76c2018-03-16 15:43:49 -0400709 }
710
Beverlyad3841a2018-07-31 11:23:35 -0400711 // booleans to determine whether to reset the rules to the default rules
712 boolean allRulesDisabled = true;
713 boolean hasDefaultRules = config.automaticRules.containsAll(
714 ZenModeConfig.DEFAULT_RULE_IDS);
715
Beverly4e2f76c2018-03-16 15:43:49 -0400716 long time = System.currentTimeMillis();
717 if (config.automaticRules != null && config.automaticRules.size() > 0) {
718 for (ZenRule automaticRule : config.automaticRules.values()) {
719 if (forRestore) {
John Spurlock995a7492015-05-28 22:13:03 -0400720 // don't restore transient state from restored automatic rules
721 automaticRule.snoozing = false;
722 automaticRule.condition = null;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500723 automaticRule.creationTime = time;
John Spurlock995a7492015-05-28 22:13:03 -0400724 }
Beverlyad3841a2018-07-31 11:23:35 -0400725
726 allRulesDisabled &= !automaticRule.enabled;
John Spurlock995a7492015-05-28 22:13:03 -0400727 }
John Spurlock35ef0a62015-05-28 11:24:10 -0400728 }
Beverly4e2f76c2018-03-16 15:43:49 -0400729
Beverlyad3841a2018-07-31 11:23:35 -0400730 if (!hasDefaultRules && allRulesDisabled
731 && (forRestore || config.version < ZenModeConfig.XML_VERSION)) {
732 // reset zen automatic rules to default on restore or upgrade if:
733 // - doesn't already have default rules and
734 // - all previous automatic rules were disabled
735 config.automaticRules = new ArrayMap<>();
Beverlyf3b92d22018-09-18 15:13:17 -0400736 for (ZenRule rule : mDefaultConfig.automaticRules.values()) {
737 config.automaticRules.put(rule.id, rule);
738 }
Beverlyad3841a2018-07-31 11:23:35 -0400739 reason += ", reset to default rules";
740 }
741
Annie Meng8b646fd2019-02-01 18:46:42 +0000742 // Resolve user id for settings.
743 userId = userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId;
Beverlyad3841a2018-07-31 11:23:35 -0400744 if (config.version < ZenModeConfig.XML_VERSION) {
Annie Meng8b646fd2019-02-01 18:46:42 +0000745 Settings.Secure.putIntForUser(mContext.getContentResolver(),
746 Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 1, userId);
Beverly301e92a2018-04-27 09:43:05 -0400747 } else {
748 // devices not restoring/upgrading already have updated zen settings
Annie Meng8b646fd2019-02-01 18:46:42 +0000749 Settings.Secure.putIntForUser(mContext.getContentResolver(),
750 Settings.Secure.ZEN_SETTINGS_UPDATED, 1, userId);
Beverly4e2f76c2018-03-16 15:43:49 -0400751 }
752 if (DEBUG) Log.d(TAG, reason);
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500753 synchronized (mConfig) {
Julia Reynolds8f056002018-07-13 15:12:29 -0400754 setConfigLocked(config, null, reason);
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500755 }
John Spurlockb2278d62015-04-07 12:47:12 -0400756 }
757 }
758
Annie Meng8b646fd2019-02-01 18:46:42 +0000759 public void writeXml(XmlSerializer out, boolean forBackup, Integer version, int userId)
760 throws IOException {
Beverly1ef2cce2019-04-29 11:08:05 -0400761 synchronized (mConfigs) {
762 final int n = mConfigs.size();
763 for (int i = 0; i < n; i++) {
764 if (forBackup && mConfigs.keyAt(i) != userId) {
765 continue;
766 }
767 mConfigs.valueAt(i).writeXml(out, version);
John Spurlock35ef0a62015-05-28 11:24:10 -0400768 }
John Spurlock21258a32015-05-27 18:22:55 -0400769 }
John Spurlockb2278d62015-04-07 12:47:12 -0400770 }
771
Beverly174d7412018-08-22 16:34:41 -0400772 /**
773 * @return user-specified default notification policy for priority only do not disturb
774 */
John Spurlock1fc476d2015-04-14 16:05:20 -0400775 public Policy getNotificationPolicy() {
776 return getNotificationPolicy(mConfig);
777 }
778
779 private static Policy getNotificationPolicy(ZenModeConfig config) {
780 return config == null ? null : config.toNotificationPolicy();
781 }
782
Beverly174d7412018-08-22 16:34:41 -0400783 /**
784 * Sets the global notification policy used for priority only do not disturb
785 */
John Spurlock1fc476d2015-04-14 16:05:20 -0400786 public void setNotificationPolicy(Policy policy) {
787 if (policy == null || mConfig == null) return;
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500788 synchronized (mConfig) {
789 final ZenModeConfig newConfig = mConfig.copy();
790 newConfig.applyNotificationPolicy(policy);
Julia Reynolds8f056002018-07-13 15:12:29 -0400791 setConfigLocked(newConfig, null, "setNotificationPolicy");
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500792 }
John Spurlock1fc476d2015-04-14 16:05:20 -0400793 }
794
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500795 /**
796 * Removes old rule instances whose owner is not installed.
797 */
798 private void cleanUpZenRules() {
799 long currentTime = System.currentTimeMillis();
800 synchronized (mConfig) {
801 final ZenModeConfig newConfig = mConfig.copy();
802 if (newConfig.automaticRules != null) {
803 for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
804 ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
805 if (RULE_INSTANCE_GRACE_PERIOD < (currentTime - rule.creationTime)) {
806 try {
Julia Reynolds68062072018-08-06 15:38:21 -0400807 if (rule.pkg != null) {
808 mPm.getPackageInfo(rule.pkg, PackageManager.MATCH_ANY_USER);
809 }
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500810 } catch (PackageManager.NameNotFoundException e) {
811 newConfig.automaticRules.removeAt(i);
812 }
813 }
814 }
815 }
Julia Reynolds8f056002018-07-13 15:12:29 -0400816 setConfigLocked(newConfig, null, "cleanUpZenRules");
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500817 }
818 }
819
820 /**
821 * @return a copy of the zen mode configuration
822 */
John Spurlockb2278d62015-04-07 12:47:12 -0400823 public ZenModeConfig getConfig() {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400824 synchronized (mConfig) {
825 return mConfig.copy();
826 }
John Spurlockb2278d62015-04-07 12:47:12 -0400827 }
828
Beverlyff2df9b2018-10-10 16:54:10 -0400829 /**
830 * @return a copy of the zen mode consolidated policy
831 */
832 public Policy getConsolidatedNotificationPolicy() {
Beverlyff2df9b2018-10-10 16:54:10 -0400833 return mConsolidatedPolicy.copy();
834 }
835
Julia Reynolds8f056002018-07-13 15:12:29 -0400836 public boolean setConfigLocked(ZenModeConfig config, ComponentName triggeringComponent,
837 String reason) {
838 return setConfigLocked(config, reason, triggeringComponent, true /*setRingerMode*/);
John Spurlockb2278d62015-04-07 12:47:12 -0400839 }
840
Julia Reynolds8f056002018-07-13 15:12:29 -0400841 public void setConfig(ZenModeConfig config, ComponentName triggeringComponent, String reason) {
Julia Reynolds89aeab02016-09-15 11:07:50 -0400842 synchronized (mConfig) {
Julia Reynolds8f056002018-07-13 15:12:29 -0400843 setConfigLocked(config, triggeringComponent, reason);
Julia Reynolds89aeab02016-09-15 11:07:50 -0400844 }
Eric Laurente0ced4d2015-09-30 17:44:28 -0700845 }
846
Julia Reynolds8f056002018-07-13 15:12:29 -0400847 private boolean setConfigLocked(ZenModeConfig config, String reason,
848 ComponentName triggeringComponent, boolean setRingerMode) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400849 final long identity = Binder.clearCallingIdentity();
850 try {
851 if (config == null || !config.isValid()) {
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500852 Log.w(TAG, "Invalid config in setConfigLocked; " + config);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400853 return false;
854 }
855 if (config.user != mUser) {
856 // simply store away for background users
857 mConfigs.put(config.user, config);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500858 if (DEBUG) Log.d(TAG, "setConfigLocked: store config for user " + config.user);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400859 return true;
860 }
Julia Reynolds68062072018-08-06 15:38:21 -0400861 // handle CPS backed conditions - danger! may modify config
Julia Reynolds8f056002018-07-13 15:12:29 -0400862 mConditions.evaluateConfig(config, null, false /*processSubscriptions*/);
Julia Reynolds68062072018-08-06 15:38:21 -0400863
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500864 mConfigs.put(config.user, config);
Julia Reynolds43b70cd2016-01-14 15:05:34 -0500865 if (DEBUG) Log.d(TAG, "setConfigLocked reason=" + reason, new Throwable());
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500866 ZenLog.traceConfig(reason, mConfig, config);
Julia Reynolds68062072018-08-06 15:38:21 -0400867
868 // send some broadcasts
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500869 final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
870 getNotificationPolicy(config));
Julia Reynolds9a25da12016-01-06 16:19:28 -0500871 if (!config.equals(mConfig)) {
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500872 dispatchOnConfigChanged();
Beverlyff2df9b2018-10-10 16:54:10 -0400873 updateConsolidatedPolicy(reason);
Julia Reynolds5a43aaa2015-12-15 13:54:41 -0500874 }
875 if (policyChanged) {
876 dispatchOnPolicyChanged();
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400877 }
Julia Reynolds9a25da12016-01-06 16:19:28 -0500878 mConfig = config;
Julia Reynolds8f056002018-07-13 15:12:29 -0400879 mHandler.postApplyConfig(config, reason, triggeringComponent, setRingerMode);
John Spurlock21258a32015-05-27 18:22:55 -0400880 return true;
Julia Reynoldscb507b82017-09-07 13:53:40 -0400881 } catch (SecurityException e) {
882 Log.wtf(TAG, "Invalid rule in config", e);
883 return false;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400884 } finally {
885 Binder.restoreCallingIdentity(identity);
John Spurlock21258a32015-05-27 18:22:55 -0400886 }
John Spurlockb2278d62015-04-07 12:47:12 -0400887 }
888
Julia Reynolds8f056002018-07-13 15:12:29 -0400889 private void applyConfig(ZenModeConfig config, String reason,
890 ComponentName triggeringComponent, boolean setRingerMode) {
Julia Reynoldsd82e9812016-04-19 13:27:41 -0400891 final String val = Integer.toString(config.hashCode());
892 Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
Beverly174d7412018-08-22 16:34:41 -0400893 evaluateZenMode(reason, setRingerMode);
Julia Reynolds8f056002018-07-13 15:12:29 -0400894 mConditions.evaluateConfig(config, triggeringComponent, true /*processSubscriptions*/);
Julia Reynoldsd82e9812016-04-19 13:27:41 -0400895 }
896
John Spurlockb2278d62015-04-07 12:47:12 -0400897 private int getZenModeSetting() {
898 return Global.getInt(mContext.getContentResolver(), Global.ZEN_MODE, Global.ZEN_MODE_OFF);
899 }
900
Beverly3bae4e52018-02-07 12:32:02 -0500901 @VisibleForTesting
902 protected void setZenModeSetting(int zen) {
John Spurlockb2278d62015-04-07 12:47:12 -0400903 Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zen);
Beverly3bae4e52018-02-07 12:32:02 -0500904 showZenUpgradeNotification(zen);
John Spurlockb2278d62015-04-07 12:47:12 -0400905 }
906
Julia Reynolds9b11fdb2015-07-31 09:49:55 -0400907 private int getPreviousRingerModeSetting() {
908 return Global.getInt(mContext.getContentResolver(),
909 Global.ZEN_MODE_RINGER_LEVEL, AudioManager.RINGER_MODE_NORMAL);
910 }
911
912 private void setPreviousRingerModeSetting(Integer previousRingerLevel) {
913 Global.putString(
914 mContext.getContentResolver(), Global.ZEN_MODE_RINGER_LEVEL,
915 previousRingerLevel == null ? null : Integer.toString(previousRingerLevel));
916 }
917
Beverlye4ee1cc2018-03-06 17:21:08 -0500918 @VisibleForTesting
Beverly174d7412018-08-22 16:34:41 -0400919 protected void evaluateZenMode(String reason, boolean setRingerMode) {
John Spurlockb2278d62015-04-07 12:47:12 -0400920 if (DEBUG) Log.d(TAG, "evaluateZenMode");
Beverlyff2df9b2018-10-10 16:54:10 -0400921 if (mConfig == null) return;
922 final int policyHashBefore = mConsolidatedPolicy == null ? 0
923 : mConsolidatedPolicy.hashCode();
Jason Monka9927322015-12-13 16:22:37 -0500924 final int zenBefore = mZenMode;
Julia Reynolds8ac63032015-08-31 15:19:43 -0400925 final int zen = computeZenMode();
John Spurlockb2278d62015-04-07 12:47:12 -0400926 ZenLog.traceSetZenMode(zen, reason);
927 mZenMode = zen;
928 setZenModeSetting(mZenMode);
Beverlyff2df9b2018-10-10 16:54:10 -0400929 updateConsolidatedPolicy(reason);
Beverlyd6964762018-02-16 14:07:03 -0500930 updateRingerModeAffectedStreams();
Beverlyff2df9b2018-10-10 16:54:10 -0400931 if (setRingerMode && (zen != zenBefore || (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
932 && policyHashBefore != mConsolidatedPolicy.hashCode()))) {
John Spurlock57627792014-12-11 11:29:54 -0500933 applyZenToRingerMode();
934 }
935 applyRestrictions();
Jason Monka9927322015-12-13 16:22:37 -0500936 if (zen != zenBefore) {
Julia Reynolds8ac63032015-08-31 15:19:43 -0400937 mHandler.postDispatchOnZenModeChanged();
938 }
John Spurlock57627792014-12-11 11:29:54 -0500939 }
940
John Spurlock50ced3f2015-05-11 16:00:09 -0400941 private void updateRingerModeAffectedStreams() {
942 if (mAudioManager != null) {
943 mAudioManager.updateRingerModeAffectedStreamsInternal();
944 }
945 }
946
Julia Reynolds8ac63032015-08-31 15:19:43 -0400947 private int computeZenMode() {
Beverlye4ee1cc2018-03-06 17:21:08 -0500948 if (mConfig == null) return Global.ZEN_MODE_OFF;
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400949 synchronized (mConfig) {
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400950 if (mConfig.manualRule != null) return mConfig.manualRule.zenMode;
951 int zen = Global.ZEN_MODE_OFF;
952 for (ZenRule automaticRule : mConfig.automaticRules.values()) {
953 if (automaticRule.isAutomaticActive()) {
954 if (zenSeverity(automaticRule.zenMode) > zenSeverity(zen)) {
Beverly301e92a2018-04-27 09:43:05 -0400955 // automatic rule triggered dnd and user hasn't seen update dnd dialog
Beverly91d0a632018-07-02 16:45:00 -0400956 if (Settings.Secure.getInt(mContext.getContentResolver(),
957 Settings.Secure.ZEN_SETTINGS_SUGGESTION_VIEWED, 1) == 0) {
958 Settings.Secure.putInt(mContext.getContentResolver(),
959 Settings.Secure.SHOW_ZEN_SETTINGS_SUGGESTION, 1);
Beverly301e92a2018-04-27 09:43:05 -0400960 }
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400961 zen = automaticRule.zenMode;
962 }
John Spurlockb2278d62015-04-07 12:47:12 -0400963 }
964 }
Julia Reynoldsaaf191c2015-10-26 15:53:28 -0400965 return zen;
John Spurlockb2278d62015-04-07 12:47:12 -0400966 }
John Spurlock8403b752014-12-10 12:47:01 -0500967 }
968
Beverly1cc502f2019-04-15 11:21:25 -0400969 private void applyCustomPolicy(ZenPolicy policy, ZenRule rule) {
Beverly1f114922019-09-03 17:00:51 -0400970 if (rule.zenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
Beverly1cc502f2019-04-15 11:21:25 -0400971 policy.apply(new ZenPolicy.Builder()
972 .disallowAllSounds()
973 .build());
Beverly1f114922019-09-03 17:00:51 -0400974 } else if (rule.zenMode == Global.ZEN_MODE_ALARMS) {
Beverly1cc502f2019-04-15 11:21:25 -0400975 policy.apply(new ZenPolicy.Builder()
976 .disallowAllSounds()
977 .allowAlarms(true)
978 .allowMedia(true)
979 .build());
980 } else {
981 policy.apply(rule.zenPolicy);
982 }
983 }
984
Beverlyff2df9b2018-10-10 16:54:10 -0400985 private void updateConsolidatedPolicy(String reason) {
986 if (mConfig == null) return;
987 synchronized (mConfig) {
988 ZenPolicy policy = new ZenPolicy();
Beverly1cc502f2019-04-15 11:21:25 -0400989 if (mConfig.manualRule != null) {
990 applyCustomPolicy(policy, mConfig.manualRule);
991 }
992
Beverlyff2df9b2018-10-10 16:54:10 -0400993 for (ZenRule automaticRule : mConfig.automaticRules.values()) {
994 if (automaticRule.isAutomaticActive()) {
Beverly1cc502f2019-04-15 11:21:25 -0400995 applyCustomPolicy(policy, automaticRule);
Beverlyff2df9b2018-10-10 16:54:10 -0400996 }
997 }
998 Policy newPolicy = mConfig.toNotificationPolicy(policy);
999 if (!Objects.equals(mConsolidatedPolicy, newPolicy)) {
1000 mConsolidatedPolicy = newPolicy;
1001 dispatchOnConsolidatedPolicyChanged();
1002 ZenLog.traceSetConsolidatedZenPolicy(mConsolidatedPolicy, reason);
1003 }
1004 }
1005 }
1006
Beverlyf3b92d22018-09-18 15:13:17 -04001007 private void updateDefaultAutomaticRuleNames() {
1008 for (ZenRule rule : mDefaultConfig.automaticRules.values()) {
1009 if (ZenModeConfig.EVENTS_DEFAULT_RULE_ID.equals(rule.id)) {
1010 rule.name = mContext.getResources()
1011 .getString(R.string.zen_mode_default_events_name);
1012 } else if (ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID.equals(rule.id)) {
1013 rule.name = mContext.getResources()
1014 .getString(R.string.zen_mode_default_every_night_name);
1015 }
1016 }
Beverly30bfbca2017-10-17 14:38:20 -04001017 }
1018
Beverly04216872017-09-28 10:55:32 -04001019 @VisibleForTesting
1020 protected void applyRestrictions() {
Julia Reynolds8f5dabd2020-02-19 08:42:07 -05001021 final boolean zenOn = mZenMode != Global.ZEN_MODE_OFF;
Beverlyd820bc22018-01-11 15:28:33 -05001022 final boolean zenPriorityOnly = mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
Beverly925cde82018-01-23 09:31:23 -05001023 final boolean zenSilence = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
Beverlyd820bc22018-01-11 15:28:33 -05001024 final boolean zenAlarmsOnly = mZenMode == Global.ZEN_MODE_ALARMS;
Julia Reynolds8f5dabd2020-02-19 08:42:07 -05001025 final boolean allowCalls = mConsolidatedPolicy.allowCalls()
1026 && mConsolidatedPolicy.allowCallsFrom() == PRIORITY_SENDERS_ANY;
Beverlyff2df9b2018-10-10 16:54:10 -04001027 final boolean allowRepeatCallers = mConsolidatedPolicy.allowRepeatCallers();
1028 final boolean allowSystem = mConsolidatedPolicy.allowSystem();
1029 final boolean allowMedia = mConsolidatedPolicy.allowMedia();
1030 final boolean allowAlarms = mConsolidatedPolicy.allowAlarms();
John Spurlock8403b752014-12-10 12:47:01 -05001031
1032 // notification restrictions
Julia Reynolds8f5dabd2020-02-19 08:42:07 -05001033 final boolean muteNotifications = zenOn
1034 || (mSuppressedEffects & SUPPRESSED_EFFECT_NOTIFICATIONS) != 0;
John Spurlock056c5192014-04-20 21:52:01 -04001035 // call restrictions
Beverlyd820bc22018-01-11 15:28:33 -05001036 final boolean muteCalls = zenAlarmsOnly
Julia Reynolds8f5dabd2020-02-19 08:42:07 -05001037 || (zenPriorityOnly && !(allowCalls || allowRepeatCallers))
Bryce Lee7219ada2016-04-08 10:54:23 -07001038 || (mSuppressedEffects & SUPPRESSED_EFFECT_CALLS) != 0;
Beverly04216872017-09-28 10:55:32 -04001039 // alarm restrictions
Beverlyff2df9b2018-10-10 16:54:10 -04001040 final boolean muteAlarms = zenPriorityOnly && !allowAlarms;
Beverlyd6964762018-02-16 14:07:03 -05001041 // media restrictions
Beverlyff2df9b2018-10-10 16:54:10 -04001042 final boolean muteMedia = zenPriorityOnly && !allowMedia;
Beverlyd6964762018-02-16 14:07:03 -05001043 // system restrictions
Beverlyff2df9b2018-10-10 16:54:10 -04001044 final boolean muteSystem = zenAlarmsOnly || (zenPriorityOnly && !allowSystem);
Julia Reynolds3fe81be2016-02-03 09:10:06 -05001045 // total silence restrictions
Beverlyff2df9b2018-10-10 16:54:10 -04001046 final boolean muteEverything = zenSilence || (zenPriorityOnly
1047 && ZenModeConfig.areAllZenBehaviorSoundsMuted(mConsolidatedPolicy));
John Spurlock25d01ee2015-06-03 12:17:46 -04001048
Jean-Michel Trivie743bda2016-09-09 11:56:48 -07001049 for (int usage : AudioAttributes.SDK_USAGES) {
1050 final int suppressionBehavior = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage);
Jean-Michel Trivi7a84eae2017-06-20 14:58:18 -07001051 if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NEVER) {
Julia Reynoldse99db5a2019-04-16 12:50:04 -04001052 applyRestrictions(zenPriorityOnly, false /*mute*/, usage);
Jean-Michel Trivi7a84eae2017-06-20 14:58:18 -07001053 } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NOTIFICATION) {
Julia Reynoldse99db5a2019-04-16 12:50:04 -04001054 applyRestrictions(zenPriorityOnly, muteNotifications || muteEverything, usage);
Jean-Michel Trivie743bda2016-09-09 11:56:48 -07001055 } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_CALL) {
Julia Reynoldse99db5a2019-04-16 12:50:04 -04001056 applyRestrictions(zenPriorityOnly, muteCalls || muteEverything, usage);
Beverly04216872017-09-28 10:55:32 -04001057 } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_ALARM) {
Julia Reynoldse99db5a2019-04-16 12:50:04 -04001058 applyRestrictions(zenPriorityOnly, muteAlarms || muteEverything, usage);
Beverlyd6964762018-02-16 14:07:03 -05001059 } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_MEDIA) {
Julia Reynoldse99db5a2019-04-16 12:50:04 -04001060 applyRestrictions(zenPriorityOnly, muteMedia || muteEverything, usage);
Beverlyd6964762018-02-16 14:07:03 -05001061 } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_SYSTEM) {
Beverly738bffd2018-03-12 10:46:17 -04001062 if (usage == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) {
1063 // normally DND will only restrict touch sounds, not haptic feedback/vibrations
Julia Reynoldse99db5a2019-04-16 12:50:04 -04001064 applyRestrictions(zenPriorityOnly, muteSystem || muteEverything, usage,
Beverly738bffd2018-03-12 10:46:17 -04001065 AppOpsManager.OP_PLAY_AUDIO);
Julia Reynoldse99db5a2019-04-16 12:50:04 -04001066 applyRestrictions(zenPriorityOnly, false, usage, AppOpsManager.OP_VIBRATE);
Beverly738bffd2018-03-12 10:46:17 -04001067 } else {
Julia Reynoldse99db5a2019-04-16 12:50:04 -04001068 applyRestrictions(zenPriorityOnly, muteSystem || muteEverything, usage);
Beverly738bffd2018-03-12 10:46:17 -04001069 }
Julia Reynolds3fe81be2016-02-03 09:10:06 -05001070 } else {
Julia Reynoldse99db5a2019-04-16 12:50:04 -04001071 applyRestrictions(zenPriorityOnly, muteEverything, usage);
Julia Reynolds3fe81be2016-02-03 09:10:06 -05001072 }
1073 }
John Spurlock8403b752014-12-10 12:47:01 -05001074 }
John Spurlockae641c92014-06-30 18:11:40 -04001075
Beverlye2d9a232017-11-08 18:14:59 -05001076
Beverly04216872017-09-28 10:55:32 -04001077 @VisibleForTesting
Julia Reynoldse99db5a2019-04-16 12:50:04 -04001078 protected void applyRestrictions(boolean zenPriorityOnly, boolean mute, int usage, int code) {
1079 final long ident = Binder.clearCallingIdentity();
1080 try {
1081 mAppOps.setRestriction(code, usage,
1082 mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
1083 zenPriorityOnly ? mPriorityOnlyDndExemptPackages : null);
1084 } finally {
1085 Binder.restoreCallingIdentity(ident);
Dianne Hackbornbf1b57d2018-03-07 12:42:47 -08001086 }
John Spurlock056c5192014-04-20 21:52:01 -04001087 }
1088
Beverly85f52412018-02-27 10:41:13 -05001089 @VisibleForTesting
Julia Reynoldse99db5a2019-04-16 12:50:04 -04001090 protected void applyRestrictions(boolean zenPriorityOnly, boolean mute, int usage) {
1091 applyRestrictions(zenPriorityOnly, mute, usage, AppOpsManager.OP_VIBRATE);
1092 applyRestrictions(zenPriorityOnly, mute, usage, AppOpsManager.OP_PLAY_AUDIO);
Beverly738bffd2018-03-12 10:46:17 -04001093 }
1094
1095
1096 @VisibleForTesting
Beverly85f52412018-02-27 10:41:13 -05001097 protected void applyZenToRingerMode() {
John Spurlock661f2cf2014-11-17 10:29:10 -05001098 if (mAudioManager == null) return;
John Spurlock661f2cf2014-11-17 10:29:10 -05001099 // force the ringer mode into compliance
1100 final int ringerModeInternal = mAudioManager.getRingerModeInternal();
1101 int newRingerModeInternal = ringerModeInternal;
John Spurlock57627792014-12-11 11:29:54 -05001102 switch (mZenMode) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001103 case Global.ZEN_MODE_NO_INTERRUPTIONS:
John Spurlock4f1163c2015-04-02 17:41:21 -04001104 case Global.ZEN_MODE_ALARMS:
John Spurlock661f2cf2014-11-17 10:29:10 -05001105 if (ringerModeInternal != AudioManager.RINGER_MODE_SILENT) {
Julia Reynolds9b11fdb2015-07-31 09:49:55 -04001106 setPreviousRingerModeSetting(ringerModeInternal);
John Spurlock661f2cf2014-11-17 10:29:10 -05001107 newRingerModeInternal = AudioManager.RINGER_MODE_SILENT;
John Spurlock8c01d882014-07-28 13:37:13 -04001108 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001109 break;
1110 case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
Beverly9e4214d2018-03-26 11:10:10 -04001111 // do not apply zen to ringer, streams zen muted in AudioService
Beverly925cde82018-01-23 09:31:23 -05001112 break;
John Spurlock661f2cf2014-11-17 10:29:10 -05001113 case Global.ZEN_MODE_OFF:
1114 if (ringerModeInternal == AudioManager.RINGER_MODE_SILENT) {
Julia Reynolds9b11fdb2015-07-31 09:49:55 -04001115 newRingerModeInternal = getPreviousRingerModeSetting();
1116 setPreviousRingerModeSetting(null);
John Spurlock661f2cf2014-11-17 10:29:10 -05001117 }
1118 break;
John Spurlock8c01d882014-07-28 13:37:13 -04001119 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001120 if (newRingerModeInternal != -1) {
1121 mAudioManager.setRingerModeInternal(newRingerModeInternal, TAG);
1122 }
1123 }
1124
John Spurlock1c923a32014-04-27 16:42:29 -04001125 private void dispatchOnConfigChanged() {
1126 for (Callback callback : mCallbacks) {
1127 callback.onConfigChanged();
1128 }
1129 }
1130
John Spurlock1fc476d2015-04-14 16:05:20 -04001131 private void dispatchOnPolicyChanged() {
1132 for (Callback callback : mCallbacks) {
1133 callback.onPolicyChanged();
1134 }
1135 }
1136
Beverlyff2df9b2018-10-10 16:54:10 -04001137 private void dispatchOnConsolidatedPolicyChanged() {
1138 for (Callback callback : mCallbacks) {
1139 callback.onConsolidatedPolicyChanged();
1140 }
1141 }
1142
John Spurlock1c923a32014-04-27 16:42:29 -04001143 private void dispatchOnZenModeChanged() {
1144 for (Callback callback : mCallbacks) {
1145 callback.onZenModeChanged();
1146 }
1147 }
1148
Julia Reynolds3ec93302019-07-11 15:27:31 -04001149 private void dispatchOnAutomaticRuleStatusChanged(int userId, String pkg, String id,
1150 int status) {
1151 for (Callback callback : mCallbacks) {
1152 callback.onAutomaticRuleStatusChanged(userId, pkg, id, status);
1153 }
1154 }
1155
John Spurlockb2278d62015-04-07 12:47:12 -04001156 private ZenModeConfig readDefaultConfig(Resources resources) {
1157 XmlResourceParser parser = null;
1158 try {
1159 parser = resources.getXml(R.xml.default_zen_mode_config);
1160 while (parser.next() != XmlPullParser.END_DOCUMENT) {
Julia Reynolds206c7e92016-09-15 10:38:03 -04001161 final ZenModeConfig config = ZenModeConfig.readXml(parser);
John Spurlockb2278d62015-04-07 12:47:12 -04001162 if (config != null) return config;
1163 }
1164 } catch (Exception e) {
1165 Log.w(TAG, "Error reading default zen mode config from resource", e);
1166 } finally {
1167 IoUtils.closeQuietly(parser);
1168 }
1169 return new ZenModeConfig();
1170 }
1171
John Spurlockb2278d62015-04-07 12:47:12 -04001172 private static int zenSeverity(int zen) {
1173 switch (zen) {
1174 case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return 1;
1175 case Global.ZEN_MODE_ALARMS: return 2;
1176 case Global.ZEN_MODE_NO_INTERRUPTIONS: return 3;
1177 default: return 0;
1178 }
1179 }
1180
Chris Wren93165692020-05-15 16:12:41 -04001181 /**
1182 * Generate pulled atoms about do not disturb configurations.
1183 */
1184 public void pullRules(List<StatsEvent> events) {
1185 synchronized (mConfig) {
1186 final int numConfigs = mConfigs.size();
1187 int id = 0;
1188 for (int i = 0; i < numConfigs; i++) {
1189 final int user = mConfigs.keyAt(i);
1190 final ZenModeConfig config = mConfigs.valueAt(i);
1191 SysUiStatsEvent.Builder data = mStatsEventBuilderFactory.newBuilder()
1192 .setAtomId(DND_MODE_RULE)
1193 .writeInt(user)
1194 .writeBoolean(config.manualRule != null) // enabled
1195 .writeBoolean(config.areChannelsBypassingDnd)
1196 .writeInt(ROOT_CONFIG)
1197 .writeString("") // name, empty for root config
1198 .writeInt(Process.SYSTEM_UID) // system owns root config
1199 .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
1200 .writeByteArray(config.toZenPolicy().toProto());
1201 events.add(data.build());
1202 if (config.manualRule != null && config.manualRule.enabler != null) {
1203 ruleToProto(user, config.manualRule, events);
1204 }
1205 for (ZenRule rule : config.automaticRules.values()) {
1206 ruleToProto(user, rule, events);
1207 }
1208 }
1209 }
1210 }
1211
1212 private void ruleToProto(int user, ZenRule rule, List<StatsEvent> events) {
1213 // Make the ID safe.
1214 String id = rule.id == null ? "" : rule.id;
1215 if (!ZenModeConfig.DEFAULT_RULE_IDS.contains(id)) {
1216 id = "";
1217 }
1218
1219 // Look for packages and enablers, enablers get priority.
1220 String pkg = rule.pkg == null ? "" : rule.pkg;
1221 if (rule.enabler != null) {
1222 pkg = rule.enabler;
1223 id = ZenModeConfig.MANUAL_RULE_ID;
1224 }
1225
1226 // TODO: fetch the uid from the package manager
1227 int uid = "android".equals(pkg) ? Process.SYSTEM_UID : 0;
1228
1229 SysUiStatsEvent.Builder data;
1230 data = mStatsEventBuilderFactory.newBuilder()
1231 .setAtomId(DND_MODE_RULE)
1232 .writeInt(user)
1233 .writeBoolean(rule.enabled)
1234 .writeBoolean(false) // channels_bypassing unused for rules
1235 .writeInt(rule.zenMode)
1236 .writeString(id)
1237 .writeInt(uid)
1238 .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
1239 byte[] policyProto = new byte[]{};
1240 if (rule.zenPolicy != null) {
1241 policyProto = rule.zenPolicy.toProto();
1242 }
1243 data.writeByteArray(policyProto);
1244 events.add(data.build());
1245 }
1246
Beverly85f52412018-02-27 10:41:13 -05001247 @VisibleForTesting
1248 protected final class RingerModeDelegate implements AudioManagerInternal.RingerModeDelegate {
John Spurlockb2278d62015-04-07 12:47:12 -04001249 @Override
1250 public String toString() {
1251 return TAG;
1252 }
1253
1254 @Override
1255 public int onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller,
1256 int ringerModeExternal, VolumePolicy policy) {
1257 final boolean isChange = ringerModeOld != ringerModeNew;
1258
1259 int ringerModeExternalOut = ringerModeNew;
1260
Beverlye4ee1cc2018-03-06 17:21:08 -05001261 if (mZenMode == Global.ZEN_MODE_OFF
1262 || (mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
Beverly85dfc2e2019-09-20 11:26:34 -04001263 && !ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(mConfig))) {
Beverlye4ee1cc2018-03-06 17:21:08 -05001264 // in priority only with ringer not muted, save ringer mode changes
1265 // in dnd off, save ringer mode changes
1266 setPreviousRingerModeSetting(ringerModeNew);
1267 }
John Spurlockb2278d62015-04-07 12:47:12 -04001268 int newZen = -1;
1269 switch (ringerModeNew) {
1270 case AudioManager.RINGER_MODE_SILENT:
1271 if (isChange && policy.doNotDisturbWhenSilent) {
Beverly925cde82018-01-23 09:31:23 -05001272 if (mZenMode == Global.ZEN_MODE_OFF) {
Julia Reynoldsf3252be2018-01-17 09:26:21 -05001273 newZen = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
John Spurlockb2278d62015-04-07 12:47:12 -04001274 }
Julia Reynolds9b11fdb2015-07-31 09:49:55 -04001275 setPreviousRingerModeSetting(ringerModeOld);
John Spurlockb2278d62015-04-07 12:47:12 -04001276 }
1277 break;
1278 case AudioManager.RINGER_MODE_VIBRATE:
1279 case AudioManager.RINGER_MODE_NORMAL:
1280 if (isChange && ringerModeOld == AudioManager.RINGER_MODE_SILENT
1281 && (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS
Beverly925cde82018-01-23 09:31:23 -05001282 || mZenMode == Global.ZEN_MODE_ALARMS
1283 || (mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
Beverly85dfc2e2019-09-20 11:26:34 -04001284 && ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(
Beverlyd6964762018-02-16 14:07:03 -05001285 mConfig)))) {
John Spurlockb2278d62015-04-07 12:47:12 -04001286 newZen = Global.ZEN_MODE_OFF;
1287 } else if (mZenMode != Global.ZEN_MODE_OFF) {
1288 ringerModeExternalOut = AudioManager.RINGER_MODE_SILENT;
1289 }
1290 break;
1291 }
Beverly85f52412018-02-27 10:41:13 -05001292
John Spurlockb2278d62015-04-07 12:47:12 -04001293 if (newZen != -1) {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04001294 setManualZenMode(newZen, null, "ringerModeInternal", null,
1295 false /*setRingerMode*/);
John Spurlockb2278d62015-04-07 12:47:12 -04001296 }
John Spurlockb2278d62015-04-07 12:47:12 -04001297 if (isChange || newZen != -1 || ringerModeExternal != ringerModeExternalOut) {
1298 ZenLog.traceSetRingerModeInternal(ringerModeOld, ringerModeNew, caller,
1299 ringerModeExternal, ringerModeExternalOut);
1300 }
1301 return ringerModeExternalOut;
1302 }
1303
1304 @Override
1305 public int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller,
1306 int ringerModeInternal, VolumePolicy policy) {
1307 int ringerModeInternalOut = ringerModeNew;
1308 final boolean isChange = ringerModeOld != ringerModeNew;
1309 final boolean isVibrate = ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE;
1310
1311 int newZen = -1;
1312 switch (ringerModeNew) {
1313 case AudioManager.RINGER_MODE_SILENT:
1314 if (isChange) {
John Spurlockb2278d62015-04-07 12:47:12 -04001315 ringerModeInternalOut = isVibrate ? AudioManager.RINGER_MODE_VIBRATE
John Spurlock05715ec2015-05-13 11:19:19 -04001316 : AudioManager.RINGER_MODE_SILENT;
John Spurlockb2278d62015-04-07 12:47:12 -04001317 } else {
1318 ringerModeInternalOut = ringerModeInternal;
1319 }
1320 break;
1321 case AudioManager.RINGER_MODE_VIBRATE:
1322 case AudioManager.RINGER_MODE_NORMAL:
1323 if (mZenMode != Global.ZEN_MODE_OFF) {
1324 newZen = Global.ZEN_MODE_OFF;
1325 }
1326 break;
1327 }
1328 if (newZen != -1) {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04001329 setManualZenMode(newZen, null, "ringerModeExternal", caller,
1330 false /*setRingerMode*/);
John Spurlockb2278d62015-04-07 12:47:12 -04001331 }
1332
1333 ZenLog.traceSetRingerModeExternal(ringerModeOld, ringerModeNew, caller,
1334 ringerModeInternal, ringerModeInternalOut);
1335 return ringerModeInternalOut;
1336 }
John Spurlockd9c75db2015-04-28 11:19:13 -04001337
1338 @Override
1339 public boolean canVolumeDownEnterSilent() {
1340 return mZenMode == Global.ZEN_MODE_OFF;
1341 }
John Spurlock50ced3f2015-05-11 16:00:09 -04001342
1343 @Override
1344 public int getRingerModeAffectedStreams(int streams) {
Beverly85dfc2e2019-09-20 11:26:34 -04001345 // ringtone, notification and system streams are always affected by ringer mode
1346 // zen muting is handled in AudioService.java's mZenModeAffectedStreams
John Spurlock50ced3f2015-05-11 16:00:09 -04001347 streams |= (1 << AudioSystem.STREAM_RING) |
Beverlyd6964762018-02-16 14:07:03 -05001348 (1 << AudioSystem.STREAM_NOTIFICATION) |
1349 (1 << AudioSystem.STREAM_SYSTEM);
John Spurlock50ced3f2015-05-11 16:00:09 -04001350
John Spurlock50ced3f2015-05-11 16:00:09 -04001351 if (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
Julia Reynoldsa6b653f2020-03-09 11:26:19 -04001352 // alarm and music and streams affected by ringer mode (cannot be adjusted) when in
Beverly85dfc2e2019-09-20 11:26:34 -04001353 // total silence
John Spurlock50ced3f2015-05-11 16:00:09 -04001354 streams |= (1 << AudioSystem.STREAM_ALARM) |
Julia Reynoldsa6b653f2020-03-09 11:26:19 -04001355 (1 << AudioSystem.STREAM_MUSIC) |
1356 (1 << AudioSystem.STREAM_ASSISTANT);
John Spurlock50ced3f2015-05-11 16:00:09 -04001357 } else {
1358 streams &= ~((1 << AudioSystem.STREAM_ALARM) |
Julia Reynoldsa6b653f2020-03-09 11:26:19 -04001359 (1 << AudioSystem.STREAM_MUSIC) |
1360 (1 << AudioSystem.STREAM_ASSISTANT)
1361 );
Beverlyd6964762018-02-16 14:07:03 -05001362 }
John Spurlock50ced3f2015-05-11 16:00:09 -04001363 return streams;
1364 }
John Spurlockb2278d62015-04-07 12:47:12 -04001365 }
1366
1367 private final class SettingsObserver extends ContentObserver {
John Spurlock056c5192014-04-20 21:52:01 -04001368 private final Uri ZEN_MODE = Global.getUriFor(Global.ZEN_MODE);
1369
1370 public SettingsObserver(Handler handler) {
1371 super(handler);
1372 }
1373
1374 public void observe() {
1375 final ContentResolver resolver = mContext.getContentResolver();
1376 resolver.registerContentObserver(ZEN_MODE, false /*notifyForDescendents*/, this);
1377 update(null);
1378 }
1379
1380 @Override
1381 public void onChange(boolean selfChange, Uri uri) {
1382 update(uri);
1383 }
1384
1385 public void update(Uri uri) {
1386 if (ZEN_MODE.equals(uri)) {
John Spurlockb2278d62015-04-07 12:47:12 -04001387 if (mZenMode != getZenModeSetting()) {
1388 if (DEBUG) Log.d(TAG, "Fixing zen mode setting");
1389 setZenModeSetting(mZenMode);
1390 }
John Spurlock056c5192014-04-20 21:52:01 -04001391 }
1392 }
1393 }
1394
Beverly3bae4e52018-02-07 12:32:02 -05001395 private void showZenUpgradeNotification(int zen) {
Nicka485ec62018-07-03 11:32:39 -07001396 final boolean isWatch = mContext.getPackageManager().hasSystemFeature(
1397 PackageManager.FEATURE_WATCH);
Beverly3bae4e52018-02-07 12:32:02 -05001398 final boolean showNotification = mIsBootComplete
Julia Reynolds76bfa602018-04-23 09:38:47 -04001399 && zen != Global.ZEN_MODE_OFF
Nicka485ec62018-07-03 11:32:39 -07001400 && !isWatch
Beverly9087cd12018-09-21 15:30:49 -04001401 && Settings.Secure.getInt(mContext.getContentResolver(),
Beverly6c60b902018-08-17 10:10:46 -04001402 Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0) != 0
Beverly9087cd12018-09-21 15:30:49 -04001403 && Settings.Secure.getInt(mContext.getContentResolver(),
Beverly6c60b902018-08-17 10:10:46 -04001404 Settings.Secure.ZEN_SETTINGS_UPDATED, 0) != 1;
Beverly3bae4e52018-02-07 12:32:02 -05001405
Nicka485ec62018-07-03 11:32:39 -07001406 if (isWatch) {
Beverly9087cd12018-09-21 15:30:49 -04001407 Settings.Secure.putInt(mContext.getContentResolver(),
Beverly91d0a632018-07-02 16:45:00 -04001408 Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0);
Nicka485ec62018-07-03 11:32:39 -07001409 }
1410
Beverly3bae4e52018-02-07 12:32:02 -05001411 if (showNotification) {
1412 mNotificationManager.notify(TAG, SystemMessage.NOTE_ZEN_UPGRADE,
1413 createZenUpgradeNotification());
Beverly91d0a632018-07-02 16:45:00 -04001414 Settings.Secure.putInt(mContext.getContentResolver(),
1415 Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0);
Beverly3bae4e52018-02-07 12:32:02 -05001416 }
1417 }
1418
1419 @VisibleForTesting
1420 protected Notification createZenUpgradeNotification() {
Beverly3bae4e52018-02-07 12:32:02 -05001421 final Bundle extras = new Bundle();
1422 extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
1423 mContext.getResources().getString(R.string.global_action_settings));
Julia Reynolds0b8455d2018-03-14 11:38:44 -04001424 int title = R.string.zen_upgrade_notification_title;
1425 int content = R.string.zen_upgrade_notification_content;
Julia Reynolds76bfa602018-04-23 09:38:47 -04001426 int drawable = R.drawable.ic_zen_24dp;
Julia Reynolds0b8455d2018-03-14 11:38:44 -04001427 if (NotificationManager.Policy.areAllVisualEffectsSuppressed(
Beverlyff2df9b2018-10-10 16:54:10 -04001428 getConsolidatedNotificationPolicy().suppressedVisualEffects)) {
Julia Reynolds0b8455d2018-03-14 11:38:44 -04001429 title = R.string.zen_upgrade_notification_visd_title;
1430 content = R.string.zen_upgrade_notification_visd_content;
Julia Reynolds76bfa602018-04-23 09:38:47 -04001431 drawable = R.drawable.ic_dnd_block_notifications;
Julia Reynolds0b8455d2018-03-14 11:38:44 -04001432 }
Julia Reynolds76bfa602018-04-23 09:38:47 -04001433
Julia Reynolds9aa1c9e2018-04-09 11:31:15 -04001434 Intent onboardingIntent = new Intent(Settings.ZEN_MODE_ONBOARDING);
1435 onboardingIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
Julia Reynolds0b8455d2018-03-14 11:38:44 -04001436 return new Notification.Builder(mContext, SystemNotificationChannels.DO_NOT_DISTURB)
Julia Reynolds9aa1c9e2018-04-09 11:31:15 -04001437 .setAutoCancel(true)
Beverlyd8b15ee2018-02-13 14:37:38 -05001438 .setSmallIcon(R.drawable.ic_settings_24dp)
Julia Reynolds76bfa602018-04-23 09:38:47 -04001439 .setLargeIcon(Icon.createWithResource(mContext, drawable))
Julia Reynolds0b8455d2018-03-14 11:38:44 -04001440 .setContentTitle(mContext.getResources().getString(title))
1441 .setContentText(mContext.getResources().getString(content))
Julia Reynolds9aa1c9e2018-04-09 11:31:15 -04001442 .setContentIntent(PendingIntent.getActivity(mContext, 0, onboardingIntent,
Julia Reynoldsd7f2b7d2020-05-08 14:14:25 -04001443 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
Beverly3bae4e52018-02-07 12:32:02 -05001444 .setAutoCancel(true)
1445 .setLocalOnly(true)
1446 .addExtras(extras)
Julia Reynolds0b8455d2018-03-14 11:38:44 -04001447 .setStyle(new Notification.BigTextStyle())
Beverly3bae4e52018-02-07 12:32:02 -05001448 .build();
1449 }
1450
Chris Wren98d235b2015-05-27 18:25:17 -04001451 private final class Metrics extends Callback {
Julia Reynolds3dfdde02018-10-08 09:17:56 -04001452 private static final String COUNTER_MODE_PREFIX = "dnd_mode_";
1453 private static final String COUNTER_TYPE_PREFIX = "dnd_type_";
1454 private static final int DND_OFF = 0;
1455 private static final int DND_ON_MANUAL = 1;
1456 private static final int DND_ON_AUTOMATIC = 2;
1457 private static final String COUNTER_RULE = "dnd_rule_count";
Chris Wren98d235b2015-05-27 18:25:17 -04001458 private static final long MINIMUM_LOG_PERIOD_MS = 60 * 1000;
1459
Julia Reynolds3dfdde02018-10-08 09:17:56 -04001460 // Total silence, alarms only, priority only
Chris Wren98d235b2015-05-27 18:25:17 -04001461 private int mPreviousZenMode = -1;
Julia Reynolds3dfdde02018-10-08 09:17:56 -04001462 private long mModeLogTimeMs = 0L;
1463
1464 private int mNumZenRules = -1;
1465 private long mRuleCountLogTime = 0L;
1466
1467 // automatic (1) vs manual (0) vs dnd off (2)
1468 private int mPreviousZenType = -1;
1469 private long mTypeLogTimeMs = 0L;
Chris Wren98d235b2015-05-27 18:25:17 -04001470
1471 @Override
1472 void onZenModeChanged() {
1473 emit();
1474 }
1475
Julia Reynolds3dfdde02018-10-08 09:17:56 -04001476 @Override
1477 void onConfigChanged() {
1478 emit();
1479 }
1480
Chris Wren98d235b2015-05-27 18:25:17 -04001481 private void emit() {
1482 mHandler.postMetricsTimer();
Julia Reynolds3dfdde02018-10-08 09:17:56 -04001483 emitZenMode();
1484 emitRules();
1485 emitDndType();
1486 }
1487
1488 private void emitZenMode() {
Chris Wren98d235b2015-05-27 18:25:17 -04001489 final long now = SystemClock.elapsedRealtime();
Julia Reynolds3dfdde02018-10-08 09:17:56 -04001490 final long since = (now - mModeLogTimeMs);
Chris Wren98d235b2015-05-27 18:25:17 -04001491 if (mPreviousZenMode != mZenMode || since > MINIMUM_LOG_PERIOD_MS) {
1492 if (mPreviousZenMode != -1) {
Julia Reynolds3dfdde02018-10-08 09:17:56 -04001493 MetricsLogger.count(
1494 mContext, COUNTER_MODE_PREFIX + mPreviousZenMode, (int) since);
Chris Wren98d235b2015-05-27 18:25:17 -04001495 }
1496 mPreviousZenMode = mZenMode;
Julia Reynolds3dfdde02018-10-08 09:17:56 -04001497 mModeLogTimeMs = now;
1498 }
1499 }
1500
1501 private void emitRules() {
1502 final long now = SystemClock.elapsedRealtime();
1503 final long since = (now - mRuleCountLogTime);
1504 synchronized (mConfig) {
1505 int numZenRules = mConfig.automaticRules.size();
1506 if (mNumZenRules != numZenRules
1507 || since > MINIMUM_LOG_PERIOD_MS) {
1508 if (mNumZenRules != -1) {
1509 MetricsLogger.count(mContext, COUNTER_RULE,
1510 numZenRules - mNumZenRules);
1511 }
1512 mNumZenRules = numZenRules;
1513
1514 mRuleCountLogTime = since;
1515 }
1516 }
1517 }
1518
1519 private void emitDndType() {
1520 final long now = SystemClock.elapsedRealtime();
1521 final long since = (now - mTypeLogTimeMs);
1522 synchronized (mConfig) {
1523 boolean dndOn = mZenMode != Global.ZEN_MODE_OFF;
1524 int zenType = !dndOn ? DND_OFF
1525 : (mConfig.manualRule != null) ? DND_ON_MANUAL : DND_ON_AUTOMATIC;
1526 if (zenType != mPreviousZenType
1527 || since > MINIMUM_LOG_PERIOD_MS) {
1528 if (mPreviousZenType != -1) {
1529 MetricsLogger.count(
1530 mContext, COUNTER_TYPE_PREFIX + mPreviousZenType, (int) since);
1531 }
1532 mTypeLogTimeMs = now;
1533 mPreviousZenType = zenType;
1534 }
Chris Wren98d235b2015-05-27 18:25:17 -04001535 }
1536 }
1537 }
1538
John Spurlockb2278d62015-04-07 12:47:12 -04001539 private final class H extends Handler {
John Spurlock57627792014-12-11 11:29:54 -05001540 private static final int MSG_DISPATCH = 1;
Chris Wren98d235b2015-05-27 18:25:17 -04001541 private static final int MSG_METRICS = 2;
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001542 private static final int MSG_APPLY_CONFIG = 4;
Eric Laurente0ced4d2015-09-30 17:44:28 -07001543
1544 private final class ConfigMessageData {
1545 public final ZenModeConfig config;
Julia Reynolds8f056002018-07-13 15:12:29 -04001546 public ComponentName triggeringComponent;
Eric Laurente0ced4d2015-09-30 17:44:28 -07001547 public final String reason;
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001548 public final boolean setRingerMode;
Eric Laurente0ced4d2015-09-30 17:44:28 -07001549
Julia Reynolds8f056002018-07-13 15:12:29 -04001550 ConfigMessageData(ZenModeConfig config, String reason,
1551 ComponentName triggeringComponent, boolean setRingerMode) {
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001552 this.config = config;
1553 this.reason = reason;
1554 this.setRingerMode = setRingerMode;
Julia Reynolds8f056002018-07-13 15:12:29 -04001555 this.triggeringComponent = triggeringComponent;
Eric Laurente0ced4d2015-09-30 17:44:28 -07001556 }
1557 }
Chris Wren98d235b2015-05-27 18:25:17 -04001558
1559 private static final long METRICS_PERIOD_MS = 6 * 60 * 60 * 1000;
John Spurlock661f2cf2014-11-17 10:29:10 -05001560
1561 private H(Looper looper) {
1562 super(looper);
John Spurlock056c5192014-04-20 21:52:01 -04001563 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001564
John Spurlock57627792014-12-11 11:29:54 -05001565 private void postDispatchOnZenModeChanged() {
1566 removeMessages(MSG_DISPATCH);
1567 sendEmptyMessage(MSG_DISPATCH);
John Spurlock661f2cf2014-11-17 10:29:10 -05001568 }
1569
Chris Wren98d235b2015-05-27 18:25:17 -04001570 private void postMetricsTimer() {
1571 removeMessages(MSG_METRICS);
1572 sendEmptyMessageDelayed(MSG_METRICS, METRICS_PERIOD_MS);
1573 }
1574
Julia Reynolds8f056002018-07-13 15:12:29 -04001575 private void postApplyConfig(ZenModeConfig config, String reason,
1576 ComponentName triggeringComponent, boolean setRingerMode) {
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001577 sendMessage(obtainMessage(MSG_APPLY_CONFIG,
Julia Reynolds8f056002018-07-13 15:12:29 -04001578 new ConfigMessageData(config, reason, triggeringComponent, setRingerMode)));
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001579 }
1580
John Spurlock661f2cf2014-11-17 10:29:10 -05001581 @Override
1582 public void handleMessage(Message msg) {
John Spurlock57627792014-12-11 11:29:54 -05001583 switch (msg.what) {
1584 case MSG_DISPATCH:
1585 dispatchOnZenModeChanged();
John Spurlock661f2cf2014-11-17 10:29:10 -05001586 break;
Chris Wren98d235b2015-05-27 18:25:17 -04001587 case MSG_METRICS:
1588 mMetrics.emit();
1589 break;
Julia Reynoldsd82e9812016-04-19 13:27:41 -04001590 case MSG_APPLY_CONFIG:
1591 ConfigMessageData applyConfigData = (ConfigMessageData) msg.obj;
1592 applyConfig(applyConfigData.config, applyConfigData.reason,
Julia Reynolds8f056002018-07-13 15:12:29 -04001593 applyConfigData.triggeringComponent, applyConfigData.setRingerMode);
John Spurlock661f2cf2014-11-17 10:29:10 -05001594 }
1595 }
1596 }
John Spurlock056c5192014-04-20 21:52:01 -04001597
John Spurlock1c923a32014-04-27 16:42:29 -04001598 public static class Callback {
1599 void onConfigChanged() {}
1600 void onZenModeChanged() {}
John Spurlock1fc476d2015-04-14 16:05:20 -04001601 void onPolicyChanged() {}
Beverlyff2df9b2018-10-10 16:54:10 -04001602 void onConsolidatedPolicyChanged() {}
Julia Reynolds3ec93302019-07-11 15:27:31 -04001603 void onAutomaticRuleStatusChanged(int userId, String pkg, String id, int status) {}
John Spurlock056c5192014-04-20 21:52:01 -04001604 }
John Spurlock056c5192014-04-20 21:52:01 -04001605}