From 462da178b1be608a74000956c53dc8ecb438c689 Mon Sep 17 00:00:00 2001 From: Yu Ping Hu Date: Mon, 22 Jul 2013 15:26:34 -0700 Subject: [PATCH] Move authenticator upgrade to app upgrade time. This used to run when the app first initializes the service map. Bug: 9391930 Bug: 9971936 Change-Id: Iebaeb2dc94ef62edb0be0a7d5a008a26c4f5edfb --- AndroidManifest.xml | 10 ++ .../EmailBroadcastProcessorService.java | 56 +++++++++ .../email/service/EmailServiceUtils.java | 110 ++++-------------- .../EmailUpgradeBroadcastReceiver.java | 17 +++ 4 files changed, 105 insertions(+), 88 deletions(-) create mode 100644 src/com/android/email/service/EmailUpgradeBroadcastReceiver.java 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); + } +}