Preferences.java revision f419287f22ae44f25e1ba1f757ec33c7941bbfa8
1/* 2 * Copyright (C) 2008 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 17package com.android.email; 18 19import android.content.Context; 20import android.content.SharedPreferences; 21import android.text.TextUtils; 22import android.util.Log; 23 24import com.android.emailcommon.Logging; 25import com.android.emailcommon.provider.Account; 26 27import org.json.JSONArray; 28import org.json.JSONException; 29 30import java.util.HashSet; 31import java.util.UUID; 32 33public class Preferences { 34 35 // Preferences file 36 public static final String PREFERENCES_FILE = "AndroidMail.Main"; 37 38 // Preferences field names 39 private static final String ACCOUNT_UUIDS = "accountUuids"; 40 private static final String ENABLE_DEBUG_LOGGING = "enableDebugLogging"; 41 private static final String ENABLE_EXCHANGE_LOGGING = "enableExchangeLogging"; 42 private static final String ENABLE_EXCHANGE_FILE_LOGGING = "enableExchangeFileLogging"; 43 private static final String INHIBIT_GRAPHICS_ACCELERATION = "inhibitGraphicsAcceleration"; 44 private static final String FORCE_ONE_MINUTE_REFRESH = "forceOneMinuteRefresh"; 45 private static final String ENABLE_STRICT_MODE = "enableStrictMode"; 46 private static final String DEVICE_UID = "deviceUID"; 47 private static final String ONE_TIME_INITIALIZATION_PROGRESS = "oneTimeInitializationProgress"; 48 private static final String AUTO_ADVANCE_DIRECTION = "autoAdvance"; 49 private static final String TEXT_ZOOM = "textZoom"; 50 private static final String BACKGROUND_ATTACHMENTS = "backgroundAttachments"; 51 private static final String TRUSTED_SENDERS = "trustedSenders"; 52 private static final String LAST_ACCOUNT_USED = "lastAccountUsed"; 53 private static final String REQUIRE_MANUAL_SYNC_DIALOG_SHOWN = "requireManualSyncDialogShown"; 54 private static final String CONFIRM_DELETE = "confirm_delete"; 55 private static final String CONFIRM_SEND = "confirm_send"; 56 private static final String HIDE_CHECKBOXES = "hide_checkboxes"; 57 58 public static final int AUTO_ADVANCE_NEWER = 0; 59 public static final int AUTO_ADVANCE_OLDER = 1; 60 public static final int AUTO_ADVANCE_MESSAGE_LIST = 2; 61 // "move to older" was the behavior on older versions. 62 private static final int AUTO_ADVANCE_DEFAULT = AUTO_ADVANCE_OLDER; 63 private static final boolean CONFIRM_DELETE_DEFAULT = false; 64 private static final boolean CONFIRM_SEND_DEFAULT = false; 65 private static final boolean HIDE_CHECKBOXES_DEFAULT = false; 66 67 // The following constants are used as offsets into R.array.general_preference_text_zoom_size. 68 public static final int TEXT_ZOOM_TINY = 0; 69 public static final int TEXT_ZOOM_SMALL = 1; 70 public static final int TEXT_ZOOM_NORMAL = 2; 71 public static final int TEXT_ZOOM_LARGE = 3; 72 public static final int TEXT_ZOOM_HUGE = 4; 73 // "normal" will be the default 74 public static final int TEXT_ZOOM_DEFAULT = TEXT_ZOOM_NORMAL; 75 76 // Starting something new here: 77 // REPLY_ALL is saved by the framework (CheckBoxPreference's parent, Preference). 78 // i.e. android:persistent=true in general_preferences.xml 79 public static final String REPLY_ALL = "reply_all"; 80 // Reply All Default - when changing this, be sure to update general_preferences.xml 81 public static final boolean REPLY_ALL_DEFAULT = false; 82 83 private static Preferences sPreferences; 84 85 private final SharedPreferences mSharedPreferences; 86 87 /** 88 * A set of trusted senders for whom images and external resources should automatically be 89 * loaded for. 90 * Lazilly created. 91 */ 92 private HashSet<String> mTrustedSenders = null; 93 94 private Preferences(Context context) { 95 mSharedPreferences = context.getSharedPreferences(PREFERENCES_FILE, Context.MODE_PRIVATE); 96 } 97 98 /** 99 * TODO need to think about what happens if this gets GCed along with the 100 * Activity that initialized it. Do we lose ability to read Preferences in 101 * further Activities? Maybe this should be stored in the Application 102 * context. 103 */ 104 public static synchronized Preferences getPreferences(Context context) { 105 if (sPreferences == null) { 106 sPreferences = new Preferences(context); 107 } 108 return sPreferences; 109 } 110 111 public static SharedPreferences getSharedPreferences(Context context) { 112 return getPreferences(context).mSharedPreferences; 113 } 114 115 public static String getLegacyBackupPreference(Context context) { 116 return getPreferences(context).mSharedPreferences.getString(ACCOUNT_UUIDS, null); 117 } 118 119 public static void clearLegacyBackupPreference(Context context) { 120 getPreferences(context).mSharedPreferences.edit().remove(ACCOUNT_UUIDS).apply(); 121 } 122 123 public void setEnableDebugLogging(boolean value) { 124 mSharedPreferences.edit().putBoolean(ENABLE_DEBUG_LOGGING, value).apply(); 125 } 126 127 public boolean getEnableDebugLogging() { 128 return mSharedPreferences.getBoolean(ENABLE_DEBUG_LOGGING, false); 129 } 130 131 public void setEnableExchangeLogging(boolean value) { 132 mSharedPreferences.edit().putBoolean(ENABLE_EXCHANGE_LOGGING, value).apply(); 133 } 134 135 public boolean getEnableExchangeLogging() { 136 return mSharedPreferences.getBoolean(ENABLE_EXCHANGE_LOGGING, false); 137 } 138 139 public void setEnableExchangeFileLogging(boolean value) { 140 mSharedPreferences.edit().putBoolean(ENABLE_EXCHANGE_FILE_LOGGING, value).apply(); 141 } 142 143 public boolean getEnableExchangeFileLogging() { 144 return mSharedPreferences.getBoolean(ENABLE_EXCHANGE_FILE_LOGGING, false); 145 } 146 147 public void setInhibitGraphicsAcceleration(boolean value) { 148 mSharedPreferences.edit().putBoolean(INHIBIT_GRAPHICS_ACCELERATION, value).apply(); 149 } 150 151 public boolean getInhibitGraphicsAcceleration() { 152 return mSharedPreferences.getBoolean(INHIBIT_GRAPHICS_ACCELERATION, false); 153 } 154 155 public void setForceOneMinuteRefresh(boolean value) { 156 mSharedPreferences.edit().putBoolean(FORCE_ONE_MINUTE_REFRESH, value).apply(); 157 } 158 159 public boolean getForceOneMinuteRefresh() { 160 return mSharedPreferences.getBoolean(FORCE_ONE_MINUTE_REFRESH, false); 161 } 162 163 public void setEnableStrictMode(boolean value) { 164 mSharedPreferences.edit().putBoolean(ENABLE_STRICT_MODE, value).apply(); 165 } 166 167 public boolean getEnableStrictMode() { 168 return mSharedPreferences.getBoolean(ENABLE_STRICT_MODE, false); 169 } 170 171 /** 172 * Generate a new "device UID". This is local to Email app only, to prevent possibility 173 * of correlation with any other user activities in any other apps. 174 * @return a persistent, unique ID 175 */ 176 public synchronized String getDeviceUID() { 177 String result = mSharedPreferences.getString(DEVICE_UID, null); 178 if (result == null) { 179 result = UUID.randomUUID().toString(); 180 mSharedPreferences.edit().putString(DEVICE_UID, result).apply(); 181 } 182 return result; 183 } 184 185 public int getOneTimeInitializationProgress() { 186 return mSharedPreferences.getInt(ONE_TIME_INITIALIZATION_PROGRESS, 0); 187 } 188 189 public void setOneTimeInitializationProgress(int progress) { 190 mSharedPreferences.edit().putInt(ONE_TIME_INITIALIZATION_PROGRESS, progress).apply(); 191 } 192 193 public int getAutoAdvanceDirection() { 194 return mSharedPreferences.getInt(AUTO_ADVANCE_DIRECTION, AUTO_ADVANCE_DEFAULT); 195 } 196 197 public void setAutoAdvanceDirection(int direction) { 198 mSharedPreferences.edit().putInt(AUTO_ADVANCE_DIRECTION, direction).apply(); 199 } 200 201 public boolean getHideCheckboxes() { 202 return mSharedPreferences.getBoolean(HIDE_CHECKBOXES, HIDE_CHECKBOXES_DEFAULT); 203 } 204 205 public void setHideCheckboxes(boolean set) { 206 mSharedPreferences.edit().putBoolean(HIDE_CHECKBOXES, set).apply(); 207 } 208 209 public boolean getConfirmDelete() { 210 return mSharedPreferences.getBoolean(CONFIRM_DELETE, CONFIRM_DELETE_DEFAULT); 211 } 212 213 public void setConfirmDelete(boolean set) { 214 mSharedPreferences.edit().putBoolean(CONFIRM_DELETE, set).apply(); 215 } 216 217 public boolean getConfirmSend() { 218 return mSharedPreferences.getBoolean(CONFIRM_SEND, CONFIRM_SEND_DEFAULT); 219 } 220 221 public void setConfirmSend(boolean set) { 222 mSharedPreferences.edit().putBoolean(CONFIRM_SEND, set).apply(); 223 } 224 225 public int getTextZoom() { 226 return mSharedPreferences.getInt(TEXT_ZOOM, TEXT_ZOOM_DEFAULT); 227 } 228 229 public void setTextZoom(int zoom) { 230 mSharedPreferences.edit().putInt(TEXT_ZOOM, zoom).apply(); 231 } 232 233 public boolean getBackgroundAttachments() { 234 return mSharedPreferences.getBoolean(BACKGROUND_ATTACHMENTS, false); 235 } 236 237 public void setBackgroundAttachments(boolean allowed) { 238 mSharedPreferences.edit().putBoolean(BACKGROUND_ATTACHMENTS, allowed).apply(); 239 } 240 241 /** 242 * Determines whether or not a sender should be trusted and images should automatically be 243 * shown for messages by that sender. 244 */ 245 public boolean shouldShowImagesFor(String email) { 246 if (mTrustedSenders == null) { 247 try { 248 mTrustedSenders = parseEmailSet(mSharedPreferences.getString(TRUSTED_SENDERS, "")); 249 } catch (JSONException e) { 250 // Something went wrong, and the data is corrupt. Just clear it to be safe. 251 Log.w(Logging.LOG_TAG, "Trusted sender set corrupted. Clearing"); 252 mSharedPreferences.edit().putString(TRUSTED_SENDERS, "").apply(); 253 mTrustedSenders = new HashSet<String>(); 254 } 255 } 256 return mTrustedSenders.contains(email); 257 } 258 259 /** 260 * Marks a sender as trusted so that images from that sender will automatically be shown. 261 */ 262 public void setSenderAsTrusted(String email) { 263 if (!mTrustedSenders.contains(email)) { 264 mTrustedSenders.add(email); 265 mSharedPreferences 266 .edit() 267 .putString(TRUSTED_SENDERS, packEmailSet(mTrustedSenders)) 268 .apply(); 269 } 270 } 271 272 /** 273 * Clears all trusted senders asynchronously. 274 */ 275 public void clearTrustedSenders() { 276 mTrustedSenders = new HashSet<String>(); 277 mSharedPreferences 278 .edit() 279 .putString(TRUSTED_SENDERS, packEmailSet(mTrustedSenders)) 280 .apply(); 281 } 282 283 HashSet<String> parseEmailSet(String serialized) throws JSONException { 284 HashSet<String> result = new HashSet<String>(); 285 if (!TextUtils.isEmpty(serialized)) { 286 JSONArray arr = new JSONArray(serialized); 287 for (int i = 0, len = arr.length(); i < len; i++) { 288 result.add((String) arr.get(i)); 289 } 290 } 291 return result; 292 } 293 294 String packEmailSet(HashSet<String> set) { 295 return new JSONArray(set).toString(); 296 } 297 298 /** 299 * Returns the last used account ID as set by {@link #setLastUsedAccountId}. 300 * The system makes no attempt to automatically track what is considered a "use" - clients 301 * are expected to call {@link #setLastUsedAccountId} manually. 302 * 303 * Note that the last used account may have been deleted in the background so there is also 304 * no guarantee that the account exists. 305 */ 306 public long getLastUsedAccountId() { 307 return mSharedPreferences.getLong(LAST_ACCOUNT_USED, Account.NO_ACCOUNT); 308 } 309 310 /** 311 * Sets the specified ID of the last account used. Treated as an opaque ID and does not 312 * validate the value. Value is saved asynchronously. 313 */ 314 public void setLastUsedAccountId(long accountId) { 315 mSharedPreferences 316 .edit() 317 .putLong(LAST_ACCOUNT_USED, accountId) 318 .apply(); 319 } 320 321 /** 322 * Gets whether the require manual sync dialog has been shown for the specified account. 323 * It should only be shown once per account. 324 */ 325 public boolean getHasShownRequireManualSync(Context context, Account account) { 326 return getBoolean(context, account.getEmailAddress(), REQUIRE_MANUAL_SYNC_DIALOG_SHOWN, 327 false); 328 } 329 330 /** 331 * Sets whether the require manual sync dialog has been shown for the specified account. 332 * It should only be shown once per account. 333 */ 334 public void setHasShownRequireManualSync(Context context, Account account, boolean value) { 335 setBoolean(context, account.getEmailAddress(), REQUIRE_MANUAL_SYNC_DIALOG_SHOWN, value); 336 } 337 338 339 /** 340 * Get whether to show the manual sync dialog. This dialog is shown when the user is roaming, 341 * connected to a mobile network, the administrator has set the RequireManualSyncWhenRoaming 342 * flag to true, and the dialog has not been shown before for the supplied account. 343 */ 344 public boolean shouldShowRequireManualSync(Context context, Account account) { 345 return Account.isAutomaticSyncDisabledByRoaming(context, account.mId) 346 && !getHasShownRequireManualSync(context, account); 347 } 348 349 public void clear() { 350 mSharedPreferences.edit().clear().apply(); 351 } 352 353 public void dump() { 354 if (Logging.LOGD) { 355 for (String key : mSharedPreferences.getAll().keySet()) { 356 Log.v(Logging.LOG_TAG, key + " = " + mSharedPreferences.getAll().get(key)); 357 } 358 } 359 } 360 361 /** 362 * Utility method for setting a boolean value on a per-account preference. 363 */ 364 private void setBoolean(Context context, String account, String key, Boolean value) { 365 mSharedPreferences.edit().putBoolean(makeKey(account, key), value).apply(); 366 } 367 368 /** 369 * Utility method for getting a boolean value from a per-account preference. 370 */ 371 private boolean getBoolean(Context context, String account, String key, boolean def) { 372 return mSharedPreferences.getBoolean(makeKey(account, key), def); 373 } 374 375 /** 376 * Utility method for creating a per account preference key. 377 */ 378 private String makeKey(String account, String key) { 379 return account != null ? account + "-" + key : key; 380 } 381} 382