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;
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_EVENTS;
22 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA;
23 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES;
24 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REMINDERS;
25 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REPEAT_CALLERS;
26 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM;
27 
28 import android.app.AutomaticZenRule;
29 import android.app.NotificationManager;
30 import android.app.NotificationManager.Policy;
31 import android.app.settings.SettingsEnums;
32 import android.content.Context;
33 import android.provider.SearchIndexableResource;
34 import android.provider.Settings;
35 import android.service.notification.ZenModeConfig;
36 
37 import androidx.annotation.VisibleForTesting;
38 import androidx.fragment.app.FragmentManager;
39 
40 import com.android.settings.R;
41 import com.android.settings.search.BaseSearchIndexProvider;
42 import com.android.settings.search.Indexable;
43 import com.android.settingslib.core.AbstractPreferenceController;
44 import com.android.settingslib.core.lifecycle.Lifecycle;
45 import com.android.settingslib.search.SearchIndexable;
46 
47 import java.util.ArrayList;
48 import java.util.Arrays;
49 import java.util.List;
50 import java.util.Map;
51 import java.util.Map.Entry;
52 import java.util.function.Predicate;
53 
54 @SearchIndexable
55 public class ZenModeSettings extends ZenModeSettingsBase {
56     @Override
onResume()57     public void onResume() {
58         super.onResume();
59     }
60 
61     @Override
getPreferenceScreenResId()62     protected int getPreferenceScreenResId() {
63         return R.xml.zen_mode_settings;
64     }
65 
66     @Override
getMetricsCategory()67     public int getMetricsCategory() {
68         return SettingsEnums.NOTIFICATION_ZEN_MODE;
69     }
70 
71     @Override
createPreferenceControllers(Context context)72     protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
73         return buildPreferenceControllers(context, getSettingsLifecycle(), getFragmentManager());
74     }
75 
76     @Override
getHelpResource()77     public int getHelpResource() {
78         return R.string.help_uri_interruptions;
79     }
80 
buildPreferenceControllers(Context context, Lifecycle lifecycle, FragmentManager fragmentManager)81     private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
82             Lifecycle lifecycle, FragmentManager fragmentManager) {
83         List<AbstractPreferenceController> controllers = new ArrayList<>();
84         controllers.add(new ZenModeCallsPreferenceController(context, lifecycle,
85                 "zen_mode_behavior_calls"));
86         controllers.add(new ZenModeMessagesPreferenceController(context, lifecycle,
87                 "zen_mode_behavior_messages"));
88         controllers.add(new ZenModeBlockedEffectsPreferenceController(context, lifecycle));
89         controllers.add(new ZenModeDurationPreferenceController(context, lifecycle));
90         controllers.add(new ZenModeAutomationPreferenceController(context));
91         controllers.add(new ZenModeButtonPreferenceController(context, lifecycle, fragmentManager));
92         controllers.add(new ZenModeSettingsFooterPreferenceController(context, lifecycle,
93                 fragmentManager));
94         return controllers;
95     }
96 
97     public static class SummaryBuilder {
98 
99         private Context mContext;
100 
SummaryBuilder(Context context)101         public SummaryBuilder(Context context) {
102             mContext = context;
103         }
104 
105         // these should match NotificationManager.Policy#ALL_PRIORITY_CATEGORIES
106         private static final int[] ALL_PRIORITY_CATEGORIES = {
107                 PRIORITY_CATEGORY_ALARMS,
108                 PRIORITY_CATEGORY_MEDIA,
109                 PRIORITY_CATEGORY_SYSTEM,
110                 PRIORITY_CATEGORY_MESSAGES,
111                 PRIORITY_CATEGORY_EVENTS,
112                 PRIORITY_CATEGORY_REMINDERS,
113                 PRIORITY_CATEGORY_CALLS,
114                 PRIORITY_CATEGORY_REPEAT_CALLERS,
115         };
116 
getSoundSettingSummary(Policy policy)117         String getSoundSettingSummary(Policy policy) {
118             List<String> enabledCategories = getEnabledCategories(policy,
119                     category -> PRIORITY_CATEGORY_ALARMS == category
120                             || PRIORITY_CATEGORY_MEDIA == category
121                             || PRIORITY_CATEGORY_SYSTEM == category, false);
122             int numCategories = enabledCategories.size();
123             if (numCategories == 0) {
124                 return mContext.getString(R.string.zen_sound_all_muted);
125             } else if (numCategories == 1) {
126                 return mContext.getString(R.string.zen_sound_one_allowed,
127                         enabledCategories.get(0));
128             } else if (numCategories == 2) {
129                 return mContext.getString(R.string.zen_sound_two_allowed,
130                         enabledCategories.get(0),
131                         enabledCategories.get(1));
132             } else if (numCategories == 3) {
133                 return mContext.getString(R.string.zen_sound_three_allowed,
134                         enabledCategories.get(0),
135                         enabledCategories.get(1),
136                         enabledCategories.get(2));
137             } else {
138                 return mContext.getString(R.string.zen_sound_none_muted);
139             }
140         }
141 
getCallsSettingSummary(Policy policy)142         String getCallsSettingSummary(Policy policy) {
143             List<String> enabledCategories = getEnabledCategories(policy,
144                     category -> PRIORITY_CATEGORY_CALLS == category
145                             || PRIORITY_CATEGORY_REPEAT_CALLERS == category, false);
146             int numCategories = enabledCategories.size();
147             if (numCategories == 0) {
148                 return mContext.getString(R.string.zen_mode_from_none_calls);
149             } else if (numCategories == 1) {
150                 return mContext.getString(R.string.zen_mode_calls_summary_one,
151                         enabledCategories.get(0));
152             } else {
153                 return mContext.getString(R.string.zen_mode_calls_summary_two,
154                         enabledCategories.get(0),
155                         enabledCategories.get(1));
156             }
157         }
158 
getMessagesSettingSummary(Policy policy)159         String getMessagesSettingSummary(Policy policy) {
160             List<String> enabledCategories = getEnabledCategories(policy,
161                     category -> PRIORITY_CATEGORY_MESSAGES == category, false);
162             int numCategories = enabledCategories.size();
163             if (numCategories == 0) {
164                 return mContext.getString(R.string.zen_mode_from_none_messages);
165             } else {
166                 return enabledCategories.get(0);
167             }
168         }
169 
getSoundSummary()170         String getSoundSummary() {
171             int zenMode = NotificationManager.from(mContext).getZenMode();
172 
173             if (zenMode != Settings.Global.ZEN_MODE_OFF) {
174                 ZenModeConfig config = NotificationManager.from(mContext).getZenModeConfig();
175                 String description = ZenModeConfig.getDescription(mContext, true, config, false);
176 
177                 if (description == null) {
178                     return mContext.getString(R.string.zen_mode_sound_summary_on);
179                 } else {
180                     return mContext.getString(R.string.zen_mode_sound_summary_on_with_info,
181                             description);
182                 }
183             } else {
184                 final int count = getEnabledAutomaticRulesCount();
185                 if (count > 0) {
186                     return mContext.getString(R.string.zen_mode_sound_summary_off_with_info,
187                             mContext.getResources().getQuantityString(
188                                     R.plurals.zen_mode_sound_summary_summary_off_info,
189                                     count, count));
190                 }
191 
192                 return mContext.getString(R.string.zen_mode_sound_summary_off);
193             }
194         }
195 
getBlockedEffectsSummary(Policy policy)196         String getBlockedEffectsSummary(Policy policy) {
197             if (policy.suppressedVisualEffects == 0) {
198                 return mContext.getResources().getString(
199                         R.string.zen_mode_restrict_notifications_summary_muted);
200             } else if (Policy.areAllVisualEffectsSuppressed(policy.suppressedVisualEffects)) {
201                 return mContext.getResources().getString(
202                         R.string.zen_mode_restrict_notifications_summary_hidden);
203             } else {
204                 return mContext.getResources().getString(
205                         R.string.zen_mode_restrict_notifications_summary_custom);
206             }
207         }
208 
getAutomaticRulesSummary()209         String getAutomaticRulesSummary() {
210             final int count = getEnabledAutomaticRulesCount();
211             return count == 0 ? mContext.getString(R.string.zen_mode_settings_summary_off)
212                     : mContext.getResources().getQuantityString(
213                             R.plurals.zen_mode_settings_summary_on, count, count);
214         }
215 
216         @VisibleForTesting
getEnabledAutomaticRulesCount()217         int getEnabledAutomaticRulesCount() {
218             int count = 0;
219             final Map<String, AutomaticZenRule> ruleMap =
220                     NotificationManager.from(mContext).getAutomaticZenRules();
221             if (ruleMap != null) {
222                 for (Entry<String, AutomaticZenRule> ruleEntry : ruleMap.entrySet()) {
223                     final AutomaticZenRule rule = ruleEntry.getValue();
224                     if (rule != null && rule.isEnabled()) {
225                         count++;
226                     }
227                 }
228             }
229             return count;
230         }
231 
getEnabledCategories(Policy policy, Predicate<Integer> filteredCategories, boolean capitalizeFirstInList)232         private List<String> getEnabledCategories(Policy policy,
233                 Predicate<Integer> filteredCategories, boolean capitalizeFirstInList) {
234             List<String> enabledCategories = new ArrayList<>();
235             for (int category : ALL_PRIORITY_CATEGORIES) {
236                 boolean isFirst = capitalizeFirstInList && enabledCategories.isEmpty();
237                 if (filteredCategories.test(category) && isCategoryEnabled(policy, category)) {
238                     if (category == Policy.PRIORITY_CATEGORY_REPEAT_CALLERS
239                             && isCategoryEnabled(policy, Policy.PRIORITY_CATEGORY_CALLS)
240                             && policy.priorityCallSenders == Policy.PRIORITY_SENDERS_ANY) {
241                         continue;
242                     }
243 
244                     enabledCategories.add(getCategory(category, policy, isFirst));
245                 }
246             }
247             return enabledCategories;
248         }
249 
isCategoryEnabled(Policy policy, int categoryType)250         private boolean isCategoryEnabled(Policy policy, int categoryType) {
251             return (policy.priorityCategories & categoryType) != 0;
252         }
253 
getCategory(int category, Policy policy, boolean isFirst)254         private String getCategory(int category, Policy policy, boolean isFirst) {
255             if (category == PRIORITY_CATEGORY_ALARMS) {
256                 if (isFirst) {
257                     return mContext.getString(R.string.zen_mode_alarms);
258                 } else {
259                     return mContext.getString(R.string.zen_mode_alarms_list);
260                 }
261             } else if (category == PRIORITY_CATEGORY_MEDIA) {
262                 if (isFirst) {
263                     return mContext.getString(R.string.zen_mode_media);
264                 } else {
265                     return mContext.getString(R.string.zen_mode_media_list);
266                 }
267             } else if (category == PRIORITY_CATEGORY_SYSTEM) {
268                 if (isFirst) {
269                     return mContext.getString(R.string.zen_mode_system);
270                 } else {
271                     return mContext.getString(R.string.zen_mode_system_list);
272                 }
273             } else if (category == Policy.PRIORITY_CATEGORY_MESSAGES) {
274                 if (policy.priorityMessageSenders == Policy.PRIORITY_SENDERS_ANY) {
275                     return mContext.getString(R.string.zen_mode_from_anyone);
276                 } else if (policy.priorityMessageSenders == Policy.PRIORITY_SENDERS_CONTACTS){
277                     return mContext.getString(R.string.zen_mode_from_contacts);
278                 } else {
279                     return mContext.getString(R.string.zen_mode_from_starred);
280                 }
281             } else if (category == Policy.PRIORITY_CATEGORY_EVENTS) {
282                 if (isFirst) {
283                     return mContext.getString(R.string.zen_mode_events);
284                 } else {
285                     return mContext.getString(R.string.zen_mode_events_list);
286                 }
287             } else if (category == Policy.PRIORITY_CATEGORY_REMINDERS) {
288                 if (isFirst) {
289                     return mContext.getString(R.string.zen_mode_reminders);
290                 } else {
291                     return mContext.getString(R.string.zen_mode_reminders_list);
292                 }
293             } else if (category == Policy.PRIORITY_CATEGORY_CALLS) {
294                 if (policy.priorityCallSenders == Policy.PRIORITY_SENDERS_ANY) {
295                     return mContext.getString(R.string.zen_mode_all_callers);
296                 } else if (policy.priorityCallSenders == Policy.PRIORITY_SENDERS_CONTACTS){
297                     return mContext.getString(R.string.zen_mode_contacts_callers);
298                 } else {
299                     return mContext.getString(R.string.zen_mode_starred_callers);
300                 }
301             } else if (category == Policy.PRIORITY_CATEGORY_REPEAT_CALLERS) {
302                 if (isFirst) {
303                     return mContext.getString(R.string.zen_mode_repeat_callers);
304                 } else {
305                     return mContext.getString(R.string.zen_mode_repeat_callers_list);
306                 }
307             }
308 
309             return "";
310         }
311     }
312 
313     /**
314      * For Search.
315      */
316     public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
317             new BaseSearchIndexProvider() {
318 
319                 @Override
320                 public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
321                         boolean enabled) {
322                     final SearchIndexableResource sir = new SearchIndexableResource(context);
323                     sir.xmlResId = R.xml.zen_mode_settings;
324                     return Arrays.asList(sir);
325                 }
326 
327                 @Override
328                 public List<String> getNonIndexableKeys(Context context) {
329                     List<String> keys = super.getNonIndexableKeys(context);
330                     keys.add(ZenModeDurationPreferenceController.KEY);
331                     return keys;
332                 }
333 
334                 @Override
335                 public List<AbstractPreferenceController> createPreferenceControllers(Context
336                         context) {
337                     return buildPreferenceControllers(context, null, null);
338                 }
339             };
340 }
341