mirror of
https://github.com/moparisthebest/k-9
synced 2024-11-27 11:42:16 -05:00
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
@ -101,35 +101,35 @@ public class Account implements Serializable {
|
|||||||
* Refresh the account from the stored settings.
|
* Refresh the account from the stored settings.
|
||||||
*/
|
*/
|
||||||
public void refresh(Preferences preferences) {
|
public void refresh(Preferences preferences) {
|
||||||
mStoreUri = Utility.base64Decode(preferences.mSharedPreferences.getString(mUuid
|
mStoreUri = Utility.base64Decode(preferences.getPreferences().getString(mUuid
|
||||||
+ ".storeUri", null));
|
+ ".storeUri", null));
|
||||||
mLocalStoreUri = preferences.mSharedPreferences.getString(mUuid + ".localStoreUri", null);
|
mLocalStoreUri = preferences.getPreferences().getString(mUuid + ".localStoreUri", null);
|
||||||
mTransportUri = Utility.base64Decode(preferences.mSharedPreferences.getString(mUuid
|
mTransportUri = Utility.base64Decode(preferences.getPreferences().getString(mUuid
|
||||||
+ ".transportUri", null));
|
+ ".transportUri", null));
|
||||||
mDescription = preferences.mSharedPreferences.getString(mUuid + ".description", null);
|
mDescription = preferences.getPreferences().getString(mUuid + ".description", null);
|
||||||
mAlwaysBcc = preferences.mSharedPreferences.getString(mUuid + ".alwaysBcc", mAlwaysBcc);
|
mAlwaysBcc = preferences.getPreferences().getString(mUuid + ".alwaysBcc", mAlwaysBcc);
|
||||||
mName = preferences.mSharedPreferences.getString(mUuid + ".name", mName);
|
mName = preferences.getPreferences().getString(mUuid + ".name", mName);
|
||||||
mEmail = preferences.mSharedPreferences.getString(mUuid + ".email", mEmail);
|
mEmail = preferences.getPreferences().getString(mUuid + ".email", mEmail);
|
||||||
mSignature = preferences.mSharedPreferences.getString(mUuid + ".signature", mSignature);
|
mSignature = preferences.getPreferences().getString(mUuid + ".signature", mSignature);
|
||||||
mAutomaticCheckIntervalMinutes = preferences.mSharedPreferences.getInt(mUuid
|
mAutomaticCheckIntervalMinutes = preferences.getPreferences().getInt(mUuid
|
||||||
+ ".automaticCheckIntervalMinutes", -1);
|
+ ".automaticCheckIntervalMinutes", -1);
|
||||||
mDisplayCount = preferences.mSharedPreferences.getInt(mUuid + ".displayCount", -1);
|
mDisplayCount = preferences.getPreferences().getInt(mUuid + ".displayCount", -1);
|
||||||
mLastAutomaticCheckTime = preferences.mSharedPreferences.getLong(mUuid
|
mLastAutomaticCheckTime = preferences.getPreferences().getLong(mUuid
|
||||||
+ ".lastAutomaticCheckTime", 0);
|
+ ".lastAutomaticCheckTime", 0);
|
||||||
mNotifyNewMail = preferences.mSharedPreferences.getBoolean(mUuid + ".notifyNewMail",
|
mNotifyNewMail = preferences.getPreferences().getBoolean(mUuid + ".notifyNewMail",
|
||||||
false);
|
false);
|
||||||
mNotifySync = preferences.mSharedPreferences.getBoolean(mUuid + ".notifyMailCheck",
|
mNotifySync = preferences.getPreferences().getBoolean(mUuid + ".notifyMailCheck",
|
||||||
false);
|
false);
|
||||||
mDeletePolicy = preferences.mSharedPreferences.getInt(mUuid + ".deletePolicy", 0);
|
mDeletePolicy = preferences.getPreferences().getInt(mUuid + ".deletePolicy", 0);
|
||||||
mDraftsFolderName = preferences.mSharedPreferences.getString(mUuid + ".draftsFolderName",
|
mDraftsFolderName = preferences.getPreferences().getString(mUuid + ".draftsFolderName",
|
||||||
"Drafts");
|
"Drafts");
|
||||||
mSentFolderName = preferences.mSharedPreferences.getString(mUuid + ".sentFolderName",
|
mSentFolderName = preferences.getPreferences().getString(mUuid + ".sentFolderName",
|
||||||
"Sent");
|
"Sent");
|
||||||
mTrashFolderName = preferences.mSharedPreferences.getString(mUuid + ".trashFolderName",
|
mTrashFolderName = preferences.getPreferences().getString(mUuid + ".trashFolderName",
|
||||||
"Trash");
|
"Trash");
|
||||||
mOutboxFolderName = preferences.mSharedPreferences.getString(mUuid + ".outboxFolderName",
|
mOutboxFolderName = preferences.getPreferences().getString(mUuid + ".outboxFolderName",
|
||||||
"Outbox");
|
"Outbox");
|
||||||
|
|
||||||
// Between r418 and r431 (version 0.103), folder names were set empty if the Incoming settings were
|
// 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
|
// opened for non-IMAP accounts. 0.103 was never a market release, so perhaps this code
|
||||||
// should be deleted sometime soon
|
// should be deleted sometime soon
|
||||||
@ -151,14 +151,15 @@ public class Account implements Serializable {
|
|||||||
}
|
}
|
||||||
// End of 0.103 repair
|
// End of 0.103 repair
|
||||||
|
|
||||||
mAutoExpandFolderName = preferences.mSharedPreferences.getString(mUuid + ".autoExpandFolderName",
|
mAutoExpandFolderName = preferences.getPreferences().getString(mUuid + ".autoExpandFolderName",
|
||||||
"Inbox");
|
"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
|
try
|
||||||
{
|
{
|
||||||
mHideMessageViewButtons = HideButtons.valueOf(preferences.mSharedPreferences.getString(mUuid + ".hideButtonsEnum",
|
mHideMessageViewButtons = HideButtons.valueOf(preferences.getPreferences().getString(mUuid + ".hideButtonsEnum",
|
||||||
HideButtons.NEVER.name()));
|
HideButtons.NEVER.name()));
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -166,11 +167,11 @@ public class Account implements Serializable {
|
|||||||
mHideMessageViewButtons = HideButtons.NEVER;
|
mHideMessageViewButtons = HideButtons.NEVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
mRingtoneUri = preferences.mSharedPreferences.getString(mUuid + ".ringtone",
|
mRingtoneUri = preferences.getPreferences().getString(mUuid + ".ringtone",
|
||||||
"content://settings/system/notification_sound");
|
"content://settings/system/notification_sound");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mFolderDisplayMode = FolderMode.valueOf(preferences.mSharedPreferences.getString(mUuid + ".folderDisplayMode",
|
mFolderDisplayMode = FolderMode.valueOf(preferences.getPreferences().getString(mUuid + ".folderDisplayMode",
|
||||||
FolderMode.NOT_SECOND_CLASS.name()));
|
FolderMode.NOT_SECOND_CLASS.name()));
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -180,7 +181,7 @@ public class Account implements Serializable {
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mFolderSyncMode = FolderMode.valueOf(preferences.mSharedPreferences.getString(mUuid + ".folderSyncMode",
|
mFolderSyncMode = FolderMode.valueOf(preferences.getPreferences().getString(mUuid + ".folderSyncMode",
|
||||||
FolderMode.FIRST_CLASS.name()));
|
FolderMode.FIRST_CLASS.name()));
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -190,7 +191,7 @@ public class Account implements Serializable {
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mFolderTargetMode = FolderMode.valueOf(preferences.mSharedPreferences.getString(mUuid + ".folderTargetMode",
|
mFolderTargetMode = FolderMode.valueOf(preferences.getPreferences().getString(mUuid + ".folderTargetMode",
|
||||||
FolderMode.NOT_SECOND_CLASS.name()));
|
FolderMode.NOT_SECOND_CLASS.name()));
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -278,7 +279,7 @@ public class Account implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void delete(Preferences preferences) {
|
public void delete(Preferences preferences) {
|
||||||
String[] uuids = preferences.mSharedPreferences.getString("accountUuids", "").split(",");
|
String[] uuids = preferences.getPreferences().getString("accountUuids", "").split(",");
|
||||||
StringBuffer sb = new StringBuffer();
|
StringBuffer sb = new StringBuffer();
|
||||||
for (int i = 0, length = uuids.length; i < length; i++) {
|
for (int i = 0, length = uuids.length; i < length; i++) {
|
||||||
if (!uuids[i].equals(mUuid)) {
|
if (!uuids[i].equals(mUuid)) {
|
||||||
@ -289,7 +290,7 @@ public class Account implements Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
String accountUuids = sb.toString();
|
String accountUuids = sb.toString();
|
||||||
SharedPreferences.Editor editor = preferences.mSharedPreferences.edit();
|
SharedPreferences.Editor editor = preferences.getPreferences().edit();
|
||||||
editor.putString("accountUuids", accountUuids);
|
editor.putString("accountUuids", accountUuids);
|
||||||
|
|
||||||
editor.remove(mUuid + ".storeUri");
|
editor.remove(mUuid + ".storeUri");
|
||||||
@ -320,9 +321,9 @@ public class Account implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void save(Preferences preferences) {
|
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
|
* 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.
|
* account number will be unique to that account for the lifetime of the account.
|
||||||
@ -348,15 +349,11 @@ public class Account implements Serializable {
|
|||||||
}
|
}
|
||||||
mAccountNumber++;
|
mAccountNumber++;
|
||||||
|
|
||||||
String accountUuids = preferences.mSharedPreferences.getString("accountUuids", "");
|
String accountUuids = preferences.getPreferences().getString("accountUuids", "");
|
||||||
accountUuids += (accountUuids.length() != 0 ? "," : "") + mUuid;
|
accountUuids += (accountUuids.length() != 0 ? "," : "") + mUuid;
|
||||||
// SharedPreferences.Editor editor = preferences.mSharedPreferences.edit();
|
|
||||||
editor.putString("accountUuids", accountUuids);
|
editor.putString("accountUuids", accountUuids);
|
||||||
// editor.commit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SharedPreferences.Editor editor = preferences.mSharedPreferences.edit();
|
|
||||||
|
|
||||||
editor.putString(mUuid + ".storeUri", Utility.base64Encode(mStoreUri));
|
editor.putString(mUuid + ".storeUri", Utility.base64Encode(mStoreUri));
|
||||||
editor.putString(mUuid + ".localStoreUri", mLocalStoreUri);
|
editor.putString(mUuid + ".localStoreUri", mLocalStoreUri);
|
||||||
editor.putString(mUuid + ".transportUri", Utility.base64Encode(mTransportUri));
|
editor.putString(mUuid + ".transportUri", Utility.base64Encode(mTransportUri));
|
||||||
|
@ -3,6 +3,9 @@ package com.android.email;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import com.android.email.preferences.Editor;
|
||||||
|
import com.android.email.preferences.Storage;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@ -12,11 +15,19 @@ import android.util.Log;
|
|||||||
public class Preferences {
|
public class Preferences {
|
||||||
private static Preferences preferences;
|
private static Preferences preferences;
|
||||||
|
|
||||||
public SharedPreferences mSharedPreferences;
|
private Storage mStorage;
|
||||||
|
|
||||||
private Preferences(Context context) {
|
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
|
* TODO need to think about what happens if this gets GCed along with the
|
||||||
@ -40,7 +51,7 @@ public class Preferences {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Account[] getAccounts() {
|
public Account[] getAccounts() {
|
||||||
String accountUuids = mSharedPreferences.getString("accountUuids", null);
|
String accountUuids = getPreferences().getString("accountUuids", null);
|
||||||
if (accountUuids == null || accountUuids.length() == 0) {
|
if (accountUuids == null || accountUuids.length() == 0) {
|
||||||
return new Account[] {};
|
return new Account[] {};
|
||||||
}
|
}
|
||||||
@ -64,7 +75,7 @@ public class Preferences {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Account getDefaultAccount() {
|
public Account getDefaultAccount() {
|
||||||
String defaultAccountUuid = mSharedPreferences.getString("defaultAccountUuid", null);
|
String defaultAccountUuid = getPreferences().getString("defaultAccountUuid", null);
|
||||||
Account defaultAccount = null;
|
Account defaultAccount = null;
|
||||||
Account[] accounts = getAccounts();
|
Account[] accounts = getAccounts();
|
||||||
if (defaultAccountUuid != null) {
|
if (defaultAccountUuid != null) {
|
||||||
@ -87,37 +98,35 @@ public class Preferences {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setDefaultAccount(Account account) {
|
public void setDefaultAccount(Account account) {
|
||||||
mSharedPreferences.edit().putString("defaultAccountUuid", account.getUuid()).commit();
|
getPreferences().edit().putString("defaultAccountUuid", account.getUuid()).commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEnableDebugLogging(boolean value) {
|
public void setEnableDebugLogging(boolean value) {
|
||||||
mSharedPreferences.edit().putBoolean("enableDebugLogging", value).commit();
|
getPreferences().edit().putBoolean("enableDebugLogging", value).commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean geteEnableDebugLogging() {
|
public boolean geteEnableDebugLogging() {
|
||||||
return mSharedPreferences.getBoolean("enableDebugLogging", false);
|
return getPreferences().getBoolean("enableDebugLogging", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEnableSensitiveLogging(boolean value) {
|
public void setEnableSensitiveLogging(boolean value) {
|
||||||
mSharedPreferences.edit().putBoolean("enableSensitiveLogging", value).commit();
|
getPreferences().edit().putBoolean("enableSensitiveLogging", value).commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getEnableSensitiveLogging() {
|
public boolean getEnableSensitiveLogging() {
|
||||||
return mSharedPreferences.getBoolean("enableSensitiveLogging", false);
|
return getPreferences().getBoolean("enableSensitiveLogging", false);
|
||||||
}
|
|
||||||
|
|
||||||
public void save() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() {
|
|
||||||
mSharedPreferences.edit().clear().commit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dump() {
|
public void dump() {
|
||||||
if (Config.LOGV) {
|
if (Config.LOGV) {
|
||||||
for (String key : mSharedPreferences.getAll().keySet()) {
|
for (String key : getPreferences().getAll().keySet()) {
|
||||||
Log.v(Email.LOG_TAG, key + " = " + mSharedPreferences.getAll().get(key));
|
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 {
|
public void delete(Preferences preferences) throws MessagingException {
|
||||||
String id = getPrefId();
|
String id = getPrefId();
|
||||||
|
|
||||||
SharedPreferences.Editor editor = preferences.mSharedPreferences.edit();
|
SharedPreferences.Editor editor = preferences.getPreferences().edit();
|
||||||
|
|
||||||
editor.remove(id + ".displayMode");
|
editor.remove(id + ".displayMode");
|
||||||
editor.remove(id + ".syncMode");
|
editor.remove(id + ".syncMode");
|
||||||
@ -712,7 +712,7 @@ public class LocalStore extends Store implements Serializable {
|
|||||||
public void save(Preferences preferences) throws MessagingException {
|
public void save(Preferences preferences) throws MessagingException {
|
||||||
String id = getPrefId();
|
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
|
// 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()))
|
if (displayClass == FolderClass.NONE && !Email.INBOX.equals(getName()))
|
||||||
{
|
{
|
||||||
@ -740,7 +740,7 @@ public class LocalStore extends Store implements Serializable {
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
displayClass = FolderClass.valueOf(preferences.mSharedPreferences.getString(id + ".displayMode",
|
displayClass = FolderClass.valueOf(preferences.getPreferences().getString(id + ".displayMode",
|
||||||
FolderClass.NONE.name()));
|
FolderClass.NONE.name()));
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -759,7 +759,7 @@ public class LocalStore extends Store implements Serializable {
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
syncClass = FolderClass.valueOf(preferences.mSharedPreferences.getString(id + ".syncMode",
|
syncClass = FolderClass.valueOf(preferences.getPreferences().getString(id + ".syncMode",
|
||||||
defSyncClass.name()));
|
defSyncClass.name()));
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
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 New Issue
Block a user