Create AccountManager acct for pop/imap on upgrade from GB
* Also, unit test for upgrade path Bug: 4439595 Change-Id: I508a3d8ea70c1a894a412528314e42a39f3ae0e7
This commit is contained in:
parent
5675ea88d3
commit
f3ff0ba910
|
@ -18,6 +18,7 @@ package com.android.emailcommon.utility;
|
|||
|
||||
import com.android.emailcommon.Logging;
|
||||
import com.android.emailcommon.provider.EmailContent.Account;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.AccountManagerFuture;
|
||||
|
@ -32,6 +33,12 @@ import java.io.IOException;
|
|||
import java.util.List;
|
||||
|
||||
public class AccountReconciler {
|
||||
// AccountManager accounts with a name beginning with this constant are ignored for purposes
|
||||
// of reconcilation. This is for unit test purposes only; the caller may NOT be in the same
|
||||
// package as this class, so we make the constant public.
|
||||
@VisibleForTesting
|
||||
public static final String ACCOUNT_MANAGER_ACCOUNT_TEST_PREFIX = " _";
|
||||
|
||||
/**
|
||||
* Compare our account list (obtained from EmailProvider) with the account list owned by
|
||||
* AccountManager. If there are any orphans (an account in one list without a corresponding
|
||||
|
@ -89,6 +96,9 @@ public class AccountReconciler {
|
|||
found = true;
|
||||
}
|
||||
}
|
||||
if (accountManagerAccountName.startsWith(ACCOUNT_MANAGER_ACCOUNT_TEST_PREFIX)) {
|
||||
found = true;
|
||||
}
|
||||
if (!found) {
|
||||
// This account has been deleted from the EmailProvider database
|
||||
Log.d(Logging.LOG_TAG,
|
||||
|
|
|
@ -20,6 +20,7 @@ import com.android.email.Email;
|
|||
import com.android.email.provider.ContentCache.CacheToken;
|
||||
import com.android.email.service.AttachmentDownloadService;
|
||||
import com.android.emailcommon.AccountManagerTypes;
|
||||
import com.android.emailcommon.CalendarProviderStub;
|
||||
import com.android.emailcommon.Logging;
|
||||
import com.android.emailcommon.provider.EmailContent;
|
||||
import com.android.emailcommon.provider.EmailContent.Account;
|
||||
|
@ -58,6 +59,7 @@ import android.database.sqlite.SQLiteDatabase;
|
|||
import android.database.sqlite.SQLiteException;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.net.Uri;
|
||||
import android.provider.ContactsContract;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -137,7 +139,9 @@ public class EmailProvider extends ContentProvider {
|
|||
// Account's policy when the Account is deleted
|
||||
// Version 20: Add new policies to Policy table
|
||||
// Version 21: Add lastSeenMessageKey column to Mailbox table
|
||||
public static final int DATABASE_VERSION = 21;
|
||||
// Version 22: Upgrade path for IMAP/POP accounts to integrate with AccountManager
|
||||
|
||||
public static final int DATABASE_VERSION = 22;
|
||||
|
||||
// Any changes to the database format *must* include update-in-place code.
|
||||
// Original version: 2
|
||||
|
@ -1070,6 +1074,10 @@ public class EmailProvider extends ContentProvider {
|
|||
upgradeFromVersion20ToVersion21(db);
|
||||
oldVersion = 21;
|
||||
}
|
||||
if (oldVersion == 21) {
|
||||
upgradeFromVersion21ToVersion22(db, mContext);
|
||||
oldVersion = 22;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2005,4 +2013,61 @@ public class EmailProvider extends ContentProvider {
|
|||
Log.w(TAG, "Exception upgrading EmailProvider.db from 20 to 21 " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Upgrade the database from v21 to v22
|
||||
* This entails creating AccountManager accounts for all pop3 and imap accounts
|
||||
*/
|
||||
|
||||
private static final String[] RECV_PROJECTION =
|
||||
new String[] {AccountColumns.HOST_AUTH_KEY_RECV};
|
||||
private static final int EMAIL_AND_RECV_COLUMN_RECV = 0;
|
||||
|
||||
static private void createAccountManagerAccount(Context context, HostAuth hostAuth) {
|
||||
AccountManager accountManager = AccountManager.get(context);
|
||||
android.accounts.Account amAccount =
|
||||
new android.accounts.Account(hostAuth.mLogin, AccountManagerTypes.TYPE_POP_IMAP);
|
||||
accountManager.addAccountExplicitly(amAccount, hostAuth.mPassword, null);
|
||||
ContentResolver.setIsSyncable(amAccount, EmailContent.AUTHORITY, 1);
|
||||
ContentResolver.setSyncAutomatically(amAccount, EmailContent.AUTHORITY, true);
|
||||
ContentResolver.setIsSyncable(amAccount, ContactsContract.AUTHORITY, 0);
|
||||
ContentResolver.setIsSyncable(amAccount, CalendarProviderStub.AUTHORITY, 0);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static void upgradeFromVersion21ToVersion22(SQLiteDatabase db, Context accountManagerContext) {
|
||||
try {
|
||||
// Loop through accounts, looking for pop/imap accounts
|
||||
Cursor accountCursor = db.query(Account.TABLE_NAME, RECV_PROJECTION, null,
|
||||
null, null, null, null);
|
||||
try {
|
||||
String[] hostAuthArgs = new String[1];
|
||||
while (accountCursor.moveToNext()) {
|
||||
hostAuthArgs[0] = accountCursor.getString(EMAIL_AND_RECV_COLUMN_RECV);
|
||||
// Get the "receive" HostAuth for this account
|
||||
Cursor hostAuthCursor = db.query(HostAuth.TABLE_NAME,
|
||||
HostAuth.CONTENT_PROJECTION, HostAuth.RECORD_ID + "=?", hostAuthArgs,
|
||||
null, null, null);
|
||||
try {
|
||||
if (hostAuthCursor.moveToFirst()) {
|
||||
HostAuth hostAuth = new HostAuth();
|
||||
hostAuth.restore(hostAuthCursor);
|
||||
String protocol = hostAuth.mProtocol;
|
||||
// If this is a pop3 or imap account, create the account manager account
|
||||
if ("imap".equals(protocol) || "pop3".equals(protocol)) {
|
||||
createAccountManagerAccount(accountManagerContext, hostAuth);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
hostAuthCursor.close();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
accountCursor.close();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
// Shouldn't be needed unless we're debugging and interrupt the process
|
||||
Log.w(TAG, "Exception upgrading EmailProvider.db from 20 to 21 " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package com.android.email.provider;
|
||||
|
||||
import com.android.emailcommon.AccountManagerTypes;
|
||||
import com.android.emailcommon.provider.EmailContent;
|
||||
import com.android.emailcommon.provider.EmailContent.Account;
|
||||
import com.android.emailcommon.provider.EmailContent.AccountColumns;
|
||||
|
@ -28,9 +29,13 @@ import com.android.emailcommon.provider.EmailContent.Message;
|
|||
import com.android.emailcommon.provider.EmailContent.MessageColumns;
|
||||
import com.android.emailcommon.provider.HostAuth;
|
||||
import com.android.emailcommon.provider.Mailbox;
|
||||
import com.android.emailcommon.utility.AccountReconciler;
|
||||
import com.android.emailcommon.utility.TextUtilities;
|
||||
import com.android.emailcommon.utility.Utility;
|
||||
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.AuthenticatorException;
|
||||
import android.accounts.OperationCanceledException;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
|
@ -2229,4 +2234,105 @@ public class ProviderTests extends ProviderTestCase2<EmailProvider> {
|
|||
assertEquals(Message.MAILBOX_KEY + "=" + out.mId,
|
||||
Message.buildMessageListSelection(c, out.mId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a list of AccountManager accounts includes a given EmailProvider account
|
||||
* @param amAccountList a list of AccountManager accounts
|
||||
* @param account an EmailProvider account
|
||||
* @param context the caller's context (our test provider's context)
|
||||
* @return whether or not the EmailProvider account is represented in AccountManager
|
||||
*/
|
||||
private boolean amAccountListHasAccount(android.accounts.Account[] amAccountList,
|
||||
Account account, Context context) {
|
||||
HostAuth hostAuth = HostAuth.restoreHostAuthWithId(context, account.mHostAuthKeyRecv);
|
||||
if (hostAuth == null) return false;
|
||||
String login = hostAuth.mLogin;
|
||||
for (android.accounts.Account amAccount: amAccountList) {
|
||||
if (amAccount.name.equals(login)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a single pop/imap account from the AccountManager
|
||||
* @param accountManager our AccountManager
|
||||
* @param name the name of the test account to remove
|
||||
*/
|
||||
private void removeAccountManagerAccount(AccountManager accountManager, String name) {
|
||||
try {
|
||||
accountManager.removeAccount(
|
||||
new android.accounts.Account(name, AccountManagerTypes.TYPE_POP_IMAP),
|
||||
null, null).getResult();
|
||||
} catch (OperationCanceledException e) {
|
||||
} catch (AuthenticatorException e) {
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all test accounts from the AccountManager
|
||||
* @param accountManager the AccountManager
|
||||
*/
|
||||
private void cleanupTestAccountManagerAccounts(AccountManager accountManager) {
|
||||
android.accounts.Account[] amAccountList =
|
||||
accountManager.getAccountsByType(AccountManagerTypes.TYPE_POP_IMAP);
|
||||
for (android.accounts.Account account: amAccountList) {
|
||||
if (account.name.startsWith(AccountReconciler.ACCOUNT_MANAGER_ACCOUNT_TEST_PREFIX)) {
|
||||
removeAccountManagerAccount(accountManager, account.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Verifies updating the DB from v21 to v22 works as expected */
|
||||
public void testUpgradeFromVersion21ToVersion22() {
|
||||
String imapTestLogin =
|
||||
AccountReconciler.ACCOUNT_MANAGER_ACCOUNT_TEST_PREFIX + "imap.host.com";
|
||||
String pop3TestLogin =
|
||||
AccountReconciler.ACCOUNT_MANAGER_ACCOUNT_TEST_PREFIX + "pop3.host.com";
|
||||
AccountManager accountManager = AccountManager.get(mContext);
|
||||
|
||||
// Create provider accounts (one of each type)
|
||||
Account a1 = createAccount(mMockContext, "exchange",
|
||||
ProviderTestUtils.setupHostAuth("eas", "exchange.host.com", true, mMockContext),
|
||||
null);
|
||||
HostAuth h2 =
|
||||
ProviderTestUtils.setupHostAuth("imap", "imap.host.com", false, mMockContext);
|
||||
h2.mLogin = imapTestLogin;
|
||||
h2.save(mMockContext);
|
||||
Account a2 = createAccount(mMockContext, "imap", h2,
|
||||
ProviderTestUtils.setupHostAuth("smtp", "smtp.host.com", true, mMockContext));
|
||||
HostAuth h3 =
|
||||
ProviderTestUtils.setupHostAuth("pop3", "pop3.host.com", false, mMockContext);
|
||||
h3.mLogin = pop3TestLogin;
|
||||
h3.save(mMockContext);
|
||||
Account a3 = createAccount(mMockContext, "pop3", h3,
|
||||
ProviderTestUtils.setupHostAuth("smtp", "smtp.host.com", true, mMockContext));
|
||||
|
||||
// Get the current list of AccountManager accounts (we have to use the real context here),
|
||||
// whereas we use the mock context for EmailProvider (this is because the mock context
|
||||
// doesn't implement AccountManager hooks)
|
||||
android.accounts.Account[] amAccountList =
|
||||
accountManager.getAccountsByType(AccountManagerTypes.TYPE_POP_IMAP);
|
||||
// There shouldn't be AccountManager accounts for these
|
||||
assertFalse(amAccountListHasAccount(amAccountList, a1, mMockContext));
|
||||
assertFalse(amAccountListHasAccount(amAccountList, a2, mMockContext));
|
||||
assertFalse(amAccountListHasAccount(amAccountList, a3, mMockContext));
|
||||
|
||||
amAccountList = null;
|
||||
try {
|
||||
// Upgrade the database
|
||||
SQLiteDatabase db = getProvider().getDatabase(mMockContext);
|
||||
EmailProvider.upgradeFromVersion21ToVersion22(db, getContext());
|
||||
|
||||
// The pop3 and imap account should now be in account manager
|
||||
amAccountList = accountManager.getAccountsByType(AccountManagerTypes.TYPE_POP_IMAP);
|
||||
assertFalse(amAccountListHasAccount(amAccountList, a1, mMockContext));
|
||||
assertTrue(amAccountListHasAccount(amAccountList, a2, mMockContext));
|
||||
assertTrue(amAccountListHasAccount(amAccountList, a3, mMockContext));
|
||||
} finally {
|
||||
cleanupTestAccountManagerAccounts(accountManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue