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 */ 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 */ 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 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 106 private static String buildSharedPrefsName(final String account, final String persistentId) { 107 return PREFS_NAME_PREFIX + '-' + account + '-' + persistentId; 108 } 109 110 @Override 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 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 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 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 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 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 */ 202 private boolean getUseInboxDefaultNotificationSettings() { 203 return mUseInboxDefaultNotificationSettings; 204 } 205 206 public boolean isNotificationsEnabledSet() { 207 return getSharedPreferences().contains(PreferenceKeys.NOTIFICATIONS_ENABLED); 208 } 209 210 public boolean areNotificationsEnabled() { 211 return getSharedPreferences().getBoolean( 212 PreferenceKeys.NOTIFICATIONS_ENABLED, getUseInboxDefaultNotificationSettings()); 213 } 214 215 public void setNotificationsEnabled(final boolean enabled) { 216 getEditor().putBoolean(PreferenceKeys.NOTIFICATIONS_ENABLED, enabled).apply(); 217 notifyBackupPreferenceChanged(); 218 } 219 220 public String getNotificationRingtoneUri() { 221 return getSharedPreferences().getString(PreferenceKeys.NOTIFICATION_RINGTONE, 222 Settings.System.DEFAULT_NOTIFICATION_URI.toString()); 223 } 224 225 public void setNotificationRingtoneUri(final String uri) { 226 getEditor().putString(PreferenceKeys.NOTIFICATION_RINGTONE, uri).apply(); 227 notifyBackupPreferenceChanged(); 228 } 229 230 public boolean isNotificationVibrateEnabled() { 231 return getSharedPreferences().getBoolean(PreferenceKeys.NOTIFICATION_VIBRATE, false); 232 } 233 234 public void setNotificationVibrateEnabled(final boolean enabled) { 235 getEditor().putBoolean(PreferenceKeys.NOTIFICATION_VIBRATE, enabled).apply(); 236 notifyBackupPreferenceChanged(); 237 } 238 239 public boolean isEveryMessageNotificationEnabled() { 240 return getSharedPreferences() 241 .getBoolean(PreferenceKeys.NOTIFICATION_NOTIFY_EVERY_MESSAGE, false); 242 } 243 244 public void setEveryMessageNotificationEnabled(final boolean enabled) { 245 getEditor().putBoolean(PreferenceKeys.NOTIFICATION_NOTIFY_EVERY_MESSAGE, enabled).apply(); 246 notifyBackupPreferenceChanged(); 247 } 248 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