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