1 /* 2 * Copyright (C) 2012 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 package com.android.mail.preferences; 17 18 import android.content.ContentUris; 19 import android.content.Context; 20 import android.database.Cursor; 21 import android.media.RingtoneManager; 22 import android.net.Uri; 23 import android.provider.Settings; 24 25 import com.android.mail.providers.Account; 26 import com.android.mail.providers.Folder; 27 import com.android.mail.providers.UIProvider.AccountCapabilities; 28 import com.android.mail.providers.UIProvider.FolderCapabilities; 29 import com.android.mail.utils.NotificationActionUtils.NotificationActionType; 30 import com.google.android.mail.common.base.Strings; 31 import com.google.common.collect.ImmutableSet; 32 33 import java.util.LinkedHashSet; 34 import java.util.Set; 35 36 /** 37 * Preferences relevant to one specific folder. In Email, this would only be used for an account's 38 * inbox. In Gmail, this is used for every account/label pair. 39 */ 40 public class FolderPreferences extends VersionedPrefs { 41 42 private static final String PREFS_NAME_PREFIX = "Folder"; 43 44 public static final class PreferenceKeys { 45 /** Boolean value indicating whether notifications are enabled */ 46 public static final String NOTIFICATIONS_ENABLED = "notifications-enabled"; 47 /** String value of the notification ringtone URI */ 48 public static final String NOTIFICATION_RINGTONE = "notification-ringtone"; 49 /** Boolean value indicating whether we should explicitly vibrate */ 50 public static final String NOTIFICATION_VIBRATE = "notification-vibrate"; 51 /** 52 * Boolean value indicating whether we notify for every message (<code>true</code>), or just 53 * once for the folder (<code>false</code>) 54 */ 55 public static final String NOTIFICATION_NOTIFY_EVERY_MESSAGE = 56 "notification-notify-every-message"; 57 58 public static final ImmutableSet<String> BACKUP_KEYS = 59 new ImmutableSet.Builder<String>() 60 .add(NOTIFICATIONS_ENABLED) 61 .add(NOTIFICATION_RINGTONE) 62 .add(NOTIFICATION_VIBRATE) 63 .add(NOTIFICATION_NOTIFY_EVERY_MESSAGE) 64 .build(); 65 } 66 67 private final Folder mFolder; 68 /** An id that is constant across app installations. */ 69 private final String mPersistentId; 70 private final boolean mUseInboxDefaultNotificationSettings; 71 72 /** 73 * @param accountEmail The account email. This must never change for the account. 74 * @param folder The folder 75 */ FolderPreferences(final Context context, final String accountEmail, final Folder folder, final boolean useInboxDefaultNotificationSettings)76 public FolderPreferences(final Context context, final String accountEmail, final Folder folder, 77 final boolean useInboxDefaultNotificationSettings) { 78 this(context, accountEmail, folder, folder.persistentId, 79 useInboxDefaultNotificationSettings); 80 } 81 82 /** 83 * A constructor that can be used when no {@link Folder} object is available (like during a 84 * restore). This will function as expected except when calling 85 * {@link #getDefaultNotificationActions(Context)}, so 86 * {@link #FolderPreferences(Context, String, Folder, boolean)} should be used if at all 87 * possible. 88 * 89 * @param accountEmail The account email. This must never change for the account. 90 * @param persistentId An identifier for the folder that does not change across app 91 * installations. 92 */ FolderPreferences(final Context context, final String accountEmail, final String persistentId, final boolean useInboxDefaultNotificationSettings)93 public FolderPreferences(final Context context, final String accountEmail, final String persistentId, 94 final boolean useInboxDefaultNotificationSettings) { 95 this(context, accountEmail, null, persistentId, useInboxDefaultNotificationSettings); 96 } 97 FolderPreferences(final Context context, final String accountEmail, final Folder folder, final String persistentId, final boolean useInboxDefaultNotificationSettings)98 private FolderPreferences(final Context context, final String accountEmail, final Folder folder, 99 final String persistentId, final boolean useInboxDefaultNotificationSettings) { 100 super(context, buildSharedPrefsName(accountEmail, persistentId)); 101 mFolder = folder; 102 mPersistentId = persistentId; 103 mUseInboxDefaultNotificationSettings = useInboxDefaultNotificationSettings; 104 } 105 buildSharedPrefsName(final String account, final String persistentId)106 private static String buildSharedPrefsName(final String account, final String persistentId) { 107 return PREFS_NAME_PREFIX + '-' + account + '-' + persistentId; 108 } 109 110 @Override performUpgrade(final int oldVersion, final int newVersion)111 protected void performUpgrade(final int oldVersion, final int newVersion) { 112 if (oldVersion > newVersion) { 113 throw new IllegalStateException( 114 "You appear to have downgraded your app. Please clear app data."); 115 } 116 } 117 118 @Override canBackup(final String key)119 protected boolean canBackup(final String key) { 120 if (mPersistentId == null) { 121 return false; 122 } 123 124 return PreferenceKeys.BACKUP_KEYS.contains(key); 125 } 126 127 @Override getBackupValue(final String key, final Object value)128 protected Object getBackupValue(final String key, final Object value) { 129 if (PreferenceKeys.NOTIFICATION_RINGTONE.equals(key)) { 130 return getRingtoneTitle((String) value); 131 } 132 133 return super.getBackupValue(key, value); 134 } 135 136 @Override getRestoreValue(final String key, final Object value)137 protected Object getRestoreValue(final String key, final Object value) { 138 if (PreferenceKeys.NOTIFICATION_RINGTONE.equals(key)) { 139 return getRingtoneUri((String) value); 140 } 141 142 return super.getBackupValue(key, value); 143 } 144 getRingtoneTitle(final String ringtoneUriString)145 private String getRingtoneTitle(final String ringtoneUriString) { 146 if (ringtoneUriString.length() == 0) { 147 return ringtoneUriString; 148 } 149 final Uri uri = Uri.parse(ringtoneUriString); 150 if (RingtoneManager.isDefault(uri)) { 151 return ringtoneUriString; 152 } 153 final RingtoneManager ringtoneManager = new RingtoneManager(getContext()); 154 ringtoneManager.setType(RingtoneManager.TYPE_NOTIFICATION); 155 final Cursor cursor = ringtoneManager.getCursor(); 156 try { 157 while (cursor.moveToNext()) { 158 final Uri cursorUri = ContentUris.withAppendedId( 159 Uri.parse(cursor.getString(RingtoneManager.URI_COLUMN_INDEX)), 160 cursor.getLong(RingtoneManager.ID_COLUMN_INDEX)); 161 if (cursorUri.toString().equals(ringtoneUriString)) { 162 final String title = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX); 163 if (!Strings.isNullOrEmpty(title)) { 164 return title; 165 } 166 } 167 } 168 } finally { 169 cursor.close(); 170 } 171 return null; 172 } 173 getRingtoneUri(final String name)174 private String getRingtoneUri(final String name) { 175 if (name.length() == 0 || RingtoneManager.isDefault(Uri.parse(name))) { 176 return name; 177 } 178 179 final RingtoneManager ringtoneManager = new RingtoneManager(getContext()); 180 ringtoneManager.setType(RingtoneManager.TYPE_NOTIFICATION); 181 final Cursor cursor = ringtoneManager.getCursor(); 182 try { 183 while (cursor.moveToNext()) { 184 String title = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX); 185 if (name.equals(title)) { 186 Uri uri = ContentUris.withAppendedId( 187 Uri.parse(cursor.getString(RingtoneManager.URI_COLUMN_INDEX)), 188 cursor.getLong(RingtoneManager.ID_COLUMN_INDEX)); 189 return uri.toString(); 190 } 191 } 192 } finally { 193 cursor.close(); 194 } 195 return null; 196 } 197 198 /** 199 * If <code>true</code>, we use inbox-defaults for notification settings. If <code>false</code>, 200 * we use standard defaults. 201 */ getUseInboxDefaultNotificationSettings()202 private boolean getUseInboxDefaultNotificationSettings() { 203 return mUseInboxDefaultNotificationSettings; 204 } 205 isNotificationsEnabledSet()206 public boolean isNotificationsEnabledSet() { 207 return getSharedPreferences().contains(PreferenceKeys.NOTIFICATIONS_ENABLED); 208 } 209 areNotificationsEnabled()210 public boolean areNotificationsEnabled() { 211 return getSharedPreferences().getBoolean( 212 PreferenceKeys.NOTIFICATIONS_ENABLED, getUseInboxDefaultNotificationSettings()); 213 } 214 setNotificationsEnabled(final boolean enabled)215 public void setNotificationsEnabled(final boolean enabled) { 216 getEditor().putBoolean(PreferenceKeys.NOTIFICATIONS_ENABLED, enabled).apply(); 217 notifyBackupPreferenceChanged(); 218 } 219 getNotificationRingtoneUri()220 public String getNotificationRingtoneUri() { 221 return getSharedPreferences().getString(PreferenceKeys.NOTIFICATION_RINGTONE, 222 Settings.System.DEFAULT_NOTIFICATION_URI.toString()); 223 } 224 setNotificationRingtoneUri(final String uri)225 public void setNotificationRingtoneUri(final String uri) { 226 getEditor().putString(PreferenceKeys.NOTIFICATION_RINGTONE, uri).apply(); 227 notifyBackupPreferenceChanged(); 228 } 229 isNotificationVibrateEnabled()230 public boolean isNotificationVibrateEnabled() { 231 return getSharedPreferences().getBoolean(PreferenceKeys.NOTIFICATION_VIBRATE, false); 232 } 233 setNotificationVibrateEnabled(final boolean enabled)234 public void setNotificationVibrateEnabled(final boolean enabled) { 235 getEditor().putBoolean(PreferenceKeys.NOTIFICATION_VIBRATE, enabled).apply(); 236 notifyBackupPreferenceChanged(); 237 } 238 isEveryMessageNotificationEnabled()239 public boolean isEveryMessageNotificationEnabled() { 240 return getSharedPreferences() 241 .getBoolean(PreferenceKeys.NOTIFICATION_NOTIFY_EVERY_MESSAGE, false); 242 } 243 setEveryMessageNotificationEnabled(final boolean enabled)244 public void setEveryMessageNotificationEnabled(final boolean enabled) { 245 getEditor().putBoolean(PreferenceKeys.NOTIFICATION_NOTIFY_EVERY_MESSAGE, enabled).apply(); 246 notifyBackupPreferenceChanged(); 247 } 248 getNotificationActions(final Account account)249 public Set<String> getNotificationActions(final Account account) { 250 final boolean supportsArchiveRemoveLabel = 251 mFolder.supportsCapability(FolderCapabilities.ARCHIVE) 252 || mFolder.supportsCapability(FolderCapabilities.ALLOWS_REMOVE_CONVERSATION); 253 final boolean preferDelete = MailPrefs.RemovalActions.DELETE.equals( 254 MailPrefs.get(getContext()).getRemovalAction( 255 account.supportsCapability(AccountCapabilities.ARCHIVE))); 256 final NotificationActionType destructiveActionType = 257 supportsArchiveRemoveLabel && !preferDelete ? 258 NotificationActionType.ARCHIVE_REMOVE_LABEL : NotificationActionType.DELETE; 259 final String destructiveAction = destructiveActionType.getPersistedValue(); 260 261 final String replyAction = 262 MailPrefs.get(getContext()).getDefaultReplyAll() 263 ? NotificationActionType.REPLY_ALL.getPersistedValue() 264 : NotificationActionType.REPLY.getPersistedValue(); 265 266 final Set<String> notificationActions = new LinkedHashSet<String>(2); 267 notificationActions.add(destructiveAction); 268 notificationActions.add(replyAction); 269 270 return notificationActions; 271 } 272 } 273