From 19e006ede1a5ea9b1e325eccc9bba07d81ebc5b2 Mon Sep 17 00:00:00 2001 From: Marc Blank Date: Mon, 4 Jun 2012 14:07:31 -0700 Subject: [PATCH] Generalize service discovery and calling * On the road to removing direct references to Exchange (and potentially others) from Email.apk Change-Id: Id0fe59936067f9cacde66f2979b21de3f69526a1 --- email2/res/xml/services.xml | 21 +++ .../setup/AccountSetupAccountType.java | 2 +- .../setup/AccountSetupExchangeFragment.java | 5 +- .../activity/setup/AccountSetupOptions.java | 2 +- .../email/activity/setup/DebugFragment.java | 2 +- .../email/mail/store/ExchangeStore.java | 2 +- .../android/email/service/AccountService.java | 2 +- .../EmailBroadcastProcessorService.java | 4 +- .../email/service/EmailServiceUtils.java | 149 ++++++++++++------ .../android/email2/ui/MailActivityEmail.java | 2 +- 10 files changed, 133 insertions(+), 58 deletions(-) create mode 100644 email2/res/xml/services.xml diff --git a/email2/res/xml/services.xml b/email2/res/xml/services.xml new file mode 100644 index 000000000..dfc332fc4 --- /dev/null +++ b/email2/res/xml/services.xml @@ -0,0 +1,21 @@ + + + + + + + + diff --git a/email2/src/com/android/email/activity/setup/AccountSetupAccountType.java b/email2/src/com/android/email/activity/setup/AccountSetupAccountType.java index 7ac7d209c..9add42107 100644 --- a/email2/src/com/android/email/activity/setup/AccountSetupAccountType.java +++ b/email2/src/com/android/email/activity/setup/AccountSetupAccountType.java @@ -67,7 +67,7 @@ public class AccountSetupAccountType extends AccountSetupActivity implements OnC // TODO If we decide to exclude the Exchange option in POP_IMAP mode, use the following line // instead of the line that follows it //if (ExchangeUtils.isExchangeAvailable(this) && flowMode != SetupData.FLOW_MODE_POP_IMAP) { - if (EmailServiceUtils.isExchangeAvailable(this)) { + if (EmailServiceUtils.isServiceAvailable(this, "eas")) { exchangeButton.setOnClickListener(this); exchangeButton.setVisibility(View.VISIBLE); if (VendorPolicyLoader.getInstance(this).useAlternateExchangeStrings()) { diff --git a/email2/src/com/android/email/activity/setup/AccountSetupExchangeFragment.java b/email2/src/com/android/email/activity/setup/AccountSetupExchangeFragment.java index 299c1f03a..4a1673d8c 100644 --- a/email2/src/com/android/email/activity/setup/AccountSetupExchangeFragment.java +++ b/email2/src/com/android/email/activity/setup/AccountSetupExchangeFragment.java @@ -117,11 +117,14 @@ public class AccountSetupExchangeFragment extends AccountServerBaseFragment // Calls validateFields() which enables or disables the Next button // based on the fields' validity. TextWatcher validationTextWatcher = new TextWatcher() { + @Override public void afterTextChanged(Editable s) { validateFields(); } + @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } + @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } }; // We're editing an existing account; don't allow modification of the user name @@ -359,7 +362,7 @@ public class AccountSetupExchangeFragment extends AccountServerBaseFragment account.mHostAuthSend.update(mContext, account.mHostAuthSend.toContentValues()); // For EAS, notify ExchangeService that the password has changed try { - EmailServiceUtils.getExchangeService(mContext, null).hostChanged(account.mId); + EmailServiceUtils.getService(mContext, null, "eas").hostChanged(account.mId); } catch (RemoteException e) { // Nothing to be done if this fails } diff --git a/email2/src/com/android/email/activity/setup/AccountSetupOptions.java b/email2/src/com/android/email/activity/setup/AccountSetupOptions.java index 1a5f646f1..972a1a35e 100644 --- a/email2/src/com/android/email/activity/setup/AccountSetupOptions.java +++ b/email2/src/com/android/email/activity/setup/AccountSetupOptions.java @@ -373,7 +373,7 @@ public class AccountSetupOptions extends AccountSetupActivity implements OnClick AccountSettingsUtils.commitSettings(context, account); // Start up services based on new account(s) MailActivityEmail.setServicesEnabledSync(context); - EmailServiceUtils.startExchangeService(context); + EmailServiceUtils.startService(context, "eas"); // Move to final setup screen AccountSetupNames.actionSetNames(context); finish(); diff --git a/email2/src/com/android/email/activity/setup/DebugFragment.java b/email2/src/com/android/email/activity/setup/DebugFragment.java index 18c96ebd9..e3ab807c5 100644 --- a/email2/src/com/android/email/activity/setup/DebugFragment.java +++ b/email2/src/com/android/email/activity/setup/DebugFragment.java @@ -72,7 +72,7 @@ public class DebugFragment extends Fragment implements OnCheckedChangeListener, // Note: To prevent recursion while presetting checkboxes, assign all listeners last mEnableDebugLoggingView.setOnCheckedChangeListener(this); - boolean exchangeAvailable = EmailServiceUtils.isExchangeAvailable(context); + boolean exchangeAvailable = EmailServiceUtils.isServiceAvailable(context, "eas"); if (exchangeAvailable) { mEnableExchangeLoggingView.setChecked(MailActivityEmail.DEBUG_EXCHANGE_VERBOSE); mEnableExchangeFileLoggingView.setChecked(MailActivityEmail.DEBUG_EXCHANGE_FILE); diff --git a/email2/src/com/android/email/mail/store/ExchangeStore.java b/email2/src/com/android/email/mail/store/ExchangeStore.java index 11a02d617..fb10552db 100644 --- a/email2/src/com/android/email/mail/store/ExchangeStore.java +++ b/email2/src/com/android/email/mail/store/ExchangeStore.java @@ -50,6 +50,6 @@ public class ExchangeStore extends ServiceStore { @Override protected IEmailService getService() { - return EmailServiceUtils.getExchangeService(mContext, null); + return EmailServiceUtils.getService(mContext, null, "eas"); } } diff --git a/email2/src/com/android/email/service/AccountService.java b/email2/src/com/android/email/service/AccountService.java index a12108a8b..da8637b16 100644 --- a/email2/src/com/android/email/service/AccountService.java +++ b/email2/src/com/android/email/service/AccountService.java @@ -104,7 +104,7 @@ public class AccountService extends Service { @Override public void run() { // Make sure the service is properly running (re: lifecycle) - EmailServiceUtils.startExchangeService(mContext); + EmailServiceUtils.startService(mContext, "eas"); // Send current logging flags MailActivityEmail.updateLoggingFlags(mContext); }}); diff --git a/email2/src/com/android/email/service/EmailBroadcastProcessorService.java b/email2/src/com/android/email/service/EmailBroadcastProcessorService.java index 88d714273..e770465ef 100644 --- a/email2/src/com/android/email/service/EmailBroadcastProcessorService.java +++ b/email2/src/com/android/email/service/EmailBroadcastProcessorService.java @@ -131,7 +131,7 @@ public class EmailBroadcastProcessorService extends IntentService { performOneTimeInitialization(); // Starts the service for Exchange, if supported. - EmailServiceUtils.startExchangeService(this); + EmailServiceUtils.startService(this, "eas"); } private void performOneTimeInitialization() { @@ -207,6 +207,6 @@ public class EmailBroadcastProcessorService extends IntentService { // If the exchange service wasn't already running, starting it will cause exchange account // reconciliation to be performed. The service stops itself it there are no EAS accounts. - EmailServiceUtils.startExchangeService(this); + EmailServiceUtils.startService(this, "eas"); } } diff --git a/email2/src/com/android/email/service/EmailServiceUtils.java b/email2/src/com/android/email/service/EmailServiceUtils.java index e7b18bb32..92c980d89 100644 --- a/email2/src/com/android/email/service/EmailServiceUtils.java +++ b/email2/src/com/android/email/service/EmailServiceUtils.java @@ -16,66 +16,46 @@ package com.android.email.service; +import android.app.Service; import android.content.Context; import android.content.Intent; +import android.content.res.XmlResourceParser; +import com.android.email.R; import com.android.emailcommon.provider.Account; -import com.android.emailcommon.provider.HostAuth; import com.android.emailcommon.service.EmailServiceProxy; -import com.android.emailcommon.service.IEmailService; import com.android.emailcommon.service.IEmailServiceCallback; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.HashMap; + /** * Utility functions for EmailService support. */ public class EmailServiceUtils { - /** - * Starts an EmailService by name - */ - public static void startService(Context context, String intentAction) { - context.startService(new Intent(intentAction)); - } + private static final HashMap sServiceMap = + new HashMap(); /** - * Returns an {@link IEmailService} for the service; otherwise returns an empty - * {@link IEmailService} implementation. - * - * @param context - * @param callback Object to get callback, or can be null + * Starts an EmailService by protocol */ - public static EmailServiceProxy getService(Context context, String intentAction, - IEmailServiceCallback callback) { - return new EmailServiceProxy(context, intentAction, callback); + public static void startService(Context context, String protocol) { + EmailServiceInfo info = getServiceInfo(context, protocol); + if (info != null && info.intentAction != null) { + context.startService(new Intent(info.intentAction)); + } } /** * Determine if the EmailService is available */ - public static boolean isServiceAvailable(Context context, String intentAction) { - return new EmailServiceProxy(context, intentAction, null).test(); - } - - public static void startExchangeService(Context context) { - startService(context, EmailServiceProxy.EXCHANGE_INTENT); - } - - public static EmailServiceProxy getExchangeService(Context context, - IEmailServiceCallback callback) { - return getService(context, EmailServiceProxy.EXCHANGE_INTENT, callback); - } - - public static EmailServiceProxy getImapService(Context context, - IEmailServiceCallback callback) { - return new EmailServiceProxy(context, ImapService.class, callback); - } - - public static EmailServiceProxy getPop3Service(Context context, - IEmailServiceCallback callback) { - return new EmailServiceProxy(context, Pop3Service.class, callback); - } - - public static boolean isExchangeAvailable(Context context) { - return isServiceAvailable(context, EmailServiceProxy.EXCHANGE_INTENT); + public static boolean isServiceAvailable(Context context, String protocol) { + EmailServiceInfo info = getServiceInfo(context, protocol); + if (info == null) return false; + if (info.klass != null) return true; + return new EmailServiceProxy(context, info.intentAction, null).test(); } /** @@ -86,15 +66,86 @@ public class EmailServiceUtils { */ public static EmailServiceProxy getServiceForAccount(Context context, IEmailServiceCallback callback, long accountId) { - String protocol = Account.getProtocol(context, accountId); - if (HostAuth.SCHEME_IMAP.equals(protocol)) { - return getImapService(context, callback); - } else if (HostAuth.SCHEME_POP3.equals(protocol)) { - return getPop3Service(context, callback); - } else if (HostAuth.SCHEME_EAS.equals(protocol)) { - return getExchangeService(context, callback); + return getService(context, callback, Account.getProtocol(context, accountId)); + } + + /** + * Holder of service information (currently just name and class/intent); if there is a class + * member, this is a (local, i.e. same process) service; otherwise, this is a remote service + */ + static class EmailServiceInfo { + String name; + Class klass; + String intentAction; + } + + public static EmailServiceProxy getService(Context context, IEmailServiceCallback callback, + String protocol) { + EmailServiceInfo info = getServiceInfo(context, protocol); + if (info.klass != null) { + return new EmailServiceProxy(context, info.klass, callback); } else { - return null; + return new EmailServiceProxy(context, info.intentAction, callback); } } + + private static EmailServiceInfo getServiceInfo(Context context, String protocol) { + if (sServiceMap.isEmpty()) { + findServices(context); + } + return sServiceMap.get(protocol); + } + + /** + * Parse services.xml file to find our available email services + */ + @SuppressWarnings("unchecked") + private static void findServices(Context context) { + try { + XmlResourceParser xml = context.getResources().getXml(R.xml.services); + int xmlEventType; + // walk through senders.xml file. + while ((xmlEventType = xml.next()) != XmlResourceParser.END_DOCUMENT) { + if (xmlEventType == XmlResourceParser.START_TAG && + "service".equals(xml.getName())) { + EmailServiceInfo info = new EmailServiceInfo(); + String protocol = xml.getAttributeValue(null, "protocol"); + if (protocol == null) { + throw new IllegalStateException( + "No protocol specified in service descriptor"); + } + info.name = xml.getAttributeValue(null, "name"); + if (info.name == null) { + throw new IllegalStateException( + "No name specified in service descriptor"); + } + String klass = xml.getAttributeValue(null, "class"); + if (klass != null) { + try { + info.klass = (Class) Class.forName(klass); + } catch (ClassNotFoundException e) { + throw new IllegalStateException( + "Class not found in service descriptor: " + klass); + } + } + info.intentAction = xml.getAttributeValue(null, "intent"); + + if (info.klass == null && info.intentAction == null) { + throw new IllegalStateException( + "No class or intent action specified in service descriptor"); + } + if (info.klass != null && info.intentAction != null) { + throw new IllegalStateException( + "Both class and intent action specified in service descriptor"); + } + sServiceMap.put(protocol, info); + } + } + } catch (XmlPullParserException e) { + // ignore + } catch (IOException e) { + // ignore + } + } + } diff --git a/email2/src/com/android/email2/ui/MailActivityEmail.java b/email2/src/com/android/email2/ui/MailActivityEmail.java index b1514dd09..f13550d24 100644 --- a/email2/src/com/android/email2/ui/MailActivityEmail.java +++ b/email2/src/com/android/email2/ui/MailActivityEmail.java @@ -193,7 +193,7 @@ public class MailActivityEmail extends com.android.mail.ui.MailActivity { int enableStrictMode = prefs.getEnableStrictMode() ? EmailServiceProxy.DEBUG_ENABLE_STRICT_MODE : 0; int debugBits = debugLogging | verboseLogging | fileLogging | enableStrictMode; - EmailServiceProxy service = EmailServiceUtils.getExchangeService(context, null); + EmailServiceProxy service = EmailServiceUtils.getService(context, null, "eas"); if (service != null) { try { service.setLogging(debugBits);