replicant-packages_apps_Email/emailcommon/src/com/android/emailcommon/service/EmailServiceProxy.java

501 lines
18 KiB
Java

/*
* Copyright (C) 2009 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.
*/
package com.android.emailcommon.service;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.android.emailcommon.Api;
import com.android.emailcommon.Device;
import com.android.emailcommon.TempDirectory;
import com.android.emailcommon.mail.MessagingException;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.HostAuth;
import com.android.emailcommon.provider.Policy;
import java.io.IOException;
/**
* The EmailServiceProxy class provides a simple interface for the UI to call into the various
* EmailService classes (e.g. ExchangeService for EAS). It wraps the service connect/disconnect
* process so that the caller need not be concerned with it.
*
* Use the class like this:
* new EmailServiceProxy(context, class).loadAttachment(attachmentId, callback)
*
* Methods without a return value return immediately (i.e. are asynchronous); methods with a
* return value wait for a result from the Service (i.e. they should not be called from the UI
* thread) with a default timeout of 30 seconds (settable)
*
* An EmailServiceProxy object cannot be reused (trying to do so generates a RemoteException)
*/
public class EmailServiceProxy extends ServiceProxy implements IEmailService {
private static final String TAG = "EmailServiceProxy";
public static final String AUTO_DISCOVER_BUNDLE_ERROR_CODE = "autodiscover_error_code";
public static final String AUTO_DISCOVER_BUNDLE_HOST_AUTH = "autodiscover_host_auth";
public static final String VALIDATE_BUNDLE_RESULT_CODE = "validate_result_code";
public static final String VALIDATE_BUNDLE_POLICY_SET = "validate_policy_set";
public static final String VALIDATE_BUNDLE_ERROR_MESSAGE = "validate_error_message";
public static final String VALIDATE_BUNDLE_UNSUPPORTED_POLICIES =
"validate_unsupported_policies";
private final IEmailServiceCallback mCallback;
private Object mReturn = null;
private IEmailService mService;
private final boolean isRemote;
// Standard debugging
public static final int DEBUG_BIT = 1;
// Verbose (parser) logging
public static final int DEBUG_VERBOSE_BIT = 2;
// File (SD card) logging
public static final int DEBUG_FILE_BIT = 4;
// Enable strict mode
public static final int DEBUG_ENABLE_STRICT_MODE = 8;
// The first two constructors are used with local services that can be referenced by class
public EmailServiceProxy(Context _context, Class<?> _class) {
this(_context, _class, null);
}
public EmailServiceProxy(Context _context, Class<?> _class, IEmailServiceCallback _callback) {
super(_context, new Intent(_context, _class));
mCallback = _callback;
isRemote = false;
}
// The following two constructors are used with remote services that must be referenced by
// a known action or by a prebuilt intent
public EmailServiceProxy(Context _context, Intent _intent, IEmailServiceCallback _callback) {
super(_context, _intent);
try {
Device.getDeviceId(_context);
TempDirectory.setTempDirectory(_context);
} catch (IOException e) {
}
mCallback = _callback;
isRemote = true;
}
public EmailServiceProxy(Context _context, String _action, IEmailServiceCallback _callback) {
super(_context, new Intent(_action));
try {
Device.getDeviceId(_context);
TempDirectory.setTempDirectory(_context);
} catch (IOException e) {
}
mCallback = _callback;
isRemote = true;
}
@Override
public void onConnected(IBinder binder) {
mService = IEmailService.Stub.asInterface(binder);
}
public boolean isRemote() {
return isRemote;
}
@Override
public int getApiLevel() {
return Api.LEVEL;
}
/**
* Request an attachment to be loaded; the service MUST give higher priority to
* non-background loading. The service MUST use the loadAttachmentStatus callback when
* loading has started and stopped and SHOULD send callbacks with progress information if
* possible.
*
* @param attachmentId the id of the attachment record
* @param background whether or not this request corresponds to a background action (i.e.
* prefetch) vs a foreground action (user request)
*/
@Override
public void loadAttachment(final long attachmentId, final boolean background)
throws RemoteException {
setTask(new ProxyTask() {
@Override
public void run() throws RemoteException {
try {
if (mCallback != null) mService.setCallback(mCallback);
mService.loadAttachment(attachmentId, background);
} catch (RemoteException e) {
try {
// Try to send a callback (if set)
if (mCallback != null) {
mCallback.loadAttachmentStatus(-1, attachmentId,
EmailServiceStatus.REMOTE_EXCEPTION, 0);
}
} catch (RemoteException e1) {
}
}
}
}, "loadAttachment");
}
/**
* Request the sync of a mailbox; the service MUST send the syncMailboxStatus callback
* indicating "starting" and "finished" (or error), regardless of whether the mailbox is
* actually syncable.
*
* @param mailboxId the id of the mailbox record
* @param userRequest whether or not the user specifically asked for the sync
*/
@Override
public void startSync(final long mailboxId, final boolean userRequest) throws RemoteException {
setTask(new ProxyTask() {
@Override
public void run() throws RemoteException {
if (mCallback != null) mService.setCallback(mCallback);
mService.startSync(mailboxId, userRequest);
}
}, "startSync");
}
/**
* Request the immediate termination of a mailbox sync. Although the service is not required to
* acknowledge this request, it MUST send a "finished" (or error) syncMailboxStatus callback if
* the sync was started via the startSync service call.
*
* @param mailboxId the id of the mailbox record
* @param userRequest whether or not the user specifically asked for the sync
*/
@Override
public void stopSync(final long mailboxId) throws RemoteException {
setTask(new ProxyTask() {
@Override
public void run() throws RemoteException {
if (mCallback != null) mService.setCallback(mCallback);
mService.stopSync(mailboxId);
}
}, "stopSync");
}
/**
* Validate a user account, given a protocol, host address, port, ssl status, and credentials.
* The result of this call is returned in a Bundle which MUST include a result code and MAY
* include a PolicySet that is required by the account. A successful validation implies a host
* address that serves the specified protocol and credentials sufficient to be authorized
* by the server to do so.
*
* @param hostAuth the hostauth object to validate
* @return a Bundle as described above
*/
@Override
public Bundle validate(final HostAuth hostAuth) throws RemoteException {
setTask(new ProxyTask() {
@Override
public void run() throws RemoteException{
if (mCallback != null) mService.setCallback(mCallback);
mReturn = mService.validate(hostAuth);
}
}, "validate");
waitForCompletion();
if (mReturn == null) {
Bundle bundle = new Bundle();
bundle.putInt(VALIDATE_BUNDLE_RESULT_CODE, MessagingException.UNSPECIFIED_EXCEPTION);
return bundle;
} else {
Bundle bundle = (Bundle) mReturn;
bundle.setClassLoader(Policy.class.getClassLoader());
Log.v(TAG, "validate returns " + bundle.getInt(VALIDATE_BUNDLE_RESULT_CODE));
return bundle;
}
}
/**
* Attempt to determine a user's host address and credentials from an email address and
* password. The result is returned in a Bundle which MUST include an error code and MAY (on
* success) include a HostAuth record sufficient to enable the service to validate the user's
* account.
*
* @param userName the user's email address
* @param password the user's password
* @return a Bundle as described above
*/
@Override
public Bundle autoDiscover(final String userName, final String password)
throws RemoteException {
setTask(new ProxyTask() {
@Override
public void run() throws RemoteException{
if (mCallback != null) mService.setCallback(mCallback);
mReturn = mService.autoDiscover(userName, password);
}
}, "autoDiscover");
waitForCompletion();
if (mReturn == null) {
return null;
} else {
Bundle bundle = (Bundle) mReturn;
bundle.setClassLoader(HostAuth.class.getClassLoader());
Log.v(TAG, "autoDiscover returns " + bundle.getInt(AUTO_DISCOVER_BUNDLE_ERROR_CODE));
return bundle;
}
}
/**
* Request that the service reload the folder list for the specified account. The service
* MUST use the syncMailboxListStatus callback to indicate "starting" and "finished"
*
* @param accoundId the id of the account whose folder list is to be updated
*/
@Override
public void updateFolderList(final long accountId) throws RemoteException {
setTask(new ProxyTask() {
@Override
public void run() throws RemoteException {
if (mCallback != null) mService.setCallback(mCallback);
mService.updateFolderList(accountId);
}
}, "updateFolderList");
}
/**
* Specify the debug flags selected by the user. The service SHOULD log debug information as
* requested.
*
* @param flags an integer whose bits represent logging flags as defined in DEBUG_* flags above
*/
@Override
public void setLogging(final int flags) throws RemoteException {
setTask(new ProxyTask() {
@Override
public void run() throws RemoteException {
if (mCallback != null) mService.setCallback(mCallback);
mService.setLogging(flags);
}
}, "setLogging");
}
/**
* Set the global callback object to be used by the service; the service MUST always use the
* most recently set callback object
*
* @param cb a callback object through which all service callbacks are executed
*/
@Override
public void setCallback(final IEmailServiceCallback cb) throws RemoteException {
setTask(new ProxyTask() {
@Override
public void run() throws RemoteException {
mService.setCallback(cb);
}
}, "setCallback");
}
/**
* Alert the sync adapter that the account's host information has (or may have) changed; the
* service MUST stop all in-process or pending syncs, clear error states related to the
* account and its mailboxes, and restart necessary sync adapters (e.g. pushed mailboxes)
*
* @param accountId the id of the account whose host information has changed
*/
@Override
public void hostChanged(final long accountId) throws RemoteException {
setTask(new ProxyTask() {
@Override
public void run() throws RemoteException {
mService.hostChanged(accountId);
}
}, "hostChanged");
}
/**
* Send a meeting response for the specified message
*
* @param messageId the id of the message containing the meeting request
* @param response the response code, as defined in EmailServiceConstants
*/
@Override
public void sendMeetingResponse(final long messageId, final int response)
throws RemoteException {
setTask(new ProxyTask() {
@Override
public void run() throws RemoteException {
if (mCallback != null) mService.setCallback(mCallback);
mService.sendMeetingResponse(messageId, response);
}
}, "sendMeetingResponse");
}
/**
* Request the sync adapter to load a complete message
*
* @param messageId the id of the message to be loaded
*/
@Override
public void loadMore(final long messageId) throws RemoteException {
setTask(new ProxyTask() {
@Override
public void run() throws RemoteException {
if (mCallback != null) mService.setCallback(mCallback);
mService.loadMore(messageId);
}
}, "startSync");
}
/**
* Not yet used
*
* @param accountId the account in which the folder is to be created
* @param name the name of the folder to be created
*/
@Override
public boolean createFolder(long accountId, String name) throws RemoteException {
return false;
}
/**
* Not yet used
*
* @param accountId the account in which the folder resides
* @param name the name of the folder to be deleted
*/
@Override
public boolean deleteFolder(long accountId, String name) throws RemoteException {
return false;
}
/**
* Not yet used
*
* @param accountId the account in which the folder resides
* @param oldName the name of the existing folder
* @param newName the new name for the folder
*/
@Override
public boolean renameFolder(long accountId, String oldName, String newName)
throws RemoteException {
return false;
}
/**
* Request the service to delete the account's PIM (personal information management) data. This
* data includes any data that is 1) associated with the account and 2) created/stored by the
* service or its sync adapters and 3) not stored in the EmailProvider database (e.g. contact
* and calendar information).
*
* @param accountId the account whose data is to be deleted
*/
@Override
public void deleteAccountPIMData(final long accountId) throws RemoteException {
setTask(new ProxyTask() {
@Override
public void run() throws RemoteException {
mService.deleteAccountPIMData(accountId);
}
}, "deleteAccountPIMData");
}
/**
* Search for messages given a query string. The string is interpreted as the logical AND of
* terms separated by white space. The search is performed on the specified mailbox in the
* specified account (including subfolders, as specified by the includeSubfolders parameter).
* At most numResults messages matching the query term(s) will be added to the mailbox specified
* as destMailboxId. If mailboxId is -1, the entire account will be searched. If firstResult is
* specified and non-zero, results will be added starting with the firstResult'th match (i.e.
* for the continuation of a previous search)
*
* @param accountId the id of the account to be searched
* @param searchParams the search specification
* @param destMailboxId the id of the mailbox into which search results are appended
* @return the total number of matches for this search (regardless of how many were requested)
*/
@Override
public int searchMessages(final long accountId, final SearchParams searchParams,
final long destMailboxId) throws RemoteException {
setTask(new ProxyTask() {
@Override
public void run() throws RemoteException{
if (mCallback != null) mService.setCallback(mCallback);
mReturn = mService.searchMessages(accountId, searchParams, destMailboxId);
}
}, "searchMessages");
waitForCompletion();
if (mReturn == null) {
return 0;
} else {
return (Integer)mReturn;
}
}
/**
* Request the service to send mail in the specified account's Outbox
*
* @param accountId the account whose outgoing mail should be sent
*/
@Override
public void sendMail(final long accountId) throws RemoteException {
setTask(new ProxyTask() {
@Override
public void run() throws RemoteException{
if (mCallback != null) mService.setCallback(mCallback);
mService.sendMail(accountId);
}
}, "sendMail");
}
@Override
public int getCapabilities(final Account acct) throws RemoteException {
setTask(new ProxyTask() {
@Override
public void run() throws RemoteException{
if (mCallback != null) mService.setCallback(mCallback);
mReturn = mService.getCapabilities(acct);
}
}, "getCapabilities");
waitForCompletion();
if (mReturn == null) {
return 0;
} else {
return (Integer)mReturn;
}
}
/**
* Request that the account be updated for this service; this call is synchronous
*
* @param the email address of the account to be updated
*/
@Override
public void serviceUpdated(final String emailAddress) throws RemoteException {
setTask(new ProxyTask() {
@Override
public void run() throws RemoteException{
if (mCallback != null) mService.setCallback(mCallback);
mService.serviceUpdated(emailAddress);
}
}, "settingsUpdate");
waitForCompletion();
}
@Override
public IBinder asBinder() {
return null;
}
}