Start of IMAP conversion to Service architecture
* Handle startSync and loadMore * Use SyncManager rather than MailService for periodic sync and upload sync * First of many CL's to disentangle sync from UI * Note that the large majority of this CL is a refactoring of IMAP specific code out of MessagingController and into ImapService; MessagingController will eventually be removed entirely from the app, as will much of Controller Change-Id: I13546d0694479b33cf93c25920dedc1d38227f6c
This commit is contained in:
parent
80535ef38c
commit
c84467afe1
|
@ -395,6 +395,17 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".service.ImapService"
|
||||||
|
android:enabled="true"
|
||||||
|
android:permission="com.android.email.permission.ACCESS_PROVIDER"
|
||||||
|
>
|
||||||
|
<intent-filter>
|
||||||
|
<action
|
||||||
|
android:name="com.android.email.IMAP_INTENT" />
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
|
|
||||||
<!--Required stanza to register the EasAuthenticatorService with AccountManager -->
|
<!--Required stanza to register the EasAuthenticatorService with AccountManager -->
|
||||||
<service
|
<service
|
||||||
android:name=".service.EasAuthenticatorService"
|
android:name=".service.EasAuthenticatorService"
|
||||||
|
|
|
@ -16,12 +16,6 @@
|
||||||
|
|
||||||
package com.android.emailcommon.service;
|
package com.android.emailcommon.service;
|
||||||
|
|
||||||
import com.android.emailcommon.Api;
|
|
||||||
import com.android.emailcommon.Device;
|
|
||||||
import com.android.emailcommon.mail.MessagingException;
|
|
||||||
import com.android.emailcommon.provider.HostAuth;
|
|
||||||
import com.android.emailcommon.provider.Policy;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
@ -29,6 +23,12 @@ import android.os.IBinder;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.emailcommon.Api;
|
||||||
|
import com.android.emailcommon.Device;
|
||||||
|
import com.android.emailcommon.mail.MessagingException;
|
||||||
|
import com.android.emailcommon.provider.HostAuth;
|
||||||
|
import com.android.emailcommon.provider.Policy;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,6 +51,7 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
|
|
||||||
// Private intent that will be used to connect to an independent Exchange service
|
// Private intent that will be used to connect to an independent Exchange service
|
||||||
public static final String EXCHANGE_INTENT = "com.android.email.EXCHANGE_INTENT";
|
public static final String EXCHANGE_INTENT = "com.android.email.EXCHANGE_INTENT";
|
||||||
|
public static final String IMAP_INTENT = "com.android.email.IMAP_INTENT";
|
||||||
|
|
||||||
public static final String AUTO_DISCOVER_BUNDLE_ERROR_CODE = "autodiscover_error_code";
|
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 AUTO_DISCOVER_BUNDLE_HOST_AUTH = "autodiscover_host_auth";
|
||||||
|
@ -64,6 +65,7 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
private final IEmailServiceCallback mCallback;
|
private final IEmailServiceCallback mCallback;
|
||||||
private Object mReturn = null;
|
private Object mReturn = null;
|
||||||
private IEmailService mService;
|
private IEmailService mService;
|
||||||
|
private final boolean isRemote;
|
||||||
|
|
||||||
// Standard debugging
|
// Standard debugging
|
||||||
public static final int DEBUG_BIT = 1;
|
public static final int DEBUG_BIT = 1;
|
||||||
|
@ -82,6 +84,7 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
public EmailServiceProxy(Context _context, Class<?> _class, IEmailServiceCallback _callback) {
|
public EmailServiceProxy(Context _context, Class<?> _class, IEmailServiceCallback _callback) {
|
||||||
super(_context, new Intent(_context, _class));
|
super(_context, new Intent(_context, _class));
|
||||||
mCallback = _callback;
|
mCallback = _callback;
|
||||||
|
isRemote = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following two constructors are used with remote services that must be referenced by
|
// The following two constructors are used with remote services that must be referenced by
|
||||||
|
@ -93,6 +96,7 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
}
|
}
|
||||||
mCallback = _callback;
|
mCallback = _callback;
|
||||||
|
isRemote = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EmailServiceProxy(Context _context, String _action, IEmailServiceCallback _callback) {
|
public EmailServiceProxy(Context _context, String _action, IEmailServiceCallback _callback) {
|
||||||
|
@ -102,6 +106,7 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
}
|
}
|
||||||
mCallback = _callback;
|
mCallback = _callback;
|
||||||
|
isRemote = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -109,6 +114,10 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
mService = IEmailService.Stub.asInterface(binder);
|
mService = IEmailService.Stub.asInterface(binder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isRemote() {
|
||||||
|
return isRemote;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getApiLevel() {
|
public int getApiLevel() {
|
||||||
return Api.LEVEL;
|
return Api.LEVEL;
|
||||||
|
@ -124,9 +133,11 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
* @param background whether or not this request corresponds to a background action (i.e.
|
* @param background whether or not this request corresponds to a background action (i.e.
|
||||||
* prefetch) vs a foreground action (user request)
|
* prefetch) vs a foreground action (user request)
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void loadAttachment(final long attachmentId, final boolean background)
|
public void loadAttachment(final long attachmentId, final boolean background)
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
setTask(new ProxyTask() {
|
setTask(new ProxyTask() {
|
||||||
|
@Override
|
||||||
public void run() throws RemoteException {
|
public void run() throws RemoteException {
|
||||||
try {
|
try {
|
||||||
if (mCallback != null) mService.setCallback(mCallback);
|
if (mCallback != null) mService.setCallback(mCallback);
|
||||||
|
@ -153,8 +164,10 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
* @param mailboxId the id of the mailbox record
|
* @param mailboxId the id of the mailbox record
|
||||||
* @param userRequest whether or not the user specifically asked for the sync
|
* @param userRequest whether or not the user specifically asked for the sync
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void startSync(final long mailboxId, final boolean userRequest) throws RemoteException {
|
public void startSync(final long mailboxId, final boolean userRequest) throws RemoteException {
|
||||||
setTask(new ProxyTask() {
|
setTask(new ProxyTask() {
|
||||||
|
@Override
|
||||||
public void run() throws RemoteException {
|
public void run() throws RemoteException {
|
||||||
if (mCallback != null) mService.setCallback(mCallback);
|
if (mCallback != null) mService.setCallback(mCallback);
|
||||||
mService.startSync(mailboxId, userRequest);
|
mService.startSync(mailboxId, userRequest);
|
||||||
|
@ -170,8 +183,10 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
* @param mailboxId the id of the mailbox record
|
* @param mailboxId the id of the mailbox record
|
||||||
* @param userRequest whether or not the user specifically asked for the sync
|
* @param userRequest whether or not the user specifically asked for the sync
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void stopSync(final long mailboxId) throws RemoteException {
|
public void stopSync(final long mailboxId) throws RemoteException {
|
||||||
setTask(new ProxyTask() {
|
setTask(new ProxyTask() {
|
||||||
|
@Override
|
||||||
public void run() throws RemoteException {
|
public void run() throws RemoteException {
|
||||||
if (mCallback != null) mService.setCallback(mCallback);
|
if (mCallback != null) mService.setCallback(mCallback);
|
||||||
mService.stopSync(mailboxId);
|
mService.stopSync(mailboxId);
|
||||||
|
@ -189,8 +204,10 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
* @param hostAuth the hostauth object to validate
|
* @param hostAuth the hostauth object to validate
|
||||||
* @return a Bundle as described above
|
* @return a Bundle as described above
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public Bundle validate(final HostAuth hostAuth) throws RemoteException {
|
public Bundle validate(final HostAuth hostAuth) throws RemoteException {
|
||||||
setTask(new ProxyTask() {
|
setTask(new ProxyTask() {
|
||||||
|
@Override
|
||||||
public void run() throws RemoteException{
|
public void run() throws RemoteException{
|
||||||
if (mCallback != null) mService.setCallback(mCallback);
|
if (mCallback != null) mService.setCallback(mCallback);
|
||||||
mReturn = mService.validate(hostAuth);
|
mReturn = mService.validate(hostAuth);
|
||||||
|
@ -219,9 +236,11 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
* @param password the user's password
|
* @param password the user's password
|
||||||
* @return a Bundle as described above
|
* @return a Bundle as described above
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public Bundle autoDiscover(final String userName, final String password)
|
public Bundle autoDiscover(final String userName, final String password)
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
setTask(new ProxyTask() {
|
setTask(new ProxyTask() {
|
||||||
|
@Override
|
||||||
public void run() throws RemoteException{
|
public void run() throws RemoteException{
|
||||||
if (mCallback != null) mService.setCallback(mCallback);
|
if (mCallback != null) mService.setCallback(mCallback);
|
||||||
mReturn = mService.autoDiscover(userName, password);
|
mReturn = mService.autoDiscover(userName, password);
|
||||||
|
@ -244,8 +263,10 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
*
|
*
|
||||||
* @param accoundId the id of the account whose folder list is to be updated
|
* @param accoundId the id of the account whose folder list is to be updated
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void updateFolderList(final long accountId) throws RemoteException {
|
public void updateFolderList(final long accountId) throws RemoteException {
|
||||||
setTask(new ProxyTask() {
|
setTask(new ProxyTask() {
|
||||||
|
@Override
|
||||||
public void run() throws RemoteException {
|
public void run() throws RemoteException {
|
||||||
if (mCallback != null) mService.setCallback(mCallback);
|
if (mCallback != null) mService.setCallback(mCallback);
|
||||||
mService.updateFolderList(accountId);
|
mService.updateFolderList(accountId);
|
||||||
|
@ -259,8 +280,10 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
*
|
*
|
||||||
* @param flags an integer whose bits represent logging flags as defined in DEBUG_* flags above
|
* @param flags an integer whose bits represent logging flags as defined in DEBUG_* flags above
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void setLogging(final int flags) throws RemoteException {
|
public void setLogging(final int flags) throws RemoteException {
|
||||||
setTask(new ProxyTask() {
|
setTask(new ProxyTask() {
|
||||||
|
@Override
|
||||||
public void run() throws RemoteException {
|
public void run() throws RemoteException {
|
||||||
if (mCallback != null) mService.setCallback(mCallback);
|
if (mCallback != null) mService.setCallback(mCallback);
|
||||||
mService.setLogging(flags);
|
mService.setLogging(flags);
|
||||||
|
@ -274,8 +297,10 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
*
|
*
|
||||||
* @param cb a callback object through which all service callbacks are executed
|
* @param cb a callback object through which all service callbacks are executed
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void setCallback(final IEmailServiceCallback cb) throws RemoteException {
|
public void setCallback(final IEmailServiceCallback cb) throws RemoteException {
|
||||||
setTask(new ProxyTask() {
|
setTask(new ProxyTask() {
|
||||||
|
@Override
|
||||||
public void run() throws RemoteException {
|
public void run() throws RemoteException {
|
||||||
mService.setCallback(cb);
|
mService.setCallback(cb);
|
||||||
}
|
}
|
||||||
|
@ -289,8 +314,10 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
*
|
*
|
||||||
* @param accountId the id of the account whose host information has changed
|
* @param accountId the id of the account whose host information has changed
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void hostChanged(final long accountId) throws RemoteException {
|
public void hostChanged(final long accountId) throws RemoteException {
|
||||||
setTask(new ProxyTask() {
|
setTask(new ProxyTask() {
|
||||||
|
@Override
|
||||||
public void run() throws RemoteException {
|
public void run() throws RemoteException {
|
||||||
mService.hostChanged(accountId);
|
mService.hostChanged(accountId);
|
||||||
}
|
}
|
||||||
|
@ -303,9 +330,11 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
* @param messageId the id of the message containing the meeting request
|
* @param messageId the id of the message containing the meeting request
|
||||||
* @param response the response code, as defined in EmailServiceConstants
|
* @param response the response code, as defined in EmailServiceConstants
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void sendMeetingResponse(final long messageId, final int response)
|
public void sendMeetingResponse(final long messageId, final int response)
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
setTask(new ProxyTask() {
|
setTask(new ProxyTask() {
|
||||||
|
@Override
|
||||||
public void run() throws RemoteException {
|
public void run() throws RemoteException {
|
||||||
if (mCallback != null) mService.setCallback(mCallback);
|
if (mCallback != null) mService.setCallback(mCallback);
|
||||||
mService.sendMeetingResponse(messageId, response);
|
mService.sendMeetingResponse(messageId, response);
|
||||||
|
@ -314,11 +343,19 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Not yet used; intended to request the sync adapter to load a complete message
|
* Request the sync adapter to load a complete message
|
||||||
*
|
*
|
||||||
* @param messageId the id of the message to be loaded
|
* @param messageId the id of the message to be loaded
|
||||||
*/
|
*/
|
||||||
public void loadMore(long messageId) throws RemoteException {
|
@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");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -327,6 +364,7 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
* @param accountId the account in which the folder is to be created
|
* @param accountId the account in which the folder is to be created
|
||||||
* @param name the name of the folder to be created
|
* @param name the name of the folder to be created
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public boolean createFolder(long accountId, String name) throws RemoteException {
|
public boolean createFolder(long accountId, String name) throws RemoteException {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -337,6 +375,7 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
* @param accountId the account in which the folder resides
|
* @param accountId the account in which the folder resides
|
||||||
* @param name the name of the folder to be deleted
|
* @param name the name of the folder to be deleted
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public boolean deleteFolder(long accountId, String name) throws RemoteException {
|
public boolean deleteFolder(long accountId, String name) throws RemoteException {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -348,6 +387,7 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
* @param oldName the name of the existing folder
|
* @param oldName the name of the existing folder
|
||||||
* @param newName the new name for the folder
|
* @param newName the new name for the folder
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public boolean renameFolder(long accountId, String oldName, String newName)
|
public boolean renameFolder(long accountId, String oldName, String newName)
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
return false;
|
return false;
|
||||||
|
@ -361,8 +401,10 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
*
|
*
|
||||||
* @param accountId the account whose data is to be deleted
|
* @param accountId the account whose data is to be deleted
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void deleteAccountPIMData(final long accountId) throws RemoteException {
|
public void deleteAccountPIMData(final long accountId) throws RemoteException {
|
||||||
setTask(new ProxyTask() {
|
setTask(new ProxyTask() {
|
||||||
|
@Override
|
||||||
public void run() throws RemoteException {
|
public void run() throws RemoteException {
|
||||||
mService.deleteAccountPIMData(accountId);
|
mService.deleteAccountPIMData(accountId);
|
||||||
}
|
}
|
||||||
|
@ -385,9 +427,11 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
* @param destMailboxId the id of the mailbox into which search results are appended
|
* @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)
|
* @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,
|
public int searchMessages(final long accountId, final SearchParams searchParams,
|
||||||
final long destMailboxId) throws RemoteException {
|
final long destMailboxId) throws RemoteException {
|
||||||
setTask(new ProxyTask() {
|
setTask(new ProxyTask() {
|
||||||
|
@Override
|
||||||
public void run() throws RemoteException{
|
public void run() throws RemoteException{
|
||||||
if (mCallback != null) mService.setCallback(mCallback);
|
if (mCallback != null) mService.setCallback(mCallback);
|
||||||
mReturn = mService.searchMessages(accountId, searchParams, destMailboxId);
|
mReturn = mService.searchMessages(accountId, searchParams, destMailboxId);
|
||||||
|
@ -400,6 +444,7 @@ public class EmailServiceProxy extends ServiceProxy implements IEmailService {
|
||||||
return (Integer)mReturn;
|
return (Integer)mReturn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
public IBinder asBinder() {
|
public IBinder asBinder() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,4 +65,12 @@ oneway interface IEmailServiceCallback {
|
||||||
* progress = 0 for "start", 1..100 for optional progress reports
|
* progress = 0 for "start", 1..100 for optional progress reports
|
||||||
*/
|
*/
|
||||||
void sendMessageStatus(long messageId, String subject, int statusCode, int progress);
|
void sendMessageStatus(long messageId, String subject, int statusCode, int progress);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback to indicate that a particular message is being loaded
|
||||||
|
* messageId = the message being sent
|
||||||
|
* statusCode = 0 for OK, 1 for progress, other codes for error
|
||||||
|
* progress = 0 for "start", 1..100 for optional progress reports
|
||||||
|
*/
|
||||||
|
void loadMessageStatus(long messageId, int statusCode, int progress);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,5 +23,6 @@
|
||||||
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
|
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:contentAuthority="com.android.email.provider"
|
android:contentAuthority="com.android.email.provider"
|
||||||
android:accountType="com.android.email"
|
android:accountType="com.android.email"
|
||||||
android:supportsUploading="false"
|
android:supportsUploading="true"
|
||||||
|
android:allowParallelSyncs="true"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -48,6 +48,7 @@ import com.android.emailcommon.provider.EmailContent.Message;
|
||||||
import com.android.emailcommon.provider.EmailContent.MessageColumns;
|
import com.android.emailcommon.provider.EmailContent.MessageColumns;
|
||||||
import com.android.emailcommon.provider.HostAuth;
|
import com.android.emailcommon.provider.HostAuth;
|
||||||
import com.android.emailcommon.provider.Mailbox;
|
import com.android.emailcommon.provider.Mailbox;
|
||||||
|
import com.android.emailcommon.service.EmailServiceProxy;
|
||||||
import com.android.emailcommon.service.EmailServiceStatus;
|
import com.android.emailcommon.service.EmailServiceStatus;
|
||||||
import com.android.emailcommon.service.IEmailService;
|
import com.android.emailcommon.service.IEmailService;
|
||||||
import com.android.emailcommon.service.IEmailServiceCallback;
|
import com.android.emailcommon.service.IEmailServiceCallback;
|
||||||
|
@ -339,6 +340,7 @@ public class Controller {
|
||||||
/**
|
/**
|
||||||
* Request a remote update of mailboxes for an account.
|
* Request a remote update of mailboxes for an account.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public void updateMailboxList(final long accountId) {
|
public void updateMailboxList(final long accountId) {
|
||||||
Utility.runAsync(new Runnable() {
|
Utility.runAsync(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -367,23 +369,15 @@ public class Controller {
|
||||||
* Functionally this is quite similar to updateMailbox(), but it's a separate API and
|
* Functionally this is quite similar to updateMailbox(), but it's a separate API and
|
||||||
* separate callback in order to keep UI callbacks from affecting the service loop.
|
* separate callback in order to keep UI callbacks from affecting the service loop.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public void serviceCheckMail(final long accountId, final long mailboxId, final long tag) {
|
public void serviceCheckMail(final long accountId, final long mailboxId, final long tag) {
|
||||||
IEmailService service = getServiceForAccount(accountId);
|
IEmailService service = getServiceForAccount(accountId);
|
||||||
if (service != null) {
|
if (service != null) {
|
||||||
// Service implementation
|
|
||||||
// try {
|
|
||||||
// TODO this isn't quite going to work, because we're going to get the
|
|
||||||
// generic (UI) callbacks and not the ones we need to restart the ol' service.
|
|
||||||
// service.startSync(mailboxId, tag);
|
|
||||||
mLegacyListener.checkMailFinished(mContext, accountId, mailboxId, tag);
|
mLegacyListener.checkMailFinished(mContext, accountId, mailboxId, tag);
|
||||||
// } catch (RemoteException e) {
|
|
||||||
// TODO Change exception handling to be consistent with however this method
|
|
||||||
// is implemented for other protocols
|
|
||||||
// Log.d("updateMailbox", "RemoteException" + e);
|
|
||||||
// }
|
|
||||||
} else {
|
} else {
|
||||||
// MessagingController implementation
|
// MessagingController implementation
|
||||||
Utility.runAsync(new Runnable() {
|
Utility.runAsync(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
mLegacyController.checkMail(accountId, tag, mLegacyListener);
|
mLegacyController.checkMail(accountId, tag, mLegacyListener);
|
||||||
}
|
}
|
||||||
|
@ -398,6 +392,7 @@ public class Controller {
|
||||||
* a simple message list. We should also at this point queue up a background task of
|
* a simple message list. We should also at this point queue up a background task of
|
||||||
* downloading some/all of the messages in this mailbox, but that should be interruptable.
|
* downloading some/all of the messages in this mailbox, but that should be interruptable.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public void updateMailbox(final long accountId, final long mailboxId, boolean userRequest) {
|
public void updateMailbox(final long accountId, final long mailboxId, boolean userRequest) {
|
||||||
|
|
||||||
IEmailService service = getServiceForAccount(accountId);
|
IEmailService service = getServiceForAccount(accountId);
|
||||||
|
@ -412,6 +407,7 @@ public class Controller {
|
||||||
} else {
|
} else {
|
||||||
// MessagingController implementation
|
// MessagingController implementation
|
||||||
Utility.runAsync(new Runnable() {
|
Utility.runAsync(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
// TODO shouldn't be passing fully-build accounts & mailboxes into APIs
|
// TODO shouldn't be passing fully-build accounts & mailboxes into APIs
|
||||||
Account account =
|
Account account =
|
||||||
|
@ -438,11 +434,13 @@ public class Controller {
|
||||||
* @param messageId the message to load
|
* @param messageId the message to load
|
||||||
* @param callback the Controller callback by which results will be reported
|
* @param callback the Controller callback by which results will be reported
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public void loadMessageForView(final long messageId) {
|
public void loadMessageForView(final long messageId) {
|
||||||
|
|
||||||
// Split here for target type (Service or MessagingController)
|
// Split here for target type (Service or MessagingController)
|
||||||
IEmailService service = getServiceForMessage(messageId);
|
EmailServiceProxy service = getServiceForMessage(messageId);
|
||||||
if (service != null) {
|
if (service != null && service.isRemote()) {
|
||||||
|
// Get rid of this!!
|
||||||
// There is no service implementation, so we'll just jam the value, log the error,
|
// There is no service implementation, so we'll just jam the value, log the error,
|
||||||
// and get out of here.
|
// and get out of here.
|
||||||
Uri uri = ContentUris.withAppendedId(Message.CONTENT_URI, messageId);
|
Uri uri = ContentUris.withAppendedId(Message.CONTENT_URI, messageId);
|
||||||
|
@ -456,9 +454,16 @@ public class Controller {
|
||||||
listener.loadMessageForViewCallback(null, accountId, messageId, 100);
|
listener.loadMessageForViewCallback(null, accountId, messageId, 100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (service != null) {
|
||||||
|
// IMAP here for now
|
||||||
|
try {
|
||||||
|
service.loadMore(messageId);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// MessagingController implementation
|
// MessagingController implementation
|
||||||
Utility.runAsync(new Runnable() {
|
Utility.runAsync(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
mLegacyController.loadMessageForView(messageId, mLegacyListener);
|
mLegacyController.loadMessageForView(messageId, mLegacyListener);
|
||||||
}
|
}
|
||||||
|
@ -593,6 +598,7 @@ public class Controller {
|
||||||
sendPendingMessages(accountId);
|
sendPendingMessages(accountId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
private void sendPendingMessagesSmtp(long accountId) {
|
private void sendPendingMessagesSmtp(long accountId) {
|
||||||
// for IMAP & POP only, (attempt to) send the message now
|
// for IMAP & POP only, (attempt to) send the message now
|
||||||
final Account account =
|
final Account account =
|
||||||
|
@ -602,6 +608,7 @@ public class Controller {
|
||||||
}
|
}
|
||||||
final long sentboxId = findOrCreateMailboxOfType(accountId, Mailbox.TYPE_SENT);
|
final long sentboxId = findOrCreateMailboxOfType(accountId, Mailbox.TYPE_SENT);
|
||||||
Utility.runAsync(new Runnable() {
|
Utility.runAsync(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
mLegacyController.sendPendingMessages(account, sentboxId, mLegacyListener);
|
mLegacyController.sendPendingMessages(account, sentboxId, mLegacyListener);
|
||||||
}
|
}
|
||||||
|
@ -644,8 +651,10 @@ public class Controller {
|
||||||
* look up limit
|
* look up limit
|
||||||
* write limit into all mailboxes for that account
|
* write limit into all mailboxes for that account
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public void resetVisibleLimits() {
|
public void resetVisibleLimits() {
|
||||||
Utility.runAsync(new Runnable() {
|
Utility.runAsync(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
ContentResolver resolver = mProviderContext.getContentResolver();
|
ContentResolver resolver = mProviderContext.getContentResolver();
|
||||||
Cursor c = null;
|
Cursor c = null;
|
||||||
|
@ -682,6 +691,7 @@ public class Controller {
|
||||||
*/
|
*/
|
||||||
public void loadMoreMessages(final long mailboxId) {
|
public void loadMoreMessages(final long mailboxId) {
|
||||||
EmailAsyncTask.runAsyncParallel(new Runnable() {
|
EmailAsyncTask.runAsyncParallel(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Mailbox mailbox = Mailbox.restoreMailboxWithId(mProviderContext, mailboxId);
|
Mailbox mailbox = Mailbox.restoreMailboxWithId(mProviderContext, mailboxId);
|
||||||
if (mailbox == null) {
|
if (mailbox == null) {
|
||||||
|
@ -746,6 +756,7 @@ public class Controller {
|
||||||
*/
|
*/
|
||||||
public void deleteMessage(final long messageId) {
|
public void deleteMessage(final long messageId) {
|
||||||
EmailAsyncTask.runAsyncParallel(new Runnable() {
|
EmailAsyncTask.runAsyncParallel(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
deleteMessageSync(messageId);
|
deleteMessageSync(messageId);
|
||||||
}
|
}
|
||||||
|
@ -760,6 +771,7 @@ public class Controller {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
EmailAsyncTask.runAsyncParallel(new Runnable() {
|
EmailAsyncTask.runAsyncParallel(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
for (long messageId: messageIds) {
|
for (long messageId: messageIds) {
|
||||||
deleteMessageSync(messageId);
|
deleteMessageSync(messageId);
|
||||||
|
@ -809,10 +821,6 @@ public class Controller {
|
||||||
cv.put(EmailContent.MessageColumns.MAILBOX_KEY, trashMailboxId);
|
cv.put(EmailContent.MessageColumns.MAILBOX_KEY, trashMailboxId);
|
||||||
resolver.update(uri, cv, null, null);
|
resolver.update(uri, cv, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isMessagingController(account)) {
|
|
||||||
mLegacyController.processPendingActions(account.mId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -834,6 +842,7 @@ public class Controller {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
return EmailAsyncTask.runAsyncParallel(new Runnable() {
|
return EmailAsyncTask.runAsyncParallel(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Account account = Account.getAccountForMessageId(mProviderContext, messageIds[0]);
|
Account account = Account.getAccountForMessageId(mProviderContext, messageIds[0]);
|
||||||
if (account != null) {
|
if (account != null) {
|
||||||
|
@ -845,9 +854,6 @@ public class Controller {
|
||||||
EmailContent.Message.SYNCED_CONTENT_URI, messageId);
|
EmailContent.Message.SYNCED_CONTENT_URI, messageId);
|
||||||
resolver.update(uri, cv, null, null);
|
resolver.update(uri, cv, null, null);
|
||||||
}
|
}
|
||||||
if (isMessagingController(account)) {
|
|
||||||
mLegacyController.processPendingActions(account.mId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -888,13 +894,6 @@ public class Controller {
|
||||||
private void updateMessageSync(long messageId, ContentValues cv) {
|
private void updateMessageSync(long messageId, ContentValues cv) {
|
||||||
Uri uri = ContentUris.withAppendedId(EmailContent.Message.SYNCED_CONTENT_URI, messageId);
|
Uri uri = ContentUris.withAppendedId(EmailContent.Message.SYNCED_CONTENT_URI, messageId);
|
||||||
mProviderContext.getContentResolver().update(uri, cv, null, null);
|
mProviderContext.getContentResolver().update(uri, cv, null, null);
|
||||||
|
|
||||||
// Service runs automatically, MessagingController needs a kick
|
|
||||||
long accountId = Account.getAccountIdForMessageId(mProviderContext, messageId);
|
|
||||||
if (accountId == Account.NO_ACCOUNT) return;
|
|
||||||
if (isMessagingController(accountId)) {
|
|
||||||
mLegacyController.processPendingActions(accountId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -906,6 +905,7 @@ public class Controller {
|
||||||
public void setMessageAnsweredOrForwarded(final long messageId,
|
public void setMessageAnsweredOrForwarded(final long messageId,
|
||||||
final int flag) {
|
final int flag) {
|
||||||
EmailAsyncTask.runAsyncParallel(new Runnable() {
|
EmailAsyncTask.runAsyncParallel(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Message msg = Message.restoreMessageWithId(mProviderContext, messageId);
|
Message msg = Message.restoreMessageWithId(mProviderContext, messageId);
|
||||||
if (msg == null) {
|
if (msg == null) {
|
||||||
|
@ -1019,7 +1019,9 @@ public class Controller {
|
||||||
if (Email.DEBUG) {
|
if (Email.DEBUG) {
|
||||||
Log.d(Logging.LOG_TAG, "Search: " + searchParams.mFilter);
|
Log.d(Logging.LOG_TAG, "Search: " + searchParams.mFilter);
|
||||||
}
|
}
|
||||||
return mLegacyController.searchMailbox(accountId, searchParams, searchMailboxId);
|
// Plumb this
|
||||||
|
return 0;
|
||||||
|
//return mLegacyController.searchMailbox(accountId, searchParams, searchMailboxId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1085,7 +1087,7 @@ public class Controller {
|
||||||
* @param messageId the message of interest
|
* @param messageId the message of interest
|
||||||
* @result service proxy, or null if n/a
|
* @result service proxy, or null if n/a
|
||||||
*/
|
*/
|
||||||
private IEmailService getServiceForMessage(long messageId) {
|
private EmailServiceProxy getServiceForMessage(long messageId) {
|
||||||
// TODO make this more efficient, caching the account, smaller lookup here, etc.
|
// TODO make this more efficient, caching the account, smaller lookup here, etc.
|
||||||
Message message = Message.restoreMessageWithId(mProviderContext, messageId);
|
Message message = Message.restoreMessageWithId(mProviderContext, messageId);
|
||||||
if (message == null) {
|
if (message == null) {
|
||||||
|
@ -1100,15 +1102,22 @@ public class Controller {
|
||||||
* @param accountId the message of interest
|
* @param accountId the message of interest
|
||||||
* @result service proxy, or null if n/a
|
* @result service proxy, or null if n/a
|
||||||
*/
|
*/
|
||||||
private IEmailService getServiceForAccount(long accountId) {
|
private EmailServiceProxy getServiceForAccount(long accountId) {
|
||||||
if (isMessagingController(accountId)) return null;
|
if (isMessagingController(accountId)) return null;
|
||||||
|
if (Account.getProtocol(mContext, accountId).equals(HostAuth.SCHEME_IMAP)) {
|
||||||
|
return getImapEmailService();
|
||||||
|
}
|
||||||
return getExchangeEmailService();
|
return getExchangeEmailService();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEmailService getExchangeEmailService() {
|
private EmailServiceProxy getExchangeEmailService() {
|
||||||
return EmailServiceUtils.getExchangeService(mContext, mServiceCallback);
|
return EmailServiceUtils.getExchangeService(mContext, mServiceCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private EmailServiceProxy getImapEmailService() {
|
||||||
|
return EmailServiceUtils.getImapService(mContext, mServiceCallback);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple helper to determine if legacy MessagingController should be used
|
* Simple helper to determine if legacy MessagingController should be used
|
||||||
*/
|
*/
|
||||||
|
@ -1121,7 +1130,7 @@ public class Controller {
|
||||||
Boolean isLegacyController = mLegacyControllerMap.get(accountId);
|
Boolean isLegacyController = mLegacyControllerMap.get(accountId);
|
||||||
if (isLegacyController == null) {
|
if (isLegacyController == null) {
|
||||||
String protocol = Account.getProtocol(mProviderContext, accountId);
|
String protocol = Account.getProtocol(mProviderContext, accountId);
|
||||||
isLegacyController = ("pop3".equals(protocol) || "imap".equals(protocol));
|
isLegacyController = (HostAuth.SCHEME_POP3.equals(protocol));
|
||||||
mLegacyControllerMap.put(accountId, isLegacyController);
|
mLegacyControllerMap.put(accountId, isLegacyController);
|
||||||
}
|
}
|
||||||
return isLegacyController;
|
return isLegacyController;
|
||||||
|
@ -1581,8 +1590,7 @@ public class Controller {
|
||||||
*/
|
*/
|
||||||
private class ServiceCallback extends IEmailServiceCallback.Stub {
|
private class ServiceCallback extends IEmailServiceCallback.Stub {
|
||||||
|
|
||||||
private final static boolean DEBUG_FAIL_DOWNLOADS = false; // do not check in "true"
|
@Override
|
||||||
|
|
||||||
public void loadAttachmentStatus(long messageId, long attachmentId, int statusCode,
|
public void loadAttachmentStatus(long messageId, long attachmentId, int statusCode,
|
||||||
int progress) {
|
int progress) {
|
||||||
MessagingException result = mapStatusToException(statusCode);
|
MessagingException result = mapStatusToException(statusCode);
|
||||||
|
@ -1591,10 +1599,6 @@ public class Controller {
|
||||||
progress = 100;
|
progress = 100;
|
||||||
break;
|
break;
|
||||||
case EmailServiceStatus.IN_PROGRESS:
|
case EmailServiceStatus.IN_PROGRESS:
|
||||||
if (DEBUG_FAIL_DOWNLOADS && progress > 75) {
|
|
||||||
result = new MessagingException(
|
|
||||||
String.valueOf(EmailServiceStatus.CONNECTION_ERROR));
|
|
||||||
}
|
|
||||||
// discard progress reports that look like sentinels
|
// discard progress reports that look like sentinels
|
||||||
if (progress < 0 || progress >= 100) {
|
if (progress < 0 || progress >= 100) {
|
||||||
return;
|
return;
|
||||||
|
@ -1616,6 +1620,7 @@ public class Controller {
|
||||||
* However, this is sufficient for basic "progress=100" notification that message send
|
* However, this is sufficient for basic "progress=100" notification that message send
|
||||||
* has just completed.
|
* has just completed.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void sendMessageStatus(long messageId, String subject, int statusCode,
|
public void sendMessageStatus(long messageId, String subject, int statusCode,
|
||||||
int progress) {
|
int progress) {
|
||||||
long accountId = -1; // This should be in the callback
|
long accountId = -1; // This should be in the callback
|
||||||
|
@ -1638,6 +1643,35 @@ public class Controller {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note, this is an incomplete implementation of this callback, because we are
|
||||||
|
* not getting things back from Service in quite the same way as from MessagingController.
|
||||||
|
* However, this is sufficient for basic "progress=100" notification that message send
|
||||||
|
* has just completed.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void loadMessageStatus(long messageId, int statusCode, int progress) {
|
||||||
|
long accountId = -1; // This should be in the callback
|
||||||
|
MessagingException result = mapStatusToException(statusCode);
|
||||||
|
switch (statusCode) {
|
||||||
|
case EmailServiceStatus.SUCCESS:
|
||||||
|
progress = 100;
|
||||||
|
break;
|
||||||
|
case EmailServiceStatus.IN_PROGRESS:
|
||||||
|
// discard progress reports that look like sentinels
|
||||||
|
if (progress < 0 || progress >= 100) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
synchronized(mListeners) {
|
||||||
|
for (Result listener : mListeners) {
|
||||||
|
listener.loadMessageForViewCallback(result, accountId, messageId, progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void syncMailboxListStatus(long accountId, int statusCode, int progress) {
|
public void syncMailboxListStatus(long accountId, int statusCode, int progress) {
|
||||||
MessagingException result = mapStatusToException(statusCode);
|
MessagingException result = mapStatusToException(statusCode);
|
||||||
switch (statusCode) {
|
switch (statusCode) {
|
||||||
|
@ -1658,6 +1692,7 @@ public class Controller {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void syncMailboxStatus(long mailboxId, int statusCode, int progress) {
|
public void syncMailboxStatus(long mailboxId, int statusCode, int progress) {
|
||||||
MessagingException result = mapStatusToException(statusCode);
|
MessagingException result = mapStatusToException(statusCode);
|
||||||
switch (statusCode) {
|
switch (statusCode) {
|
||||||
|
@ -1752,6 +1787,7 @@ public class Controller {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void loadAttachmentStatus(final long messageId, final long attachmentId,
|
public void loadAttachmentStatus(final long messageId, final long attachmentId,
|
||||||
final int status, final int progress) {
|
final int status, final int progress) {
|
||||||
broadcastCallback(new ServiceCallbackWrapper() {
|
broadcastCallback(new ServiceCallbackWrapper() {
|
||||||
|
@ -1766,6 +1802,10 @@ public class Controller {
|
||||||
public void sendMessageStatus(long messageId, String subject, int statusCode, int progress){
|
public void sendMessageStatus(long messageId, String subject, int statusCode, int progress){
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadMessageStatus(long messageId, int statusCode, int progress){
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void syncMailboxListStatus(long accountId, int statusCode, int progress) {
|
public void syncMailboxListStatus(long accountId, int statusCode, int progress) {
|
||||||
}
|
}
|
||||||
|
@ -1782,20 +1822,25 @@ public class Controller {
|
||||||
*/
|
*/
|
||||||
private final IEmailService.Stub mBinder = new IEmailService.Stub() {
|
private final IEmailService.Stub mBinder = new IEmailService.Stub() {
|
||||||
|
|
||||||
|
@Override
|
||||||
public Bundle validate(HostAuth hostAuth) {
|
public Bundle validate(HostAuth hostAuth) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Bundle autoDiscover(String userName, String password) {
|
public Bundle autoDiscover(String userName, String password) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void startSync(long mailboxId, boolean userRequest) {
|
public void startSync(long mailboxId, boolean userRequest) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void stopSync(long mailboxId) {
|
public void stopSync(long mailboxId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void loadAttachment(long attachmentId, boolean background)
|
public void loadAttachment(long attachmentId, boolean background)
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
Attachment att = Attachment.restoreAttachmentWithId(ControllerService.this,
|
Attachment att = Attachment.restoreAttachmentWithId(ControllerService.this,
|
||||||
|
@ -1835,41 +1880,52 @@ public class Controller {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void updateFolderList(long accountId) {
|
public void updateFolderList(long accountId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void hostChanged(long accountId) {
|
public void hostChanged(long accountId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setLogging(int flags) {
|
public void setLogging(int flags) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void sendMeetingResponse(long messageId, int response) {
|
public void sendMeetingResponse(long messageId, int response) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void loadMore(long messageId) {
|
public void loadMore(long messageId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following three methods are not implemented in this version
|
// The following three methods are not implemented in this version
|
||||||
|
@Override
|
||||||
public boolean createFolder(long accountId, String name) {
|
public boolean createFolder(long accountId, String name) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean deleteFolder(long accountId, String name) {
|
public boolean deleteFolder(long accountId, String name) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean renameFolder(long accountId, String oldName, String newName) {
|
public boolean renameFolder(long accountId, String oldName, String newName) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setCallback(IEmailServiceCallback cb) {
|
public void setCallback(IEmailServiceCallback cb) {
|
||||||
sCallbackList.register(cb);
|
sCallbackList.register(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void deleteAccountPIMData(long accountId) {
|
public void deleteAccountPIMData(long accountId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int searchMessages(long accountId, SearchParams searchParams,
|
public int searchMessages(long accountId, SearchParams searchParams,
|
||||||
long destMailboxId) {
|
long destMailboxId) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -41,7 +41,6 @@ import com.android.emailcommon.mail.Flag;
|
||||||
import com.android.emailcommon.mail.Folder;
|
import com.android.emailcommon.mail.Folder;
|
||||||
import com.android.emailcommon.mail.Folder.FolderType;
|
import com.android.emailcommon.mail.Folder.FolderType;
|
||||||
import com.android.emailcommon.mail.Folder.MessageRetrievalListener;
|
import com.android.emailcommon.mail.Folder.MessageRetrievalListener;
|
||||||
import com.android.emailcommon.mail.Folder.MessageUpdateCallbacks;
|
|
||||||
import com.android.emailcommon.mail.Folder.OpenMode;
|
import com.android.emailcommon.mail.Folder.OpenMode;
|
||||||
import com.android.emailcommon.mail.Message;
|
import com.android.emailcommon.mail.Message;
|
||||||
import com.android.emailcommon.mail.MessagingException;
|
import com.android.emailcommon.mail.MessagingException;
|
||||||
|
@ -54,15 +53,12 @@ import com.android.emailcommon.provider.EmailContent.MailboxColumns;
|
||||||
import com.android.emailcommon.provider.EmailContent.MessageColumns;
|
import com.android.emailcommon.provider.EmailContent.MessageColumns;
|
||||||
import com.android.emailcommon.provider.EmailContent.SyncColumns;
|
import com.android.emailcommon.provider.EmailContent.SyncColumns;
|
||||||
import com.android.emailcommon.provider.Mailbox;
|
import com.android.emailcommon.provider.Mailbox;
|
||||||
import com.android.emailcommon.service.SearchParams;
|
|
||||||
import com.android.emailcommon.utility.AttachmentUtilities;
|
import com.android.emailcommon.utility.AttachmentUtilities;
|
||||||
import com.android.emailcommon.utility.ConversionUtilities;
|
import com.android.emailcommon.utility.ConversionUtilities;
|
||||||
import com.android.emailcommon.utility.Utility;
|
import com.android.emailcommon.utility.Utility;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -103,23 +99,11 @@ public class MessagingController implements Runnable {
|
||||||
*/
|
*/
|
||||||
private static final int MAX_SMALL_MESSAGE_SIZE = (25 * 1024);
|
private static final int MAX_SMALL_MESSAGE_SIZE = (25 * 1024);
|
||||||
|
|
||||||
private static final Flag[] FLAG_LIST_SEEN = new Flag[] { Flag.SEEN };
|
|
||||||
private static final Flag[] FLAG_LIST_FLAGGED = new Flag[] { Flag.FLAGGED };
|
|
||||||
private static final Flag[] FLAG_LIST_ANSWERED = new Flag[] { Flag.ANSWERED };
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We write this into the serverId field of messages that will never be upsynced.
|
* We write this into the serverId field of messages that will never be upsynced.
|
||||||
*/
|
*/
|
||||||
private static final String LOCAL_SERVERID_PREFIX = "Local-";
|
private static final String LOCAL_SERVERID_PREFIX = "Local-";
|
||||||
|
|
||||||
/**
|
|
||||||
* Cache search results by account; this allows for "load more" support without having to
|
|
||||||
* redo the search (which can be quite slow). SortableMessage is a smallish class, so memory
|
|
||||||
* shouldn't be an issue
|
|
||||||
*/
|
|
||||||
private static final HashMap<Long, SortableMessage[]> sSearchResults =
|
|
||||||
new HashMap<Long, SortableMessage[]>();
|
|
||||||
|
|
||||||
private static final ContentValues PRUNE_ATTACHMENT_CV = new ContentValues();
|
private static final ContentValues PRUNE_ATTACHMENT_CV = new ContentValues();
|
||||||
static {
|
static {
|
||||||
PRUNE_ATTACHMENT_CV.putNull(AttachmentColumns.CONTENT_URI);
|
PRUNE_ATTACHMENT_CV.putNull(AttachmentColumns.CONTENT_URI);
|
||||||
|
@ -363,7 +347,6 @@ public class MessagingController implements Runnable {
|
||||||
}
|
}
|
||||||
NotificationController nc = NotificationController.getInstance(mContext);
|
NotificationController nc = NotificationController.getInstance(mContext);
|
||||||
try {
|
try {
|
||||||
processPendingActionsSynchronous(account);
|
|
||||||
|
|
||||||
// Select generic sync or store-specific sync
|
// Select generic sync or store-specific sync
|
||||||
SyncResults results = synchronizeMailboxGeneric(account, folder);
|
SyncResults results = synchronizeMailboxGeneric(account, folder);
|
||||||
|
@ -592,135 +575,6 @@ public class MessagingController implements Runnable {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A message and numeric uid that's easily sortable
|
|
||||||
*/
|
|
||||||
private static class SortableMessage {
|
|
||||||
private final Message mMessage;
|
|
||||||
private final long mUid;
|
|
||||||
|
|
||||||
SortableMessage(Message message, long uid) {
|
|
||||||
mMessage = message;
|
|
||||||
mUid = uid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int searchMailbox(long accountId, SearchParams searchParams, long destMailboxId)
|
|
||||||
throws MessagingException {
|
|
||||||
try {
|
|
||||||
return searchMailboxImpl(accountId, searchParams, destMailboxId);
|
|
||||||
} finally {
|
|
||||||
// Tell UI that we're done loading any search results (no harm calling this even if we
|
|
||||||
// encountered an error or never sent a "started" message)
|
|
||||||
mListeners.synchronizeMailboxFinished(accountId, destMailboxId, 0, 0, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int searchMailboxImpl(long accountId, SearchParams searchParams,
|
|
||||||
final long destMailboxId) throws MessagingException {
|
|
||||||
final Account account = Account.restoreAccountWithId(mContext, accountId);
|
|
||||||
final Mailbox mailbox = Mailbox.restoreMailboxWithId(mContext, searchParams.mMailboxId);
|
|
||||||
final Mailbox destMailbox = Mailbox.restoreMailboxWithId(mContext, destMailboxId);
|
|
||||||
if (account == null || mailbox == null || destMailbox == null) {
|
|
||||||
Log.d(Logging.LOG_TAG, "Attempted search for " + searchParams
|
|
||||||
+ " but account or mailbox information was missing");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tell UI that we're loading messages
|
|
||||||
mListeners.synchronizeMailboxStarted(accountId, destMailbox.mId);
|
|
||||||
|
|
||||||
Store remoteStore = Store.getInstance(account, mContext);
|
|
||||||
Folder remoteFolder = remoteStore.getFolder(mailbox.mServerId);
|
|
||||||
remoteFolder.open(OpenMode.READ_WRITE);
|
|
||||||
|
|
||||||
SortableMessage[] sortableMessages = new SortableMessage[0];
|
|
||||||
if (searchParams.mOffset == 0) {
|
|
||||||
// Get the "bare" messages (basically uid)
|
|
||||||
Message[] remoteMessages = remoteFolder.getMessages(searchParams, null);
|
|
||||||
int remoteCount = remoteMessages.length;
|
|
||||||
if (remoteCount > 0) {
|
|
||||||
sortableMessages = new SortableMessage[remoteCount];
|
|
||||||
int i = 0;
|
|
||||||
for (Message msg : remoteMessages) {
|
|
||||||
sortableMessages[i++] = new SortableMessage(msg, Long.parseLong(msg.getUid()));
|
|
||||||
}
|
|
||||||
// Sort the uid's, most recent first
|
|
||||||
// Note: Not all servers will be nice and return results in the order of request;
|
|
||||||
// those that do will see messages arrive from newest to oldest
|
|
||||||
Arrays.sort(sortableMessages, new Comparator<SortableMessage>() {
|
|
||||||
@Override
|
|
||||||
public int compare(SortableMessage lhs, SortableMessage rhs) {
|
|
||||||
return lhs.mUid > rhs.mUid ? -1 : lhs.mUid < rhs.mUid ? 1 : 0;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
sSearchResults.put(accountId, sortableMessages);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sortableMessages = sSearchResults.get(accountId);
|
|
||||||
}
|
|
||||||
|
|
||||||
final int numSearchResults = sortableMessages.length;
|
|
||||||
final int numToLoad =
|
|
||||||
Math.min(numSearchResults - searchParams.mOffset, searchParams.mLimit);
|
|
||||||
if (numToLoad <= 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
final ArrayList<Message> messageList = new ArrayList<Message>();
|
|
||||||
for (int i = searchParams.mOffset; i < numToLoad + searchParams.mOffset; i++) {
|
|
||||||
messageList.add(sortableMessages[i].mMessage);
|
|
||||||
}
|
|
||||||
// Get everything in one pass, rather than two (as in sync); this starts getting us
|
|
||||||
// usable results quickly.
|
|
||||||
FetchProfile fp = new FetchProfile();
|
|
||||||
fp.add(FetchProfile.Item.FLAGS);
|
|
||||||
fp.add(FetchProfile.Item.ENVELOPE);
|
|
||||||
fp.add(FetchProfile.Item.STRUCTURE);
|
|
||||||
fp.add(FetchProfile.Item.BODY_SANE);
|
|
||||||
remoteFolder.fetch(messageList.toArray(new Message[0]), fp,
|
|
||||||
new MessageRetrievalListener() {
|
|
||||||
@Override
|
|
||||||
public void messageRetrieved(Message message) {
|
|
||||||
try {
|
|
||||||
// Determine if the new message was already known (e.g. partial)
|
|
||||||
// And create or reload the full message info
|
|
||||||
EmailContent.Message localMessage = new EmailContent.Message();
|
|
||||||
try {
|
|
||||||
// Copy the fields that are available into the message
|
|
||||||
LegacyConversions.updateMessageFields(localMessage,
|
|
||||||
message, account.mId, mailbox.mId);
|
|
||||||
// Commit the message to the local store
|
|
||||||
saveOrUpdate(localMessage, mContext);
|
|
||||||
localMessage.mMailboxKey = destMailboxId;
|
|
||||||
// We load 50k or so; maybe it's complete, maybe not...
|
|
||||||
int flag = EmailContent.Message.FLAG_LOADED_COMPLETE;
|
|
||||||
// We store the serverId of the source mailbox into protocolSearchInfo
|
|
||||||
// This will be used by loadMessageForView, etc. to use the proper remote
|
|
||||||
// folder
|
|
||||||
localMessage.mProtocolSearchInfo = mailbox.mServerId;
|
|
||||||
if (message.getSize() > Store.FETCH_BODY_SANE_SUGGESTED_SIZE) {
|
|
||||||
flag = EmailContent.Message.FLAG_LOADED_PARTIAL;
|
|
||||||
}
|
|
||||||
copyOneMessageToProvider(message, localMessage, flag, mContext);
|
|
||||||
} catch (MessagingException me) {
|
|
||||||
Log.e(Logging.LOG_TAG,
|
|
||||||
"Error while copying downloaded message." + me);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(Logging.LOG_TAG,
|
|
||||||
"Error while storing downloaded message." + e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void loadAttachmentProgress(int progress) {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return numSearchResults;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic synchronizer - used for POP3 and IMAP.
|
* Generic synchronizer - used for POP3 and IMAP.
|
||||||
*
|
*
|
||||||
|
@ -1053,667 +907,6 @@ public class MessagingController implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void processPendingActions(final long accountId) {
|
|
||||||
put("processPendingActions", null, new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
Account account = Account.restoreAccountWithId(mContext, accountId);
|
|
||||||
if (account == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
processPendingActionsSynchronous(account);
|
|
||||||
}
|
|
||||||
catch (MessagingException me) {
|
|
||||||
if (Logging.LOGD) {
|
|
||||||
Log.v(Logging.LOG_TAG, "processPendingActions", me);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Ignore any exceptions from the commands. Commands will be processed
|
|
||||||
* on the next round.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find messages in the updated table that need to be written back to server.
|
|
||||||
*
|
|
||||||
* Handles:
|
|
||||||
* Read/Unread
|
|
||||||
* Flagged
|
|
||||||
* Append (upload)
|
|
||||||
* Move To Trash
|
|
||||||
* Empty trash
|
|
||||||
* TODO:
|
|
||||||
* Move
|
|
||||||
*
|
|
||||||
* @param account the account to scan for pending actions
|
|
||||||
* @throws MessagingException
|
|
||||||
*/
|
|
||||||
private void processPendingActionsSynchronous(Account account)
|
|
||||||
throws MessagingException {
|
|
||||||
TrafficStats.setThreadStatsTag(TrafficFlags.getSyncFlags(mContext, account));
|
|
||||||
ContentResolver resolver = mContext.getContentResolver();
|
|
||||||
String[] accountIdArgs = new String[] { Long.toString(account.mId) };
|
|
||||||
|
|
||||||
// Handle deletes first, it's always better to get rid of things first
|
|
||||||
processPendingDeletesSynchronous(account, resolver, accountIdArgs);
|
|
||||||
|
|
||||||
// Handle uploads (currently, only to sent messages)
|
|
||||||
processPendingUploadsSynchronous(account, resolver, accountIdArgs);
|
|
||||||
|
|
||||||
// Now handle updates / upsyncs
|
|
||||||
processPendingUpdatesSynchronous(account, resolver, accountIdArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the mailbox corresponding to the remote location of a message; this will normally be
|
|
||||||
* the mailbox whose _id is mailboxKey, except for search results, where we must look it up
|
|
||||||
* by serverId
|
|
||||||
* @param message the message in question
|
|
||||||
* @return the mailbox in which the message resides on the server
|
|
||||||
*/
|
|
||||||
private Mailbox getRemoteMailboxForMessage(EmailContent.Message message) {
|
|
||||||
// If this is a search result, use the protocolSearchInfo field to get the server info
|
|
||||||
if (!TextUtils.isEmpty(message.mProtocolSearchInfo)) {
|
|
||||||
long accountKey = message.mAccountKey;
|
|
||||||
String protocolSearchInfo = message.mProtocolSearchInfo;
|
|
||||||
if (accountKey == mLastSearchAccountKey &&
|
|
||||||
protocolSearchInfo.equals(mLastSearchServerId)) {
|
|
||||||
return mLastSearchRemoteMailbox;
|
|
||||||
}
|
|
||||||
Cursor c = mContext.getContentResolver().query(Mailbox.CONTENT_URI,
|
|
||||||
Mailbox.CONTENT_PROJECTION, Mailbox.PATH_AND_ACCOUNT_SELECTION,
|
|
||||||
new String[] {protocolSearchInfo, Long.toString(accountKey)},
|
|
||||||
null);
|
|
||||||
try {
|
|
||||||
if (c.moveToNext()) {
|
|
||||||
Mailbox mailbox = new Mailbox();
|
|
||||||
mailbox.restore(c);
|
|
||||||
mLastSearchAccountKey = accountKey;
|
|
||||||
mLastSearchServerId = protocolSearchInfo;
|
|
||||||
mLastSearchRemoteMailbox = mailbox;
|
|
||||||
return mailbox;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
c.close();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Mailbox.restoreMailboxWithId(mContext, message.mMailboxKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scan for messages that are in the Message_Deletes table, look for differences that
|
|
||||||
* we can deal with, and do the work.
|
|
||||||
*
|
|
||||||
* @param account
|
|
||||||
* @param resolver
|
|
||||||
* @param accountIdArgs
|
|
||||||
*/
|
|
||||||
private void processPendingDeletesSynchronous(Account account,
|
|
||||||
ContentResolver resolver, String[] accountIdArgs) {
|
|
||||||
Cursor deletes = resolver.query(EmailContent.Message.DELETED_CONTENT_URI,
|
|
||||||
EmailContent.Message.CONTENT_PROJECTION,
|
|
||||||
EmailContent.MessageColumns.ACCOUNT_KEY + "=?", accountIdArgs,
|
|
||||||
EmailContent.MessageColumns.MAILBOX_KEY);
|
|
||||||
long lastMessageId = -1;
|
|
||||||
try {
|
|
||||||
// Defer setting up the store until we know we need to access it
|
|
||||||
Store remoteStore = null;
|
|
||||||
// loop through messages marked as deleted
|
|
||||||
while (deletes.moveToNext()) {
|
|
||||||
boolean deleteFromTrash = false;
|
|
||||||
|
|
||||||
EmailContent.Message oldMessage =
|
|
||||||
EmailContent.getContent(deletes, EmailContent.Message.class);
|
|
||||||
|
|
||||||
if (oldMessage != null) {
|
|
||||||
lastMessageId = oldMessage.mId;
|
|
||||||
|
|
||||||
Mailbox mailbox = getRemoteMailboxForMessage(oldMessage);
|
|
||||||
if (mailbox == null) {
|
|
||||||
continue; // Mailbox removed. Move to the next message.
|
|
||||||
}
|
|
||||||
deleteFromTrash = mailbox.mType == Mailbox.TYPE_TRASH;
|
|
||||||
|
|
||||||
// Load the remote store if it will be needed
|
|
||||||
if (remoteStore == null && deleteFromTrash) {
|
|
||||||
remoteStore = Store.getInstance(account, mContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dispatch here for specific change types
|
|
||||||
if (deleteFromTrash) {
|
|
||||||
// Move message to trash
|
|
||||||
processPendingDeleteFromTrash(remoteStore, account, mailbox, oldMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, delete the update
|
|
||||||
Uri uri = ContentUris.withAppendedId(EmailContent.Message.DELETED_CONTENT_URI,
|
|
||||||
oldMessage.mId);
|
|
||||||
resolver.delete(uri, null, null);
|
|
||||||
}
|
|
||||||
} catch (MessagingException me) {
|
|
||||||
// Presumably an error here is an account connection failure, so there is
|
|
||||||
// no point in continuing through the rest of the pending updates.
|
|
||||||
if (Email.DEBUG) {
|
|
||||||
Log.d(Logging.LOG_TAG, "Unable to process pending delete for id="
|
|
||||||
+ lastMessageId + ": " + me);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
deletes.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scan for messages that are in Sent, and are in need of upload,
|
|
||||||
* and send them to the server. "In need of upload" is defined as:
|
|
||||||
* serverId == null (no UID has been assigned)
|
|
||||||
* or
|
|
||||||
* message is in the updated list
|
|
||||||
*
|
|
||||||
* Note we also look for messages that are moving from drafts->outbox->sent. They never
|
|
||||||
* go through "drafts" or "outbox" on the server, so we hang onto these until they can be
|
|
||||||
* uploaded directly to the Sent folder.
|
|
||||||
*
|
|
||||||
* @param account
|
|
||||||
* @param resolver
|
|
||||||
* @param accountIdArgs
|
|
||||||
*/
|
|
||||||
private void processPendingUploadsSynchronous(Account account,
|
|
||||||
ContentResolver resolver, String[] accountIdArgs) {
|
|
||||||
// Find the Sent folder (since that's all we're uploading for now
|
|
||||||
Cursor mailboxes = resolver.query(Mailbox.CONTENT_URI, Mailbox.ID_PROJECTION,
|
|
||||||
MailboxColumns.ACCOUNT_KEY + "=?"
|
|
||||||
+ " and " + MailboxColumns.TYPE + "=" + Mailbox.TYPE_SENT,
|
|
||||||
accountIdArgs, null);
|
|
||||||
long lastMessageId = -1;
|
|
||||||
try {
|
|
||||||
// Defer setting up the store until we know we need to access it
|
|
||||||
Store remoteStore = null;
|
|
||||||
while (mailboxes.moveToNext()) {
|
|
||||||
long mailboxId = mailboxes.getLong(Mailbox.ID_PROJECTION_COLUMN);
|
|
||||||
String[] mailboxKeyArgs = new String[] { Long.toString(mailboxId) };
|
|
||||||
// Demand load mailbox
|
|
||||||
Mailbox mailbox = null;
|
|
||||||
|
|
||||||
// First handle the "new" messages (serverId == null)
|
|
||||||
Cursor upsyncs1 = resolver.query(EmailContent.Message.CONTENT_URI,
|
|
||||||
EmailContent.Message.ID_PROJECTION,
|
|
||||||
EmailContent.Message.MAILBOX_KEY + "=?"
|
|
||||||
+ " and (" + EmailContent.Message.SERVER_ID + " is null"
|
|
||||||
+ " or " + EmailContent.Message.SERVER_ID + "=''" + ")",
|
|
||||||
mailboxKeyArgs,
|
|
||||||
null);
|
|
||||||
try {
|
|
||||||
while (upsyncs1.moveToNext()) {
|
|
||||||
// Load the remote store if it will be needed
|
|
||||||
if (remoteStore == null) {
|
|
||||||
remoteStore = Store.getInstance(account, mContext);
|
|
||||||
}
|
|
||||||
// Load the mailbox if it will be needed
|
|
||||||
if (mailbox == null) {
|
|
||||||
mailbox = Mailbox.restoreMailboxWithId(mContext, mailboxId);
|
|
||||||
if (mailbox == null) {
|
|
||||||
continue; // Mailbox removed. Move to the next message.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// upsync the message
|
|
||||||
long id = upsyncs1.getLong(EmailContent.Message.ID_PROJECTION_COLUMN);
|
|
||||||
lastMessageId = id;
|
|
||||||
processUploadMessage(resolver, remoteStore, account, mailbox, id);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (upsyncs1 != null) {
|
|
||||||
upsyncs1.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next, handle any updates (e.g. edited in place, although this shouldn't happen)
|
|
||||||
Cursor upsyncs2 = resolver.query(EmailContent.Message.UPDATED_CONTENT_URI,
|
|
||||||
EmailContent.Message.ID_PROJECTION,
|
|
||||||
EmailContent.MessageColumns.MAILBOX_KEY + "=?", mailboxKeyArgs,
|
|
||||||
null);
|
|
||||||
try {
|
|
||||||
while (upsyncs2.moveToNext()) {
|
|
||||||
// Load the remote store if it will be needed
|
|
||||||
if (remoteStore == null) {
|
|
||||||
remoteStore = Store.getInstance(account, mContext);
|
|
||||||
}
|
|
||||||
// Load the mailbox if it will be needed
|
|
||||||
if (mailbox == null) {
|
|
||||||
mailbox = Mailbox.restoreMailboxWithId(mContext, mailboxId);
|
|
||||||
if (mailbox == null) {
|
|
||||||
continue; // Mailbox removed. Move to the next message.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// upsync the message
|
|
||||||
long id = upsyncs2.getLong(EmailContent.Message.ID_PROJECTION_COLUMN);
|
|
||||||
lastMessageId = id;
|
|
||||||
processUploadMessage(resolver, remoteStore, account, mailbox, id);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (upsyncs2 != null) {
|
|
||||||
upsyncs2.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (MessagingException me) {
|
|
||||||
// Presumably an error here is an account connection failure, so there is
|
|
||||||
// no point in continuing through the rest of the pending updates.
|
|
||||||
if (Email.DEBUG) {
|
|
||||||
Log.d(Logging.LOG_TAG, "Unable to process pending upsync for id="
|
|
||||||
+ lastMessageId + ": " + me);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (mailboxes != null) {
|
|
||||||
mailboxes.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scan for messages that are in the Message_Updates table, look for differences that
|
|
||||||
* we can deal with, and do the work.
|
|
||||||
*
|
|
||||||
* @param account
|
|
||||||
* @param resolver
|
|
||||||
* @param accountIdArgs
|
|
||||||
*/
|
|
||||||
private void processPendingUpdatesSynchronous(Account account,
|
|
||||||
ContentResolver resolver, String[] accountIdArgs) {
|
|
||||||
Cursor updates = resolver.query(EmailContent.Message.UPDATED_CONTENT_URI,
|
|
||||||
EmailContent.Message.CONTENT_PROJECTION,
|
|
||||||
EmailContent.MessageColumns.ACCOUNT_KEY + "=?", accountIdArgs,
|
|
||||||
EmailContent.MessageColumns.MAILBOX_KEY);
|
|
||||||
long lastMessageId = -1;
|
|
||||||
try {
|
|
||||||
// Defer setting up the store until we know we need to access it
|
|
||||||
Store remoteStore = null;
|
|
||||||
// Demand load mailbox (note order-by to reduce thrashing here)
|
|
||||||
Mailbox mailbox = null;
|
|
||||||
// loop through messages marked as needing updates
|
|
||||||
while (updates.moveToNext()) {
|
|
||||||
boolean changeMoveToTrash = false;
|
|
||||||
boolean changeRead = false;
|
|
||||||
boolean changeFlagged = false;
|
|
||||||
boolean changeMailbox = false;
|
|
||||||
boolean changeAnswered = false;
|
|
||||||
|
|
||||||
EmailContent.Message oldMessage =
|
|
||||||
EmailContent.getContent(updates, EmailContent.Message.class);
|
|
||||||
lastMessageId = oldMessage.mId;
|
|
||||||
EmailContent.Message newMessage =
|
|
||||||
EmailContent.Message.restoreMessageWithId(mContext, oldMessage.mId);
|
|
||||||
if (newMessage != null) {
|
|
||||||
mailbox = Mailbox.restoreMailboxWithId(mContext, newMessage.mMailboxKey);
|
|
||||||
if (mailbox == null) {
|
|
||||||
continue; // Mailbox removed. Move to the next message.
|
|
||||||
}
|
|
||||||
if (oldMessage.mMailboxKey != newMessage.mMailboxKey) {
|
|
||||||
if (mailbox.mType == Mailbox.TYPE_TRASH) {
|
|
||||||
changeMoveToTrash = true;
|
|
||||||
} else {
|
|
||||||
changeMailbox = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
changeRead = oldMessage.mFlagRead != newMessage.mFlagRead;
|
|
||||||
changeFlagged = oldMessage.mFlagFavorite != newMessage.mFlagFavorite;
|
|
||||||
changeAnswered = (oldMessage.mFlags & EmailContent.Message.FLAG_REPLIED_TO) !=
|
|
||||||
(newMessage.mFlags & EmailContent.Message.FLAG_REPLIED_TO);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the remote store if it will be needed
|
|
||||||
if (remoteStore == null &&
|
|
||||||
(changeMoveToTrash || changeRead || changeFlagged || changeMailbox ||
|
|
||||||
changeAnswered)) {
|
|
||||||
remoteStore = Store.getInstance(account, mContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dispatch here for specific change types
|
|
||||||
if (changeMoveToTrash) {
|
|
||||||
// Move message to trash
|
|
||||||
processPendingMoveToTrash(remoteStore, account, mailbox, oldMessage,
|
|
||||||
newMessage);
|
|
||||||
} else if (changeRead || changeFlagged || changeMailbox || changeAnswered) {
|
|
||||||
processPendingDataChange(remoteStore, mailbox, changeRead, changeFlagged,
|
|
||||||
changeMailbox, changeAnswered, oldMessage, newMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, delete the update
|
|
||||||
Uri uri = ContentUris.withAppendedId(EmailContent.Message.UPDATED_CONTENT_URI,
|
|
||||||
oldMessage.mId);
|
|
||||||
resolver.delete(uri, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (MessagingException me) {
|
|
||||||
// Presumably an error here is an account connection failure, so there is
|
|
||||||
// no point in continuing through the rest of the pending updates.
|
|
||||||
if (Email.DEBUG) {
|
|
||||||
Log.d(Logging.LOG_TAG, "Unable to process pending update for id="
|
|
||||||
+ lastMessageId + ": " + me);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
updates.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Upsync an entire message. This must also unwind whatever triggered it (either by
|
|
||||||
* updating the serverId, or by deleting the update record, or it's going to keep happening
|
|
||||||
* over and over again.
|
|
||||||
*
|
|
||||||
* Note: If the message is being uploaded into an unexpected mailbox, we *do not* upload.
|
|
||||||
* This is to avoid unnecessary uploads into the trash. Although the caller attempts to select
|
|
||||||
* only the Drafts and Sent folders, this can happen when the update record and the current
|
|
||||||
* record mismatch. In this case, we let the update record remain, because the filters
|
|
||||||
* in processPendingUpdatesSynchronous() will pick it up as a move and handle it (or drop it)
|
|
||||||
* appropriately.
|
|
||||||
*
|
|
||||||
* @param resolver
|
|
||||||
* @param remoteStore
|
|
||||||
* @param account
|
|
||||||
* @param mailbox the actual mailbox
|
|
||||||
* @param messageId
|
|
||||||
*/
|
|
||||||
private void processUploadMessage(ContentResolver resolver, Store remoteStore,
|
|
||||||
Account account, Mailbox mailbox, long messageId)
|
|
||||||
throws MessagingException {
|
|
||||||
EmailContent.Message newMessage =
|
|
||||||
EmailContent.Message.restoreMessageWithId(mContext, messageId);
|
|
||||||
boolean deleteUpdate = false;
|
|
||||||
if (newMessage == null) {
|
|
||||||
deleteUpdate = true;
|
|
||||||
Log.d(Logging.LOG_TAG, "Upsync failed for null message, id=" + messageId);
|
|
||||||
} else if (mailbox.mType == Mailbox.TYPE_DRAFTS) {
|
|
||||||
deleteUpdate = false;
|
|
||||||
Log.d(Logging.LOG_TAG, "Upsync skipped for mailbox=drafts, id=" + messageId);
|
|
||||||
} else if (mailbox.mType == Mailbox.TYPE_OUTBOX) {
|
|
||||||
deleteUpdate = false;
|
|
||||||
Log.d(Logging.LOG_TAG, "Upsync skipped for mailbox=outbox, id=" + messageId);
|
|
||||||
} else if (mailbox.mType == Mailbox.TYPE_TRASH) {
|
|
||||||
deleteUpdate = false;
|
|
||||||
Log.d(Logging.LOG_TAG, "Upsync skipped for mailbox=trash, id=" + messageId);
|
|
||||||
} else if (newMessage != null && newMessage.mMailboxKey != mailbox.mId) {
|
|
||||||
deleteUpdate = false;
|
|
||||||
Log.d(Logging.LOG_TAG, "Upsync skipped; mailbox changed, id=" + messageId);
|
|
||||||
} else {
|
|
||||||
Log.d(Logging.LOG_TAG, "Upsyc triggered for message id=" + messageId);
|
|
||||||
deleteUpdate = processPendingAppend(remoteStore, account, mailbox, newMessage);
|
|
||||||
}
|
|
||||||
if (deleteUpdate) {
|
|
||||||
// Finally, delete the update (if any)
|
|
||||||
Uri uri = ContentUris.withAppendedId(
|
|
||||||
EmailContent.Message.UPDATED_CONTENT_URI, messageId);
|
|
||||||
resolver.delete(uri, null, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Upsync changes to read, flagged, or mailbox
|
|
||||||
*
|
|
||||||
* @param remoteStore the remote store for this mailbox
|
|
||||||
* @param mailbox the mailbox the message is stored in
|
|
||||||
* @param changeRead whether the message's read state has changed
|
|
||||||
* @param changeFlagged whether the message's flagged state has changed
|
|
||||||
* @param changeMailbox whether the message's mailbox has changed
|
|
||||||
* @param oldMessage the message in it's pre-change state
|
|
||||||
* @param newMessage the current version of the message
|
|
||||||
*/
|
|
||||||
private void processPendingDataChange(Store remoteStore, Mailbox mailbox, boolean changeRead,
|
|
||||||
boolean changeFlagged, boolean changeMailbox, boolean changeAnswered,
|
|
||||||
EmailContent.Message oldMessage, final EmailContent.Message newMessage)
|
|
||||||
throws MessagingException {
|
|
||||||
// New mailbox is the mailbox this message WILL be in (same as the one it WAS in if it isn't
|
|
||||||
// being moved
|
|
||||||
Mailbox newMailbox = mailbox;
|
|
||||||
// Mailbox is the original remote mailbox (the one we're acting on)
|
|
||||||
mailbox = getRemoteMailboxForMessage(oldMessage);
|
|
||||||
|
|
||||||
// 0. No remote update if the message is local-only
|
|
||||||
if (newMessage.mServerId == null || newMessage.mServerId.equals("")
|
|
||||||
|| newMessage.mServerId.startsWith(LOCAL_SERVERID_PREFIX) || (mailbox == null)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. No remote update for DRAFTS or OUTBOX
|
|
||||||
if (mailbox.mType == Mailbox.TYPE_DRAFTS || mailbox.mType == Mailbox.TYPE_OUTBOX) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Open the remote store & folder
|
|
||||||
Folder remoteFolder = remoteStore.getFolder(mailbox.mServerId);
|
|
||||||
if (!remoteFolder.exists()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
remoteFolder.open(OpenMode.READ_WRITE);
|
|
||||||
if (remoteFolder.getMode() != OpenMode.READ_WRITE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Finally, apply the changes to the message
|
|
||||||
Message remoteMessage = remoteFolder.getMessage(newMessage.mServerId);
|
|
||||||
if (remoteMessage == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Email.DEBUG) {
|
|
||||||
Log.d(Logging.LOG_TAG,
|
|
||||||
"Update for msg id=" + newMessage.mId
|
|
||||||
+ " read=" + newMessage.mFlagRead
|
|
||||||
+ " flagged=" + newMessage.mFlagFavorite
|
|
||||||
+ " answered="
|
|
||||||
+ ((newMessage.mFlags & EmailContent.Message.FLAG_REPLIED_TO) != 0)
|
|
||||||
+ " new mailbox=" + newMessage.mMailboxKey);
|
|
||||||
}
|
|
||||||
Message[] messages = new Message[] { remoteMessage };
|
|
||||||
if (changeRead) {
|
|
||||||
remoteFolder.setFlags(messages, FLAG_LIST_SEEN, newMessage.mFlagRead);
|
|
||||||
}
|
|
||||||
if (changeFlagged) {
|
|
||||||
remoteFolder.setFlags(messages, FLAG_LIST_FLAGGED, newMessage.mFlagFavorite);
|
|
||||||
}
|
|
||||||
if (changeAnswered) {
|
|
||||||
remoteFolder.setFlags(messages, FLAG_LIST_ANSWERED,
|
|
||||||
(newMessage.mFlags & EmailContent.Message.FLAG_REPLIED_TO) != 0);
|
|
||||||
}
|
|
||||||
if (changeMailbox) {
|
|
||||||
Folder toFolder = remoteStore.getFolder(newMailbox.mServerId);
|
|
||||||
if (!remoteFolder.exists()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// We may need the message id to search for the message in the destination folder
|
|
||||||
remoteMessage.setMessageId(newMessage.mMessageId);
|
|
||||||
// Copy the message to its new folder
|
|
||||||
remoteFolder.copyMessages(messages, toFolder, new MessageUpdateCallbacks() {
|
|
||||||
@Override
|
|
||||||
public void onMessageUidChange(Message message, String newUid) {
|
|
||||||
ContentValues cv = new ContentValues();
|
|
||||||
cv.put(EmailContent.Message.SERVER_ID, newUid);
|
|
||||||
// We only have one message, so, any updates _must_ be for it. Otherwise,
|
|
||||||
// we'd have to cycle through to find the one with the same server ID.
|
|
||||||
mContext.getContentResolver().update(ContentUris.withAppendedId(
|
|
||||||
EmailContent.Message.CONTENT_URI, newMessage.mId), cv, null, null);
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void onMessageNotFound(Message message) {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Delete the message from the remote source folder
|
|
||||||
remoteMessage.setFlag(Flag.DELETED, true);
|
|
||||||
remoteFolder.expunge();
|
|
||||||
}
|
|
||||||
remoteFolder.close(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process a pending trash message command.
|
|
||||||
*
|
|
||||||
* @param remoteStore the remote store we're working in
|
|
||||||
* @param account The account in which we are working
|
|
||||||
* @param newMailbox The local trash mailbox
|
|
||||||
* @param oldMessage The message copy that was saved in the updates shadow table
|
|
||||||
* @param newMessage The message that was moved to the mailbox
|
|
||||||
*/
|
|
||||||
private void processPendingMoveToTrash(Store remoteStore,
|
|
||||||
Account account, Mailbox newMailbox, EmailContent.Message oldMessage,
|
|
||||||
final EmailContent.Message newMessage) throws MessagingException {
|
|
||||||
|
|
||||||
// 0. No remote move if the message is local-only
|
|
||||||
if (newMessage.mServerId == null || newMessage.mServerId.equals("")
|
|
||||||
|| newMessage.mServerId.startsWith(LOCAL_SERVERID_PREFIX)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. Escape early if we can't find the local mailbox
|
|
||||||
// TODO smaller projection here
|
|
||||||
Mailbox oldMailbox = getRemoteMailboxForMessage(oldMessage);
|
|
||||||
if (oldMailbox == null) {
|
|
||||||
// can't find old mailbox, it may have been deleted. just return.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 2. We don't support delete-from-trash here
|
|
||||||
if (oldMailbox.mType == Mailbox.TYPE_TRASH) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. If DELETE_POLICY_NEVER, simply write back the deleted sentinel and return
|
|
||||||
//
|
|
||||||
// This sentinel takes the place of the server-side message, and locally "deletes" it
|
|
||||||
// by inhibiting future sync or display of the message. It will eventually go out of
|
|
||||||
// scope when it becomes old, or is deleted on the server, and the regular sync code
|
|
||||||
// will clean it up for us.
|
|
||||||
if (account.getDeletePolicy() == Account.DELETE_POLICY_NEVER) {
|
|
||||||
EmailContent.Message sentinel = new EmailContent.Message();
|
|
||||||
sentinel.mAccountKey = oldMessage.mAccountKey;
|
|
||||||
sentinel.mMailboxKey = oldMessage.mMailboxKey;
|
|
||||||
sentinel.mFlagLoaded = EmailContent.Message.FLAG_LOADED_DELETED;
|
|
||||||
sentinel.mFlagRead = true;
|
|
||||||
sentinel.mServerId = oldMessage.mServerId;
|
|
||||||
sentinel.save(mContext);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The rest of this method handles server-side deletion
|
|
||||||
|
|
||||||
// 4. Find the remote mailbox (that we deleted from), and open it
|
|
||||||
Folder remoteFolder = remoteStore.getFolder(oldMailbox.mServerId);
|
|
||||||
if (!remoteFolder.exists()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
remoteFolder.open(OpenMode.READ_WRITE);
|
|
||||||
if (remoteFolder.getMode() != OpenMode.READ_WRITE) {
|
|
||||||
remoteFolder.close(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. Find the remote original message
|
|
||||||
Message remoteMessage = remoteFolder.getMessage(oldMessage.mServerId);
|
|
||||||
if (remoteMessage == null) {
|
|
||||||
remoteFolder.close(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6. Find the remote trash folder, and create it if not found
|
|
||||||
Folder remoteTrashFolder = remoteStore.getFolder(newMailbox.mServerId);
|
|
||||||
if (!remoteTrashFolder.exists()) {
|
|
||||||
/*
|
|
||||||
* If the remote trash folder doesn't exist we try to create it.
|
|
||||||
*/
|
|
||||||
remoteTrashFolder.create(FolderType.HOLDS_MESSAGES);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 7. Try to copy the message into the remote trash folder
|
|
||||||
// Note, this entire section will be skipped for POP3 because there's no remote trash
|
|
||||||
if (remoteTrashFolder.exists()) {
|
|
||||||
/*
|
|
||||||
* Because remoteTrashFolder may be new, we need to explicitly open it
|
|
||||||
*/
|
|
||||||
remoteTrashFolder.open(OpenMode.READ_WRITE);
|
|
||||||
if (remoteTrashFolder.getMode() != OpenMode.READ_WRITE) {
|
|
||||||
remoteFolder.close(false);
|
|
||||||
remoteTrashFolder.close(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
remoteFolder.copyMessages(new Message[] { remoteMessage }, remoteTrashFolder,
|
|
||||||
new Folder.MessageUpdateCallbacks() {
|
|
||||||
@Override
|
|
||||||
public void onMessageUidChange(Message message, String newUid) {
|
|
||||||
// update the UID in the local trash folder, because some stores will
|
|
||||||
// have to change it when copying to remoteTrashFolder
|
|
||||||
ContentValues cv = new ContentValues();
|
|
||||||
cv.put(EmailContent.Message.SERVER_ID, newUid);
|
|
||||||
mContext.getContentResolver().update(newMessage.getUri(), cv, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This will be called if the deleted message doesn't exist and can't be
|
|
||||||
* deleted (e.g. it was already deleted from the server.) In this case,
|
|
||||||
* attempt to delete the local copy as well.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onMessageNotFound(Message message) {
|
|
||||||
mContext.getContentResolver().delete(newMessage.getUri(), null, null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
remoteTrashFolder.close(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 8. Delete the message from the remote source folder
|
|
||||||
remoteMessage.setFlag(Flag.DELETED, true);
|
|
||||||
remoteFolder.expunge();
|
|
||||||
remoteFolder.close(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process a pending trash message command.
|
|
||||||
*
|
|
||||||
* @param remoteStore the remote store we're working in
|
|
||||||
* @param account The account in which we are working
|
|
||||||
* @param oldMailbox The local trash mailbox
|
|
||||||
* @param oldMessage The message that was deleted from the trash
|
|
||||||
*/
|
|
||||||
private void processPendingDeleteFromTrash(Store remoteStore,
|
|
||||||
Account account, Mailbox oldMailbox, EmailContent.Message oldMessage)
|
|
||||||
throws MessagingException {
|
|
||||||
|
|
||||||
// 1. We only support delete-from-trash here
|
|
||||||
if (oldMailbox.mType != Mailbox.TYPE_TRASH) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Find the remote trash folder (that we are deleting from), and open it
|
|
||||||
Folder remoteTrashFolder = remoteStore.getFolder(oldMailbox.mServerId);
|
|
||||||
if (!remoteTrashFolder.exists()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
remoteTrashFolder.open(OpenMode.READ_WRITE);
|
|
||||||
if (remoteTrashFolder.getMode() != OpenMode.READ_WRITE) {
|
|
||||||
remoteTrashFolder.close(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Find the remote original message
|
|
||||||
Message remoteMessage = remoteTrashFolder.getMessage(oldMessage.mServerId);
|
|
||||||
if (remoteMessage == null) {
|
|
||||||
remoteTrashFolder.close(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. Delete the message from the remote trash folder
|
|
||||||
remoteMessage.setFlag(Flag.DELETED, true);
|
|
||||||
remoteTrashFolder.expunge();
|
|
||||||
remoteTrashFolder.close(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process a pending append message command. This command uploads a local message to the
|
* Process a pending append message command. This command uploads a local message to the
|
||||||
* server, first checking to be sure that the server message is not newer than
|
* server, first checking to be sure that the server message is not newer than
|
||||||
|
|
|
@ -16,15 +16,15 @@
|
||||||
|
|
||||||
package com.android.email;
|
package com.android.email;
|
||||||
|
|
||||||
import com.android.emailcommon.Logging;
|
|
||||||
import com.android.emailcommon.mail.MessagingException;
|
|
||||||
import com.android.emailcommon.utility.Utility;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.emailcommon.Logging;
|
||||||
|
import com.android.emailcommon.mail.MessagingException;
|
||||||
|
import com.android.emailcommon.utility.Utility;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -107,11 +107,13 @@ public class RefreshManager {
|
||||||
private long mLastRefreshTime;
|
private long mLastRefreshTime;
|
||||||
|
|
||||||
public boolean isRefreshing() {
|
public boolean isRefreshing() {
|
||||||
return mIsRefreshRequested || mIsRefreshing;
|
// NOTE: For now, we're always allowing refresh (during service refactor)
|
||||||
|
return false; //return mIsRefreshRequested || mIsRefreshing;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canRefresh() {
|
public boolean canRefresh() {
|
||||||
return !isRefreshing();
|
// NOTE: For now, we're always allowing refresh (during service refactor)
|
||||||
|
return true; //return !isRefreshing();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onRefreshRequested() {
|
public void onRefreshRequested() {
|
||||||
|
|
|
@ -155,6 +155,7 @@ public class AttachmentDownloadService extends Service implements Runnable {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(final Context context, Intent intent) {
|
public void onReceive(final Context context, Intent intent) {
|
||||||
new Thread(new Runnable() {
|
new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
watchdogAlarm();
|
watchdogAlarm();
|
||||||
}
|
}
|
||||||
|
@ -652,6 +653,7 @@ public class AttachmentDownloadService extends Service implements Runnable {
|
||||||
* single callback that's defined by the EmailServiceCallback interface.
|
* single callback that's defined by the EmailServiceCallback interface.
|
||||||
*/
|
*/
|
||||||
private class ServiceCallback extends IEmailServiceCallback.Stub {
|
private class ServiceCallback extends IEmailServiceCallback.Stub {
|
||||||
|
@Override
|
||||||
public void loadAttachmentStatus(long messageId, long attachmentId, int statusCode,
|
public void loadAttachmentStatus(long messageId, long attachmentId, int statusCode,
|
||||||
int progress) {
|
int progress) {
|
||||||
// Record status and progress
|
// Record status and progress
|
||||||
|
@ -697,6 +699,11 @@ public class AttachmentDownloadService extends Service implements Runnable {
|
||||||
public void syncMailboxStatus(long mailboxId, int statusCode, int progress)
|
public void syncMailboxStatus(long mailboxId, int statusCode, int progress)
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadMessageStatus(long messageId, int statusCode, int progress)
|
||||||
|
throws RemoteException {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -801,6 +808,7 @@ public class AttachmentDownloadService extends Service implements Runnable {
|
||||||
*/
|
*/
|
||||||
public static void attachmentChanged(final Context context, final long id, final int flags) {
|
public static void attachmentChanged(final Context context, final long id, final int flags) {
|
||||||
Utility.runAsync(new Runnable() {
|
Utility.runAsync(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Attachment attachment = Attachment.restoreAttachmentWithId(context, id);
|
Attachment attachment = Attachment.restoreAttachmentWithId(context, id);
|
||||||
if (attachment != null) {
|
if (attachment != null) {
|
||||||
|
@ -867,6 +875,7 @@ public class AttachmentDownloadService extends Service implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
// These fields are only used within the service thread
|
// These fields are only used within the service thread
|
||||||
mContext = this;
|
mContext = this;
|
||||||
|
|
|
@ -48,7 +48,7 @@ public class EmailServiceUtils {
|
||||||
* @param context
|
* @param context
|
||||||
* @param callback Object to get callback, or can be null
|
* @param callback Object to get callback, or can be null
|
||||||
*/
|
*/
|
||||||
public static IEmailService getService(Context context, String intentAction,
|
public static EmailServiceProxy getService(Context context, String intentAction,
|
||||||
IEmailServiceCallback callback) {
|
IEmailServiceCallback callback) {
|
||||||
return new EmailServiceProxy(context, intentAction, callback);
|
return new EmailServiceProxy(context, intentAction, callback);
|
||||||
}
|
}
|
||||||
|
@ -64,11 +64,16 @@ public class EmailServiceUtils {
|
||||||
startService(context, EmailServiceProxy.EXCHANGE_INTENT);
|
startService(context, EmailServiceProxy.EXCHANGE_INTENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEmailService getExchangeService(Context context,
|
public static EmailServiceProxy getExchangeService(Context context,
|
||||||
IEmailServiceCallback callback) {
|
IEmailServiceCallback callback) {
|
||||||
return getService(context, EmailServiceProxy.EXCHANGE_INTENT, 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 boolean isExchangeAvailable(Context context) {
|
public static boolean isExchangeAvailable(Context context) {
|
||||||
return isServiceAvailable(context, EmailServiceProxy.EXCHANGE_INTENT);
|
return isServiceAvailable(context, EmailServiceProxy.EXCHANGE_INTENT);
|
||||||
}
|
}
|
||||||
|
@ -85,65 +90,83 @@ public class EmailServiceUtils {
|
||||||
public static class NullEmailService extends Service implements IEmailService {
|
public static class NullEmailService extends Service implements IEmailService {
|
||||||
public static final NullEmailService INSTANCE = new NullEmailService();
|
public static final NullEmailService INSTANCE = new NullEmailService();
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getApiLevel() {
|
public int getApiLevel() {
|
||||||
return Api.LEVEL;
|
return Api.LEVEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Bundle autoDiscover(String userName, String password) throws RemoteException {
|
public Bundle autoDiscover(String userName, String password) throws RemoteException {
|
||||||
return Bundle.EMPTY;
|
return Bundle.EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean createFolder(long accountId, String name) throws RemoteException {
|
public boolean createFolder(long accountId, String name) throws RemoteException {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean deleteFolder(long accountId, String name) throws RemoteException {
|
public boolean deleteFolder(long accountId, String name) throws RemoteException {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void hostChanged(long accountId) throws RemoteException {
|
public void hostChanged(long accountId) throws RemoteException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void loadAttachment(long attachmentId, boolean background) throws RemoteException {
|
public void loadAttachment(long attachmentId, boolean background) throws RemoteException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void loadMore(long messageId) throws RemoteException {
|
public void loadMore(long messageId) throws RemoteException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean renameFolder(long accountId, String oldName, String newName)
|
public boolean renameFolder(long accountId, String oldName, String newName)
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void sendMeetingResponse(long messageId, int response) throws RemoteException {
|
public void sendMeetingResponse(long messageId, int response) throws RemoteException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setCallback(IEmailServiceCallback cb) throws RemoteException {
|
public void setCallback(IEmailServiceCallback cb) throws RemoteException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setLogging(int flags) throws RemoteException {
|
public void setLogging(int flags) throws RemoteException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void startSync(long mailboxId, boolean userRequest) throws RemoteException {
|
public void startSync(long mailboxId, boolean userRequest) throws RemoteException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void stopSync(long mailboxId) throws RemoteException {
|
public void stopSync(long mailboxId) throws RemoteException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void updateFolderList(long accountId) throws RemoteException {
|
public void updateFolderList(long accountId) throws RemoteException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Bundle validate(HostAuth hostAuth) throws RemoteException {
|
public Bundle validate(HostAuth hostAuth) throws RemoteException {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void deleteAccountPIMData(long accountId) throws RemoteException {
|
public void deleteAccountPIMData(long accountId) throws RemoteException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int searchMessages(long accountId, SearchParams searchParams, long destMailboxId) {
|
public int searchMessages(long accountId, SearchParams searchParams, long destMailboxId) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public IBinder asBinder() {
|
public IBinder asBinder() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -69,8 +69,6 @@ public class MailService extends Service {
|
||||||
"com.android.email.intent.action.MAIL_SERVICE_CANCEL";
|
"com.android.email.intent.action.MAIL_SERVICE_CANCEL";
|
||||||
private static final String ACTION_SEND_PENDING_MAIL =
|
private static final String ACTION_SEND_PENDING_MAIL =
|
||||||
"com.android.email.intent.action.MAIL_SERVICE_SEND_PENDING";
|
"com.android.email.intent.action.MAIL_SERVICE_SEND_PENDING";
|
||||||
private static final String ACTION_DELETE_EXCHANGE_ACCOUNTS =
|
|
||||||
"com.android.email.intent.action.MAIL_SERVICE_DELETE_EXCHANGE_ACCOUNTS";
|
|
||||||
|
|
||||||
private static final String EXTRA_ACCOUNT = "com.android.email.intent.extra.ACCOUNT";
|
private static final String EXTRA_ACCOUNT = "com.android.email.intent.extra.ACCOUNT";
|
||||||
private static final String EXTRA_ACCOUNT_INFO = "com.android.email.intent.extra.ACCOUNT_INFO";
|
private static final String EXTRA_ACCOUNT_INFO = "com.android.email.intent.extra.ACCOUNT_INFO";
|
||||||
|
@ -114,13 +112,6 @@ public class MailService extends Service {
|
||||||
context.startService(i);
|
context.startService(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void actionDeleteExchangeAccounts(Context context) {
|
|
||||||
Intent i = new Intent();
|
|
||||||
i.setClass(context, MailService.class);
|
|
||||||
i.setAction(MailService.ACTION_DELETE_EXCHANGE_ACCOUNTS);
|
|
||||||
context.startService(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entry point for AttachmentDownloadService to ask that pending mail be sent
|
* Entry point for AttachmentDownloadService to ask that pending mail be sent
|
||||||
* @param context the caller's context
|
* @param context the caller's context
|
||||||
|
@ -157,7 +148,7 @@ public class MailService extends Service {
|
||||||
|
|
||||||
final AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
|
final AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
|
||||||
|
|
||||||
if (ACTION_CHECK_MAIL.equals(action)) {
|
if ((ACTION_CHECK_MAIL).equals(action)) {
|
||||||
// DB access required to satisfy this intent, so offload from UI thread
|
// DB access required to satisfy this intent, so offload from UI thread
|
||||||
EmailAsyncTask.runAsyncParallel(new Runnable() {
|
EmailAsyncTask.runAsyncParallel(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -180,7 +171,10 @@ public class MailService extends Service {
|
||||||
synchronized(mSyncReports) {
|
synchronized(mSyncReports) {
|
||||||
for (AccountSyncReport report: mSyncReports.values()) {
|
for (AccountSyncReport report: mSyncReports.values()) {
|
||||||
if (report.accountId == accountId) {
|
if (report.accountId == accountId) {
|
||||||
if (report.syncEnabled) {
|
// Only sync POP3 here (will remove POP3 sync soon)
|
||||||
|
if (report.syncEnabled &&
|
||||||
|
Account.getProtocol(MailService.this, accountId)
|
||||||
|
.equals(HostAuth.SCHEME_POP3)) {
|
||||||
syncStarted = syncOneAccount(mController, accountId,
|
syncStarted = syncOneAccount(mController, accountId,
|
||||||
startId);
|
startId);
|
||||||
}
|
}
|
||||||
|
@ -211,31 +205,6 @@ public class MailService extends Service {
|
||||||
cancel();
|
cancel();
|
||||||
stopSelf(startId);
|
stopSelf(startId);
|
||||||
}
|
}
|
||||||
else if (ACTION_DELETE_EXCHANGE_ACCOUNTS.equals(action)) {
|
|
||||||
if (Email.DEBUG) {
|
|
||||||
Log.d(LOG_TAG, "action: delete exchange accounts");
|
|
||||||
}
|
|
||||||
EmailAsyncTask.runAsyncParallel(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Cursor c = mContentResolver.query(Account.CONTENT_URI, Account.ID_PROJECTION,
|
|
||||||
null, null, null);
|
|
||||||
try {
|
|
||||||
while (c.moveToNext()) {
|
|
||||||
long accountId = c.getLong(Account.ID_PROJECTION_COLUMN);
|
|
||||||
if ("eas".equals(Account.getProtocol(mContext, accountId))) {
|
|
||||||
// Always log this
|
|
||||||
Log.d(LOG_TAG, "Deleting EAS account: " + accountId);
|
|
||||||
mController.deleteAccountSync(accountId, mContext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
c.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
stopSelf(startId);
|
|
||||||
}
|
|
||||||
else if (ACTION_SEND_PENDING_MAIL.equals(action)) {
|
else if (ACTION_SEND_PENDING_MAIL.equals(action)) {
|
||||||
if (Email.DEBUG) {
|
if (Email.DEBUG) {
|
||||||
Log.d(LOG_TAG, "action: send pending mail");
|
Log.d(LOG_TAG, "action: send pending mail");
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package com.android.email.service;
|
package com.android.email.service;
|
||||||
|
|
||||||
import android.accounts.Account;
|
|
||||||
import android.accounts.OperationCanceledException;
|
import android.accounts.OperationCanceledException;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.content.AbstractThreadedSyncAdapter;
|
import android.content.AbstractThreadedSyncAdapter;
|
||||||
|
@ -30,11 +29,15 @@ import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.email.Controller;
|
import com.android.emailcommon.mail.MessagingException;
|
||||||
import com.android.emailcommon.provider.EmailContent;
|
import com.android.emailcommon.provider.Account;
|
||||||
import com.android.emailcommon.provider.EmailContent.AccountColumns;
|
import com.android.emailcommon.provider.EmailContent.AccountColumns;
|
||||||
|
import com.android.emailcommon.provider.EmailContent.Message;
|
||||||
|
import com.android.emailcommon.provider.HostAuth;
|
||||||
import com.android.emailcommon.provider.Mailbox;
|
import com.android.emailcommon.provider.Mailbox;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class PopImapSyncAdapterService extends Service {
|
public class PopImapSyncAdapterService extends Service {
|
||||||
private static final String TAG = "PopImapSyncAdapterService";
|
private static final String TAG = "PopImapSyncAdapterService";
|
||||||
private static SyncAdapterImpl sSyncAdapter = null;
|
private static SyncAdapterImpl sSyncAdapter = null;
|
||||||
|
@ -53,7 +56,7 @@ public class PopImapSyncAdapterService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPerformSync(Account account, Bundle extras,
|
public void onPerformSync(android.accounts.Account account, Bundle extras,
|
||||||
String authority, ContentProviderClient provider, SyncResult syncResult) {
|
String authority, ContentProviderClient provider, SyncResult syncResult) {
|
||||||
try {
|
try {
|
||||||
PopImapSyncAdapterService.performSync(mContext, account, extras,
|
PopImapSyncAdapterService.performSync(mContext, account, extras,
|
||||||
|
@ -78,29 +81,96 @@ public class PopImapSyncAdapterService extends Service {
|
||||||
return sSyncAdapter.getSyncAdapterBinder();
|
return sSyncAdapter.getSyncAdapterBinder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void sync(Context context, long mailboxId, SyncResult syncResult) {
|
||||||
|
Mailbox mailbox = Mailbox.restoreMailboxWithId(context, mailboxId);
|
||||||
|
if (mailbox == null) return;
|
||||||
|
Log.d(TAG, "Mailbox: " + mailbox.mDisplayName);
|
||||||
|
Account account = Account.restoreAccountWithId(context, mailbox.mAccountKey);
|
||||||
|
if (account == null) return;
|
||||||
|
try {
|
||||||
|
ImapService.synchronizeMailboxSynchronous(context, account, mailbox);
|
||||||
|
} catch (MessagingException e) {
|
||||||
|
int cause = e.getExceptionType();
|
||||||
|
switch(cause) {
|
||||||
|
case MessagingException.IOERROR:
|
||||||
|
syncResult.stats.numIoExceptions++;
|
||||||
|
break;
|
||||||
|
case MessagingException.AUTHENTICATION_FAILED:
|
||||||
|
syncResult.stats.numAuthExceptions++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Partial integration with system SyncManager; we initiate manual syncs upon request
|
* Partial integration with system SyncManager; we initiate manual syncs upon request
|
||||||
*/
|
*/
|
||||||
private static void performSync(Context context, Account account, Bundle extras,
|
private static void performSync(Context context, android.accounts.Account account,
|
||||||
String authority, ContentProviderClient provider, SyncResult syncResult)
|
Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult)
|
||||||
throws OperationCanceledException {
|
throws OperationCanceledException {
|
||||||
if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)) {
|
// Find an EmailProvider account with the Account's email address
|
||||||
String emailAddress = account.name;
|
Cursor c = null;
|
||||||
// Find an EmailProvider account with the Account's email address
|
try {
|
||||||
Cursor c = context.getContentResolver().query(
|
c = provider.query(com.android.emailcommon.provider.Account.CONTENT_URI,
|
||||||
com.android.emailcommon.provider.Account.CONTENT_URI,
|
Account.CONTENT_PROJECTION, AccountColumns.EMAIL_ADDRESS + "=?",
|
||||||
EmailContent.ID_PROJECTION, AccountColumns.EMAIL_ADDRESS + "=?",
|
new String[] {account.name}, null);
|
||||||
new String[] {emailAddress}, null);
|
if (c != null && c.moveToNext()) {
|
||||||
if (c.moveToNext()) {
|
Account acct = new Account();
|
||||||
// If we have one, find the inbox and start it syncing
|
acct.restore(c);
|
||||||
long accountId = c.getLong(EmailContent.ID_PROJECTION_COLUMN);
|
String protocol = acct.getProtocol(context);
|
||||||
long mailboxId = Mailbox.findMailboxOfType(context, accountId,
|
if (protocol.equals(HostAuth.SCHEME_IMAP)) {
|
||||||
Mailbox.TYPE_INBOX);
|
if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD)) {
|
||||||
if (mailboxId > 0) {
|
Log.d(TAG, "Upload sync request for " + acct.mDisplayName);
|
||||||
Log.d(TAG, "Starting manual sync for account " + emailAddress);
|
// See if any boxes have mail...
|
||||||
Controller.getInstance(context).updateMailbox(accountId, mailboxId, false);
|
Cursor updatesCursor = provider.query(Message.UPDATED_CONTENT_URI,
|
||||||
|
new String[] {Message.MAILBOX_KEY},
|
||||||
|
Message.ACCOUNT_KEY + "=?",
|
||||||
|
new String[] {Long.toString(acct.mId)},
|
||||||
|
null);
|
||||||
|
if ((updatesCursor == null) || (updatesCursor.getCount() == 0)) return;
|
||||||
|
ArrayList<Long> mailboxesToUpdate = new ArrayList<Long>();
|
||||||
|
while (updatesCursor.moveToNext()) {
|
||||||
|
Long mailboxId = updatesCursor.getLong(0);
|
||||||
|
if (!mailboxesToUpdate.contains(mailboxId)) {
|
||||||
|
mailboxesToUpdate.add(mailboxId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (long mailboxId: mailboxesToUpdate) {
|
||||||
|
sync(context, mailboxId, syncResult);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "Sync request for " + acct.mDisplayName);
|
||||||
|
Log.d(TAG, extras.toString());
|
||||||
|
long mailboxId = extras.getLong("MAILBOX_ID", Mailbox.NO_MAILBOX);
|
||||||
|
boolean isInbox = false;
|
||||||
|
if (mailboxId == Mailbox.NO_MAILBOX) {
|
||||||
|
mailboxId = Mailbox.findMailboxOfType(context, acct.mId,
|
||||||
|
Mailbox.TYPE_INBOX);
|
||||||
|
isInbox = true;
|
||||||
|
}
|
||||||
|
if (mailboxId == Mailbox.NO_MAILBOX) return;
|
||||||
|
sync(context, mailboxId, syncResult);
|
||||||
|
|
||||||
|
// Convert from minutes to seconds
|
||||||
|
int syncFrequency = acct.mSyncInterval * 60;
|
||||||
|
// Values < 0 are for "never" or "push"; 0 is undefined
|
||||||
|
if (syncFrequency <= 0) return;
|
||||||
|
Bundle ex = new Bundle();
|
||||||
|
if (!isInbox) {
|
||||||
|
ex.putLong("MAILBOX_ID", mailboxId);
|
||||||
|
}
|
||||||
|
Log.d(TAG, "Setting periodic sync for " + acct.mDisplayName + ": " +
|
||||||
|
syncFrequency + " seconds");
|
||||||
|
ContentResolver.addPeriodicSync(account, authority, ex, syncFrequency);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
if (c != null) {
|
||||||
|
c.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue