Move account backup/restore to userdata in AccountManager
Change-Id: Iea9f2a1b1f2d87e07d63cbb1df5a0d6355ea4031
This commit is contained in:
parent
97ddf6e5fa
commit
82a207132b
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user