Issue 143
Merged from branch issue143 @ revision 426: Complete replacement for SharedPreferences. Uses SQLite database stored in application's databases folder. Will load from legacy preferences if DB-backed preferences are empty. Editor conforms to atomic commit contract.
This commit is contained in:
parent
06a90571cd
commit
932adf5ed2
5 changed files with 516 additions and 58 deletions
|
@ -101,35 +101,35 @@ public class Account implements Serializable {
|
|||
* Refresh the account from the stored settings.
|
||||
*/
|
||||
public void refresh(Preferences preferences) {
|
||||
mStoreUri = Utility.base64Decode(preferences.mSharedPreferences.getString(mUuid
|
||||
mStoreUri = Utility.base64Decode(preferences.getPreferences().getString(mUuid
|
||||
+ ".storeUri", null));
|
||||
mLocalStoreUri = preferences.mSharedPreferences.getString(mUuid + ".localStoreUri", null);
|
||||
mTransportUri = Utility.base64Decode(preferences.mSharedPreferences.getString(mUuid
|
||||
mLocalStoreUri = preferences.getPreferences().getString(mUuid + ".localStoreUri", null);
|
||||
mTransportUri = Utility.base64Decode(preferences.getPreferences().getString(mUuid
|
||||
+ ".transportUri", null));
|
||||
mDescription = preferences.mSharedPreferences.getString(mUuid + ".description", null);
|
||||
mAlwaysBcc = preferences.mSharedPreferences.getString(mUuid + ".alwaysBcc", mAlwaysBcc);
|
||||
mName = preferences.mSharedPreferences.getString(mUuid + ".name", mName);
|
||||
mEmail = preferences.mSharedPreferences.getString(mUuid + ".email", mEmail);
|
||||
mSignature = preferences.mSharedPreferences.getString(mUuid + ".signature", mSignature);
|
||||
mAutomaticCheckIntervalMinutes = preferences.mSharedPreferences.getInt(mUuid
|
||||
mDescription = preferences.getPreferences().getString(mUuid + ".description", null);
|
||||
mAlwaysBcc = preferences.getPreferences().getString(mUuid + ".alwaysBcc", mAlwaysBcc);
|
||||
mName = preferences.getPreferences().getString(mUuid + ".name", mName);
|
||||
mEmail = preferences.getPreferences().getString(mUuid + ".email", mEmail);
|
||||
mSignature = preferences.getPreferences().getString(mUuid + ".signature", mSignature);
|
||||
mAutomaticCheckIntervalMinutes = preferences.getPreferences().getInt(mUuid
|
||||
+ ".automaticCheckIntervalMinutes", -1);
|
||||
mDisplayCount = preferences.mSharedPreferences.getInt(mUuid + ".displayCount", -1);
|
||||
mLastAutomaticCheckTime = preferences.mSharedPreferences.getLong(mUuid
|
||||
mDisplayCount = preferences.getPreferences().getInt(mUuid + ".displayCount", -1);
|
||||
mLastAutomaticCheckTime = preferences.getPreferences().getLong(mUuid
|
||||
+ ".lastAutomaticCheckTime", 0);
|
||||
mNotifyNewMail = preferences.mSharedPreferences.getBoolean(mUuid + ".notifyNewMail",
|
||||
mNotifyNewMail = preferences.getPreferences().getBoolean(mUuid + ".notifyNewMail",
|
||||
false);
|
||||
mNotifySync = preferences.mSharedPreferences.getBoolean(mUuid + ".notifyMailCheck",
|
||||
mNotifySync = preferences.getPreferences().getBoolean(mUuid + ".notifyMailCheck",
|
||||
false);
|
||||
mDeletePolicy = preferences.mSharedPreferences.getInt(mUuid + ".deletePolicy", 0);
|
||||
mDraftsFolderName = preferences.mSharedPreferences.getString(mUuid + ".draftsFolderName",
|
||||
mDeletePolicy = preferences.getPreferences().getInt(mUuid + ".deletePolicy", 0);
|
||||
mDraftsFolderName = preferences.getPreferences().getString(mUuid + ".draftsFolderName",
|
||||
"Drafts");
|
||||
mSentFolderName = preferences.mSharedPreferences.getString(mUuid + ".sentFolderName",
|
||||
mSentFolderName = preferences.getPreferences().getString(mUuid + ".sentFolderName",
|
||||
"Sent");
|
||||
mTrashFolderName = preferences.mSharedPreferences.getString(mUuid + ".trashFolderName",
|
||||
mTrashFolderName = preferences.getPreferences().getString(mUuid + ".trashFolderName",
|
||||
"Trash");
|
||||
mOutboxFolderName = preferences.mSharedPreferences.getString(mUuid + ".outboxFolderName",
|
||||
mOutboxFolderName = preferences.getPreferences().getString(mUuid + ".outboxFolderName",
|
||||
"Outbox");
|
||||
|
||||
|
||||
// Between r418 and r431 (version 0.103), folder names were set empty if the Incoming settings were
|
||||
// opened for non-IMAP accounts. 0.103 was never a market release, so perhaps this code
|
||||
// should be deleted sometime soon
|
||||
|
@ -151,14 +151,15 @@ public class Account implements Serializable {
|
|||
}
|
||||
// End of 0.103 repair
|
||||
|
||||
mAutoExpandFolderName = preferences.mSharedPreferences.getString(mUuid + ".autoExpandFolderName",
|
||||
mAutoExpandFolderName = preferences.getPreferences().getString(mUuid + ".autoExpandFolderName",
|
||||
"Inbox");
|
||||
mAccountNumber = preferences.mSharedPreferences.getInt(mUuid + ".accountNumber", 0);
|
||||
mVibrate = preferences.mSharedPreferences.getBoolean(mUuid + ".vibrate", false);
|
||||
|
||||
mAccountNumber = preferences.getPreferences().getInt(mUuid + ".accountNumber", 0);
|
||||
mVibrate = preferences.getPreferences().getBoolean(mUuid + ".vibrate", false);
|
||||
|
||||
try
|
||||
{
|
||||
mHideMessageViewButtons = HideButtons.valueOf(preferences.mSharedPreferences.getString(mUuid + ".hideButtonsEnum",
|
||||
mHideMessageViewButtons = HideButtons.valueOf(preferences.getPreferences().getString(mUuid + ".hideButtonsEnum",
|
||||
HideButtons.NEVER.name()));
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -166,11 +167,11 @@ public class Account implements Serializable {
|
|||
mHideMessageViewButtons = HideButtons.NEVER;
|
||||
}
|
||||
|
||||
mRingtoneUri = preferences.mSharedPreferences.getString(mUuid + ".ringtone",
|
||||
mRingtoneUri = preferences.getPreferences().getString(mUuid + ".ringtone",
|
||||
"content://settings/system/notification_sound");
|
||||
try
|
||||
{
|
||||
mFolderDisplayMode = FolderMode.valueOf(preferences.mSharedPreferences.getString(mUuid + ".folderDisplayMode",
|
||||
mFolderDisplayMode = FolderMode.valueOf(preferences.getPreferences().getString(mUuid + ".folderDisplayMode",
|
||||
FolderMode.NOT_SECOND_CLASS.name()));
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -180,7 +181,7 @@ public class Account implements Serializable {
|
|||
|
||||
try
|
||||
{
|
||||
mFolderSyncMode = FolderMode.valueOf(preferences.mSharedPreferences.getString(mUuid + ".folderSyncMode",
|
||||
mFolderSyncMode = FolderMode.valueOf(preferences.getPreferences().getString(mUuid + ".folderSyncMode",
|
||||
FolderMode.FIRST_CLASS.name()));
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -190,7 +191,7 @@ public class Account implements Serializable {
|
|||
|
||||
try
|
||||
{
|
||||
mFolderTargetMode = FolderMode.valueOf(preferences.mSharedPreferences.getString(mUuid + ".folderTargetMode",
|
||||
mFolderTargetMode = FolderMode.valueOf(preferences.getPreferences().getString(mUuid + ".folderTargetMode",
|
||||
FolderMode.NOT_SECOND_CLASS.name()));
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -278,7 +279,7 @@ public class Account implements Serializable {
|
|||
}
|
||||
|
||||
public void delete(Preferences preferences) {
|
||||
String[] uuids = preferences.mSharedPreferences.getString("accountUuids", "").split(",");
|
||||
String[] uuids = preferences.getPreferences().getString("accountUuids", "").split(",");
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0, length = uuids.length; i < length; i++) {
|
||||
if (!uuids[i].equals(mUuid)) {
|
||||
|
@ -289,7 +290,7 @@ public class Account implements Serializable {
|
|||
}
|
||||
}
|
||||
String accountUuids = sb.toString();
|
||||
SharedPreferences.Editor editor = preferences.mSharedPreferences.edit();
|
||||
SharedPreferences.Editor editor = preferences.getPreferences().edit();
|
||||
editor.putString("accountUuids", accountUuids);
|
||||
|
||||
editor.remove(mUuid + ".storeUri");
|
||||
|
@ -320,9 +321,9 @@ public class Account implements Serializable {
|
|||
}
|
||||
|
||||
public void save(Preferences preferences) {
|
||||
SharedPreferences.Editor editor = preferences.mSharedPreferences.edit();
|
||||
SharedPreferences.Editor editor = preferences.getPreferences().edit();
|
||||
|
||||
if (!preferences.mSharedPreferences.getString("accountUuids", "").contains(mUuid)) {
|
||||
if (!preferences.getPreferences().getString("accountUuids", "").contains(mUuid)) {
|
||||
/*
|
||||
* When the account is first created we assign it a unique account number. The
|
||||
* account number will be unique to that account for the lifetime of the account.
|
||||
|
@ -348,15 +349,11 @@ public class Account implements Serializable {
|
|||
}
|
||||
mAccountNumber++;
|
||||
|
||||
String accountUuids = preferences.mSharedPreferences.getString("accountUuids", "");
|
||||
String accountUuids = preferences.getPreferences().getString("accountUuids", "");
|
||||
accountUuids += (accountUuids.length() != 0 ? "," : "") + mUuid;
|
||||
// SharedPreferences.Editor editor = preferences.mSharedPreferences.edit();
|
||||
editor.putString("accountUuids", accountUuids);
|
||||
// editor.commit();
|
||||
}
|
||||
|
||||
// SharedPreferences.Editor editor = preferences.mSharedPreferences.edit();
|
||||
|
||||
editor.putString(mUuid + ".storeUri", Utility.base64Encode(mStoreUri));
|
||||
editor.putString(mUuid + ".localStoreUri", mLocalStoreUri);
|
||||
editor.putString(mUuid + ".transportUri", Utility.base64Encode(mTransportUri));
|
||||
|
|
|
@ -3,6 +3,9 @@ package com.android.email;
|
|||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.android.email.preferences.Editor;
|
||||
import com.android.email.preferences.Storage;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
|
@ -12,11 +15,19 @@ import android.util.Log;
|
|||
public class Preferences {
|
||||
private static Preferences preferences;
|
||||
|
||||
public SharedPreferences mSharedPreferences;
|
||||
private Storage mStorage;
|
||||
|
||||
private Preferences(Context context) {
|
||||
mSharedPreferences = context.getSharedPreferences("AndroidMail.Main", Context.MODE_PRIVATE);
|
||||
mStorage = Storage.getStorage(context);
|
||||
if (mStorage.size() == 0)
|
||||
{
|
||||
Log.i(Email.LOG_TAG, "Preferences storage is zero-size, importing from Android-style preferences");
|
||||
Editor editor = mStorage.edit();
|
||||
editor.copy(context.getSharedPreferences("AndroidMail.Main", Context.MODE_PRIVATE));
|
||||
editor.commit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* TODO need to think about what happens if this gets GCed along with the
|
||||
|
@ -40,7 +51,7 @@ public class Preferences {
|
|||
* @return
|
||||
*/
|
||||
public Account[] getAccounts() {
|
||||
String accountUuids = mSharedPreferences.getString("accountUuids", null);
|
||||
String accountUuids = getPreferences().getString("accountUuids", null);
|
||||
if (accountUuids == null || accountUuids.length() == 0) {
|
||||
return new Account[] {};
|
||||
}
|
||||
|
@ -64,7 +75,7 @@ public class Preferences {
|
|||
* @return
|
||||
*/
|
||||
public Account getDefaultAccount() {
|
||||
String defaultAccountUuid = mSharedPreferences.getString("defaultAccountUuid", null);
|
||||
String defaultAccountUuid = getPreferences().getString("defaultAccountUuid", null);
|
||||
Account defaultAccount = null;
|
||||
Account[] accounts = getAccounts();
|
||||
if (defaultAccountUuid != null) {
|
||||
|
@ -87,37 +98,35 @@ public class Preferences {
|
|||
}
|
||||
|
||||
public void setDefaultAccount(Account account) {
|
||||
mSharedPreferences.edit().putString("defaultAccountUuid", account.getUuid()).commit();
|
||||
getPreferences().edit().putString("defaultAccountUuid", account.getUuid()).commit();
|
||||
}
|
||||
|
||||
public void setEnableDebugLogging(boolean value) {
|
||||
mSharedPreferences.edit().putBoolean("enableDebugLogging", value).commit();
|
||||
getPreferences().edit().putBoolean("enableDebugLogging", value).commit();
|
||||
}
|
||||
|
||||
public boolean geteEnableDebugLogging() {
|
||||
return mSharedPreferences.getBoolean("enableDebugLogging", false);
|
||||
return getPreferences().getBoolean("enableDebugLogging", false);
|
||||
}
|
||||
|
||||
public void setEnableSensitiveLogging(boolean value) {
|
||||
mSharedPreferences.edit().putBoolean("enableSensitiveLogging", value).commit();
|
||||
getPreferences().edit().putBoolean("enableSensitiveLogging", value).commit();
|
||||
}
|
||||
|
||||
public boolean getEnableSensitiveLogging() {
|
||||
return mSharedPreferences.getBoolean("enableSensitiveLogging", false);
|
||||
}
|
||||
|
||||
public void save() {
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
mSharedPreferences.edit().clear().commit();
|
||||
return getPreferences().getBoolean("enableSensitiveLogging", false);
|
||||
}
|
||||
|
||||
public void dump() {
|
||||
if (Config.LOGV) {
|
||||
for (String key : mSharedPreferences.getAll().keySet()) {
|
||||
Log.v(Email.LOG_TAG, key + " = " + mSharedPreferences.getAll().get(key));
|
||||
for (String key : getPreferences().getAll().keySet()) {
|
||||
Log.v(Email.LOG_TAG, key + " = " + getPreferences().getAll().get(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SharedPreferences getPreferences()
|
||||
{
|
||||
return mStorage;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -701,7 +701,7 @@ public class LocalStore extends Store implements Serializable {
|
|||
public void delete(Preferences preferences) throws MessagingException {
|
||||
String id = getPrefId();
|
||||
|
||||
SharedPreferences.Editor editor = preferences.mSharedPreferences.edit();
|
||||
SharedPreferences.Editor editor = preferences.getPreferences().edit();
|
||||
|
||||
editor.remove(id + ".displayMode");
|
||||
editor.remove(id + ".syncMode");
|
||||
|
@ -712,7 +712,7 @@ public class LocalStore extends Store implements Serializable {
|
|||
public void save(Preferences preferences) throws MessagingException {
|
||||
String id = getPrefId();
|
||||
|
||||
SharedPreferences.Editor editor = preferences.mSharedPreferences.edit();
|
||||
SharedPreferences.Editor editor = preferences.getPreferences().edit();
|
||||
// there can be a lot of folders. For the defaults, let's not save prefs, saving space, except for INBOX
|
||||
if (displayClass == FolderClass.NONE && !Email.INBOX.equals(getName()))
|
||||
{
|
||||
|
@ -740,7 +740,7 @@ public class LocalStore extends Store implements Serializable {
|
|||
|
||||
try
|
||||
{
|
||||
displayClass = FolderClass.valueOf(preferences.mSharedPreferences.getString(id + ".displayMode",
|
||||
displayClass = FolderClass.valueOf(preferences.getPreferences().getString(id + ".displayMode",
|
||||
FolderClass.NONE.name()));
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -759,7 +759,7 @@ public class LocalStore extends Store implements Serializable {
|
|||
|
||||
try
|
||||
{
|
||||
syncClass = FolderClass.valueOf(preferences.mSharedPreferences.getString(id + ".syncMode",
|
||||
syncClass = FolderClass.valueOf(preferences.getPreferences().getString(id + ".syncMode",
|
||||
defSyncClass.name()));
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
161
src/com/android/email/preferences/Editor.java
Normal file
161
src/com/android/email/preferences/Editor.java
Normal file
|
@ -0,0 +1,161 @@
|
|||
package com.android.email.preferences;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.android.email.Email;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
public class Editor implements android.content.SharedPreferences.Editor
|
||||
{
|
||||
private Storage storage;
|
||||
private HashMap<String, String> changes = new HashMap<String, String>();
|
||||
private ArrayList<String> removals = new ArrayList<String>();
|
||||
private boolean removeAll = false;
|
||||
|
||||
Map<String, String> snapshot = new HashMap<String, String>();
|
||||
|
||||
|
||||
protected Editor(Storage storage)
|
||||
{
|
||||
this.storage = storage;
|
||||
snapshot.putAll(storage.getAll());
|
||||
}
|
||||
|
||||
public void copy(android.content.SharedPreferences input)
|
||||
{
|
||||
Map<String, ?> oldVals = input.getAll();
|
||||
for (Entry<String, ?> entry : oldVals.entrySet())
|
||||
{
|
||||
String key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
if (key != null && value != null)
|
||||
{
|
||||
if (Email.DEBUG)
|
||||
{
|
||||
Log.d(Email.LOG_TAG, "Copying key '" + key + "', value '" + value + "'");
|
||||
}
|
||||
changes.put(key, "" + value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Email.DEBUG)
|
||||
{
|
||||
Log.d(Email.LOG_TAG, "Skipping copying key '" + key + "', value '" + value + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public android.content.SharedPreferences.Editor clear()
|
||||
{
|
||||
removeAll = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/* This method is poorly defined. It should throw an Exception on failure */
|
||||
@Override
|
||||
public boolean commit()
|
||||
{
|
||||
try
|
||||
{
|
||||
commitChanges();
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.e(Email.LOG_TAG, "Failed to save preferences", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void commitChanges() throws Exception
|
||||
{
|
||||
long startTime = System.currentTimeMillis();
|
||||
Log.i(Email.LOG_TAG, "Committing preference changes");
|
||||
Runnable committer = new Runnable() {
|
||||
public void run()
|
||||
{
|
||||
if (removeAll)
|
||||
{
|
||||
storage.removeAll();
|
||||
}
|
||||
for (String removeKey : removals)
|
||||
{
|
||||
storage.remove(removeKey);
|
||||
}
|
||||
for (Entry<String, String> entry : changes.entrySet())
|
||||
{
|
||||
String key = entry.getKey();
|
||||
String newValue = entry.getValue();
|
||||
String oldValue = snapshot.get(key);
|
||||
if (removeAll || removals.contains(key) || newValue.equals(oldValue) != true)
|
||||
{
|
||||
storage.put(key, newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
storage.doInTransaction(committer);
|
||||
long endTime = System.currentTimeMillis();
|
||||
Log.i(Email.LOG_TAG, "Preferences commit took " + (endTime - startTime) + "ms");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public android.content.SharedPreferences.Editor putBoolean(String key,
|
||||
boolean value)
|
||||
{
|
||||
changes.put(key, "" + value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public android.content.SharedPreferences.Editor putFloat(String key,
|
||||
float value)
|
||||
{
|
||||
changes.put(key, "" + value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public android.content.SharedPreferences.Editor putInt(String key, int value)
|
||||
{
|
||||
changes.put(key, "" + value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public android.content.SharedPreferences.Editor putLong(String key, long value)
|
||||
{
|
||||
changes.put(key, "" + value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public android.content.SharedPreferences.Editor putString(String key,
|
||||
String value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
remove(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
changes.put(key, value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public android.content.SharedPreferences.Editor remove(String key)
|
||||
{
|
||||
removals.add(key);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
291
src/com/android/email/preferences/Storage.java
Normal file
291
src/com/android/email/preferences/Storage.java
Normal file
|
@ -0,0 +1,291 @@
|
|||
package com.android.email.preferences;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import com.android.email.Email;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.util.Log;
|
||||
|
||||
public class Storage implements SharedPreferences
|
||||
{
|
||||
private static ConcurrentHashMap<Context, Storage> storages =
|
||||
new ConcurrentHashMap<Context, Storage>();
|
||||
|
||||
private volatile ConcurrentHashMap<String, String> storage = new ConcurrentHashMap<String, String>();
|
||||
|
||||
private CopyOnWriteArrayList<OnSharedPreferenceChangeListener> listeners =
|
||||
new CopyOnWriteArrayList<OnSharedPreferenceChangeListener>();
|
||||
|
||||
private int DB_VERSION = 1; // CHANGING THIS WILL DESTROY ALL USER PREFERENCES!
|
||||
private String DB_NAME = "preferences_storage";
|
||||
|
||||
private ThreadLocal<ConcurrentHashMap<String, String>> workingStorage
|
||||
= new ThreadLocal<ConcurrentHashMap<String, String>>();
|
||||
private ThreadLocal<SQLiteDatabase> workingDB =
|
||||
new ThreadLocal<SQLiteDatabase>();
|
||||
private ThreadLocal<ArrayList<String>> workingChangedKeys = new ThreadLocal<ArrayList<String>>();
|
||||
|
||||
|
||||
private Context context = null;
|
||||
|
||||
private SQLiteDatabase openDB()
|
||||
{
|
||||
SQLiteDatabase mDb = context.openOrCreateDatabase(DB_NAME, Context.MODE_PRIVATE, null);
|
||||
if (mDb.getVersion() != DB_VERSION)
|
||||
{
|
||||
Log.i(Email.LOG_TAG, "Creating Storage database");
|
||||
mDb.execSQL("DROP TABLE IF EXISTS preferences_storage");
|
||||
mDb.execSQL("CREATE TABLE preferences_storage " +
|
||||
"(primkey TEXT PRIMARY KEY ON CONFLICT REPLACE, value TEXT)");
|
||||
mDb.setVersion(DB_VERSION);
|
||||
}
|
||||
return mDb;
|
||||
}
|
||||
|
||||
|
||||
public static Storage getStorage(Context context)
|
||||
{
|
||||
Storage tmpStorage = storages.get(context);
|
||||
if (tmpStorage != null)
|
||||
{
|
||||
if (Email.DEBUG)
|
||||
{
|
||||
Log.d(Email.LOG_TAG, "Returning already existing Storage");
|
||||
}
|
||||
return tmpStorage;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Email.DEBUG)
|
||||
{
|
||||
Log.d(Email.LOG_TAG, "Creating provisional storage");
|
||||
}
|
||||
tmpStorage = new Storage(context);
|
||||
Storage oldStorage = storages.putIfAbsent(context, tmpStorage);
|
||||
if (oldStorage != null)
|
||||
{
|
||||
if (Email.DEBUG)
|
||||
{
|
||||
Log.d(Email.LOG_TAG, "Another thread beat us to creating the Storage, returning that one");
|
||||
}
|
||||
return oldStorage;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Email.DEBUG)
|
||||
{
|
||||
Log.d(Email.LOG_TAG, "Returning the Storage we created");
|
||||
}
|
||||
return tmpStorage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadValues()
|
||||
{
|
||||
long startTime = System.currentTimeMillis();
|
||||
Log.i(Email.LOG_TAG, "Loading preferences from DB into Storage");
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
SQLiteDatabase mDb = openDB();
|
||||
|
||||
cursor = mDb.rawQuery("SELECT primkey, value FROM preferences_storage", null);
|
||||
while (cursor.moveToNext()) {
|
||||
String key = cursor.getString(0);
|
||||
String value = cursor.getString(1);
|
||||
if (Email.DEBUG)
|
||||
{
|
||||
Log.d(Email.LOG_TAG, "Loading key '" + key + "', value = '" + value + "'");
|
||||
}
|
||||
storage.put(key, value);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
long endTime = System.currentTimeMillis();
|
||||
Log.i(Email.LOG_TAG, "Preferences load took " + (endTime - startTime) + "ms");
|
||||
}
|
||||
}
|
||||
|
||||
private Storage(Context context)
|
||||
{
|
||||
this.context = context;
|
||||
loadValues();
|
||||
}
|
||||
|
||||
private void keyChange(String key)
|
||||
{
|
||||
ArrayList<String> changedKeys = workingChangedKeys.get();
|
||||
if (changedKeys.contains(key) == false)
|
||||
{
|
||||
changedKeys.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
protected void put(String key, String value)
|
||||
{
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put("primkey", key);
|
||||
cv.put("value", value);
|
||||
workingDB.get().insert("preferences_storage", "primkey", cv);
|
||||
workingStorage.get().put(key, value);
|
||||
|
||||
keyChange(key);
|
||||
}
|
||||
|
||||
protected void remove(String key)
|
||||
{
|
||||
workingDB.get().delete("preferences_storage", "primkey = ?", new String[] { key });
|
||||
workingStorage.get().remove(key);
|
||||
|
||||
keyChange(key);
|
||||
}
|
||||
|
||||
protected void removeAll()
|
||||
{
|
||||
for (String key : workingStorage.get().keySet())
|
||||
{
|
||||
keyChange(key);
|
||||
}
|
||||
workingDB.get().execSQL("DELETE FROM preferences_storage");
|
||||
workingStorage.get().clear();
|
||||
}
|
||||
|
||||
protected void doInTransaction(Runnable dbWork)
|
||||
{
|
||||
ConcurrentHashMap<String, String> newStorage = new ConcurrentHashMap<String, String>();
|
||||
newStorage.putAll(storage);
|
||||
workingStorage.set(newStorage);
|
||||
|
||||
SQLiteDatabase mDb = openDB();
|
||||
workingDB.set(mDb);
|
||||
|
||||
ArrayList<String> changedKeys = new ArrayList<String>();
|
||||
workingChangedKeys.set(changedKeys);
|
||||
|
||||
mDb.beginTransaction();
|
||||
try
|
||||
{
|
||||
dbWork.run();
|
||||
mDb.setTransactionSuccessful();
|
||||
storage = newStorage;
|
||||
for (String changedKey : changedKeys)
|
||||
{
|
||||
for (OnSharedPreferenceChangeListener listener : listeners)
|
||||
{
|
||||
listener.onSharedPreferenceChanged(this, changedKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
workingDB.remove();
|
||||
workingStorage.remove();
|
||||
workingChangedKeys.remove();
|
||||
mDb.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
public long size()
|
||||
{
|
||||
return storage.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(String key)
|
||||
{
|
||||
return storage.contains(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public com.android.email.preferences.Editor edit()
|
||||
{
|
||||
return new com.android.email.preferences.Editor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAll()
|
||||
{
|
||||
return storage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(String key, boolean defValue)
|
||||
{
|
||||
String val = storage.get(key);
|
||||
if (val == null)
|
||||
{
|
||||
return defValue;
|
||||
}
|
||||
return Boolean.parseBoolean(val);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat(String key, float defValue)
|
||||
{
|
||||
String val = storage.get(key);
|
||||
if (val == null)
|
||||
{
|
||||
return defValue;
|
||||
}
|
||||
return Float.parseFloat(val);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(String key, int defValue)
|
||||
{
|
||||
String val = storage.get(key);
|
||||
if (val == null)
|
||||
{
|
||||
return defValue;
|
||||
}
|
||||
return Integer.parseInt(val);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(String key, long defValue)
|
||||
{
|
||||
String val = storage.get(key);
|
||||
if (val == null)
|
||||
{
|
||||
return defValue;
|
||||
}
|
||||
return Long.parseLong(val);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(String key, String defValue)
|
||||
{
|
||||
String val = storage.get(key);
|
||||
if (val == null)
|
||||
{
|
||||
return defValue;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerOnSharedPreferenceChangeListener(
|
||||
OnSharedPreferenceChangeListener listener)
|
||||
{
|
||||
listeners.addIfAbsent(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterOnSharedPreferenceChangeListener(
|
||||
OnSharedPreferenceChangeListener listener)
|
||||
{
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue