Generalize service discovery and calling

* On the road to removing direct references to
  Exchange (and potentially others) from Email.apk

Change-Id: Id0fe59936067f9cacde66f2979b21de3f69526a1
This commit is contained in:
Marc Blank 2012-06-04 14:07:31 -07:00
parent 8410a296c5
commit 19e006ede1
10 changed files with 133 additions and 58 deletions

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2012 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<services>
<service protocol="pop3" name="POP3" class="com.android.email.service.ImapService" />
<service protocol="imap" name="IMAP" class="com.android.email.service.Pop3Service" />
<service protocol="eas" name="Exchange" intent="com.android.email.EXCHANGE_INTENT" />
</services>

View File

@ -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()) {

View File

@ -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
}

View File

@ -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();

View File

@ -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);

View File

@ -50,6 +50,6 @@ public class ExchangeStore extends ServiceStore {
@Override
protected IEmailService getService() {
return EmailServiceUtils.getExchangeService(mContext, null);
return EmailServiceUtils.getService(mContext, null, "eas");
}
}

View File

@ -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);
}});

View File

@ -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");
}
}

View File

@ -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<String, EmailServiceInfo> sServiceMap =
new HashMap<String, EmailServiceInfo>();
/**
* 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<? extends Service> 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<? extends Service>) 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
}
}
}

View File

@ -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);