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