Move account backup/restore to userdata in AccountManager

Change-Id: Iea9f2a1b1f2d87e07d63cbb1df5a0d6355ea4031
This commit is contained in:
Tony Mantler 2014-05-14 11:16:56 -07:00
parent 97ddf6e5fa
commit 82a207132b
9 changed files with 270 additions and 238 deletions

View File

@ -34,6 +34,10 @@ import android.os.Parcelable;
import android.os.RemoteException;
import com.android.emailcommon.utility.Utility;
import com.android.mail.utils.LogUtils;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
@ -132,12 +136,14 @@ public final class Account extends EmailContent implements Parcelable {
@Deprecated
private String mRingtoneUri;
public String mProtocolVersion;
public int mNewMessageCount;
public String mSecuritySyncKey;
public String mSignature;
public long mPolicyKey;
public long mPingDuration;
private static final String JSON_TAG_HOST_AUTH_RECV = "hostAuthRecv";
private static final String JSON_TAG_HOST_AUTH_SEND = "hostAuthSend";
// Convenience for creating/working with an account
public transient HostAuth mHostAuthRecv;
public transient HostAuth mHostAuthSend;
@ -727,7 +733,6 @@ public final class Account extends EmailContent implements Parcelable {
values.put(AccountColumns.SENDER_NAME, mSenderName);
values.put(AccountColumns.RINGTONE_URI, mRingtoneUri);
values.put(AccountColumns.PROTOCOL_VERSION, mProtocolVersion);
values.put(AccountColumns.NEW_MESSAGE_COUNT, mNewMessageCount);
values.put(AccountColumns.SECURITY_SYNC_KEY, mSecuritySyncKey);
values.put(AccountColumns.SIGNATURE, mSignature);
values.put(AccountColumns.POLICY_KEY, mPolicyKey);
@ -735,6 +740,96 @@ public final class Account extends EmailContent implements Parcelable {
return values;
}
public String toJsonString(final Context context) {
ensureLoaded(context);
final JSONObject json = toJson();
if (json != null) {
return json.toString();
}
return null;
}
protected JSONObject toJson() {
try {
final JSONObject json = new JSONObject();
json.putOpt(AccountColumns.DISPLAY_NAME, mDisplayName);
json.put(AccountColumns.EMAIL_ADDRESS, mEmailAddress);
json.put(AccountColumns.SYNC_LOOKBACK, mSyncLookback);
json.put(AccountColumns.SYNC_INTERVAL, mSyncInterval);
final JSONObject recvJson = mHostAuthRecv.toJson();
json.put(JSON_TAG_HOST_AUTH_RECV, recvJson);
if (mHostAuthSend != null) {
final JSONObject sendJson = mHostAuthSend.toJson();
json.put(JSON_TAG_HOST_AUTH_SEND, sendJson);
}
json.put(AccountColumns.FLAGS, mFlags);
json.putOpt(AccountColumns.SENDER_NAME, mSenderName);
json.putOpt(AccountColumns.PROTOCOL_VERSION, mProtocolVersion);
json.putOpt(AccountColumns.SIGNATURE, mSignature);
json.put(AccountColumns.PING_DURATION, mPingDuration);
return json;
} catch (final JSONException e) {
LogUtils.d(LogUtils.TAG, e, "Exception while serializing Account");
}
return null;
}
public static Account fromJsonString(final String jsonString) {
try {
final JSONObject json = new JSONObject(jsonString);
return fromJson(json);
} catch (final JSONException e) {
LogUtils.d(LogUtils.TAG, e, "Could not parse json for account");
}
return null;
}
protected static Account fromJson(final JSONObject json) {
try {
final Account a = new Account();
a.mDisplayName = json.optString(AccountColumns.DISPLAY_NAME);
a.mEmailAddress = json.getString(AccountColumns.EMAIL_ADDRESS);
// SYNC_KEY is not stored
a.mSyncLookback = json.getInt(AccountColumns.SYNC_LOOKBACK);
a.mSyncInterval = json.getInt(AccountColumns.SYNC_INTERVAL);
final JSONObject recvJson = json.getJSONObject(JSON_TAG_HOST_AUTH_RECV);
a.mHostAuthRecv = HostAuth.fromJson(recvJson);
final JSONObject sendJson = json.optJSONObject(JSON_TAG_HOST_AUTH_SEND);
if (sendJson != null) {
a.mHostAuthSend = HostAuth.fromJson(sendJson);
}
a.mFlags = json.getInt(AccountColumns.FLAGS);
a.mSenderName = json.optString(AccountColumns.SENDER_NAME);
a.mProtocolVersion = json.optString(AccountColumns.PROTOCOL_VERSION);
// SECURITY_SYNC_KEY is not stored
a.mSignature = json.optString(AccountColumns.SIGNATURE);
// POLICY_KEY is not stored
a.mPingDuration = json.optInt(AccountColumns.PING_DURATION, 0);
return a;
} catch (final JSONException e) {
LogUtils.d(LogUtils.TAG, e, "Exception while deserializing Account");
}
return null;
}
/**
* Ensure that all optionally-loaded fields are populated from the provider.
* @param context for provider loads
*/
public void ensureLoaded(final Context context) {
if (mHostAuthKeyRecv == 0 && mHostAuthRecv == null) {
throw new IllegalStateException("Trying to load incomplete Account object");
}
getOrCreateHostAuthRecv(context).ensureLoaded(context);
if (mHostAuthKeySend != 0) {
getOrCreateHostAuthSend(context);
if (mHostAuthSend != null) {
mHostAuthSend.ensureLoaded(context);
}
}
}
/**
* Supports Parcelable
*/
@ -778,7 +873,7 @@ public final class Account extends EmailContent implements Parcelable {
dest.writeString(mSenderName);
dest.writeString(mRingtoneUri);
dest.writeString(mProtocolVersion);
dest.writeInt(mNewMessageCount);
dest.writeInt(0 /* mNewMessageCount */);
dest.writeString(mSecuritySyncKey);
dest.writeString(mSignature);
dest.writeLong(mPolicyKey);
@ -816,7 +911,7 @@ public final class Account extends EmailContent implements Parcelable {
mSenderName = in.readString();
mRingtoneUri = in.readString();
mProtocolVersion = in.readString();
mNewMessageCount = in.readInt();
/* mNewMessageCount = */ in.readInt();
mSecuritySyncKey = in.readString();
mSignature = in.readString();
mPolicyKey = in.readLong();

View File

@ -9,10 +9,12 @@ import android.os.Parcelable;
import android.provider.BaseColumns;
import android.text.TextUtils;
import com.android.emailcommon.utility.Utility;
import com.android.mail.utils.LogUtils;
import com.google.common.base.Objects;
import org.json.JSONException;
import org.json.JSONObject;
public class Credential extends EmailContent implements Parcelable, BaseColumns {
public static final String TABLE_NAME = "Credential";
@ -143,9 +145,9 @@ public class Credential extends EmailContent implements Parcelable, BaseColumns
return false;
}
Credential that = (Credential)o;
return Utility.areStringsEqual(mProviderId, that.mProviderId)
&& Utility.areStringsEqual(mAccessToken, that.mAccessToken)
&& Utility.areStringsEqual(mRefreshToken, that.mRefreshToken)
return TextUtils.equals(mProviderId, that.mProviderId)
&& TextUtils.equals(mAccessToken, that.mAccessToken)
&& TextUtils.equals(mRefreshToken, that.mRefreshToken)
&& mExpiration == that.mExpiration;
}
@ -166,4 +168,32 @@ public class Credential extends EmailContent implements Parcelable, BaseColumns
values.put(EXPIRATION_COLUMN, mExpiration);
return values;
}
protected JSONObject toJson() {
try {
final JSONObject json = new JSONObject();
json.put(PROVIDER_COLUMN, mProviderId);
json.putOpt(ACCESS_TOKEN_COLUMN, mAccessToken);
json.putOpt(REFRESH_TOKEN_COLUMN, mRefreshToken);
json.put(EXPIRATION_COLUMN, mExpiration);
return json;
} catch (final JSONException e) {
LogUtils.d(LogUtils.TAG, e, "Exception while serializing Credential");
}
return null;
}
protected static Credential fromJson(final JSONObject json) {
try {
final Credential c = new Credential();
c.mProviderId = json.getString(PROVIDER_COLUMN);
c.mAccessToken = json.optString(ACCESS_TOKEN_COLUMN);
c.mRefreshToken = json.optString(REFRESH_TOKEN_COLUMN);
c.mExpiration = json.optInt(EXPIRATION_COLUMN, 0);
return c;
} catch (final JSONException e) {
LogUtils.d(LogUtils.TAG, e, "Exception while deserializing Credential");
}
return null;
}
}

View File

@ -92,10 +92,6 @@ public abstract class EmailContent {
public static final String ID_SELECTION = BaseColumns._ID + " =?";
public static final String FIELD_COLUMN_NAME = "field";
public static final String ADD_COLUMN_NAME = "add";
public static final String SET_COLUMN_NAME = "set";
public static final int SYNC_STATUS_NONE = UIProvider.SyncStatus.NO_SYNC;
public static final int SYNC_STATUS_USER = UIProvider.SyncStatus.USER_REFRESH;
public static final int SYNC_STATUS_BACKGROUND = UIProvider.SyncStatus.BACKGROUND_SYNC;
@ -1695,6 +1691,7 @@ public abstract class EmailContent {
// Protocol version (arbitrary string, used by EAS currently)
public static final String PROTOCOL_VERSION = "protocolVersion";
// The number of new messages (reported by the sync/download engines
@Deprecated
public static final String NEW_MESSAGE_COUNT = "newMessageCount";
// Legacy flags defining security (provisioning) requirements of this account; this
// information is now found in the Policy table; POLICY_KEY (below) is the foreign key

View File

@ -25,9 +25,11 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import com.android.emailcommon.provider.EmailContent.HostAuthColumns;
import com.android.emailcommon.utility.SSLUtils;
import com.android.emailcommon.utility.Utility;
import com.android.mail.utils.LogUtils;
import org.json.JSONException;
import org.json.JSONObject;
import java.net.URI;
import java.net.URISyntaxException;
@ -69,6 +71,7 @@ public class HostAuth extends EmailContent implements Parcelable {
public byte[] mServerCert = null;
public long mCredentialKey;
private static final String JSON_TAG_CREDENTIAL = "credential";
public transient Credential mCredential;
public static final int CONTENT_ID_COLUMN = 0;
@ -83,8 +86,8 @@ public class HostAuth extends EmailContent implements Parcelable {
public static final int CONTENT_CREDENTIAL_KEY_COLUMN = 9;
public static final String[] CONTENT_PROJECTION = new String[] {
RECORD_ID, HostAuthColumns.PROTOCOL, HostAuthColumns.ADDRESS, HostAuthColumns.PORT,
HostAuthColumns.FLAGS, HostAuthColumns.LOGIN,
HostAuthColumns._ID, HostAuthColumns.PROTOCOL, HostAuthColumns.ADDRESS,
HostAuthColumns.PORT, HostAuthColumns.FLAGS, HostAuthColumns.LOGIN,
HostAuthColumns.PASSWORD, HostAuthColumns.DOMAIN, HostAuthColumns.CLIENT_CERT_ALIAS,
HostAuthColumns.CREDENTIAL_KEY
};
@ -97,8 +100,8 @@ public class HostAuth extends EmailContent implements Parcelable {
/**
* Restore a HostAuth from the database, given its unique id
* @param context
* @param id
* @param context for provider loads
* @param id corresponds to rowid
* @return the instantiated HostAuth
*/
public static HostAuth restoreHostAuthWithId(Context context, long id) {
@ -106,13 +109,6 @@ public class HostAuth extends EmailContent implements Parcelable {
HostAuth.CONTENT_URI, HostAuth.CONTENT_PROJECTION, id);
}
/**
* Returns the scheme for the specified flags.
*/
public static String getSchemeString(String protocol, int flags) {
return getSchemeString(protocol, flags, null);
}
/**
* Returns the credential object for this HostAuth. This will load from the
* database if the HosAuth has a valid credential key, or return null if not.
@ -131,7 +127,7 @@ public class HostAuth extends EmailContent implements Parcelable {
* creating it if it does not yet exist. This should not be called on the
* main thread.
*
* @param context
* @param context for provider loads
* @return the credential object for this HostAuth
*/
public Credential getOrCreateCredential(Context context) {
@ -157,7 +153,11 @@ public class HostAuth extends EmailContent implements Parcelable {
* Builds a URI scheme name given the parameters for a {@code HostAuth}. If
* a {@code clientAlias} is provided, this indicates that a secure
* connection must be used.
*
* This is not used in live code, but is kept here for reference when creating providers.xml
* entries
*/
@SuppressWarnings("unused")
public static String getSchemeString(String protocol, int flags, String clientAlias) {
String security = "";
switch (flags & USER_CONFIG_MASK) {
@ -244,6 +244,57 @@ public class HostAuth extends EmailContent implements Parcelable {
return values;
}
protected JSONObject toJson() {
try {
final JSONObject json = new JSONObject();
json.put(HostAuthColumns.PROTOCOL, mProtocol);
json.put(HostAuthColumns.ADDRESS, mAddress);
json.put(HostAuthColumns.PORT, mPort);
json.put(HostAuthColumns.FLAGS, mFlags);
json.put(HostAuthColumns.LOGIN, mLogin);
json.putOpt(HostAuthColumns.PASSWORD, mPassword);
json.putOpt(HostAuthColumns.DOMAIN, mDomain);
json.putOpt(HostAuthColumns.CLIENT_CERT_ALIAS, mClientCertAlias);
if (mCredential != null) {
json.putOpt(JSON_TAG_CREDENTIAL, mCredential.toJson());
}
return json;
} catch (final JSONException e) {
LogUtils.d(LogUtils.TAG, e, "Exception while serializing HostAuth");
}
return null;
}
protected static HostAuth fromJson(final JSONObject json) {
try {
final HostAuth h = new HostAuth();
h.mProtocol = json.getString(HostAuthColumns.PROTOCOL);
h.mAddress = json.getString(HostAuthColumns.ADDRESS);
h.mPort = json.getInt(HostAuthColumns.PORT);
h.mFlags = json.getInt(HostAuthColumns.FLAGS);
h.mLogin = json.getString(HostAuthColumns.LOGIN);
h.mPassword = json.optString(HostAuthColumns.PASSWORD);
h.mDomain = json.optString(HostAuthColumns.DOMAIN);
h.mClientCertAlias = json.optString(HostAuthColumns.CLIENT_CERT_ALIAS);
final JSONObject credJson = json.optJSONObject(JSON_TAG_CREDENTIAL);
if (credJson != null) {
h.mCredential = Credential.fromJson(credJson);
}
return h;
} catch (final JSONException e) {
LogUtils.d(LogUtils.TAG, e, "Exception while deserializing HostAuth");
}
return null;
}
/**
* Ensure that all optionally-loaded fields are populated from the provider.
* @param context for provider loads
*/
public void ensureLoaded(final Context context) {
getCredential(context);
}
/**
* Sets the user name and password from URI user info string
*/
@ -432,12 +483,12 @@ public class HostAuth extends EmailContent implements Parcelable {
return mPort == that.mPort
&& mId == that.mId
&& mFlags == that.mFlags
&& Utility.areStringsEqual(mProtocol, that.mProtocol)
&& Utility.areStringsEqual(mAddress, that.mAddress)
&& Utility.areStringsEqual(mLogin, that.mLogin)
&& Utility.areStringsEqual(mPassword, that.mPassword)
&& Utility.areStringsEqual(mDomain, that.mDomain)
&& Utility.areStringsEqual(mClientCertAlias, that.mClientCertAlias);
&& TextUtils.equals(mProtocol, that.mProtocol)
&& TextUtils.equals(mAddress, that.mAddress)
&& TextUtils.equals(mLogin, that.mLogin)
&& TextUtils.equals(mPassword, that.mPassword)
&& TextUtils.equals(mDomain, that.mDomain)
&& TextUtils.equals(mClientCertAlias, that.mClientCertAlias);
// We don't care about the server certificate for equals
}

View File

@ -780,15 +780,6 @@ public class Utility {
return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
}
/**
* Test that the given strings are equal in a null-pointer safe fashion.
*/
// Use TextUtils.equals()
@Deprecated
public static boolean areStringsEqual(String s1, String s2) {
return (s1 != null && s1.equals(s2)) || (s1 == null && s2 == null);
}
public static void enableStrictMode(boolean enabled) {
StrictMode.setThreadPolicy(enabled
? new StrictMode.ThreadPolicy.Builder().detectAll().build()

View File

@ -16,6 +16,7 @@
package com.android.email.provider;
import android.accounts.AccountManager;
import android.appwidget.AppWidgetManager;
import android.content.ComponentCallbacks;
import android.content.ComponentName;
@ -66,6 +67,7 @@ import com.android.common.content.ProjectionMap;
import com.android.email.Preferences;
import com.android.email.R;
import com.android.email.SecurityPolicy;
import com.android.email.activity.setup.AccountSettingsUtils;
import com.android.email.service.AttachmentDownloadService;
import com.android.email.service.EmailServiceUtils;
import com.android.email.service.EmailServiceUtils.EmailServiceInfo;
@ -133,6 +135,7 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@ -164,7 +167,11 @@ public class EmailProvider extends ContentProvider {
public static final String DATABASE_NAME = "EmailProvider.db";
public static final String BODY_DATABASE_NAME = "EmailProviderBody.db";
// We don't back up to the backup database anymore, just keep this constant here so we can
// delete the old backups and trigger a new backup to the account manager
@Deprecated
private static final String BACKUP_DATABASE_NAME = "EmailProviderBackup.db";
private static final String ACCOUNT_MANAGER_JSON_TAG = "accountJson";
/**
* Notifies that changes happened. Certain UI components, e.g., widgets, can register for this
@ -203,11 +210,9 @@ public class EmailProvider extends ContentProvider {
private static final int ACCOUNT_BASE = 0;
private static final int ACCOUNT = ACCOUNT_BASE;
private static final int ACCOUNT_ID = ACCOUNT_BASE + 1;
private static final int ACCOUNT_RESET_NEW_COUNT = ACCOUNT_BASE + 2;
private static final int ACCOUNT_RESET_NEW_COUNT_ID = ACCOUNT_BASE + 3;
private static final int ACCOUNT_CHECK = ACCOUNT_BASE + 4;
private static final int ACCOUNT_PICK_TRASH_FOLDER = ACCOUNT_BASE + 5;
private static final int ACCOUNT_PICK_SENT_FOLDER = ACCOUNT_BASE + 6;
private static final int ACCOUNT_CHECK = ACCOUNT_BASE + 2;
private static final int ACCOUNT_PICK_TRASH_FOLDER = ACCOUNT_BASE + 3;
private static final int ACCOUNT_PICK_SENT_FOLDER = ACCOUNT_BASE + 4;
private static final int MAILBOX_BASE = 0x1000;
private static final int MAILBOX = MAILBOX_BASE;
@ -337,7 +342,6 @@ public class EmailProvider extends ContentProvider {
private static final String DELETE_BODY = "delete from " + Body.TABLE_NAME +
" where " + BodyColumns.MESSAGE_KEY + '=';
private static ContentValues CONTENT_VALUES_RESET_NEW_MESSAGE_COUNT;
private static final ContentValues EMPTY_CONTENT_VALUES = new ContentValues();
private static final String MESSAGE_URI_PARAMETER_MAILBOX_ID = "mailboxId";
@ -530,6 +534,16 @@ public class EmailProvider extends ContentProvider {
return;
}
// If there's a backup database (old style) delete it and trigger an account manager backup.
// Roughly the same comment as above applies
final File backupDb = context.getDatabasePath(BACKUP_DATABASE_NAME);
if (backupDb.exists()) {
backupAccounts(context, mainDatabase);
context.deleteDatabase(BACKUP_DATABASE_NAME);
LogUtils.w(TAG, "Migrated from backup database to account manager");
return;
}
// If we have accounts, we're done
if (DatabaseUtils.longForQuery(mainDatabase,
"SELECT EXISTS (SELECT ? FROM " + Account.TABLE_NAME + " )",
@ -540,7 +554,7 @@ public class EmailProvider extends ContentProvider {
return;
}
restoreAccounts(context, mainDatabase);
restoreAccounts(context);
}
/** {@inheritDoc} */
@ -1041,13 +1055,6 @@ public class EmailProvider extends ContentProvider {
sURIMatcher.addURI(EmailContent.AUTHORITY, "account/#", ACCOUNT_ID);
sURIMatcher.addURI(EmailContent.AUTHORITY, "accountCheck/#", ACCOUNT_CHECK);
// Special URI to reset the new message count. Only update works, and values
// will be ignored.
sURIMatcher.addURI(EmailContent.AUTHORITY, "resetNewMessageCount",
ACCOUNT_RESET_NEW_COUNT);
sURIMatcher.addURI(EmailContent.AUTHORITY, "resetNewMessageCount/#",
ACCOUNT_RESET_NEW_COUNT_ID);
// All mailboxes
sURIMatcher.addURI(EmailContent.AUTHORITY, "mailbox", MAILBOX);
// A specific mailbox
@ -1122,9 +1129,6 @@ public class EmailProvider extends ContentProvider {
// A specific updated message
sURIMatcher.addURI(EmailContent.AUTHORITY, "updatedMessage/#", UPDATED_MESSAGE_ID);
CONTENT_VALUES_RESET_NEW_MESSAGE_COUNT = new ContentValues();
CONTENT_VALUES_RESET_NEW_MESSAGE_COUNT.put(AccountColumns.NEW_MESSAGE_COUNT, 0);
sURIMatcher.addURI(EmailContent.AUTHORITY, "policy", POLICY);
sURIMatcher.addURI(EmailContent.AUTHORITY, "policy/#", POLICY_ID);
@ -1531,57 +1535,66 @@ public class EmailProvider extends ContentProvider {
return copyCount;
}
private static SQLiteDatabase getBackupDatabase(Context context) {
DBHelper.DatabaseHelper helper = new DBHelper.DatabaseHelper(context, BACKUP_DATABASE_NAME);
return helper.getWritableDatabase();
}
/**
* Backup account data, returning the number of accounts backed up
*/
private static int backupAccounts(Context context, SQLiteDatabase mainDatabase) {
if (MailActivityEmail.DEBUG) {
LogUtils.d(TAG, "backupAccounts...");
}
SQLiteDatabase backupDatabase = getBackupDatabase(context);
private static int backupAccounts(final Context context, final SQLiteDatabase db) {
final AccountManager am = AccountManager.get(context);
final Cursor accountCursor = db.query(Account.TABLE_NAME, Account.CONTENT_PROJECTION,
null, null, null, null, null);
int updatedCount = 0;
try {
int numBackedUp = copyAccountTables(mainDatabase, backupDatabase);
if (numBackedUp < 0) {
LogUtils.e(TAG, "Account backup failed!");
} else if (MailActivityEmail.DEBUG) {
LogUtils.d(TAG, "Backed up " + numBackedUp + " accounts...");
while (accountCursor.moveToNext()) {
final Account account = new Account();
account.restore(accountCursor);
EmailServiceInfo serviceInfo =
EmailServiceUtils.getServiceInfo(context, account.getProtocol(context));
if (serviceInfo == null) {
LogUtils.d(LogUtils.TAG, "Could not find service info for account");
continue;
}
final String jsonString = account.toJsonString(context);
final android.accounts.Account amAccount =
account.getAccountManagerAccount(serviceInfo.accountType);
am.setUserData(amAccount, ACCOUNT_MANAGER_JSON_TAG, jsonString);
updatedCount++;
}
return numBackedUp;
} finally {
if (backupDatabase != null) {
backupDatabase.close();
}
accountCursor.close();
}
return updatedCount;
}
/**
* Restore account data, returning the number of accounts restored
*/
private static int restoreAccounts(Context context, SQLiteDatabase mainDatabase) {
if (MailActivityEmail.DEBUG) {
LogUtils.d(TAG, "restoreAccounts...");
private static int restoreAccounts(final Context context) {
final Collection<EmailServiceInfo> infos = EmailServiceUtils.getServiceInfoList(context);
// Find all possible account types
final Set<String> accountTypes = new HashSet<String>(3);
for (final EmailServiceInfo info : infos) {
accountTypes.add(info.accountType);
}
SQLiteDatabase backupDatabase = getBackupDatabase(context);
try {
int numRecovered = copyAccountTables(backupDatabase, mainDatabase);
if (numRecovered > 0) {
LogUtils.e(TAG, "Recovered " + numRecovered + " accounts!");
} else if (numRecovered < 0) {
LogUtils.e(TAG, "Account recovery failed?");
} else if (MailActivityEmail.DEBUG) {
LogUtils.d(TAG, "No accounts to restore...");
// Find all accounts we own
final List<android.accounts.Account> amAccounts = new ArrayList<android.accounts.Account>();
final AccountManager am = AccountManager.get(context);
for (final String accountType : accountTypes) {
amAccounts.addAll(Arrays.asList(am.getAccountsByType(accountType)));
}
// Try to restore them from saved JSON
int restoredCount = 0;
for (final android.accounts.Account amAccount : amAccounts) {
final String jsonString = am.getUserData(amAccount, ACCOUNT_MANAGER_JSON_TAG);
if (TextUtils.isEmpty(jsonString)) {
continue;
}
return numRecovered;
} finally {
if (backupDatabase != null) {
backupDatabase.close();
final Account account = Account.fromJsonString(jsonString);
if (account != null) {
AccountSettingsUtils.commitSettings(context, account);
restoredCount++;
}
}
return restoredCount;
}
private static final String MESSAGE_CHANGE_LOG_TABLE_INSERT_PREFIX = "insert into %s ("
@ -1981,27 +1994,6 @@ public class EmailProvider extends ContentProvider {
}
result = db.update(tableName, values, selection, selectionArgs);
break;
case ACCOUNT_RESET_NEW_COUNT_ID:
id = uri.getPathSegments().get(1);
ContentValues newMessageCount = CONTENT_VALUES_RESET_NEW_MESSAGE_COUNT;
if (values != null) {
Long set = values.getAsLong(EmailContent.SET_COLUMN_NAME);
if (set != null) {
newMessageCount = new ContentValues();
newMessageCount.put(AccountColumns.NEW_MESSAGE_COUNT, set);
}
}
result = db.update(tableName, newMessageCount,
whereWithId(id, selection), selectionArgs);
notificationUri = Account.CONTENT_URI; // Only notify account cursors.
break;
case ACCOUNT_RESET_NEW_COUNT:
result = db.update(tableName, CONTENT_VALUES_RESET_NEW_MESSAGE_COUNT,
selection, selectionArgs);
// Affects all accounts. Just invalidate all account cache.
notificationUri = Account.CONTENT_URI; // Only notify account cursors.
break;
case MESSAGE_MOVE:
result = db.update(MessageMove.TABLE_NAME, values, selection, selectionArgs);
break;

View File

@ -67,8 +67,6 @@ public class AccountBackupRestoreTests extends ProviderTestCase2<EmailProvider>
assertEquals(" mSenderName", expect.mSenderName, actual.mSenderName);
assertEquals(" mProtocolVersion", expect.mProtocolVersion,
actual.mProtocolVersion);
assertEquals(" mNewMessageCount", expect.mNewMessageCount,
actual.mNewMessageCount);
assertEquals(" mSignature", expect.mSignature, actual.mSignature);
// Nulled out by backup

View File

@ -60,7 +60,6 @@ public class ProviderTestUtils extends Assert {
account.mFlags = 4;
account.mSenderName = name;
account.mProtocolVersion = "2.5" + name;
account.mNewMessageCount = 5 + name.length();
account.mPolicyKey = 0;
account.mSecuritySyncKey = "sec-sync-key-" + name;
account.mSignature = "signature-" + name;
@ -303,8 +302,6 @@ public class ProviderTestUtils extends Assert {
assertEquals(caller + " mSenderName", expect.mSenderName, actual.mSenderName);
assertEquals(caller + " mProtocolVersion", expect.mProtocolVersion,
actual.mProtocolVersion);
assertEquals(caller + " mNewMessageCount", expect.mNewMessageCount,
actual.mNewMessageCount);
assertEquals(caller + " mSecuritySyncKey", expect.mSecuritySyncKey,
actual.mSecuritySyncKey);
assertEquals(caller + " mSignature", expect.mSignature, actual.mSignature);

View File

@ -2044,125 +2044,6 @@ public class ProviderTests extends ProviderTestCase2<EmailProvider> {
assertEquals(-1, Account.getInboxId(c, 999999));
}
/**
* Check if update to {@link Account#RESET_NEW_MESSAGE_COUNT_URI} resets the new message count.
*/
public void testResetNewMessageCount() {
final Context c = mMockContext;
final ContentResolver cr = c.getContentResolver();
// Prepare test data
Account a1 = ProviderTestUtils.setupAccount("acct1", false, c);
a1.mNewMessageCount = 1;
a1.save(c);
Account a2 = ProviderTestUtils.setupAccount("acct2", false, c);
a2.mNewMessageCount = 2;
a2.save(c);
Account a3 = ProviderTestUtils.setupAccount("acct3", false, c);
a3.mNewMessageCount = 3;
a3.save(c);
Account a4 = ProviderTestUtils.setupAccount("acct4", false, c);
a4.mNewMessageCount = 4;
a4.save(c);
Account a5 = ProviderTestUtils.setupAccount("acct5", false, c);
a5.mNewMessageCount = 5;
a5.save(c);
// With ID in URI, no selection
cr.update(ContentUris.withAppendedId(Account.RESET_NEW_MESSAGE_COUNT_URI, a1.mId), null,
null, null);
assertEquals(0, Account.restoreAccountWithId(c, a1.mId).mNewMessageCount);
assertEquals(2, Account.restoreAccountWithId(c, a2.mId).mNewMessageCount);
assertEquals(3, Account.restoreAccountWithId(c, a3.mId).mNewMessageCount);
assertEquals(4, Account.restoreAccountWithId(c, a4.mId).mNewMessageCount);
assertEquals(5, Account.restoreAccountWithId(c, a5.mId).mNewMessageCount);
// No ID in URI, with selection
cr.update(Account.RESET_NEW_MESSAGE_COUNT_URI, null, EmailContent.ID_SELECTION,
new String[] {Long.toString(a2.mId)});
assertEquals(0, Account.restoreAccountWithId(c, a1.mId).mNewMessageCount);
assertEquals(0, Account.restoreAccountWithId(c, a2.mId).mNewMessageCount);
assertEquals(3, Account.restoreAccountWithId(c, a3.mId).mNewMessageCount);
assertEquals(4, Account.restoreAccountWithId(c, a4.mId).mNewMessageCount);
assertEquals(5, Account.restoreAccountWithId(c, a5.mId).mNewMessageCount);
// With ID, with selection
cr.update(ContentUris.withAppendedId(Account.RESET_NEW_MESSAGE_COUNT_URI, a3.mId), null,
EmailContent.ID_SELECTION, new String[] {Long.toString(a3.mId)});
assertEquals(0, Account.restoreAccountWithId(c, a1.mId).mNewMessageCount);
assertEquals(0, Account.restoreAccountWithId(c, a2.mId).mNewMessageCount);
assertEquals(0, Account.restoreAccountWithId(c, a3.mId).mNewMessageCount);
assertEquals(4, Account.restoreAccountWithId(c, a4.mId).mNewMessageCount);
assertEquals(5, Account.restoreAccountWithId(c, a5.mId).mNewMessageCount);
// No ID in URI, no selection
cr.update(Account.RESET_NEW_MESSAGE_COUNT_URI, null, null, null);
assertEquals(0, Account.restoreAccountWithId(c, a1.mId).mNewMessageCount);
assertEquals(0, Account.restoreAccountWithId(c, a2.mId).mNewMessageCount);
assertEquals(0, Account.restoreAccountWithId(c, a3.mId).mNewMessageCount);
assertEquals(0, Account.restoreAccountWithId(c, a4.mId).mNewMessageCount);
assertEquals(0, Account.restoreAccountWithId(c, a5.mId).mNewMessageCount);
}
/**
* Check if update on ACCOUNT_ID_ADD_TO_FIELD updates the cache properly.
*/
public void testUpdateCacheAccountIdAddToField() {
final Context c = mMockContext;
// make sure Account.CONTENT_URI is defined
EmailContent.init(c);
Account.initAccount();
Account a1 = ProviderTestUtils.setupAccount("a1", true, c);
int start = Account.restoreAccountWithId(c, a1.mId).mNewMessageCount;
// +1 to NEW_MESSAGE_COUNT
ContentValues cv = new ContentValues();
cv.put(EmailContent.FIELD_COLUMN_NAME, AccountColumns.NEW_MESSAGE_COUNT);
cv.put(EmailContent.ADD_COLUMN_NAME, 1);
mProvider.update(ContentUris.withAppendedId(Account.CONTENT_URI, a1.mId), cv, null, null);
// Check
assertEquals(start + 1, Account.restoreAccountWithId(c, a1.mId).mNewMessageCount);
}
/**
* Check if update on ACCOUNT_RESET_NEW_COUNT updates the cache properly.
*/
public void testUpdateCacheAccountResetNewCount() {
final Context c = mMockContext;
Account a1 = ProviderTestUtils.setupAccount("a1", true, c);
// precondition
assertTrue(Account.restoreAccountWithId(c, a1.mId).mNewMessageCount > 0);
// Reset
mProvider.update(Account.RESET_NEW_MESSAGE_COUNT_URI, null, null, null);
// Check
assertEquals(0, Account.restoreAccountWithId(c, a1.mId).mNewMessageCount);
}
/**
* Check if update on ACCOUNT_RESET_NEW_COUNT_ID updates the cache properly.
*/
public void testUpdateCacheAccountResetNewCountId() {
final Context c = mMockContext;
Account a1 = ProviderTestUtils.setupAccount("a1", true, c);
// precondition
assertTrue(Account.restoreAccountWithId(c, a1.mId).mNewMessageCount > 0);
// Reset
mProvider.update(ContentUris.withAppendedId(Account.RESET_NEW_MESSAGE_COUNT_URI, a1.mId),
null, null, null);
// Check
assertEquals(0, Account.restoreAccountWithId(c, a1.mId).mNewMessageCount);
}
/**
* Check that we're handling illegal uri's properly (by throwing an exception unless it's a
* query for an id of -1, in which case we return a zero-length cursor)