1 /* 2 * Copyright (C) 2020 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.NotificationManager; 20 import android.app.settings.SettingsEnums; 21 import android.content.Context; 22 import android.content.pm.ParceledListSlice; 23 import android.icu.text.MessageFormat; 24 import android.os.AsyncTask; 25 import android.service.notification.ConversationChannelWrapper; 26 import android.view.View; 27 28 import androidx.annotation.VisibleForTesting; 29 import androidx.preference.Preference; 30 import androidx.preference.PreferenceCategory; 31 import androidx.preference.PreferenceScreen; 32 33 import com.android.settings.R; 34 import com.android.settings.core.SubSettingLauncher; 35 import com.android.settings.notification.NotificationBackend; 36 import com.android.settings.notification.app.ConversationListSettings; 37 import com.android.settingslib.core.lifecycle.Lifecycle; 38 import com.android.settingslib.widget.RadioButtonPreference; 39 40 import java.util.ArrayList; 41 import java.util.HashMap; 42 import java.util.List; 43 import java.util.Locale; 44 import java.util.Map; 45 46 /** 47 * Options to choose the priority conversations that are allowed to bypass DND. 48 */ 49 public class ZenModePriorityConversationsPreferenceController 50 extends AbstractZenModePreferenceController { 51 private static final int UNSET = -1; 52 @VisibleForTesting static final String KEY_ALL = "conversations_all"; 53 @VisibleForTesting static final String KEY_IMPORTANT = "conversations_important"; 54 @VisibleForTesting static final String KEY_NONE = "conversations_none"; 55 56 private final NotificationBackend mNotificationBackend; 57 58 private int mNumImportantConversations = UNSET; 59 private int mNumConversations = UNSET; 60 private PreferenceCategory mPreferenceCategory; 61 private List<RadioButtonPreference> mRadioButtonPreferences = new ArrayList<>(); 62 private Context mPreferenceScreenContext; 63 ZenModePriorityConversationsPreferenceController(Context context, String key, Lifecycle lifecycle, NotificationBackend notificationBackend)64 public ZenModePriorityConversationsPreferenceController(Context context, String key, 65 Lifecycle lifecycle, NotificationBackend notificationBackend) { 66 super(context, key, lifecycle); 67 mNotificationBackend = notificationBackend; 68 } 69 70 @Override displayPreference(PreferenceScreen screen)71 public void displayPreference(PreferenceScreen screen) { 72 mPreferenceScreenContext = screen.getContext(); 73 mPreferenceCategory = screen.findPreference(getPreferenceKey()); 74 if (mPreferenceCategory.findPreference(KEY_ALL) == null) { 75 makeRadioPreference(KEY_ALL, R.string.zen_mode_from_all_conversations); 76 makeRadioPreference(KEY_IMPORTANT, R.string.zen_mode_from_important_conversations); 77 makeRadioPreference(KEY_NONE, R.string.zen_mode_from_no_conversations); 78 updateChannelCounts(); 79 } 80 81 super.displayPreference(screen); 82 } 83 84 @Override onResume()85 public void onResume() { 86 super.onResume(); 87 updateChannelCounts(); 88 } 89 90 @Override isAvailable()91 public boolean isAvailable() { 92 return true; 93 } 94 95 @Override getPreferenceKey()96 public String getPreferenceKey() { 97 return KEY; 98 } 99 100 @Override updateState(Preference preference)101 public void updateState(Preference preference) { 102 final int currSetting = mBackend.getPriorityConversationSenders(); 103 104 for (RadioButtonPreference pref : mRadioButtonPreferences) { 105 pref.setChecked(keyToSetting(pref.getKey()) == currSetting); 106 pref.setSummary(getSummary(pref.getKey())); 107 } 108 } 109 keyToSetting(String key)110 private static int keyToSetting(String key) { 111 switch (key) { 112 case KEY_ALL: 113 return NotificationManager.Policy.CONVERSATION_SENDERS_ANYONE; 114 case KEY_IMPORTANT: 115 return NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT; 116 default: 117 return NotificationManager.Policy.CONVERSATION_SENDERS_NONE; 118 } 119 } 120 getSummary(String key)121 private String getSummary(String key) { 122 int numConversations; 123 if (KEY_ALL.equals(key)) { 124 numConversations = mNumConversations; 125 } else if (KEY_IMPORTANT.equals(key)) { 126 numConversations = mNumImportantConversations; 127 } else { 128 return null; 129 } 130 131 if (numConversations == UNSET) { 132 return null; 133 } else { 134 MessageFormat msgFormat = new MessageFormat( 135 mContext.getString(R.string.zen_mode_conversations_count), 136 Locale.getDefault()); 137 Map<String, Object> args = new HashMap<>(); 138 args.put("count", numConversations); 139 return msgFormat.format(args); 140 } 141 } 142 updateChannelCounts()143 private void updateChannelCounts() { 144 // Load conversations 145 new AsyncTask<Void, Void, Void>() { 146 @Override 147 protected Void doInBackground(Void... unused) { 148 ParceledListSlice<ConversationChannelWrapper> allConversations = 149 mNotificationBackend.getConversations(false); 150 int numConversations = 0; 151 if (allConversations != null) { 152 for (ConversationChannelWrapper conversation : allConversations.getList()) { 153 if (!conversation.getNotificationChannel().isDemoted()) { 154 numConversations++; 155 } 156 } 157 } 158 mNumConversations = numConversations; 159 160 ParceledListSlice<ConversationChannelWrapper> impConversations = 161 mNotificationBackend.getConversations(true); 162 int numImportantConversations = 0; 163 if (impConversations != null) { 164 for (ConversationChannelWrapper conversation : impConversations.getList()) { 165 if (!conversation.getNotificationChannel().isDemoted()) { 166 numImportantConversations++; 167 } 168 } 169 } 170 mNumImportantConversations = numImportantConversations; 171 return null; 172 } 173 174 @Override 175 protected void onPostExecute(Void unused) { 176 if (mContext == null) { 177 return; 178 } 179 updateState(mPreferenceCategory); 180 } 181 }.execute(); 182 } 183 makeRadioPreference(String key, int titleId)184 private RadioButtonPreference makeRadioPreference(String key, int titleId) { 185 final RadioButtonPreference pref = 186 new RadioButtonPreference(mPreferenceCategory.getContext()); 187 if (KEY_ALL.equals(key) || KEY_IMPORTANT.equals(key)) { 188 pref.setExtraWidgetOnClickListener(mConversationSettingsWidgetClickListener); 189 } 190 pref.setKey(key); 191 pref.setTitle(titleId); 192 pref.setOnClickListener(mRadioButtonClickListener); 193 mPreferenceCategory.addPreference(pref); 194 mRadioButtonPreferences.add(pref); 195 return pref; 196 } 197 198 private View.OnClickListener mConversationSettingsWidgetClickListener = 199 new View.OnClickListener() { 200 @Override 201 public void onClick(View v) { 202 new SubSettingLauncher(mPreferenceScreenContext) 203 .setDestination(ConversationListSettings.class.getName()) 204 .setSourceMetricsCategory(SettingsEnums.DND_CONVERSATIONS) 205 .launch(); 206 } 207 }; 208 209 private RadioButtonPreference.OnClickListener mRadioButtonClickListener = 210 new RadioButtonPreference.OnClickListener() { 211 @Override 212 public void onRadioButtonClicked(RadioButtonPreference preference) { 213 int selectedConversationSetting = keyToSetting(preference.getKey()); 214 if (selectedConversationSetting != mBackend.getPriorityConversationSenders()) { 215 mBackend.saveConversationSenders(selectedConversationSetting); 216 } 217 } 218 }; 219 } 220