1 /** 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 17 package com.android.server.notification; 18 19 import static android.media.AudioAttributes.USAGE_NOTIFICATION; 20 import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; 21 import static android.media.AudioAttributes.USAGE_UNKNOWN; 22 import static android.media.AudioAttributes.USAGE_VIRTUAL_SOURCE; 23 24 import android.app.AppOpsManager; 25 import android.app.AutomaticZenRule; 26 import android.app.NotificationManager; 27 import android.app.NotificationManager.Policy; 28 import android.content.ComponentName; 29 import android.content.ContentResolver; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.content.pm.PackageManager; 33 import android.content.pm.ResolveInfo; 34 import android.content.pm.ServiceInfo; 35 import android.content.res.Resources; 36 import android.content.res.XmlResourceParser; 37 import android.database.ContentObserver; 38 import android.media.AudioAttributes; 39 import android.media.AudioManager; 40 import android.media.AudioManagerInternal; 41 import android.media.AudioSystem; 42 import android.media.VolumePolicy; 43 import android.net.Uri; 44 import android.os.Binder; 45 import android.os.Bundle; 46 import android.os.Handler; 47 import android.os.Looper; 48 import android.os.Message; 49 import android.os.Process; 50 import android.os.SystemClock; 51 import android.os.UserHandle; 52 import android.provider.Settings.Global; 53 import android.service.notification.ConditionProviderService; 54 import android.service.notification.ZenModeConfig; 55 import android.service.notification.ZenModeConfig.EventInfo; 56 import android.service.notification.ZenModeConfig.ScheduleInfo; 57 import android.service.notification.ZenModeConfig.ZenRule; 58 import android.util.AndroidRuntimeException; 59 import android.util.Log; 60 import android.util.SparseArray; 61 62 import com.android.internal.R; 63 import com.android.internal.logging.MetricsLogger; 64 import com.android.server.LocalServices; 65 66 import libcore.io.IoUtils; 67 68 import org.xmlpull.v1.XmlPullParser; 69 import org.xmlpull.v1.XmlPullParserException; 70 import org.xmlpull.v1.XmlSerializer; 71 72 import java.io.IOException; 73 import java.io.PrintWriter; 74 import java.util.ArrayList; 75 import java.util.List; 76 import java.util.Objects; 77 78 /** 79 * NotificationManagerService helper for functionality related to zen mode. 80 */ 81 public class ZenModeHelper { 82 static final String TAG = "ZenModeHelper"; 83 static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 84 85 // 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 88 private final Context mContext; 89 private final H mHandler; 90 private final SettingsObserver mSettingsObserver; 91 private final AppOpsManager mAppOps; 92 private final ZenModeConfig mDefaultConfig; 93 private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); 94 private final ZenModeFiltering mFiltering; 95 private final RingerModeDelegate mRingerModeDelegate = new RingerModeDelegate(); 96 private final ZenModeConditions mConditions; 97 private final SparseArray<ZenModeConfig> mConfigs = new SparseArray<>(); 98 private final Metrics mMetrics = new Metrics(); 99 private final ConditionProviders.Config mServiceConfig; 100 101 private int mZenMode; 102 private int mUser = UserHandle.USER_SYSTEM; 103 private ZenModeConfig mConfig; 104 private AudioManagerInternal mAudioManager; 105 private PackageManager mPm; 106 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; 112 ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders)113 public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) { 114 mContext = context; 115 mHandler = new H(looper); 116 addCallback(mMetrics); 117 mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); 118 mDefaultConfig = readDefaultConfig(context.getResources()); 119 appendDefaultScheduleRules(mDefaultConfig); 120 appendDefaultEventRules(mDefaultConfig); 121 mConfig = mDefaultConfig; 122 mConfigs.put(UserHandle.USER_SYSTEM, mConfig); 123 mSettingsObserver = new SettingsObserver(mHandler); 124 mSettingsObserver.observe(); 125 mFiltering = new ZenModeFiltering(mContext); 126 mConditions = new ZenModeConditions(this, conditionProviders); 127 mServiceConfig = conditionProviders.getConfig(); 128 } 129 getLooper()130 public Looper getLooper() { 131 return mHandler.getLooper(); 132 } 133 134 @Override toString()135 public String toString() { 136 return TAG; 137 } 138 matchesCallFilter(UserHandle userHandle, Bundle extras, ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity)139 public boolean matchesCallFilter(UserHandle userHandle, Bundle extras, 140 ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity) { 141 synchronized (mConfig) { 142 return ZenModeFiltering.matchesCallFilter(mContext, mZenMode, mConfig, userHandle, 143 extras, validator, contactsTimeoutMs, timeoutAffinity); 144 } 145 } 146 isCall(NotificationRecord record)147 public boolean isCall(NotificationRecord record) { 148 return mFiltering.isCall(record); 149 } 150 recordCaller(NotificationRecord record)151 public void recordCaller(NotificationRecord record) { 152 mFiltering.recordCall(record); 153 } 154 shouldIntercept(NotificationRecord record)155 public boolean shouldIntercept(NotificationRecord record) { 156 synchronized (mConfig) { 157 return mFiltering.shouldIntercept(mZenMode, mConfig, record); 158 } 159 } 160 shouldSuppressWhenScreenOff()161 public boolean shouldSuppressWhenScreenOff() { 162 synchronized (mConfig) { 163 return !mConfig.allowWhenScreenOff; 164 } 165 } 166 shouldSuppressWhenScreenOn()167 public boolean shouldSuppressWhenScreenOn() { 168 synchronized (mConfig) { 169 return !mConfig.allowWhenScreenOn; 170 } 171 } 172 addCallback(Callback callback)173 public void addCallback(Callback callback) { 174 mCallbacks.add(callback); 175 } 176 removeCallback(Callback callback)177 public void removeCallback(Callback callback) { 178 mCallbacks.remove(callback); 179 } 180 initZenMode()181 public void initZenMode() { 182 if (DEBUG) Log.d(TAG, "initZenMode"); 183 evaluateZenMode("init", true /*setRingerMode*/); 184 } 185 onSystemReady()186 public void onSystemReady() { 187 if (DEBUG) Log.d(TAG, "onSystemReady"); 188 mAudioManager = LocalServices.getService(AudioManagerInternal.class); 189 if (mAudioManager != null) { 190 mAudioManager.setRingerModeDelegate(mRingerModeDelegate); 191 } 192 mPm = mContext.getPackageManager(); 193 mHandler.postMetricsTimer(); 194 cleanUpZenRules(); 195 evaluateZenMode("onSystemReady", true); 196 } 197 onUserSwitched(int user)198 public void onUserSwitched(int user) { 199 loadConfigForUser(user, "onUserSwitched"); 200 } 201 onUserRemoved(int user)202 public void onUserRemoved(int user) { 203 if (user < UserHandle.USER_SYSTEM) return; 204 if (DEBUG) Log.d(TAG, "onUserRemoved u=" + user); 205 mConfigs.remove(user); 206 } 207 onUserUnlocked(int user)208 public void onUserUnlocked(int user) { 209 loadConfigForUser(user, "onUserUnlocked"); 210 } 211 loadConfigForUser(int user, String reason)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 getZenModeListenerInterruptionFilter()228 public int getZenModeListenerInterruptionFilter() { 229 return NotificationManager.zenModeToInterruptionFilter(mZenMode); 230 } 231 requestFromListener(ComponentName name, int filter)232 public void requestFromListener(ComponentName name, int filter) { 233 final int newZen = NotificationManager.zenModeFromInterruptionFilter(filter, -1); 234 if (newZen != -1) { 235 setManualZenMode(newZen, null, name != null ? name.getPackageName() : null, 236 "listener:" + (name != null ? name.flattenToShortString() : null)); 237 } 238 } 239 setSuppressedEffects(long suppressedEffects)240 public void setSuppressedEffects(long suppressedEffects) { 241 if (mSuppressedEffects == suppressedEffects) return; 242 mSuppressedEffects = suppressedEffects; 243 applyRestrictions(); 244 } 245 getSuppressedEffects()246 public long getSuppressedEffects() { 247 return mSuppressedEffects; 248 } 249 getZenMode()250 public int getZenMode() { 251 return mZenMode; 252 } 253 getZenRules()254 public List<ZenRule> getZenRules() { 255 List<ZenRule> rules = new ArrayList<>(); 256 synchronized (mConfig) { 257 if (mConfig == null) return rules; 258 for (ZenRule rule : mConfig.automaticRules.values()) { 259 if (canManageAutomaticZenRule(rule)) { 260 rules.add(rule); 261 } 262 } 263 } 264 return rules; 265 } 266 getAutomaticZenRule(String id)267 public AutomaticZenRule getAutomaticZenRule(String id) { 268 ZenRule rule; 269 synchronized (mConfig) { 270 if (mConfig == null) return null; 271 rule = mConfig.automaticRules.get(id); 272 } 273 if (rule == null) return null; 274 if (canManageAutomaticZenRule(rule)) { 275 return createAutomaticZenRule(rule); 276 } 277 return null; 278 } 279 addAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason)280 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) { 281 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 287 int ruleInstanceLimit = -1; 288 if (owner.metaData != null) { 289 ruleInstanceLimit = owner.metaData.getInt( 290 ConditionProviderService.META_DATA_RULE_INSTANCE_LIMIT, -1); 291 } 292 if (ruleInstanceLimit > 0 && ruleInstanceLimit 293 < (getCurrentInstanceCount(automaticZenRule.getOwner()) + 1)) { 294 throw new IllegalArgumentException("Rule instance limit exceeded"); 295 } 296 } 297 298 ZenModeConfig newConfig; 299 synchronized (mConfig) { 300 if (mConfig == null) { 301 throw new AndroidRuntimeException("Could not create rule"); 302 } 303 if (DEBUG) { 304 Log.d(TAG, "addAutomaticZenRule rule= " + automaticZenRule + " reason=" + reason); 305 } 306 newConfig = mConfig.copy(); 307 ZenRule rule = new ZenRule(); 308 populateZenRule(automaticZenRule, rule, true); 309 newConfig.automaticRules.put(rule.id, rule); 310 if (setConfigLocked(newConfig, reason, true)) { 311 return rule.id; 312 } else { 313 throw new AndroidRuntimeException("Could not create rule"); 314 } 315 } 316 } 317 updateAutomaticZenRule(String ruleId, AutomaticZenRule automaticZenRule, String reason)318 public boolean updateAutomaticZenRule(String ruleId, AutomaticZenRule automaticZenRule, 319 String reason) { 320 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(); 328 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 } 337 } 338 populateZenRule(automaticZenRule, rule, false); 339 newConfig.automaticRules.put(ruleId, rule); 340 return setConfigLocked(newConfig, reason, true); 341 } 342 } 343 removeAutomaticZenRule(String id, String reason)344 public boolean removeAutomaticZenRule(String id, String reason) { 345 ZenModeConfig newConfig; 346 synchronized (mConfig) { 347 if (mConfig == null) return false; 348 newConfig = mConfig.copy(); 349 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 } 358 return setConfigLocked(newConfig, reason, true); 359 } 360 } 361 removeAutomaticZenRules(String packageName, String reason)362 public boolean removeAutomaticZenRules(String packageName, String reason) { 363 ZenModeConfig newConfig; 364 synchronized (mConfig) { 365 if (mConfig == null) return false; 366 newConfig = mConfig.copy(); 367 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 } 373 } 374 return setConfigLocked(newConfig, reason, true); 375 } 376 } 377 getCurrentInstanceCount(ComponentName owner)378 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 canManageAutomaticZenRule(ZenRule rule)390 public boolean canManageAutomaticZenRule(ZenRule rule) { 391 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) 395 == PackageManager.PERMISSION_GRANTED) { 396 return true; 397 } else { 398 String[] packages = mPm.getPackagesForUid(Binder.getCallingUid()); 399 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 isSystemRule(AutomaticZenRule rule)411 private boolean isSystemRule(AutomaticZenRule rule) { 412 return ZenModeConfig.SYSTEM_AUTHORITY.equals(rule.getOwner().getPackageName()); 413 } 414 getServiceInfo(ComponentName owner)415 private ServiceInfo getServiceInfo(ComponentName owner) { 416 Intent queryIntent = new Intent(); 417 queryIntent.setComponent(owner); 418 List<ResolveInfo> installedServices = mPm.queryIntentServicesAsUser( 419 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)) { 427 return info; 428 } 429 } 430 } 431 return null; 432 } 433 populateZenRule(AutomaticZenRule automaticZenRule, ZenRule rule, boolean isNew)434 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 createAutomaticZenRule(ZenRule rule)452 private AutomaticZenRule createAutomaticZenRule(ZenRule rule) { 453 return new AutomaticZenRule(rule.name, rule.component, rule.conditionId, 454 NotificationManager.zenModeToInterruptionFilter(rule.zenMode), rule.enabled, 455 rule.creationTime); 456 } 457 setManualZenMode(int zenMode, Uri conditionId, String caller, String reason)458 public void setManualZenMode(int zenMode, Uri conditionId, String caller, String reason) { 459 setManualZenMode(zenMode, conditionId, reason, caller, true /*setRingerMode*/); 460 } 461 setManualZenMode(int zenMode, Uri conditionId, String reason, String caller, boolean setRingerMode)462 private void setManualZenMode(int zenMode, Uri conditionId, String reason, String caller, 463 boolean setRingerMode) { 464 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(); 472 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 } 478 } 479 } else { 480 final ZenRule newRule = new ZenRule(); 481 newRule.enabled = true; 482 newRule.zenMode = zenMode; 483 newRule.conditionId = conditionId; 484 newRule.enabler = caller; 485 newConfig.manualRule = newRule; 486 } 487 setConfigLocked(newConfig, reason, setRingerMode); 488 } 489 } 490 dump(PrintWriter pw, String prefix)491 public void dump(PrintWriter pw, String prefix) { 492 pw.print(prefix); pw.print("mZenMode="); 493 pw.println(Global.zenModeToString(mZenMode)); 494 dump(pw, prefix, "mDefaultConfig", mDefaultConfig); 495 final int N = mConfigs.size(); 496 for (int i = 0; i < N; i++) { 497 dump(pw, prefix, "mConfigs[u=" + mConfigs.keyAt(i) + "]", mConfigs.valueAt(i)); 498 } 499 pw.print(prefix); pw.print("mUser="); pw.println(mUser); 500 synchronized (mConfig) { 501 dump(pw, prefix, "mConfig", mConfig); 502 } 503 504 pw.print(prefix); pw.print("mSuppressedEffects="); pw.println(mSuppressedEffects); 505 mFiltering.dump(pw, prefix); 506 mConditions.dump(pw, prefix); 507 } 508 dump(PrintWriter pw, String prefix, String var, ZenModeConfig config)509 private static void dump(PrintWriter pw, String prefix, String var, ZenModeConfig config) { 510 pw.print(prefix); pw.print(var); pw.print('='); 511 if (config == null) { 512 pw.println(config); 513 return; 514 } 515 pw.printf("allow(calls=%s,callsFrom=%s,repeatCallers=%s,messages=%s,messagesFrom=%s," 516 + "events=%s,reminders=%s,whenScreenOff,whenScreenOn=%s)\n", 517 config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom), 518 config.allowRepeatCallers, config.allowMessages, 519 ZenModeConfig.sourceToString(config.allowMessagesFrom), 520 config.allowEvents, config.allowReminders, config.allowWhenScreenOff, 521 config.allowWhenScreenOn); 522 pw.print(prefix); pw.print(" manualRule="); pw.println(config.manualRule); 523 if (config.automaticRules.isEmpty()) return; 524 final int N = config.automaticRules.size(); 525 for (int i = 0; i < N; i++) { 526 pw.print(prefix); pw.print(i == 0 ? " automaticRules=" : " "); 527 pw.println(config.automaticRules.valueAt(i)); 528 } 529 } 530 readXml(XmlPullParser parser, boolean forRestore)531 public void readXml(XmlPullParser parser, boolean forRestore) 532 throws XmlPullParserException, IOException { 533 final ZenModeConfig config = ZenModeConfig.readXml(parser, mConfigMigration); 534 if (config != null) { 535 if (forRestore) { 536 //TODO: http://b/22388012 537 if (config.user != UserHandle.USER_SYSTEM) { 538 return; 539 } 540 config.manualRule = null; // don't restore the manual rule 541 long time = System.currentTimeMillis(); 542 if (config.automaticRules != null) { 543 for (ZenRule automaticRule : config.automaticRules.values()) { 544 // don't restore transient state from restored automatic rules 545 automaticRule.snoozing = false; 546 automaticRule.condition = null; 547 automaticRule.creationTime = time; 548 } 549 } 550 } 551 if (DEBUG) Log.d(TAG, "readXml"); 552 synchronized (mConfig) { 553 setConfigLocked(config, "readXml"); 554 } 555 } 556 } 557 writeXml(XmlSerializer out, boolean forBackup)558 public void writeXml(XmlSerializer out, boolean forBackup) throws IOException { 559 final int N = mConfigs.size(); 560 for (int i = 0; i < N; i++) { 561 //TODO: http://b/22388012 562 if (forBackup && mConfigs.keyAt(i) != UserHandle.USER_SYSTEM) { 563 continue; 564 } 565 mConfigs.valueAt(i).writeXml(out); 566 } 567 } 568 getNotificationPolicy()569 public Policy getNotificationPolicy() { 570 return getNotificationPolicy(mConfig); 571 } 572 getNotificationPolicy(ZenModeConfig config)573 private static Policy getNotificationPolicy(ZenModeConfig config) { 574 return config == null ? null : config.toNotificationPolicy(); 575 } 576 setNotificationPolicy(Policy policy)577 public void setNotificationPolicy(Policy policy) { 578 if (policy == null || mConfig == null) return; 579 synchronized (mConfig) { 580 final ZenModeConfig newConfig = mConfig.copy(); 581 newConfig.applyNotificationPolicy(policy); 582 setConfigLocked(newConfig, "setNotificationPolicy"); 583 } 584 } 585 586 /** 587 * Removes old rule instances whose owner is not installed. 588 */ cleanUpZenRules()589 private void cleanUpZenRules() { 590 long currentTime = System.currentTimeMillis(); 591 synchronized (mConfig) { 592 final ZenModeConfig newConfig = mConfig.copy(); 593 if (newConfig.automaticRules != null) { 594 for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) { 595 ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i)); 596 if (RULE_INSTANCE_GRACE_PERIOD < (currentTime - rule.creationTime)) { 597 try { 598 mPm.getPackageInfo(rule.component.getPackageName(), 599 PackageManager.MATCH_UNINSTALLED_PACKAGES); 600 } catch (PackageManager.NameNotFoundException e) { 601 newConfig.automaticRules.removeAt(i); 602 } 603 } 604 } 605 } 606 setConfigLocked(newConfig, "cleanUpZenRules"); 607 } 608 } 609 610 /** 611 * @return a copy of the zen mode configuration 612 */ getConfig()613 public ZenModeConfig getConfig() { 614 synchronized (mConfig) { 615 return mConfig.copy(); 616 } 617 } 618 setConfigLocked(ZenModeConfig config, String reason)619 public boolean setConfigLocked(ZenModeConfig config, String reason) { 620 return setConfigLocked(config, reason, true /*setRingerMode*/); 621 } 622 setConfig(ZenModeConfig config, String reason)623 public void setConfig(ZenModeConfig config, String reason) { 624 synchronized (mConfig) { 625 setConfigLocked(config, reason); 626 } 627 } 628 setConfigLocked(ZenModeConfig config, String reason, boolean setRingerMode)629 private boolean setConfigLocked(ZenModeConfig config, String reason, boolean setRingerMode) { 630 final long identity = Binder.clearCallingIdentity(); 631 try { 632 if (config == null || !config.isValid()) { 633 Log.w(TAG, "Invalid config in setConfigLocked; " + config); 634 return false; 635 } 636 if (config.user != mUser) { 637 // simply store away for background users 638 mConfigs.put(config.user, config); 639 if (DEBUG) Log.d(TAG, "setConfigLocked: store config for user " + config.user); 640 return true; 641 } 642 mConditions.evaluateConfig(config, false /*processSubscriptions*/); // may modify config 643 mConfigs.put(config.user, config); 644 if (DEBUG) Log.d(TAG, "setConfigLocked reason=" + reason, new Throwable()); 645 ZenLog.traceConfig(reason, mConfig, config); 646 final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig), 647 getNotificationPolicy(config)); 648 if (!config.equals(mConfig)) { 649 dispatchOnConfigChanged(); 650 } 651 if (policyChanged) { 652 dispatchOnPolicyChanged(); 653 } 654 mConfig = config; 655 mHandler.postApplyConfig(config, reason, setRingerMode); 656 return true; 657 } finally { 658 Binder.restoreCallingIdentity(identity); 659 } 660 } 661 applyConfig(ZenModeConfig config, String reason, boolean setRingerMode)662 private void applyConfig(ZenModeConfig config, String reason, boolean setRingerMode) { 663 final String val = Integer.toString(config.hashCode()); 664 Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val); 665 if (!evaluateZenMode(reason, setRingerMode)) { 666 applyRestrictions(); // evaluateZenMode will also apply restrictions if changed 667 } 668 mConditions.evaluateConfig(config, true /*processSubscriptions*/); 669 } 670 getZenModeSetting()671 private int getZenModeSetting() { 672 return Global.getInt(mContext.getContentResolver(), Global.ZEN_MODE, Global.ZEN_MODE_OFF); 673 } 674 setZenModeSetting(int zen)675 private void setZenModeSetting(int zen) { 676 Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zen); 677 } 678 getPreviousRingerModeSetting()679 private int getPreviousRingerModeSetting() { 680 return Global.getInt(mContext.getContentResolver(), 681 Global.ZEN_MODE_RINGER_LEVEL, AudioManager.RINGER_MODE_NORMAL); 682 } 683 setPreviousRingerModeSetting(Integer previousRingerLevel)684 private void setPreviousRingerModeSetting(Integer previousRingerLevel) { 685 Global.putString( 686 mContext.getContentResolver(), Global.ZEN_MODE_RINGER_LEVEL, 687 previousRingerLevel == null ? null : Integer.toString(previousRingerLevel)); 688 } 689 evaluateZenMode(String reason, boolean setRingerMode)690 private boolean evaluateZenMode(String reason, boolean setRingerMode) { 691 if (DEBUG) Log.d(TAG, "evaluateZenMode"); 692 final int zenBefore = mZenMode; 693 final int zen = computeZenMode(); 694 ZenLog.traceSetZenMode(zen, reason); 695 mZenMode = zen; 696 updateRingerModeAffectedStreams(); 697 setZenModeSetting(mZenMode); 698 if (setRingerMode) { 699 applyZenToRingerMode(); 700 } 701 applyRestrictions(); 702 if (zen != zenBefore) { 703 mHandler.postDispatchOnZenModeChanged(); 704 } 705 return true; 706 } 707 updateRingerModeAffectedStreams()708 private void updateRingerModeAffectedStreams() { 709 if (mAudioManager != null) { 710 mAudioManager.updateRingerModeAffectedStreamsInternal(); 711 } 712 } 713 computeZenMode()714 private int computeZenMode() { 715 synchronized (mConfig) { 716 if (mConfig == null) return Global.ZEN_MODE_OFF; 717 if (mConfig.manualRule != null) return mConfig.manualRule.zenMode; 718 int zen = Global.ZEN_MODE_OFF; 719 for (ZenRule automaticRule : mConfig.automaticRules.values()) { 720 if (automaticRule.isAutomaticActive()) { 721 if (zenSeverity(automaticRule.zenMode) > zenSeverity(zen)) { 722 zen = automaticRule.zenMode; 723 } 724 } 725 } 726 return zen; 727 } 728 } 729 applyRestrictions()730 private void applyRestrictions() { 731 final boolean zen = mZenMode != Global.ZEN_MODE_OFF; 732 733 // notification restrictions 734 final boolean muteNotifications = 735 (mSuppressedEffects & SUPPRESSED_EFFECT_NOTIFICATIONS) != 0; 736 // call restrictions 737 final boolean muteCalls = zen && !mConfig.allowCalls && !mConfig.allowRepeatCallers 738 || (mSuppressedEffects & SUPPRESSED_EFFECT_CALLS) != 0; 739 // total silence restrictions 740 final boolean muteEverything = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS; 741 742 for (int usage : AudioAttributes.SDK_USAGES) { 743 final int suppressionBehavior = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage); 744 if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NOTIFICATION) { 745 applyRestrictions(muteNotifications || muteEverything, usage); 746 } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_CALL) { 747 applyRestrictions(muteCalls || muteEverything, usage); 748 } else { 749 applyRestrictions(muteEverything, usage); 750 } 751 } 752 } 753 applyRestrictions(boolean mute, int usage)754 private void applyRestrictions(boolean mute, int usage) { 755 final String[] exceptionPackages = null; // none (for now) 756 mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, usage, 757 mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, 758 exceptionPackages); 759 mAppOps.setRestriction(AppOpsManager.OP_PLAY_AUDIO, usage, 760 mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED, 761 exceptionPackages); 762 } 763 applyZenToRingerMode()764 private void applyZenToRingerMode() { 765 if (mAudioManager == null) return; 766 // force the ringer mode into compliance 767 final int ringerModeInternal = mAudioManager.getRingerModeInternal(); 768 int newRingerModeInternal = ringerModeInternal; 769 switch (mZenMode) { 770 case Global.ZEN_MODE_NO_INTERRUPTIONS: 771 case Global.ZEN_MODE_ALARMS: 772 if (ringerModeInternal != AudioManager.RINGER_MODE_SILENT) { 773 setPreviousRingerModeSetting(ringerModeInternal); 774 newRingerModeInternal = AudioManager.RINGER_MODE_SILENT; 775 } 776 break; 777 case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: 778 case Global.ZEN_MODE_OFF: 779 if (ringerModeInternal == AudioManager.RINGER_MODE_SILENT) { 780 newRingerModeInternal = getPreviousRingerModeSetting(); 781 setPreviousRingerModeSetting(null); 782 } 783 break; 784 } 785 if (newRingerModeInternal != -1) { 786 mAudioManager.setRingerModeInternal(newRingerModeInternal, TAG); 787 } 788 } 789 dispatchOnConfigChanged()790 private void dispatchOnConfigChanged() { 791 for (Callback callback : mCallbacks) { 792 callback.onConfigChanged(); 793 } 794 } 795 dispatchOnPolicyChanged()796 private void dispatchOnPolicyChanged() { 797 for (Callback callback : mCallbacks) { 798 callback.onPolicyChanged(); 799 } 800 } 801 dispatchOnZenModeChanged()802 private void dispatchOnZenModeChanged() { 803 for (Callback callback : mCallbacks) { 804 callback.onZenModeChanged(); 805 } 806 } 807 readDefaultConfig(Resources resources)808 private ZenModeConfig readDefaultConfig(Resources resources) { 809 XmlResourceParser parser = null; 810 try { 811 parser = resources.getXml(R.xml.default_zen_mode_config); 812 while (parser.next() != XmlPullParser.END_DOCUMENT) { 813 final ZenModeConfig config = ZenModeConfig.readXml(parser, mConfigMigration); 814 if (config != null) return config; 815 } 816 } catch (Exception e) { 817 Log.w(TAG, "Error reading default zen mode config from resource", e); 818 } finally { 819 IoUtils.closeQuietly(parser); 820 } 821 return new ZenModeConfig(); 822 } 823 appendDefaultScheduleRules(ZenModeConfig config)824 private void appendDefaultScheduleRules(ZenModeConfig config) { 825 if (config == null) return; 826 827 final ScheduleInfo weeknights = new ScheduleInfo(); 828 weeknights.days = ZenModeConfig.WEEKNIGHT_DAYS; 829 weeknights.startHour = 22; 830 weeknights.endHour = 7; 831 final ZenRule rule1 = new ZenRule(); 832 rule1.enabled = false; 833 rule1.name = mContext.getResources() 834 .getString(R.string.zen_mode_default_weeknights_name); 835 rule1.conditionId = ZenModeConfig.toScheduleConditionId(weeknights); 836 rule1.zenMode = Global.ZEN_MODE_ALARMS; 837 rule1.component = ScheduleConditionProvider.COMPONENT; 838 rule1.id = ZenModeConfig.newRuleId(); 839 rule1.creationTime = System.currentTimeMillis(); 840 config.automaticRules.put(rule1.id, rule1); 841 842 final ScheduleInfo weekends = new ScheduleInfo(); 843 weekends.days = ZenModeConfig.WEEKEND_DAYS; 844 weekends.startHour = 23; 845 weekends.startMinute = 30; 846 weekends.endHour = 10; 847 final ZenRule rule2 = new ZenRule(); 848 rule2.enabled = false; 849 rule2.name = mContext.getResources() 850 .getString(R.string.zen_mode_default_weekends_name); 851 rule2.conditionId = ZenModeConfig.toScheduleConditionId(weekends); 852 rule2.zenMode = Global.ZEN_MODE_ALARMS; 853 rule2.component = ScheduleConditionProvider.COMPONENT; 854 rule2.id = ZenModeConfig.newRuleId(); 855 rule2.creationTime = System.currentTimeMillis(); 856 config.automaticRules.put(rule2.id, rule2); 857 } 858 appendDefaultEventRules(ZenModeConfig config)859 private void appendDefaultEventRules(ZenModeConfig config) { 860 if (config == null) return; 861 862 final EventInfo events = new EventInfo(); 863 events.calendar = null; // any calendar 864 events.reply = EventInfo.REPLY_YES_OR_MAYBE; 865 final ZenRule rule = new ZenRule(); 866 rule.enabled = false; 867 rule.name = mContext.getResources().getString(R.string.zen_mode_default_events_name); 868 rule.conditionId = ZenModeConfig.toEventConditionId(events); 869 rule.zenMode = Global.ZEN_MODE_ALARMS; 870 rule.component = EventConditionProvider.COMPONENT; 871 rule.id = ZenModeConfig.newRuleId(); 872 rule.creationTime = System.currentTimeMillis(); 873 config.automaticRules.put(rule.id, rule); 874 } 875 zenSeverity(int zen)876 private static int zenSeverity(int zen) { 877 switch (zen) { 878 case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return 1; 879 case Global.ZEN_MODE_ALARMS: return 2; 880 case Global.ZEN_MODE_NO_INTERRUPTIONS: return 3; 881 default: return 0; 882 } 883 } 884 885 private final ZenModeConfig.Migration mConfigMigration = new ZenModeConfig.Migration() { 886 @Override 887 public ZenModeConfig migrate(ZenModeConfig.XmlV1 v1) { 888 if (v1 == null) return null; 889 final ZenModeConfig rt = new ZenModeConfig(); 890 rt.allowCalls = v1.allowCalls; 891 rt.allowEvents = v1.allowEvents; 892 rt.allowCallsFrom = v1.allowFrom; 893 rt.allowMessages = v1.allowMessages; 894 rt.allowMessagesFrom = v1.allowFrom; 895 rt.allowReminders = v1.allowReminders; 896 // don't migrate current exit condition 897 final int[] days = ZenModeConfig.XmlV1.tryParseDays(v1.sleepMode); 898 if (days != null && days.length > 0) { 899 Log.i(TAG, "Migrating existing V1 downtime to single schedule"); 900 final ScheduleInfo schedule = new ScheduleInfo(); 901 schedule.days = days; 902 schedule.startHour = v1.sleepStartHour; 903 schedule.startMinute = v1.sleepStartMinute; 904 schedule.endHour = v1.sleepEndHour; 905 schedule.endMinute = v1.sleepEndMinute; 906 final ZenRule rule = new ZenRule(); 907 rule.enabled = true; 908 rule.name = mContext.getResources() 909 .getString(R.string.zen_mode_downtime_feature_name); 910 rule.conditionId = ZenModeConfig.toScheduleConditionId(schedule); 911 rule.zenMode = v1.sleepNone ? Global.ZEN_MODE_NO_INTERRUPTIONS 912 : Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; 913 rule.component = ScheduleConditionProvider.COMPONENT; 914 rt.automaticRules.put(ZenModeConfig.newRuleId(), rule); 915 } else { 916 Log.i(TAG, "No existing V1 downtime found, generating default schedules"); 917 appendDefaultScheduleRules(rt); 918 } 919 appendDefaultEventRules(rt); 920 return rt; 921 } 922 }; 923 924 private final class RingerModeDelegate implements AudioManagerInternal.RingerModeDelegate { 925 @Override toString()926 public String toString() { 927 return TAG; 928 } 929 930 @Override onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller, int ringerModeExternal, VolumePolicy policy)931 public int onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller, 932 int ringerModeExternal, VolumePolicy policy) { 933 final boolean isChange = ringerModeOld != ringerModeNew; 934 935 int ringerModeExternalOut = ringerModeNew; 936 937 int newZen = -1; 938 switch (ringerModeNew) { 939 case AudioManager.RINGER_MODE_SILENT: 940 if (isChange && policy.doNotDisturbWhenSilent) { 941 if (mZenMode != Global.ZEN_MODE_NO_INTERRUPTIONS 942 && mZenMode != Global.ZEN_MODE_ALARMS) { 943 newZen = Global.ZEN_MODE_ALARMS; 944 } 945 setPreviousRingerModeSetting(ringerModeOld); 946 } 947 break; 948 case AudioManager.RINGER_MODE_VIBRATE: 949 case AudioManager.RINGER_MODE_NORMAL: 950 if (isChange && ringerModeOld == AudioManager.RINGER_MODE_SILENT 951 && (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS 952 || mZenMode == Global.ZEN_MODE_ALARMS)) { 953 newZen = Global.ZEN_MODE_OFF; 954 } else if (mZenMode != Global.ZEN_MODE_OFF) { 955 ringerModeExternalOut = AudioManager.RINGER_MODE_SILENT; 956 } 957 break; 958 } 959 if (newZen != -1) { 960 setManualZenMode(newZen, null, "ringerModeInternal", null, 961 false /*setRingerMode*/); 962 } 963 964 if (isChange || newZen != -1 || ringerModeExternal != ringerModeExternalOut) { 965 ZenLog.traceSetRingerModeInternal(ringerModeOld, ringerModeNew, caller, 966 ringerModeExternal, ringerModeExternalOut); 967 } 968 return ringerModeExternalOut; 969 } 970 971 @Override onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller, int ringerModeInternal, VolumePolicy policy)972 public int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller, 973 int ringerModeInternal, VolumePolicy policy) { 974 int ringerModeInternalOut = ringerModeNew; 975 final boolean isChange = ringerModeOld != ringerModeNew; 976 final boolean isVibrate = ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE; 977 978 int newZen = -1; 979 switch (ringerModeNew) { 980 case AudioManager.RINGER_MODE_SILENT: 981 if (isChange) { 982 if (mZenMode == Global.ZEN_MODE_OFF) { 983 newZen = Global.ZEN_MODE_ALARMS; 984 } 985 ringerModeInternalOut = isVibrate ? AudioManager.RINGER_MODE_VIBRATE 986 : AudioManager.RINGER_MODE_SILENT; 987 } else { 988 ringerModeInternalOut = ringerModeInternal; 989 } 990 break; 991 case AudioManager.RINGER_MODE_VIBRATE: 992 case AudioManager.RINGER_MODE_NORMAL: 993 if (mZenMode != Global.ZEN_MODE_OFF) { 994 newZen = Global.ZEN_MODE_OFF; 995 } 996 break; 997 } 998 if (newZen != -1) { 999 setManualZenMode(newZen, null, "ringerModeExternal", caller, 1000 false /*setRingerMode*/); 1001 } 1002 1003 ZenLog.traceSetRingerModeExternal(ringerModeOld, ringerModeNew, caller, 1004 ringerModeInternal, ringerModeInternalOut); 1005 return ringerModeInternalOut; 1006 } 1007 1008 @Override canVolumeDownEnterSilent()1009 public boolean canVolumeDownEnterSilent() { 1010 return mZenMode == Global.ZEN_MODE_OFF; 1011 } 1012 1013 @Override getRingerModeAffectedStreams(int streams)1014 public int getRingerModeAffectedStreams(int streams) { 1015 // ringtone, notification and system streams are always affected by ringer mode 1016 streams |= (1 << AudioSystem.STREAM_RING) | 1017 (1 << AudioSystem.STREAM_NOTIFICATION) | 1018 (1 << AudioSystem.STREAM_SYSTEM); 1019 1020 // alarm and music streams are only affected by ringer mode when in total silence 1021 if (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) { 1022 streams |= (1 << AudioSystem.STREAM_ALARM) | 1023 (1 << AudioSystem.STREAM_MUSIC); 1024 } else { 1025 streams &= ~((1 << AudioSystem.STREAM_ALARM) | 1026 (1 << AudioSystem.STREAM_MUSIC)); 1027 } 1028 return streams; 1029 } 1030 } 1031 1032 private final class SettingsObserver extends ContentObserver { 1033 private final Uri ZEN_MODE = Global.getUriFor(Global.ZEN_MODE); 1034 SettingsObserver(Handler handler)1035 public SettingsObserver(Handler handler) { 1036 super(handler); 1037 } 1038 observe()1039 public void observe() { 1040 final ContentResolver resolver = mContext.getContentResolver(); 1041 resolver.registerContentObserver(ZEN_MODE, false /*notifyForDescendents*/, this); 1042 update(null); 1043 } 1044 1045 @Override onChange(boolean selfChange, Uri uri)1046 public void onChange(boolean selfChange, Uri uri) { 1047 update(uri); 1048 } 1049 update(Uri uri)1050 public void update(Uri uri) { 1051 if (ZEN_MODE.equals(uri)) { 1052 if (mZenMode != getZenModeSetting()) { 1053 if (DEBUG) Log.d(TAG, "Fixing zen mode setting"); 1054 setZenModeSetting(mZenMode); 1055 } 1056 } 1057 } 1058 } 1059 1060 private final class Metrics extends Callback { 1061 private static final String COUNTER_PREFIX = "dnd_mode_"; 1062 private static final long MINIMUM_LOG_PERIOD_MS = 60 * 1000; 1063 1064 private int mPreviousZenMode = -1; 1065 private long mBeginningMs = 0L; 1066 1067 @Override onZenModeChanged()1068 void onZenModeChanged() { 1069 emit(); 1070 } 1071 emit()1072 private void emit() { 1073 mHandler.postMetricsTimer(); 1074 final long now = SystemClock.elapsedRealtime(); 1075 final long since = (now - mBeginningMs); 1076 if (mPreviousZenMode != mZenMode || since > MINIMUM_LOG_PERIOD_MS) { 1077 if (mPreviousZenMode != -1) { 1078 MetricsLogger.count(mContext, COUNTER_PREFIX + mPreviousZenMode, (int) since); 1079 } 1080 mPreviousZenMode = mZenMode; 1081 mBeginningMs = now; 1082 } 1083 } 1084 } 1085 1086 private final class H extends Handler { 1087 private static final int MSG_DISPATCH = 1; 1088 private static final int MSG_METRICS = 2; 1089 private static final int MSG_APPLY_CONFIG = 4; 1090 1091 private final class ConfigMessageData { 1092 public final ZenModeConfig config; 1093 public final String reason; 1094 public final boolean setRingerMode; 1095 ConfigMessageData(ZenModeConfig config, String reason, boolean setRingerMode)1096 ConfigMessageData(ZenModeConfig config, String reason, boolean setRingerMode) { 1097 this.config = config; 1098 this.reason = reason; 1099 this.setRingerMode = setRingerMode; 1100 } 1101 } 1102 1103 private static final long METRICS_PERIOD_MS = 6 * 60 * 60 * 1000; 1104 H(Looper looper)1105 private H(Looper looper) { 1106 super(looper); 1107 } 1108 postDispatchOnZenModeChanged()1109 private void postDispatchOnZenModeChanged() { 1110 removeMessages(MSG_DISPATCH); 1111 sendEmptyMessage(MSG_DISPATCH); 1112 } 1113 postMetricsTimer()1114 private void postMetricsTimer() { 1115 removeMessages(MSG_METRICS); 1116 sendEmptyMessageDelayed(MSG_METRICS, METRICS_PERIOD_MS); 1117 } 1118 postApplyConfig(ZenModeConfig config, String reason, boolean setRingerMode)1119 private void postApplyConfig(ZenModeConfig config, String reason, boolean setRingerMode) { 1120 sendMessage(obtainMessage(MSG_APPLY_CONFIG, 1121 new ConfigMessageData(config, reason, setRingerMode))); 1122 } 1123 1124 @Override handleMessage(Message msg)1125 public void handleMessage(Message msg) { 1126 switch (msg.what) { 1127 case MSG_DISPATCH: 1128 dispatchOnZenModeChanged(); 1129 break; 1130 case MSG_METRICS: 1131 mMetrics.emit(); 1132 break; 1133 case MSG_APPLY_CONFIG: 1134 ConfigMessageData applyConfigData = (ConfigMessageData) msg.obj; 1135 applyConfig(applyConfigData.config, applyConfigData.reason, 1136 applyConfigData.setRingerMode); 1137 } 1138 } 1139 } 1140 1141 public static class Callback { onConfigChanged()1142 void onConfigChanged() {} onZenModeChanged()1143 void onZenModeChanged() {} onPolicyChanged()1144 void onPolicyChanged() {} 1145 } 1146 1147 } 1148