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