Various EAS related changes related to accounts and services.
* Renamed ISyncManager/ISyncManagerCallback to IEmailService/IEmailServiceCallback * Restored ExchangeTransportExample to its original state; created ExchangeStore to handle validation functionality instead; updated stores.xml to reflect these changes. * Add support for AccountManager in EAS code (this is necessary for the contacts and calendar providers to work with syncable data); created EasAuthenticatorService to as our authenticator, which required adding authenticator.xml and modifying the manifest to register our service with AccountManager metadata * Created EmailServiceProxy as a convenience for the UI in calling into the EAS service; created EmailServiceStatus class for status codes in callbacks.
This commit is contained in:
parent
ded3c915d8
commit
17250429db
|
@ -17,8 +17,9 @@ include $(CLEAR_VARS)
|
||||||
|
|
||||||
LOCAL_SRC_FILES := $(call all-java-files-under, src)
|
LOCAL_SRC_FILES := $(call all-java-files-under, src)
|
||||||
LOCAL_SRC_FILES += \
|
LOCAL_SRC_FILES += \
|
||||||
src/com/android/exchange/ISyncManager.aidl \
|
src/com/android/exchange/IEmailService.aidl \
|
||||||
src/com/android/exchange/ISyncManagerCallback.aidl
|
src/com/android/exchange/IEmailServiceCallback.aidl
|
||||||
|
|
||||||
|
|
||||||
LOCAL_PACKAGE_NAME := Email
|
LOCAL_PACKAGE_NAME := Email
|
||||||
|
|
||||||
|
|
|
@ -178,6 +178,16 @@
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
>
|
>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
<!--Required stanza to register the EasAuthenticatorService with AccountManager -->
|
||||||
|
<service android:name=".service.EasAuthenticatorService" android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.accounts.AccountAuthenticator" />
|
||||||
|
</intent-filter>
|
||||||
|
<meta-data android:name="android.accounts.AccountAuthenticator"
|
||||||
|
android:resource="@xml/authenticator" />
|
||||||
|
</service>
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name=".provider.AttachmentProvider"
|
android:name=".provider.AttachmentProvider"
|
||||||
android:authorities="com.android.email.attachmentprovider"
|
android:authorities="com.android.email.attachmentprovider"
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- The attributes in this XML file provide configuration information -->
|
||||||
|
<!-- for the Account Manager. -->
|
||||||
|
|
||||||
|
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:accountType="com.android.exchange"
|
||||||
|
android:icon="@drawable/icon"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
/>
|
|
@ -35,6 +35,6 @@
|
||||||
<store scheme="imap" class="com.android.email.mail.store.ImapStore" />
|
<store scheme="imap" class="com.android.email.mail.store.ImapStore" />
|
||||||
|
|
||||||
<!-- This is here for temporary demo purposes only. Do not ship with this. -->
|
<!-- This is here for temporary demo purposes only. Do not ship with this. -->
|
||||||
<store scheme="eas" class="com.android.email.mail.exchange.ExchangeStoreExample"
|
<store scheme="eas" class="com.android.email.mail.store.ExchangeStore"
|
||||||
push="true" visibleLimitDefault="-1" visibleLimitIncrement="-1" accountInstanceLimit="1" />
|
push="true" visibleLimitDefault="-1" visibleLimitIncrement="-1" />
|
||||||
</stores>
|
</stores>
|
||||||
|
|
|
@ -33,6 +33,8 @@ import com.android.email.mail.Message.RecipientType;
|
||||||
import com.android.email.mail.store.LocalStore;
|
import com.android.email.mail.store.LocalStore;
|
||||||
import com.android.email.mail.store.LocalStore.LocalMessage;
|
import com.android.email.mail.store.LocalStore.LocalMessage;
|
||||||
import com.android.email.provider.EmailContent;
|
import com.android.email.provider.EmailContent;
|
||||||
|
import com.android.email.provider.EmailContent.Mailbox;
|
||||||
|
import com.android.email.provider.EmailContent.MailboxColumns;
|
||||||
|
|
||||||
import android.app.ExpandableListActivity;
|
import android.app.ExpandableListActivity;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
|
@ -996,12 +998,14 @@ public class FolderMessageList extends ExpandableListActivity {
|
||||||
// to match desired UI presentation (e.g. INBOX at the top)
|
// to match desired UI presentation (e.g. INBOX at the top)
|
||||||
@Override
|
@Override
|
||||||
protected Cursor doInBackground(Void... params) {
|
protected Cursor doInBackground(Void... params) {
|
||||||
|
// Only show boxes with mail, and sort secondarily by name
|
||||||
return FolderMessageList.this.managedQuery(
|
return FolderMessageList.this.managedQuery(
|
||||||
EmailContent.Mailbox.CONTENT_URI,
|
Mailbox.CONTENT_URI,
|
||||||
EmailContent.Mailbox.CONTENT_PROJECTION,
|
Mailbox.CONTENT_PROJECTION,
|
||||||
EmailContent.MailboxColumns.ACCOUNT_KEY + "=?",
|
MailboxColumns.ACCOUNT_KEY + "=? and "
|
||||||
|
+ MailboxColumns.TYPE + '<' + Mailbox.TYPE_NOT_EMAIL,
|
||||||
new String[] { String.valueOf(FolderMessageList.this.mAccountId) },
|
new String[] { String.valueOf(FolderMessageList.this.mAccountId) },
|
||||||
EmailContent.MailboxColumns.TYPE);
|
MailboxColumns.TYPE + ',' + MailboxColumns.DISPLAY_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -82,7 +82,7 @@ public class MessageListItem extends RelativeLayout {
|
||||||
int touchX = (int) event.getX();
|
int touchX = (int) event.getX();
|
||||||
|
|
||||||
if (!mCachedViewPositions) {
|
if (!mCachedViewPositions) {
|
||||||
float paddingScale = mContext.getResources().getDisplayMetrics().density;
|
float paddingScale = getContext().getResources().getDisplayMetrics().density;
|
||||||
int checkPadding = (int) ((CHECKMARK_PAD * paddingScale) + 0.5);
|
int checkPadding = (int) ((CHECKMARK_PAD * paddingScale) + 0.5);
|
||||||
int starPadding = (int) ((STAR_PAD * paddingScale) + 0.5);
|
int starPadding = (int) ((STAR_PAD * paddingScale) + 0.5);
|
||||||
mCheckRight = findViewById(R.id.selected).getRight() + checkPadding;
|
mCheckRight = findViewById(R.id.selected).getRight() + checkPadding;
|
||||||
|
|
|
@ -17,18 +17,9 @@
|
||||||
package com.android.email.mail.exchange;
|
package com.android.email.mail.exchange;
|
||||||
|
|
||||||
import com.android.email.Email;
|
import com.android.email.Email;
|
||||||
import com.android.email.mail.AuthenticationFailedException;
|
|
||||||
import com.android.email.mail.MessagingException;
|
import com.android.email.mail.MessagingException;
|
||||||
import com.android.exchange.ISyncManager;
|
|
||||||
import com.android.exchange.SyncManager;
|
|
||||||
//import com.android.exchange.EasService;
|
|
||||||
|
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.ServiceConnection;
|
|
||||||
import android.os.IBinder;
|
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
@ -44,6 +35,7 @@ public class ExchangeTransportExample {
|
||||||
|
|
||||||
public static final String FOLDER_INBOX = Email.INBOX;
|
public static final String FOLDER_INBOX = Email.INBOX;
|
||||||
|
|
||||||
|
private static final String TAG = "ExchangeTransportExample";
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
|
|
||||||
private String mHost;
|
private String mHost;
|
||||||
|
@ -115,52 +107,10 @@ public class ExchangeTransportExample {
|
||||||
* @param uri the server/account to try and connect to
|
* @param uri the server/account to try and connect to
|
||||||
* @throws MessagingException thrown if the connection, server, account are not useable
|
* @throws MessagingException thrown if the connection, server, account are not useable
|
||||||
*/
|
*/
|
||||||
ISyncManager mSyncManagerService = null;
|
|
||||||
|
|
||||||
private ServiceConnection mSyncManagerConnection = new ServiceConnection () {
|
|
||||||
public void onServiceConnected(ComponentName name, IBinder binder) {
|
|
||||||
mSyncManagerService = ISyncManager.Stub.asInterface(binder);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onServiceDisconnected(ComponentName name) {
|
|
||||||
mSyncManagerService = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public void checkSettings(URI uri) throws MessagingException {
|
public void checkSettings(URI uri) throws MessagingException {
|
||||||
setUri(uri);
|
setUri(uri);
|
||||||
boolean ssl = uri.getScheme().contains("ssl+");
|
}
|
||||||
try {
|
|
||||||
mContext.bindService(new Intent(mContext, SyncManager.class), mSyncManagerConnection, Context.BIND_AUTO_CREATE);
|
|
||||||
// TODO Is this the right way of waiting for a connection??
|
|
||||||
int count = 0;
|
|
||||||
while ((count++ < 10) && (mSyncManagerService == null)) {
|
|
||||||
Thread.sleep(500);
|
|
||||||
}
|
|
||||||
if (mSyncManagerService == null) {
|
|
||||||
throw new MessagingException(MessagingException.UNSPECIFIED_EXCEPTION);
|
|
||||||
}
|
|
||||||
// The result of validate is a MessagingException error code
|
|
||||||
// We use NO_ERROR to indicate a validated account
|
|
||||||
int result = mSyncManagerService.validate("eas", mHost, mUsername, mPassword, ssl ? 443 : 80, ssl);
|
|
||||||
if (result != MessagingException.NO_ERROR) {
|
|
||||||
if (result == MessagingException.AUTHENTICATION_FAILED) {
|
|
||||||
throw new AuthenticationFailedException("Authentication failed.");
|
|
||||||
} else {
|
|
||||||
throw new MessagingException(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
throw new MessagingException("Call to validate generated an exception", e);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
} finally {
|
|
||||||
if (mSyncManagerService != null) {
|
|
||||||
mContext.unbindService(mSyncManagerConnection);
|
|
||||||
} else
|
|
||||||
throw new MessagingException(MessagingException.UNSPECIFIED_EXCEPTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Typical helper function: Return existence of a given folder
|
* Typical helper function: Return existence of a given folder
|
||||||
|
|
|
@ -0,0 +1,497 @@
|
||||||
|
/*
|
||||||
|
* 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.email.mail.store;
|
||||||
|
|
||||||
|
import com.android.email.Email;
|
||||||
|
import com.android.email.mail.AuthenticationFailedException;
|
||||||
|
import com.android.email.mail.FetchProfile;
|
||||||
|
import com.android.email.mail.Flag;
|
||||||
|
import com.android.email.mail.Folder;
|
||||||
|
import com.android.email.mail.Message;
|
||||||
|
import com.android.email.mail.MessageRetrievalListener;
|
||||||
|
import com.android.email.mail.MessagingException;
|
||||||
|
import com.android.email.mail.Store;
|
||||||
|
import com.android.email.mail.StoreSynchronizer;
|
||||||
|
import com.android.email.service.EmailServiceProxy;
|
||||||
|
import com.android.exchange.Eas;
|
||||||
|
import com.android.exchange.IEmailService;
|
||||||
|
import com.android.exchange.IEmailServiceCallback;
|
||||||
|
import com.android.exchange.SyncManager;
|
||||||
|
import com.android.exchange.EmailContent.Attachment;
|
||||||
|
|
||||||
|
import android.accounts.AccountManager;
|
||||||
|
import android.accounts.AuthenticatorException;
|
||||||
|
import android.accounts.Future2;
|
||||||
|
import android.accounts.Future2Callback;
|
||||||
|
import android.accounts.OperationCanceledException;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Config;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a placeholder for use in Exchange implementations. It is based on the notion of
|
||||||
|
* lightweight adapter classes for Store, Folder, and Sender, and a common facade for the common
|
||||||
|
* Transport code.
|
||||||
|
*/
|
||||||
|
public class ExchangeStore extends Store {
|
||||||
|
public static final String LOG_TAG = "ExchangeStore";
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
private URI mUri;
|
||||||
|
private PersistentDataCallbacks mCallbacks;
|
||||||
|
|
||||||
|
private final ExchangeTransport mTransport;
|
||||||
|
private final HashMap<String, Folder> mFolders = new HashMap<String, Folder>();
|
||||||
|
|
||||||
|
private boolean mPushModeRunning = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory method.
|
||||||
|
*/
|
||||||
|
public static Store newInstance(String uri, Context context, PersistentDataCallbacks callbacks)
|
||||||
|
throws MessagingException {
|
||||||
|
return new ExchangeStore(uri, context, callbacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eas://user:password@server/domain
|
||||||
|
*
|
||||||
|
* @param _uri
|
||||||
|
* @param application
|
||||||
|
* @throws MessagingException
|
||||||
|
*/
|
||||||
|
private ExchangeStore(String _uri, Context context, PersistentDataCallbacks callbacks)
|
||||||
|
throws MessagingException {
|
||||||
|
mContext = context;
|
||||||
|
try {
|
||||||
|
mUri = new URI(_uri);
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
throw new MessagingException("Invalid uri for ExchangeStore");
|
||||||
|
}
|
||||||
|
mCallbacks = callbacks;
|
||||||
|
|
||||||
|
String scheme = mUri.getScheme();
|
||||||
|
int connectionSecurity;
|
||||||
|
if (scheme.equals("eas")) {
|
||||||
|
connectionSecurity = ExchangeTransport.CONNECTION_SECURITY_NONE;
|
||||||
|
} else if (scheme.equals("eas+ssl+")) {
|
||||||
|
connectionSecurity = ExchangeTransport.CONNECTION_SECURITY_SSL_REQUIRED;
|
||||||
|
} else {
|
||||||
|
throw new MessagingException("Unsupported protocol");
|
||||||
|
}
|
||||||
|
|
||||||
|
mTransport = ExchangeTransport.getInstance(mUri, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the underlying transport. Used primarily for testing.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
/* package */ ExchangeTransport getTransport() {
|
||||||
|
return mTransport;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkSettings() throws MessagingException {
|
||||||
|
mTransport.checkSettings(mUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Folder getFolder(String name) throws MessagingException {
|
||||||
|
synchronized (mFolders) {
|
||||||
|
Folder folder = mFolders.get(name);
|
||||||
|
if (folder == null) {
|
||||||
|
folder = new ExchangeFolder(this, name);
|
||||||
|
mFolders.put(folder.getName(), folder);
|
||||||
|
}
|
||||||
|
return folder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Folder[] getPersonalNamespaces() throws MessagingException {
|
||||||
|
return new Folder[] {
|
||||||
|
getFolder(ExchangeTransport.FOLDER_INBOX),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For a store that supports push mode, this is the API that enables it or disables it.
|
||||||
|
* The store should use this API to start or stop its persistent connection service or thread.
|
||||||
|
*
|
||||||
|
* <p>Note, may be called multiple times, even after push mode has been started or stopped.
|
||||||
|
*
|
||||||
|
* @param enablePushMode start or stop push mode delivery
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void enablePushModeDelivery(boolean enablePushMode) {
|
||||||
|
if (Config.LOGD && Email.DEBUG) {
|
||||||
|
if (enablePushMode && !mPushModeRunning) {
|
||||||
|
Log.d(Email.LOG_TAG, "start push mode");
|
||||||
|
} else if (!enablePushMode && mPushModeRunning) {
|
||||||
|
Log.d(Email.LOG_TAG, "stop push mode");
|
||||||
|
} else {
|
||||||
|
Log.d(Email.LOG_TAG, enablePushMode ?
|
||||||
|
"push mode already started" : "push mode already stopped");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mPushModeRunning = enablePushMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get class of SettingActivity for this Store class.
|
||||||
|
* @return Activity class that has class method actionEditIncomingSettings()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Class<? extends android.app.Activity> getSettingActivityClass() {
|
||||||
|
return com.android.email.activity.setup.AccountSetupExchange.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get class of sync'er for this Store class. Because exchange Sync rules are so different
|
||||||
|
* than IMAP or POP3, it's likely that an Exchange implementation will need its own sync
|
||||||
|
* controller. If so, this function must return a non-null value.
|
||||||
|
*
|
||||||
|
* @return Message Sync controller, or null to use default
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public StoreSynchronizer getMessageSynchronizer() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inform MessagingController that this store requires message structures to be prefetched
|
||||||
|
* before it can fetch message bodies (this is due to EAS protocol restrictions.)
|
||||||
|
* @return always true for EAS
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean requireStructurePrefetch() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inform MessagingController that messages sent via EAS will be placed in the Sent folder
|
||||||
|
* automatically (server-side) and don't need to be uploaded.
|
||||||
|
* @return always false for EAS (assuming server-side copy is supported)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean requireCopyMessageToSentFolder() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ExchangeTransport {
|
||||||
|
public static final int CONNECTION_SECURITY_NONE = 0;
|
||||||
|
public static final int CONNECTION_SECURITY_SSL_REQUIRED = 1;
|
||||||
|
|
||||||
|
public static final String FOLDER_INBOX = Email.INBOX;
|
||||||
|
|
||||||
|
private static final String TAG = "ExchangeTransport";
|
||||||
|
private final Context mContext;
|
||||||
|
|
||||||
|
private String mHost;
|
||||||
|
private String mDomain;
|
||||||
|
private String mUsername;
|
||||||
|
private String mPassword;
|
||||||
|
|
||||||
|
private static HashMap<String, ExchangeTransport> sUriToInstanceMap =
|
||||||
|
new HashMap<String, ExchangeTransport>();
|
||||||
|
private static final HashMap<String, Integer> sFolderMap = new HashMap<String, Integer>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public factory. The transport should be a singleton (per Uri)
|
||||||
|
*/
|
||||||
|
public synchronized static ExchangeTransport getInstance(URI uri, Context context)
|
||||||
|
throws MessagingException {
|
||||||
|
if (!uri.getScheme().equals("eas") && !uri.getScheme().equals("eas+ssl+")) {
|
||||||
|
throw new MessagingException("Invalid scheme");
|
||||||
|
}
|
||||||
|
|
||||||
|
final String key = uri.toString();
|
||||||
|
ExchangeTransport transport = sUriToInstanceMap.get(key);
|
||||||
|
if (transport == null) {
|
||||||
|
transport = new ExchangeTransport(uri, context);
|
||||||
|
sUriToInstanceMap.put(key, transport);
|
||||||
|
}
|
||||||
|
return transport;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private constructor - use public factory.
|
||||||
|
*/
|
||||||
|
private ExchangeTransport(URI uri, Context context) throws MessagingException {
|
||||||
|
mContext = context;
|
||||||
|
setUri(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use the Uri to set up a newly-constructed transport
|
||||||
|
* @param uri
|
||||||
|
* @throws MessagingException
|
||||||
|
*/
|
||||||
|
private void setUri(final URI uri) throws MessagingException {
|
||||||
|
mHost = uri.getHost();
|
||||||
|
if (mHost == null) {
|
||||||
|
throw new MessagingException("host not specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
mDomain = uri.getPath();
|
||||||
|
if (!TextUtils.isEmpty(mDomain)) {
|
||||||
|
mDomain = mDomain.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String userInfo = uri.getUserInfo();
|
||||||
|
if (userInfo == null) {
|
||||||
|
throw new MessagingException("user information not specifed");
|
||||||
|
}
|
||||||
|
final String[] uinfo = userInfo.split(":", 2);
|
||||||
|
if (uinfo.length != 2) {
|
||||||
|
throw new MessagingException("user name and password not specified");
|
||||||
|
}
|
||||||
|
mUsername = uinfo[0];
|
||||||
|
mPassword = uinfo[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blocking call that checks for a useable server connection, credentials, etc.
|
||||||
|
* @param uri the server/account to try and connect to
|
||||||
|
* @throws MessagingException thrown if the connection, server, account are not useable
|
||||||
|
*/
|
||||||
|
|
||||||
|
IEmailServiceCallback mCallback = new IEmailServiceCallback () {
|
||||||
|
|
||||||
|
public void status(int statusCode, int progress) throws RemoteException {
|
||||||
|
Log.d("Status: ", "Code = " + statusCode + ", progress = " + progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IBinder asBinder() { return null; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Here's where we check the settings for EAS.
|
||||||
|
* @param uri the URI of the account to create
|
||||||
|
* @throws MessagingException if we can't authenticate the account
|
||||||
|
*/
|
||||||
|
public void checkSettings(URI uri) throws MessagingException {
|
||||||
|
setUri(uri);
|
||||||
|
boolean ssl = uri.getScheme().contains("ssl+");
|
||||||
|
try {
|
||||||
|
IEmailService svc = EmailServiceProxy.getService(mContext, SyncManager.class);
|
||||||
|
int result = svc.validate("eas", mHost, mUsername, mPassword, ssl ? 443 : 80, ssl);
|
||||||
|
if (result != MessagingException.NO_ERROR) {
|
||||||
|
if (result == MessagingException.AUTHENTICATION_FAILED) {
|
||||||
|
throw new AuthenticationFailedException("Authentication failed.");
|
||||||
|
} else {
|
||||||
|
throw new MessagingException(result);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This code was taken from sample code in AccountsTester
|
||||||
|
Bundle options = new Bundle();
|
||||||
|
options.putString("username", mUsername);
|
||||||
|
options.putString("password", mPassword);
|
||||||
|
Future2Callback callback = new Future2Callback() {
|
||||||
|
public void run(Future2 future) {
|
||||||
|
try {
|
||||||
|
Bundle bundle = future.getResult();
|
||||||
|
bundle.keySet();
|
||||||
|
Log.d(TAG, "account added: " + bundle);
|
||||||
|
} catch (OperationCanceledException e) {
|
||||||
|
Log.d(TAG, "addAccount was canceled");
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(TAG, "addAccount failed: " + e);
|
||||||
|
} catch (AuthenticatorException e) {
|
||||||
|
Log.d(TAG, "addAccount failed: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Here's where we tell AccountManager about the new account. The addAccount
|
||||||
|
// method in AccountManager calls the addAccount method in our authenticator
|
||||||
|
// service (EasAuthenticatorService)
|
||||||
|
AccountManager.get(mContext).addAccount(Eas.ACCOUNT_MANAGER_TYPE, null, null,
|
||||||
|
options, null, callback, null);
|
||||||
|
}
|
||||||
|
svc.loadAttachment(0, new Attachment(), mCallback);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw new MessagingException("Call to validate generated an exception", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Typical helper function: Return existence of a given folder
|
||||||
|
*/
|
||||||
|
public boolean isFolderAvailable(final String folder) {
|
||||||
|
return sFolderMap.containsKey(folder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ExchangeFolder extends Folder {
|
||||||
|
|
||||||
|
private final ExchangeTransport mTransport;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final ExchangeStore mStore;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final String mName;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private PersistentDataCallbacks mPersistenceCallbacks;
|
||||||
|
|
||||||
|
public ExchangeFolder(ExchangeStore store, String name)
|
||||||
|
throws MessagingException {
|
||||||
|
mStore = store;
|
||||||
|
mTransport = store.getTransport();
|
||||||
|
mName = name;
|
||||||
|
if (!mTransport.isFolderAvailable(name)) {
|
||||||
|
throw new MessagingException("folder not supported: " + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void appendMessages(Message[] messages) throws MessagingException {
|
||||||
|
// TODO Implement this function
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close(boolean expunge) throws MessagingException {
|
||||||
|
mPersistenceCallbacks = null;
|
||||||
|
// TODO Implement this function
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copyMessages(Message[] msgs, Folder folder, MessageUpdateCallbacks callbacks)
|
||||||
|
throws MessagingException {
|
||||||
|
// TODO Implement this function
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean create(FolderType type) throws MessagingException {
|
||||||
|
// TODO Implement this function
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(boolean recurse) throws MessagingException {
|
||||||
|
// TODO Implement this function
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean exists() throws MessagingException {
|
||||||
|
// TODO Implement this function
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message[] expunge() throws MessagingException {
|
||||||
|
// TODO Implement this function
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fetch(Message[] messages, FetchProfile fp, MessageRetrievalListener listener)
|
||||||
|
throws MessagingException {
|
||||||
|
// TODO Implement this function
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message getMessage(String uid) throws MessagingException {
|
||||||
|
// TODO Implement this function
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMessageCount() throws MessagingException {
|
||||||
|
// TODO Implement this function
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message[] getMessages(int start, int end, MessageRetrievalListener listener)
|
||||||
|
throws MessagingException {
|
||||||
|
// TODO Implement this function
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message[] getMessages(MessageRetrievalListener listener) throws MessagingException {
|
||||||
|
// TODO Implement this function
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message[] getMessages(String[] uids, MessageRetrievalListener listener)
|
||||||
|
throws MessagingException {
|
||||||
|
// TODO Implement this function
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OpenMode getMode() throws MessagingException {
|
||||||
|
// TODO Implement this function
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
// TODO Implement this function
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Flag[] getPermanentFlags() throws MessagingException {
|
||||||
|
// TODO Implement this function
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getUnreadMessageCount() throws MessagingException {
|
||||||
|
// TODO Implement this function
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOpen() {
|
||||||
|
// TODO Implement this function
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void open(OpenMode mode, PersistentDataCallbacks callbacks)
|
||||||
|
throws MessagingException {
|
||||||
|
mPersistenceCallbacks = callbacks;
|
||||||
|
// TODO Implement this function
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFlags(Message[] messages, Flag[] flags, boolean value)
|
||||||
|
throws MessagingException {
|
||||||
|
// TODO Implement this function
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* 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.email.service;
|
||||||
|
|
||||||
|
import com.android.exchange.Eas;
|
||||||
|
|
||||||
|
import android.accounts.AbstractAccountAuthenticator;
|
||||||
|
import android.accounts.Account;
|
||||||
|
import android.accounts.AccountAuthenticatorResponse;
|
||||||
|
import android.accounts.AccountManager;
|
||||||
|
import android.accounts.Constants;
|
||||||
|
import android.accounts.NetworkErrorException;
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.IBinder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A very basic authenticator service for EAS. At the moment, it has no UI hooks. When called
|
||||||
|
* with addAccount, it simply adds the account to AccountManager directly with a username and
|
||||||
|
* password. We will need to implement confirmPassword, confirmCredentials, and updateCredentials.
|
||||||
|
*/
|
||||||
|
public class EasAuthenticatorService extends Service {
|
||||||
|
|
||||||
|
class EasAuthenticator extends AbstractAccountAuthenticator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle addAccount(AccountAuthenticatorResponse response, String accountType,
|
||||||
|
String authTokenType, String[] requiredFeatures, Bundle options)
|
||||||
|
throws NetworkErrorException {
|
||||||
|
// The Bundle we are passed has username and password set
|
||||||
|
AccountManager.get(EasAuthenticatorService.this).blockingAddAccountExplicitly(
|
||||||
|
new Account(options.getString("username"), Eas.ACCOUNT_MANAGER_TYPE),
|
||||||
|
options.getString("password"), null);
|
||||||
|
Bundle b = new Bundle();
|
||||||
|
b.putString(Constants.ACCOUNT_NAME_KEY, options.getString("username"));
|
||||||
|
b.putString(Constants.ACCOUNT_TYPE_KEY, Eas.ACCOUNT_MANAGER_TYPE);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean confirmPassword(AccountAuthenticatorResponse response, Account account,
|
||||||
|
String password) throws NetworkErrorException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account,
|
||||||
|
String authTokenType, Bundle loginOptions) throws NetworkErrorException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account,
|
||||||
|
String[] features) throws NetworkErrorException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account,
|
||||||
|
String authTokenType, Bundle loginOptions) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent intent) {
|
||||||
|
// TODO Replace this with an appropriate constant in AccountManager, when it's created
|
||||||
|
String authenticatorIntent = "android.accounts.AccountAuthenticator";
|
||||||
|
|
||||||
|
if (authenticatorIntent.equals(intent.getAction())) {
|
||||||
|
return new EasAuthenticator().getIAccountAuthenticator().asBinder();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2008-2009 Marc Blank
|
||||||
|
* Licensed to 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.email.service;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.ServiceConnection;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
|
||||||
|
import com.android.exchange.IEmailService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proxy for an IEmailService (remote email service); handles all connections to the service.
|
||||||
|
* All calls via the proxy are synchronous; the UI must ensure that these calls are running
|
||||||
|
* on appropriate background threads.
|
||||||
|
*
|
||||||
|
* A call to loadAttachment, for example, would look like this (assuming MyService is the service)
|
||||||
|
* EmailProxyService.getService(context, MyService.class).loadAttachment(..args..);
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class EmailServiceProxy {
|
||||||
|
|
||||||
|
// Map associating a context and a proxy
|
||||||
|
static HashMap<Context, EmailServiceProxy> sProxyMap =
|
||||||
|
new HashMap<Context, EmailServiceProxy>();
|
||||||
|
|
||||||
|
// Map associating, for a given proxy, a class name (String) and a connected service
|
||||||
|
public HashMap<String, IEmailService> serviceMap =
|
||||||
|
new HashMap<String, IEmailService>();
|
||||||
|
|
||||||
|
public EmailServiceProxy () {
|
||||||
|
}
|
||||||
|
|
||||||
|
class EmailServiceConnection implements ServiceConnection {
|
||||||
|
EmailServiceProxy mProxy;
|
||||||
|
|
||||||
|
EmailServiceConnection (EmailServiceProxy proxy) {
|
||||||
|
mProxy = proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setProxy (EmailServiceProxy proxy) {
|
||||||
|
mProxy = proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onServiceConnected(ComponentName name, IBinder binder) {
|
||||||
|
synchronized (mProxy) {
|
||||||
|
IEmailService service = IEmailService.Stub.asInterface(binder);
|
||||||
|
mProxy.serviceMap.put(name.getClassName(), service);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onServiceDisconnected(ComponentName name) {
|
||||||
|
synchronized (mProxy) {
|
||||||
|
mProxy.serviceMap.remove(name.getClassName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceConnection mSyncManagerConnection = new EmailServiceConnection (this);
|
||||||
|
|
||||||
|
static public IEmailService getService(Context context, Class<? extends Service> klass)
|
||||||
|
throws RemoteException {
|
||||||
|
String className = klass.getName();
|
||||||
|
|
||||||
|
// First, lets get the proxy for this context
|
||||||
|
// Make sure we're synchronized on the map
|
||||||
|
EmailServiceProxy proxy;
|
||||||
|
synchronized (sProxyMap) {
|
||||||
|
proxy = sProxyMap.get(context);
|
||||||
|
if (proxy == null) {
|
||||||
|
proxy = new EmailServiceProxy();
|
||||||
|
sProxyMap.put(context, proxy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once we have the proxy, we need to synchronize working with its map, connect to the
|
||||||
|
// appropriate service (if not already connected) and return that service
|
||||||
|
synchronized (proxy) {
|
||||||
|
if (proxy.serviceMap.get(klass) == null) {
|
||||||
|
context.bindService(new Intent(context, klass), proxy.mSyncManagerConnection,
|
||||||
|
Context.BIND_AUTO_CREATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait up to 5 seconds for the connection
|
||||||
|
int count = 0;
|
||||||
|
IEmailService service = null;
|
||||||
|
while (count++ < 10) {
|
||||||
|
synchronized (proxy) {
|
||||||
|
service = proxy.serviceMap.get(className);
|
||||||
|
if (service != null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep(500);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (service == null) {
|
||||||
|
throw new RemoteException();
|
||||||
|
}
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,7 +27,9 @@ public class Eas {
|
||||||
// For temporary use while debugging
|
// For temporary use while debugging
|
||||||
public static boolean TEST_DEBUG = false; // DO NOT CHECK IN WITH THIS SET TO TRUE
|
public static boolean TEST_DEBUG = false; // DO NOT CHECK IN WITH THIS SET TO TRUE
|
||||||
|
|
||||||
public static String VERSION = "0.1";
|
public static final String VERSION = "0.1";
|
||||||
|
|
||||||
|
public static final String ACCOUNT_MANAGER_TYPE = "com.android.exchange";
|
||||||
|
|
||||||
// From EAS spec
|
// From EAS spec
|
||||||
// Mail Cal
|
// Mail Cal
|
||||||
|
|
|
@ -176,7 +176,7 @@ public class EasSyncService extends InteractiveSyncService {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadAttachment(Attachment att, ISyncManagerCallback cb) {
|
public void loadAttachment(Attachment att, IEmailServiceCallback cb) {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2008-2009 Marc Blank
|
||||||
|
* Licensed to 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.exchange;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Definitions of service status codes returned to IEmailServiceCallback's status method
|
||||||
|
*/
|
||||||
|
public interface EmailServiceStatus {
|
||||||
|
public static final int SUCCESS = 0;
|
||||||
|
public static final int IN_PROGRESS = 1;
|
||||||
|
|
||||||
|
public static final int MESSAGE_NOT_FOUND = 0x10;
|
||||||
|
public static final int ATTACHMENT_NOT_FOUND = 0x11;
|
||||||
|
public static final int FOLDER_NOT_DELETED = 0x12;
|
||||||
|
public static final int FOLDER_NOT_RENAMED = 0x13;
|
||||||
|
public static final int FOLDER_NOT_CREATED = 0x14;
|
||||||
|
|
||||||
|
// Maybe we should automatically retry these?
|
||||||
|
public static final int CONNECTION_ERROR = 0x20;
|
||||||
|
}
|
|
@ -14,28 +14,25 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.exchange;
|
package com.android.exchange;
|
||||||
|
|
||||||
import com.android.exchange.ISyncManagerCallback;
|
import com.android.exchange.IEmailServiceCallback;
|
||||||
import com.android.exchange.EmailContent;
|
import com.android.exchange.EmailContent;
|
||||||
|
|
||||||
interface ISyncManager {
|
interface IEmailService {
|
||||||
int validate(in String protocol, in String host, in String userName, in String password, int port, boolean ssl) ;
|
int validate(in String protocol, in String host, in String userName, in String password,
|
||||||
|
int port, boolean ssl) ;
|
||||||
void registerCallback(ISyncManagerCallback cb);
|
|
||||||
void unregisterCallback(ISyncManagerCallback cb);
|
|
||||||
|
|
||||||
boolean startSync(long mailboxId);
|
boolean startSync(long mailboxId);
|
||||||
boolean stopSync(long mailboxId);
|
boolean stopSync(long mailboxId);
|
||||||
|
|
||||||
boolean updateFolderList(long accountId);
|
boolean loadMore(long messageId, IEmailServiceCallback cb);
|
||||||
|
boolean loadAttachment(long messageId, in EmailContent.Attachment att,
|
||||||
|
IEmailServiceCallback cb);
|
||||||
|
|
||||||
boolean loadMore(long messageId, ISyncManagerCallback cb);
|
boolean updateFolderList(long accountId);
|
||||||
boolean loadAttachment(long messageId, in EmailContent.Attachment att, ISyncManagerCallback cb);
|
|
||||||
|
|
||||||
boolean createFolder(long accountId, String name);
|
boolean createFolder(long accountId, String name);
|
||||||
boolean deleteFolder(long accountId, String name);
|
boolean deleteFolder(long accountId, String name);
|
||||||
boolean renameFolder(long accountId, String oldName, String newName);
|
boolean renameFolder(long accountId, String oldName, String newName);
|
||||||
//AddressLookup - real-time address lookup (EAS)
|
|
||||||
}
|
}
|
|
@ -17,6 +17,6 @@
|
||||||
|
|
||||||
package com.android.exchange;
|
package com.android.exchange;
|
||||||
|
|
||||||
oneway interface ISyncManagerCallback {
|
oneway interface IEmailServiceCallback {
|
||||||
void progress(int value);
|
void status(int statusCode, int progress);
|
||||||
}
|
}
|
|
@ -46,5 +46,5 @@ public abstract class InteractiveSyncService extends AbstractSyncService {
|
||||||
|
|
||||||
public abstract void reloadFolderList();
|
public abstract void reloadFolderList();
|
||||||
|
|
||||||
public abstract void loadAttachment(Attachment att, ISyncManagerCallback cb);
|
public abstract void loadAttachment(Attachment att, IEmailServiceCallback cb);
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,9 +49,9 @@ import android.net.NetworkInfo;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.net.NetworkInfo.State;
|
import android.net.NetworkInfo.State;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Debug;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.os.RemoteCallbackList;
|
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.PowerManager.WakeLock;
|
import android.os.PowerManager.WakeLock;
|
||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
|
@ -94,33 +94,23 @@ public class SyncManager extends Service implements Runnable {
|
||||||
new HashMap<Long, PendingIntent>();
|
new HashMap<Long, PendingIntent>();
|
||||||
static private WakeLock mWakeLock = null;
|
static private WakeLock mWakeLock = null;
|
||||||
|
|
||||||
final RemoteCallbackList<ISyncManagerCallback> mCallbacks =
|
/**
|
||||||
new RemoteCallbackList<ISyncManagerCallback>();
|
* Create the binder for EmailService implementation here. These are the calls that are
|
||||||
|
* defined in AbstractSyncService. Only validate is now implemented; loadAttachment currently
|
||||||
private final ISyncManager.Stub mBinder = new ISyncManager.Stub() {
|
* spins its wheels counting up to 100%.
|
||||||
|
*/
|
||||||
|
private final IEmailService.Stub mBinder = new IEmailService.Stub() {
|
||||||
public int validate(String protocol, String host, String userName, String password,
|
public int validate(String protocol, String host, String userName, String password,
|
||||||
int port, boolean ssl) throws RemoteException {
|
int port, boolean ssl) throws RemoteException {
|
||||||
try {
|
try {
|
||||||
AbstractSyncService.validate(EasSyncService.class, host, userName, password, port, ssl,
|
AbstractSyncService.validate(EasSyncService.class, host, userName, password, port,
|
||||||
SyncManager.this);
|
ssl, SyncManager.this);
|
||||||
return MessagingException.NO_ERROR;
|
return MessagingException.NO_ERROR;
|
||||||
} catch (MessagingException e) {
|
} catch (MessagingException e) {
|
||||||
return e.getExceptionType();
|
return e.getExceptionType();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerCallback(ISyncManagerCallback cb) {
|
|
||||||
if (cb != null) {
|
|
||||||
mCallbacks.register(cb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unregisterCallback(ISyncManagerCallback cb) {
|
|
||||||
if (cb != null) {
|
|
||||||
mCallbacks.unregister(cb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean startSync(long mailboxId) throws RemoteException {
|
public boolean startSync(long mailboxId) throws RemoteException {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
return false;
|
return false;
|
||||||
|
@ -136,7 +126,7 @@ public class SyncManager extends Service implements Runnable {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean loadMore(long messageId, ISyncManagerCallback cb) throws RemoteException {
|
public boolean loadMore(long messageId, IEmailServiceCallback cb) throws RemoteException {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -157,9 +147,17 @@ public class SyncManager extends Service implements Runnable {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean loadAttachment(long messageId, Attachment att, ISyncManagerCallback cb)
|
public boolean loadAttachment(long messageId, Attachment att, IEmailServiceCallback cb)
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
cb.status(EmailServiceStatus.IN_PROGRESS, i * 10);
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
|
cb.status(EmailServiceStatus.SUCCESS, 0);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -237,7 +235,7 @@ public class SyncManager extends Service implements Runnable {
|
||||||
main.mDisplayName = "_main";
|
main.mDisplayName = "_main";
|
||||||
main.mServerId = "_main";
|
main.mServerId = "_main";
|
||||||
main.mAccountKey = acct.mId;
|
main.mAccountKey = acct.mId;
|
||||||
main.mType = Mailbox.TYPE_MAIL;
|
main.mType = Mailbox.TYPE_NOT_EMAIL;
|
||||||
main.mSyncFrequency = Account.CHECK_INTERVAL_PUSH;
|
main.mSyncFrequency = Account.CHECK_INTERVAL_PUSH;
|
||||||
main.mFlagVisible = false;
|
main.mFlagVisible = false;
|
||||||
main.save(getContext());
|
main.save(getContext());
|
||||||
|
|
|
@ -212,6 +212,7 @@ public class EasFolderSyncParser extends EasParser {
|
||||||
m.mDisplayName = name;
|
m.mDisplayName = name;
|
||||||
m.mServerId = serverId;
|
m.mServerId = serverId;
|
||||||
m.mAccountKey = mAccountId;
|
m.mAccountKey = mAccountId;
|
||||||
|
m.mType = Mailbox.TYPE_MAIL;
|
||||||
m.mSyncFrequency = Account.CHECK_INTERVAL_NEVER;
|
m.mSyncFrequency = Account.CHECK_INTERVAL_NEVER;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case INBOX_TYPE:
|
case INBOX_TYPE:
|
||||||
|
|
Loading…
Reference in New Issue