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.zen; 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.switch_off_text; 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