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