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.settings.notification.zen; 18 19 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS; 20 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS; 21 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CONVERSATIONS; 22 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_EVENTS; 23 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA; 24 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES; 25 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REMINDERS; 26 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REPEAT_CALLERS; 27 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM; 28 29 import android.app.Activity; 30 import android.app.Application; 31 import android.app.AutomaticZenRule; 32 import android.app.NotificationManager; 33 import android.app.NotificationManager.Policy; 34 import android.app.settings.SettingsEnums; 35 import android.content.Context; 36 import android.icu.text.MessageFormat; 37 import android.provider.Settings; 38 import android.service.notification.ZenModeConfig; 39 40 import androidx.annotation.VisibleForTesting; 41 import androidx.fragment.app.Fragment; 42 import androidx.fragment.app.FragmentManager; 43 44 import com.android.settings.R; 45 import com.android.settings.search.BaseSearchIndexProvider; 46 import com.android.settingslib.core.AbstractPreferenceController; 47 import com.android.settingslib.core.lifecycle.Lifecycle; 48 import com.android.settingslib.search.SearchIndexable; 49 50 import java.util.ArrayList; 51 import java.util.HashMap; 52 import java.util.List; 53 import java.util.Locale; 54 import java.util.Map; 55 import java.util.Map.Entry; 56 import java.util.function.Predicate; 57 58 @SearchIndexable 59 public class ZenModeSettings extends ZenModeSettingsBase { 60 @Override onResume()61 public void onResume() { 62 super.onResume(); 63 } 64 65 @Override getPreferenceScreenResId()66 protected int getPreferenceScreenResId() { 67 return R.xml.zen_mode_settings; 68 } 69 70 @Override getMetricsCategory()71 public int getMetricsCategory() { 72 return SettingsEnums.NOTIFICATION_ZEN_MODE; 73 } 74 75 @Override createPreferenceControllers(Context context)76 protected List<AbstractPreferenceController> createPreferenceControllers(Context context) { 77 final Activity activity = getActivity(); 78 return buildPreferenceControllers(context, getSettingsLifecycle(), getFragmentManager(), 79 activity != null ? activity.getApplication() : null, this); 80 } 81 82 @Override getHelpResource()83 public int getHelpResource() { 84 return R.string.help_uri_interruptions; 85 } 86 buildPreferenceControllers(Context context, Lifecycle lifecycle, FragmentManager fragmentManager, Application app, Fragment fragment)87 private static List<AbstractPreferenceController> buildPreferenceControllers(Context context, 88 Lifecycle lifecycle, FragmentManager fragmentManager, Application app, 89 Fragment fragment) { 90 List<AbstractPreferenceController> controllers = new ArrayList<>(); 91 controllers.add(new ZenModeButtonPreferenceController(context, lifecycle, fragmentManager)); 92 controllers.add(new ZenModePeoplePreferenceController(context, lifecycle, 93 "zen_mode_behavior_people")); 94 controllers.add(new ZenModeBypassingAppsPreferenceController(context, app, 95 fragment, lifecycle)); 96 controllers.add(new ZenModeSoundVibrationPreferenceController(context, lifecycle, 97 "zen_sound_vibration_settings")); 98 controllers.add(new ZenModeAutomationPreferenceController(context)); 99 controllers.add(new ZenModeDurationPreferenceController(context, lifecycle)); 100 controllers.add(new ZenModeBlockedEffectsPreferenceController(context, lifecycle)); 101 controllers.add(new ZenModeSettingsFooterPreferenceController(context, lifecycle, 102 fragmentManager)); 103 return controllers; 104 } 105 106 public static class SummaryBuilder { 107 108 private Context mContext; 109 SummaryBuilder(Context context)110 public SummaryBuilder(Context context) { 111 mContext = context; 112 } 113 114 // these should match NotificationManager.Policy#ALL_PRIORITY_CATEGORIES 115 private static final int[] ALL_PRIORITY_CATEGORIES = { 116 PRIORITY_CATEGORY_ALARMS, 117 PRIORITY_CATEGORY_MEDIA, 118 PRIORITY_CATEGORY_SYSTEM, 119 PRIORITY_CATEGORY_MESSAGES, 120 PRIORITY_CATEGORY_CONVERSATIONS, 121 PRIORITY_CATEGORY_EVENTS, 122 PRIORITY_CATEGORY_REMINDERS, 123 PRIORITY_CATEGORY_CALLS, 124 PRIORITY_CATEGORY_REPEAT_CALLERS, 125 }; 126 getOtherSoundCategoriesSummary(Policy policy)127 String getOtherSoundCategoriesSummary(Policy policy) { 128 List<String> enabledCategories = getEnabledCategories( 129 policy, 130 category -> PRIORITY_CATEGORY_ALARMS == category 131 || PRIORITY_CATEGORY_MEDIA == category 132 || PRIORITY_CATEGORY_SYSTEM == category 133 || PRIORITY_CATEGORY_REMINDERS == category 134 || PRIORITY_CATEGORY_EVENTS == category, 135 true); 136 int numCategories = enabledCategories.size(); 137 MessageFormat msgFormat = new MessageFormat( 138 mContext.getString(R.string.zen_mode_other_sounds_summary), 139 Locale.getDefault()); 140 Map<String, Object> args = new HashMap<>(); 141 args.put("count", numCategories); 142 if (numCategories >= 1) { 143 args.put("sound_category_1", enabledCategories.get(0)); 144 if (numCategories >= 2) { 145 args.put("sound_category_2", enabledCategories.get(1)); 146 if (numCategories == 3) { 147 args.put("sound_category_3", enabledCategories.get(2)); 148 } 149 } 150 } 151 return msgFormat.format(args); 152 } 153 getCallsSettingSummary(Policy policy)154 String getCallsSettingSummary(Policy policy) { 155 List<String> enabledCategories = getEnabledCategories(policy, 156 category -> PRIORITY_CATEGORY_CALLS == category 157 || PRIORITY_CATEGORY_REPEAT_CALLERS == category, true); 158 int numCategories = enabledCategories.size(); 159 if (numCategories == 0) { 160 return mContext.getString(R.string.zen_mode_none_calls); 161 } else if (numCategories == 1) { 162 return mContext.getString(R.string.zen_mode_calls_summary_one, 163 enabledCategories.get(0)); 164 } else { 165 return mContext.getString(R.string.zen_mode_calls_summary_two, 166 enabledCategories.get(0), 167 enabledCategories.get(1)); 168 } 169 } 170 getMessagesSettingSummary(Policy policy)171 String getMessagesSettingSummary(Policy policy) { 172 List<String> enabledCategories = getEnabledCategories(policy, 173 category -> PRIORITY_CATEGORY_MESSAGES == category 174 || PRIORITY_CATEGORY_CONVERSATIONS == category, true); 175 int numCategories = enabledCategories.size(); 176 if (numCategories == 0) { 177 return mContext.getString(R.string.zen_mode_none_messages); 178 } else if (numCategories == 1) { 179 return enabledCategories.get(0); 180 } else { 181 // While this string name seems like a slight misnomer: it's borrowing the analogous 182 // calls-summary functionality to combine two permissions. 183 return mContext.getString(R.string.zen_mode_calls_summary_two, 184 enabledCategories.get(0), 185 enabledCategories.get(1)); 186 } 187 } 188 getSoundSummary()189 String getSoundSummary() { 190 int zenMode = NotificationManager.from(mContext).getZenMode(); 191 192 if (zenMode != Settings.Global.ZEN_MODE_OFF) { 193 ZenModeConfig config = NotificationManager.from(mContext).getZenModeConfig(); 194 String description = ZenModeConfig.getDescription(mContext, true, config, false); 195 196 if (description == null) { 197 return mContext.getString(R.string.zen_mode_sound_summary_on); 198 } else { 199 return mContext.getString(R.string.zen_mode_sound_summary_on_with_info, 200 description); 201 } 202 } else { 203 MessageFormat msgFormat = new MessageFormat( 204 mContext.getString(R.string.zen_mode_sound_summary_off), 205 Locale.getDefault()); 206 Map<String, Object> msgArgs = new HashMap<>(); 207 msgArgs.put("count", getEnabledAutomaticRulesCount()); 208 return msgFormat.format(msgArgs); 209 } 210 } 211 getBlockedEffectsSummary(Policy policy)212 String getBlockedEffectsSummary(Policy policy) { 213 if (policy.suppressedVisualEffects == 0) { 214 return mContext.getResources().getString( 215 R.string.zen_mode_restrict_notifications_summary_muted); 216 } else if (Policy.areAllVisualEffectsSuppressed(policy.suppressedVisualEffects)) { 217 return mContext.getResources().getString( 218 R.string.zen_mode_restrict_notifications_summary_hidden); 219 } else { 220 return mContext.getResources().getString( 221 R.string.zen_mode_restrict_notifications_summary_custom); 222 } 223 } 224 getAutomaticRulesSummary()225 String getAutomaticRulesSummary() { 226 MessageFormat msgFormat = new MessageFormat( 227 mContext.getString(R.string.zen_mode_settings_schedules_summary), 228 Locale.getDefault()); 229 Map<String, Object> msgArgs = new HashMap<>(); 230 msgArgs.put("count", getEnabledAutomaticRulesCount()); 231 return msgFormat.format(msgArgs); 232 } 233 234 @VisibleForTesting getEnabledAutomaticRulesCount()235 int getEnabledAutomaticRulesCount() { 236 int count = 0; 237 final Map<String, AutomaticZenRule> ruleMap = 238 NotificationManager.from(mContext).getAutomaticZenRules(); 239 if (ruleMap != null) { 240 for (Entry<String, AutomaticZenRule> ruleEntry : ruleMap.entrySet()) { 241 final AutomaticZenRule rule = ruleEntry.getValue(); 242 if (rule != null && rule.isEnabled()) { 243 count++; 244 } 245 } 246 } 247 return count; 248 } 249 getEnabledCategories(Policy policy, Predicate<Integer> filteredCategories, boolean capitalizeFirstInList)250 private List<String> getEnabledCategories(Policy policy, 251 Predicate<Integer> filteredCategories, boolean capitalizeFirstInList) { 252 List<String> enabledCategories = new ArrayList<>(); 253 for (int category : ALL_PRIORITY_CATEGORIES) { 254 boolean isFirst = capitalizeFirstInList && enabledCategories.isEmpty(); 255 if (filteredCategories.test(category) && isCategoryEnabled(policy, category)) { 256 if (category == Policy.PRIORITY_CATEGORY_REPEAT_CALLERS 257 && isCategoryEnabled(policy, Policy.PRIORITY_CATEGORY_CALLS) 258 && policy.priorityCallSenders == Policy.PRIORITY_SENDERS_ANY) { 259 continue; 260 } 261 262 // For conversations, only the "priority conversations" setting is relevant; any 263 // other setting is subsumed by the messages-specific messaging. 264 if (category == Policy.PRIORITY_CATEGORY_CONVERSATIONS 265 && isCategoryEnabled(policy, Policy.PRIORITY_CATEGORY_CONVERSATIONS) 266 && policy.priorityConversationSenders 267 != Policy.CONVERSATION_SENDERS_IMPORTANT) { 268 continue; 269 } 270 271 enabledCategories.add(getCategory(category, policy, isFirst)); 272 } 273 } 274 return enabledCategories; 275 } 276 isCategoryEnabled(Policy policy, int categoryType)277 private boolean isCategoryEnabled(Policy policy, int categoryType) { 278 return (policy.priorityCategories & categoryType) != 0; 279 } 280 getCategory(int category, Policy policy, boolean isFirst)281 private String getCategory(int category, Policy policy, boolean isFirst) { 282 if (category == PRIORITY_CATEGORY_ALARMS) { 283 if (isFirst) { 284 return mContext.getString(R.string.zen_mode_alarms_list_first); 285 } else { 286 return mContext.getString(R.string.zen_mode_alarms_list); 287 } 288 } else if (category == PRIORITY_CATEGORY_MEDIA) { 289 if (isFirst) { 290 return mContext.getString(R.string.zen_mode_media_list_first); 291 } else { 292 return mContext.getString(R.string.zen_mode_media_list); 293 } 294 } else if (category == PRIORITY_CATEGORY_SYSTEM) { 295 if (isFirst) { 296 return mContext.getString(R.string.zen_mode_system_list_first); 297 } else { 298 return mContext.getString(R.string.zen_mode_system_list); 299 } 300 } else if (category == Policy.PRIORITY_CATEGORY_MESSAGES) { 301 if (policy.priorityMessageSenders == Policy.PRIORITY_SENDERS_ANY) { 302 return mContext.getString(R.string.zen_mode_from_anyone); 303 } else if (policy.priorityMessageSenders == Policy.PRIORITY_SENDERS_CONTACTS) { 304 return mContext.getString(R.string.zen_mode_from_contacts); 305 } else { 306 return mContext.getString(R.string.zen_mode_from_starred); 307 } 308 } else if (category == Policy.PRIORITY_CATEGORY_CONVERSATIONS 309 && policy.priorityConversationSenders 310 == Policy.CONVERSATION_SENDERS_IMPORTANT) { 311 if (isFirst) { 312 return mContext.getString(R.string.zen_mode_from_important_conversations); 313 } else { 314 return mContext.getString( 315 R.string.zen_mode_from_important_conversations_second); 316 } 317 } else if (category == Policy.PRIORITY_CATEGORY_EVENTS) { 318 if (isFirst) { 319 return mContext.getString(R.string.zen_mode_events_list_first); 320 } else { 321 return mContext.getString(R.string.zen_mode_events_list); 322 } 323 } else if (category == Policy.PRIORITY_CATEGORY_REMINDERS) { 324 if (isFirst) { 325 return mContext.getString(R.string.zen_mode_reminders_list_first); 326 } else { 327 return mContext.getString(R.string.zen_mode_reminders_list); 328 } 329 } else if (category == Policy.PRIORITY_CATEGORY_CALLS) { 330 if (policy.priorityCallSenders == Policy.PRIORITY_SENDERS_ANY) { 331 if (isFirst) { 332 return mContext.getString(R.string.zen_mode_from_anyone); 333 } 334 return mContext.getString(R.string.zen_mode_all_callers); 335 } else if (policy.priorityCallSenders == Policy.PRIORITY_SENDERS_CONTACTS){ 336 if (isFirst) { 337 return mContext.getString(R.string.zen_mode_from_contacts); 338 } 339 return mContext.getString(R.string.zen_mode_contacts_callers); 340 } else { 341 if (isFirst) { 342 return mContext.getString(R.string.zen_mode_from_starred); 343 } 344 return mContext.getString(R.string.zen_mode_starred_callers); 345 } 346 } else if (category == Policy.PRIORITY_CATEGORY_REPEAT_CALLERS) { 347 if (isFirst) { 348 return mContext.getString(R.string.zen_mode_repeat_callers); 349 } else { 350 return mContext.getString(R.string.zen_mode_repeat_callers_list); 351 } 352 } 353 354 return ""; 355 } 356 } 357 358 /** 359 * For Search. 360 */ 361 public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 362 new BaseSearchIndexProvider(R.xml.zen_mode_settings) { 363 364 @Override 365 public List<String> getNonIndexableKeys(Context context) { 366 List<String> keys = super.getNonIndexableKeys(context); 367 keys.add(ZenModeDurationPreferenceController.KEY); 368 return keys; 369 } 370 371 @Override 372 public List<AbstractPreferenceController> createPreferenceControllers(Context 373 context) { 374 return buildPreferenceControllers(context, null, null, 375 null, null); 376 } 377 }; 378 } 379