• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 android.app.Dialog;
20 import android.app.NotificationManager;
21 import android.app.settings.SettingsEnums;
22 import android.content.Context;
23 import android.content.DialogInterface;
24 import android.icu.text.ListFormatter;
25 import android.net.Uri;
26 import android.os.Bundle;
27 import android.provider.Settings;
28 import android.service.notification.ZenModeConfig;
29 import android.text.TextUtils;
30 import android.view.LayoutInflater;
31 import android.view.View;
32 import android.widget.TextView;
33 
34 import androidx.appcompat.app.AlertDialog;
35 import androidx.fragment.app.FragmentManager;
36 import androidx.preference.Preference;
37 
38 import com.android.settings.R;
39 import com.android.settings.core.SubSettingLauncher;
40 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
41 import com.android.settings.utils.AnnotationSpan;
42 import com.android.settingslib.core.lifecycle.Lifecycle;
43 
44 import java.util.ArrayList;
45 import java.util.List;
46 import java.util.Objects;
47 
48 public class ZenModeSettingsFooterPreferenceController extends AbstractZenModePreferenceController {
49     static final String KEY = "footer_preference";
50     private FragmentManager mFragment;
51 
ZenModeSettingsFooterPreferenceController(Context context, Lifecycle lifecycle, FragmentManager fragment)52     public ZenModeSettingsFooterPreferenceController(Context context, Lifecycle lifecycle,
53             FragmentManager fragment) {
54         super(context, KEY, lifecycle);
55         mFragment = fragment;
56     }
57 
58     @Override
isAvailable()59     public boolean isAvailable() {
60         switch(getZenMode()) {
61             case Settings.Global.ZEN_MODE_ALARMS:
62             case Settings.Global.ZEN_MODE_NO_INTERRUPTIONS:
63             case Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
64                 return true;
65             case Settings.Global.ZEN_MODE_OFF:
66             default:
67                 return false;
68         }
69     }
70 
71     @Override
getPreferenceKey()72     public String getPreferenceKey() {
73         return KEY;
74     }
75 
76     @Override
updateState(Preference preference)77     public void updateState(Preference preference) {
78         super.updateState(preference);
79 
80         boolean isAvailable = isAvailable();
81         preference.setVisible(isAvailable);
82         if (isAvailable) {
83             preference.setTitle(getFooterText());
84         }
85     }
86 
getFooterText()87     protected CharSequence getFooterText() {
88         ZenModeConfig config = getZenModeConfig();
89 
90         NotificationManager.Policy appliedPolicy = mBackend.getConsolidatedPolicy();
91         NotificationManager.Policy defaultPolicy = config.toNotificationPolicy();
92         final boolean usingCustomPolicy = !Objects.equals(appliedPolicy, defaultPolicy);
93 
94         if (usingCustomPolicy) {
95             final List<ZenModeConfig.ZenRule> activeRules = getActiveRules(config);
96             final List<String> rulesNames = new ArrayList<>();
97             for (ZenModeConfig.ZenRule rule : activeRules) {
98                 if (rule.name != null) {
99                     rulesNames.add(rule.name);
100                 }
101             }
102             if (rulesNames.size() > 0) {
103                 String rules = ListFormatter.getInstance().format(rulesNames);
104                 if (!rules.isEmpty()) {
105                     final AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo(
106                             AnnotationSpan.LinkInfo.DEFAULT_ANNOTATION, new View.OnClickListener() {
107                                 @Override
108                                 public void onClick(View v) {
109                                     showCustomSettingsDialog();
110                                 }
111                             });
112                     return TextUtils.concat(mContext.getResources().getString(
113                             R.string.zen_mode_settings_dnd_custom_settings_footer, rules),
114                             AnnotationSpan.linkify(mContext.getResources().getText(
115                             R.string.zen_mode_settings_dnd_custom_settings_footer_link),
116                             linkInfo));
117                 }
118             }
119         }
120         return getDefaultPolicyFooter(config);
121     }
122 
getDefaultPolicyFooter(ZenModeConfig config)123     private String getDefaultPolicyFooter(ZenModeConfig config) {
124         String footerText = "";
125         long latestEndTime = -1;
126 
127         // DND turned on by manual rule
128         if (config.manualRule != null) {
129             final Uri id = config.manualRule.conditionId;
130             if (config.manualRule.enabler != null) {
131                 // app triggered manual rule
132                 String appOwner = mZenModeConfigWrapper.getOwnerCaption(config.manualRule.enabler);
133                 if (!appOwner.isEmpty()) {
134                     footerText = mContext.getString(
135                             R.string.zen_mode_settings_dnd_automatic_rule_app, appOwner);
136                 }
137             } else {
138                 if (id == null) {
139                     return mContext.getString(
140                             R.string.zen_mode_settings_dnd_manual_indefinite);
141                 } else {
142                     latestEndTime = mZenModeConfigWrapper.parseManualRuleTime(id);
143                     if (latestEndTime > 0) {
144                         final CharSequence formattedTime = mZenModeConfigWrapper.getFormattedTime(
145                                 latestEndTime, mContext.getUserId());
146                         footerText = mContext.getString(
147                                 R.string.zen_mode_settings_dnd_manual_end_time,
148                                 formattedTime);
149                     }
150                 }
151             }
152         }
153 
154         // DND turned on by an automatic rule
155         for (ZenModeConfig.ZenRule automaticRule : config.automaticRules.values()) {
156             if (automaticRule.isAutomaticActive()) {
157                 // set footer if 3rd party rule
158                 if (!mZenModeConfigWrapper.isTimeRule(automaticRule.conditionId)) {
159                     return mContext.getString(R.string.zen_mode_settings_dnd_automatic_rule,
160                             automaticRule.name);
161                 } else {
162                     // set footer if automatic rule end time is the latest active rule end time
163                     long endTime = mZenModeConfigWrapper.parseAutomaticRuleEndTime(
164                             automaticRule.conditionId);
165                     if (endTime > latestEndTime) {
166                         latestEndTime = endTime;
167                         footerText = mContext.getString(
168                                 R.string.zen_mode_settings_dnd_automatic_rule, automaticRule.name);
169                     }
170                 }
171             }
172         }
173         return footerText;
174     }
175 
getActiveRules(ZenModeConfig config)176     private List<ZenModeConfig.ZenRule> getActiveRules(ZenModeConfig config) {
177         List<ZenModeConfig.ZenRule> zenRules = new ArrayList<>();
178         if (config.manualRule != null) {
179             zenRules.add(config.manualRule);
180         }
181 
182         for (ZenModeConfig.ZenRule automaticRule : config.automaticRules.values()) {
183             if (automaticRule.isAutomaticActive()) {
184                 zenRules.add(automaticRule);
185             }
186         }
187         return zenRules;
188     }
189 
showCustomSettingsDialog()190     private void showCustomSettingsDialog() {
191         ZenCustomSettingsDialog dialog = new ZenCustomSettingsDialog();
192         dialog.setNotificationPolicy(mBackend.getConsolidatedPolicy());
193         dialog.show(mFragment, ZenCustomSettingsDialog.class.getName());
194     }
195 
196     public static class ZenCustomSettingsDialog extends InstrumentedDialogFragment {
197         private String KEY_POLICY = "policy";
198         private NotificationManager.Policy mPolicy;
199         private ZenModeSettings.SummaryBuilder mSummaryBuilder;
200 
setNotificationPolicy(NotificationManager.Policy policy)201         public void setNotificationPolicy(NotificationManager.Policy policy) {
202             mPolicy = policy;
203         }
204 
205         @Override
onCreateDialog(Bundle savedInstanceState)206         public Dialog onCreateDialog(Bundle savedInstanceState) {
207             Context context  = getActivity();
208             if (savedInstanceState != null) {
209                 NotificationManager.Policy policy = savedInstanceState.getParcelable(KEY_POLICY);
210                 if (policy != null) {
211                     mPolicy = policy;
212                 }
213             }
214 
215             mSummaryBuilder = new ZenModeSettings.SummaryBuilder(context);
216 
217             AlertDialog customSettingsDialog = new AlertDialog.Builder(context)
218                     .setTitle(R.string.zen_custom_settings_dialog_title)
219                     .setNeutralButton(R.string.zen_custom_settings_dialog_review_schedule,
220                             new DialogInterface.OnClickListener() {
221                                 @Override
222                                 public void onClick(DialogInterface dialog,
223                                         int which) {
224                                     new SubSettingLauncher(context)
225                                             .setDestination(
226                                                     ZenModeAutomationSettings.class.getName())
227                                             .setSourceMetricsCategory(
228                                                     SettingsEnums.NOTIFICATION_ZEN_MODE_AUTOMATION)
229                                             .launch();
230                                 }
231                             })
232                     .setPositiveButton(R.string.zen_custom_settings_dialog_ok, null)
233                     .setView(LayoutInflater.from(context).inflate(context.getResources().getLayout(
234                             R.layout.zen_custom_settings_dialog), null, false))
235                     .create();
236 
237             customSettingsDialog.setOnShowListener(new DialogInterface.OnShowListener() {
238                 @Override
239                 public void onShow(DialogInterface dialog) {
240                     TextView allowCallsText = customSettingsDialog.findViewById(
241                             R.id.zen_custom_settings_dialog_calls_allow);
242                     TextView allowMessagesText = customSettingsDialog.findViewById(
243                             R.id.zen_custom_settings_dialog_messages_allow);
244                     TextView allowAlarmsText = customSettingsDialog.findViewById(
245                             R.id.zen_custom_settings_dialog_alarms_allow);
246                     TextView allowMediaText = customSettingsDialog.findViewById(
247                             R.id.zen_custom_settings_dialog_media_allow);
248                     TextView allowSystemText = customSettingsDialog.findViewById(
249                             R.id.zen_custom_settings_dialog_system_allow);
250                     TextView allowRemindersText = customSettingsDialog.findViewById(
251                             R.id.zen_custom_settings_dialog_reminders_allow);
252                     TextView allowEventsText = customSettingsDialog.findViewById(
253                             R.id.zen_custom_settings_dialog_events_allow);
254                     TextView notificationsText = customSettingsDialog.findViewById(
255                             R.id.zen_custom_settings_dialog_show_notifications);
256 
257                     allowCallsText.setText(mSummaryBuilder.getCallsSettingSummary(mPolicy));
258                     allowMessagesText.setText(mSummaryBuilder.getMessagesSettingSummary(mPolicy));
259                     allowAlarmsText.setText(getAllowRes(mPolicy.allowAlarms()));
260                     allowMediaText.setText(getAllowRes(mPolicy.allowMedia()));
261                     allowSystemText.setText(getAllowRes(mPolicy.allowSystem()));
262                     allowRemindersText.setText(getAllowRes(mPolicy.allowReminders()));
263                     allowEventsText.setText(getAllowRes(mPolicy.allowEvents()));
264                     notificationsText.setText(mSummaryBuilder.getBlockedEffectsSummary(mPolicy));
265                 }
266             });
267 
268             return customSettingsDialog;
269         }
270 
271         @Override
getMetricsCategory()272         public int getMetricsCategory() {
273             return SettingsEnums.ZEN_CUSTOM_SETTINGS_DIALOG;
274         }
275 
getAllowRes(boolean allow)276         private int getAllowRes(boolean allow) {
277             return allow ? R.string.zen_mode_sound_summary_on : R.string.zen_mode_sound_summary_off;
278         }
279 
280         @Override
onSaveInstanceState(Bundle outState)281         public void onSaveInstanceState(Bundle outState) {
282             super.onSaveInstanceState(outState);
283             outState.putParcelable(KEY_POLICY, mPolicy);
284         }
285     }
286 }
287