diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9c5c476b1..6e5e96268 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -401,6 +401,16 @@
android:name=".service.AttachmentDownloadService$Watchdog"
android:enabled="true"/>
+
+
+
+
+
+
+
+
diff --git a/src/com/android/email/service/EmailBroadcastProcessorService.java b/src/com/android/email/service/EmailBroadcastProcessorService.java
index 5a63620e4..e12a97b35 100644
--- a/src/com/android/email/service/EmailBroadcastProcessorService.java
+++ b/src/com/android/email/service/EmailBroadcastProcessorService.java
@@ -39,6 +39,8 @@ import com.android.emailcommon.provider.EmailContent.AccountColumns;
import com.android.emailcommon.provider.HostAuth;
import com.android.mail.utils.LogUtils;
+import java.util.HashMap;
+
/**
* The service that really handles broadcast intents on a worker thread.
*
@@ -64,6 +66,9 @@ public class EmailBroadcastProcessorService extends IntentService {
private static final String ACTION_DEVICE_POLICY_ADMIN = "com.android.email.devicepolicy";
private static final String EXTRA_DEVICE_POLICY_ADMIN = "message_code";
+ // Action used for EmailUpgradeBroadcastReceiver.
+ private static final String ACTION_UPGRADE_BROADCAST = "upgrade_broadcast_receiver";
+
public EmailBroadcastProcessorService() {
// Class name will be the thread name.
super(EmailBroadcastProcessorService.class.getName());
@@ -82,6 +87,12 @@ public class EmailBroadcastProcessorService extends IntentService {
context.startService(i);
}
+ public static void processUpgradeBroadcastIntent(final Context context) {
+ final Intent i = new Intent(context, EmailBroadcastProcessorService.class);
+ i.setAction(ACTION_UPGRADE_BROADCAST);
+ context.startService(i);
+ }
+
/**
* Entry point for {@link com.android.email.SecurityPolicy.PolicyAdmin}. These will
* simply callback to {@link
@@ -115,9 +126,54 @@ public class EmailBroadcastProcessorService extends IntentService {
} else if (ACTION_DEVICE_POLICY_ADMIN.equals(action)) {
int message = intent.getIntExtra(EXTRA_DEVICE_POLICY_ADMIN, -1);
SecurityPolicy.onDeviceAdminReceiverMessage(this, message);
+ } else if (ACTION_UPGRADE_BROADCAST.equals(action)) {
+ onAppUpgrade();
}
}
+ private void disableComponent(final Class> klass) {
+ getPackageManager().setComponentEnabledSetting(new ComponentName(this, klass),
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
+ }
+
+ private void updateAccountManagerAccountsOfType(final String amAccountType,
+ final HashMap protocolMap) {
+ final android.accounts.Account[] amAccounts =
+ AccountManager.get(this).getAccountsByType(amAccountType);
+
+ for (android.accounts.Account amAccount: amAccounts) {
+ EmailServiceUtils.updateAccountManagerType(this, amAccount, protocolMap);
+ }
+ }
+
+ private void onAppUpgrade() {
+ // TODO: Only do this for Email2Google.
+ // When upgrading to Email2Google, we need to essentially rename the account manager
+ // type for all existing accounts, so we add new ones and delete the old.
+ // We specify the translations in this map. We map from old protocol name to new protocol
+ // name, and from protocol name + "_type" to new account manager type name. (Email1 did
+ // not use distinct account manager types for POP and IMAP, but Email2 does, hence this
+ // weird mapping.)
+ final HashMap protocolMap = new HashMap();
+ protocolMap.put("imap", getString(R.string.protocol_legacy_imap));
+ protocolMap.put("pop3", getString(R.string.protocol_pop3));
+ protocolMap.put("imap_type", getString(R.string.account_manager_type_legacy_imap));
+ protocolMap.put("pop3_type", getString(R.string.account_manager_type_pop3));
+ updateAccountManagerAccountsOfType("com.android.email", protocolMap);
+
+ protocolMap.clear();
+ protocolMap.put("eas", getString(R.string.protocol_eas));
+ protocolMap.put("eas_type", getString(R.string.account_manager_type_exchange));
+ updateAccountManagerAccountsOfType("com.android.exchange", protocolMap);
+
+ // Disable the old authenticators.
+ disableComponent(LegacyEmailAuthenticatorService.class);
+ disableComponent(LegacyEasAuthenticatorService.class);
+
+ // Disable the upgrade broadcast receiver now that we're fully upgraded.
+ disableComponent(EmailUpgradeBroadcastReceiver.class);
+ }
+
/**
* Handles {@link Intent#ACTION_BOOT_COMPLETED}. Called on a worker thread.
*/
diff --git a/src/com/android/email/service/EmailServiceUtils.java b/src/com/android/email/service/EmailServiceUtils.java
index 458d300a2..eebe5d936 100644
--- a/src/com/android/email/service/EmailServiceUtils.java
+++ b/src/com/android/email/service/EmailServiceUtils.java
@@ -21,20 +21,17 @@ import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.app.Service;
-import android.content.ComponentName;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.database.Cursor;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -57,13 +54,14 @@ import com.android.emailcommon.service.IEmailServiceCallback;
import com.android.emailcommon.service.SearchParams;
import com.android.emailcommon.service.SyncWindow;
import com.android.mail.utils.LogUtils;
-
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -253,47 +251,8 @@ public class EmailServiceUtils {
}
}
- private static class UpdateAccountManagerTask extends AsyncTask {
- private final Context mContext;
- private final android.accounts.Account mAccount;
- private final EmailServiceInfo mOldInfo;
- private final EmailServiceInfo mNewInfo;
-
- public UpdateAccountManagerTask(Context context, android.accounts.Account amAccount,
- EmailServiceInfo oldInfo, EmailServiceInfo newInfo) {
- super();
- mContext = context;
- mAccount = amAccount;
- mOldInfo = oldInfo;
- mNewInfo = newInfo;
- }
-
- @Override
- protected Void doInBackground(Void... params) {
- updateAccountManagerType(mContext, mAccount, mOldInfo, mNewInfo);
- return null;
- }
- }
-
- private static class DisableComponentsTask extends AsyncTask {
- private final Context mContext;
-
- public DisableComponentsTask(Context context) {
- super();
- mContext = context;
- }
-
- @Override
- protected Void doInBackground(Void... params) {
- disableComponent(mContext, LegacyEmailAuthenticatorService.class);
- disableComponent(mContext, LegacyEasAuthenticatorService.class);
- return null;
- }
- }
-
- private static void updateAccountManagerType(Context context,
- android.accounts.Account amAccount, EmailServiceInfo oldInfo,
- EmailServiceInfo newInfo) {
+ public static void updateAccountManagerType(Context context,
+ android.accounts.Account amAccount, final HashMap protocolMap) {
final ContentResolver resolver = context.getContentResolver();
final Cursor c = resolver.query(Account.CONTENT_URI, Account.CONTENT_PROJECTION,
AccountColumns.EMAIL_ADDRESS + "=?", new String[] { amAccount.name }, null);
@@ -310,14 +269,14 @@ public class EmailServiceUtils {
return;
}
- // Make sure this email address is using the expected protocol; our query to
- // AccountManager doesn't know which protocol was being used (com.android.email
- // was used for both pop3 and imap
- if (!hostAuth.mProtocol.equals(oldInfo.protocol)) {
+ final String newProtocol = protocolMap.get(hostAuth.mProtocol);
+ if (newProtocol == null) {
+ // This account doesn't need updating.
return;
}
+
LogUtils.w(Logging.LOG_TAG, "Converting " + amAccount.name + " to "
- + newInfo.protocol);
+ + newProtocol);
final ContentValues accountValues = new ContentValues();
int oldFlags = account.mFlags;
@@ -331,7 +290,7 @@ public class EmailServiceUtils {
// Change the HostAuth to reference the new protocol; this has to be done before
// trying to create the AccountManager account (below)
final ContentValues hostValues = new ContentValues();
- hostValues.put(HostAuth.PROTOCOL, newInfo.protocol);
+ hostValues.put(HostAuth.PROTOCOL, newProtocol);
resolver.update(ContentUris.withAppendedId(HostAuth.CONTENT_URI, hostAuth.mId),
hostValues, null, null);
LogUtils.w(Logging.LOG_TAG, "Updated HostAuths");
@@ -401,14 +360,17 @@ public class EmailServiceUtils {
LogUtils.w(Logging.LOG_TAG, "Deleted old AccountManager account");
// Restore sync keys for contacts/calendar
- if (calendarSyncKey != null && calendarSyncKey.length != 0) {
+ // TODO: Clean up how we determine the type.
+ final String accountType = protocolMap.get(hostAuth.mProtocol + "_type");
+ if (accountType != null &&
+ calendarSyncKey != null && calendarSyncKey.length != 0) {
client = context.getContentResolver()
.acquireContentProviderClient(CalendarContract.CONTENT_URI);
try {
SyncStateContract.Helpers.set(client,
asCalendarSyncAdapter(SyncState.CONTENT_URI, amName,
- newInfo.accountType),
- new android.accounts.Account(amName, newInfo.accountType),
+ accountType),
+ new android.accounts.Account(amName, accountType),
calendarSyncKey);
LogUtils.w(Logging.LOG_TAG, "Set calendar key...");
} catch (RemoteException e) {
@@ -417,13 +379,14 @@ public class EmailServiceUtils {
client.release();
}
}
- if (contactsSyncKey != null && contactsSyncKey.length != 0) {
+ if (accountType != null &&
+ contactsSyncKey != null && contactsSyncKey.length != 0) {
client = context.getContentResolver()
.acquireContentProviderClient(ContactsContract.AUTHORITY_URI);
try {
SyncStateContract.Helpers.set(client,
ContactsContract.SyncState.CONTENT_URI,
- new android.accounts.Account(amName, newInfo.accountType),
+ new android.accounts.Account(amName, accountType),
contactsSyncKey);
LogUtils.w(Logging.LOG_TAG, "Set contacts key...");
} catch (RemoteException e) {
@@ -431,17 +394,6 @@ public class EmailServiceUtils {
}
}
- if (oldInfo.requiresAccountUpdate) {
- EmailServiceProxy service =
- EmailServiceUtils.getServiceFromInfo(context, null, newInfo);
- try {
- service.serviceUpdated(amAccount.name);
- LogUtils.w(Logging.LOG_TAG, "Updated account settings");
- } catch (RemoteException e) {
- // Old settings won't hurt anyone
- }
- }
-
// That's all folks!
LogUtils.w(Logging.LOG_TAG, "Account update completed.");
} finally {
@@ -456,14 +408,6 @@ public class EmailServiceUtils {
}
}
- private static void disableComponent(Context context, Class> klass) {
- LogUtils.w(Logging.LOG_TAG, "Disabling legacy authenticator " + klass.getSimpleName());
- final ComponentName c = new ComponentName(context, klass);
- context.getPackageManager().setComponentEnabledSetting(c,
- PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
- PackageManager.DONT_KILL_APP);
- }
-
/**
* Parse services.xml file to find our available email services
*/
@@ -481,7 +425,9 @@ public class EmailServiceUtils {
final TypedArray ta = res.obtainAttributes(xml, R.styleable.EmailServiceInfo);
info.protocol = ta.getString(R.styleable.EmailServiceInfo_protocol);
info.accountType = ta.getString(R.styleable.EmailServiceInfo_accountType);
- // Handle upgrade of one protocol to another (e.g. imap to imap2)
+ // Protocol upgrades are handled by the upgrade broadcast receiver.
+ // However, we still create the entry from the old protocol to the new type.
+ // TODO: Remove the need for this entry.
final String newProtocol =
ta.getString(R.styleable.EmailServiceInfo_replaceWith);
@@ -492,16 +438,6 @@ public class EmailServiceUtils {
"Replacement service not found: " + newProtocol);
}
sServiceMap.put(info.protocol, newInfo);
-
- info.requiresAccountUpdate = ta.getBoolean(
- R.styleable.EmailServiceInfo_requiresAccountUpdate, false);
- final AccountManager am = AccountManager.get(context);
- final android.accounts.Account[] amAccounts =
- am.getAccountsByType(info.accountType);
- for (android.accounts.Account amAccount: amAccounts) {
- new UpdateAccountManagerTask(context, amAccount, info, newInfo)
- .executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
- }
continue;
}
info.name = ta.getString(R.styleable.EmailServiceInfo_name);
@@ -569,8 +505,6 @@ public class EmailServiceUtils {
sServiceMap.put(info.protocol, info);
}
}
- // Disable our legacy components
- new DisableComponentsTask(context).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
} catch (XmlPullParserException e) {
// ignore
} catch (IOException e) {
diff --git a/src/com/android/email/service/EmailUpgradeBroadcastReceiver.java b/src/com/android/email/service/EmailUpgradeBroadcastReceiver.java
new file mode 100644
index 000000000..fe48e33a6
--- /dev/null
+++ b/src/com/android/email/service/EmailUpgradeBroadcastReceiver.java
@@ -0,0 +1,17 @@
+package com.android.email.service;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * {@link BroadcastReceiver} for app upgrade. This listens to package replacement (for unbundled
+ * upgrade) and reboot (for OTA upgrade). The code in the {@link EmailBroadcastProcessorService}
+ * disables this receiver after it runs.
+ */
+public class EmailUpgradeBroadcastReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(final Context context, final Intent intent) {
+ EmailBroadcastProcessorService.processUpgradeBroadcastIntent(context);
+ }
+}