Fixes Issue 827

Fixes Issue 734

On reconnection, IMAP IDLE folders will now fetch up to the most
recent 10 message that arrived while a IDLE connection was not
available.

Fixes Issue 232

A serving of NAMESPACE-based auto-configuration on the side.  If the
IMAP prefix is empty, and the IMAP server supports NAMESPACE, use the
IMAP prefix supplied by NAMESPACE.  Also, if the user manually puts
the separator as the last character in the prefix, don't append the
separator.

Also:
Improved reliability of IMAP IDLE incoming message and flag state
change handling.  Reduction (but not elimination) of multiple
connections under startup conditions.
This commit is contained in:
Daniel Applebaum 2009-11-28 14:51:44 +00:00
parent b18e88cf0d
commit d871d2d2ee
9 changed files with 482 additions and 314 deletions

View file

@ -289,7 +289,7 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
<string name="account_setup_incoming_delete_policy_markread_label">Mark as read on server</string>
<string name="account_setup_incoming_imap_path_prefix_label">IMAP path prefix</string>
<string name="account_setup_incoming_imap_path_prefix_hint">Optional</string>
<string name="account_setup_incoming_imap_path_prefix_hint">(Automatic using NAMESPACE if available)</string>
<string name="account_setup_incoming_imap_folder_drafts">Drafts folder name</string>
<string name="account_setup_incoming_imap_folder_sent">Sent folder name</string>

View file

@ -831,6 +831,12 @@ public class Account implements Serializable
}
return super.equals(o);
}
@Override
public int hashCode()
{
return mUuid.hashCode();
}
public FolderMode getFolderDisplayMode()
{

View file

@ -3995,147 +3995,15 @@ public class MessagingController implements Runnable
return pushers.values();
}
public Pusher setupPushing(final Account account)
public boolean setupPushing(final Account account)
{
Pusher pusher = pushers.get(account);
if (pusher != null)
{
return pusher;
}
Store store = null;
try
{
store = Store.getInstance(account.getStoreUri(), mApplication);
if (store.isPushCapable() == false)
Pusher previousPusher = pushers.remove(account);
if (previousPusher != null)
{
Log.i(Email.LOG_TAG, "Account " + account.getDescription() + " is not push capable, skipping");
return null;
previousPusher.stop();
}
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Could not get remote store", e);
return null;
}
final MessagingController controller = this;
PushReceiver receiver = new PushReceiver()
{
ThreadLocal<WakeLock> threadWakeLock = new ThreadLocal<WakeLock>();
public void acquireWakeLock()
{
WakeLock wakeLock = threadWakeLock.get();
if (wakeLock == null)
{
PowerManager pm = (PowerManager) mApplication.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Email");
wakeLock.setReferenceCounted(false);
threadWakeLock.set(wakeLock);
}
wakeLock.acquire(Email.PUSH_WAKE_LOCK_TIMEOUT);
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Acquired WakeLock for Pushing for thread " + Thread.currentThread().getName());
}
}
public void releaseWakeLock()
{
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Considering releasing WakeLock for Pushing");
}
WakeLock wakeLock = threadWakeLock.get();
if (wakeLock != null)
{
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Releasing WakeLock for Pushing for thread " + Thread.currentThread().getName());
}
wakeLock.release();
}
else
{
Log.e(Email.LOG_TAG, "No WakeLock waiting to be released for thread " + Thread.currentThread().getName());
}
}
public void messagesFlagsChanged(Folder folder,
List<Message> messages)
{
controller.messagesArrived(account, folder, messages, true);
}
public void messagesArrived(Folder folder, List<Message> messages)
{
controller.messagesArrived(account, folder, messages, false);
}
public void sleep(long millis)
{
SleepService.sleep(mApplication, millis, threadWakeLock.get(), Email.PUSH_WAKE_LOCK_TIMEOUT);
}
public void pushError(String errorMessage, Exception e)
{
String errMess = errorMessage;
String body = null;
if (errMess == null && e != null)
{
errMess = e.getMessage();
}
body = errMess;
if (e != null)
{
body = e.toString();
}
controller.addErrorMessage(account, errMess, body);
}
public String getPushState(String folderName)
{
LocalFolder localFolder = null;
try
{
LocalStore localStore = (LocalStore) Store.getInstance(account.getLocalStoreUri(), mApplication);
localFolder= (LocalFolder) localStore.getFolder(folderName);
localFolder.open(OpenMode.READ_WRITE);
return localFolder.getPushState();
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Unable to get push state from account " + account.getDescription()
+ ", folder " + folderName, e);
return null;
}
finally
{
if (localFolder != null)
{
try
{
localFolder.close(false);
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Unable to close folder '" + folderName + "' in account " + account.getDescription(), e);
}
}
}
}
public void setPushActive(String folderName, boolean enabled)
{
for (MessagingListener l : getListeners())
{
l.setPushActive(account, folderName, enabled);
}
}
};
try
{
Preferences prefs = Preferences.getPreferences(mApplication);
Account.FolderMode aDisplayMode = account.getFolderDisplayMode();
@ -4178,19 +4046,46 @@ public class MessagingController implements Runnable
Log.i(Email.LOG_TAG, "Starting pusher for " + account.getDescription() + ":" + folder.getName());
names.add(folder.getName());
}
if (names.size() > 0)
{
pusher = store.getPusher(receiver, names);
if (pusher != null)
PushReceiver receiver = new MessagingControllerPushReceiver(mApplication, account, this);
try
{
pushers.put(account, pusher);
Store store = Store.getInstance(account.getStoreUri(), mApplication);
if (store.isPushCapable() == false)
{
Log.i(Email.LOG_TAG, "Account " + account.getDescription() + " is not push capable, skipping");
return false;
}
Pusher pusher = store.getPusher(receiver);
Pusher oldPusher = null;
if (pusher != null)
{
oldPusher = pushers.putIfAbsent(account, pusher);
}
if (oldPusher != null)
{
pusher = oldPusher;
}
else
{
pusher.start(names);
}
}
return pusher;
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Could not get remote store", e);
return false;
}
return true;
}
else
{
Log.i(Email.LOG_TAG, "No folders are configured for pushing in account " + account.getDescription());
return null;
return false;
}
}
@ -4198,16 +4093,7 @@ public class MessagingController implements Runnable
{
Log.e(Email.LOG_TAG, "Got exception while setting up pushing", e);
}
return null;
}
public void stopPushing(Account account)
{
Pusher pusher = pushers.remove(account);
if (pusher != null)
{
pusher.stop();
}
return false;
}
public void stopAllPushing()
@ -4220,7 +4106,6 @@ public class MessagingController implements Runnable
iter.remove();
pusher.stop();
}
}
public void messagesArrived(final Account account, final Folder remoteFolder, final List<Message> messages, final boolean flagSyncOnly)
@ -4239,7 +4124,6 @@ public class MessagingController implements Runnable
LocalStore localStore = (LocalStore) Store.getInstance(account.getLocalStoreUri(), mApplication);
localFolder= (LocalFolder) localStore.getFolder(remoteFolder.getName());
localFolder.open(OpenMode.READ_WRITE);
remoteFolder.open(OpenMode.READ_WRITE);
int newCount = downloadMessages(account, remoteFolder, localFolder, messages, flagSyncOnly);
setLocalUnreadCountToRemote(localFolder, remoteFolder, messages.size());

View file

@ -0,0 +1,145 @@
package com.android.email;
import java.util.List;
import android.app.Application;
import android.content.Context;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
import com.android.email.mail.Folder;
import com.android.email.mail.Message;
import com.android.email.mail.PushReceiver;
import com.android.email.mail.Store;
import com.android.email.mail.Folder.OpenMode;
import com.android.email.mail.store.LocalStore;
import com.android.email.mail.store.LocalStore.LocalFolder;
import com.android.email.service.SleepService;
public class MessagingControllerPushReceiver implements PushReceiver
{
final Account account;
final MessagingController controller;
final Application mApplication;
public MessagingControllerPushReceiver(Application nApplication, Account nAccount, MessagingController nController)
{
account = nAccount;
controller = nController;
mApplication = nApplication;
}
ThreadLocal<WakeLock> threadWakeLock = new ThreadLocal<WakeLock>();
public void acquireWakeLock()
{
WakeLock wakeLock = threadWakeLock.get();
if (wakeLock == null)
{
PowerManager pm = (PowerManager) mApplication.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Email");
wakeLock.setReferenceCounted(false);
threadWakeLock.set(wakeLock);
}
wakeLock.acquire(Email.PUSH_WAKE_LOCK_TIMEOUT);
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Acquired WakeLock for Pushing for thread " + Thread.currentThread().getName());
}
}
public void releaseWakeLock()
{
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Considering releasing WakeLock for Pushing");
}
WakeLock wakeLock = threadWakeLock.get();
if (wakeLock != null)
{
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Releasing WakeLock for Pushing for thread " + Thread.currentThread().getName());
}
wakeLock.release();
}
else
{
Log.e(Email.LOG_TAG, "No WakeLock waiting to be released for thread " + Thread.currentThread().getName());
}
}
public void messagesFlagsChanged(Folder folder,
List<Message> messages)
{
controller.messagesArrived(account, folder, messages, true);
}
public void messagesArrived(Folder folder, List<Message> messages)
{
controller.messagesArrived(account, folder, messages, false);
}
public void sleep(long millis)
{
SleepService.sleep(mApplication, millis, threadWakeLock.get(), Email.PUSH_WAKE_LOCK_TIMEOUT);
}
public void pushError(String errorMessage, Exception e)
{
String errMess = errorMessage;
String body = null;
if (errMess == null && e != null)
{
errMess = e.getMessage();
}
body = errMess;
if (e != null)
{
body = e.toString();
}
controller.addErrorMessage(account, errMess, body);
}
public String getPushState(String folderName)
{
LocalFolder localFolder = null;
try
{
LocalStore localStore = (LocalStore) Store.getInstance(account.getLocalStoreUri(), mApplication);
localFolder= (LocalFolder) localStore.getFolder(folderName);
localFolder.open(OpenMode.READ_WRITE);
return localFolder.getPushState();
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Unable to get push state from account " + account.getDescription()
+ ", folder " + folderName, e);
return null;
}
finally
{
if (localFolder != null)
{
try
{
localFolder.close(false);
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Unable to close folder '" + folderName + "' in account " + account.getDescription(), e);
}
}
}
}
public void setPushActive(String folderName, boolean enabled)
{
for (MessagingListener l : controller.getListeners())
{
l.setPushActive(account, folderName, enabled);
}
}
}

View file

@ -1,9 +1,11 @@
package com.android.email.mail;
import java.util.List;
public interface Pusher
{
public void start();
public void start(List<String> folderNames);
public void refresh();
public void stop();
/**

View file

@ -113,7 +113,7 @@ public abstract class Store
{
}
public Pusher getPusher(PushReceiver receiver, List<String> names)
public Pusher getPusher(PushReceiver receiver)
{
return null;
}

View file

@ -33,6 +33,7 @@ import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@ -99,14 +100,20 @@ public class ImapStore extends Store
private static final int IDLE_REFRESH_INTERVAL = 20 * 60 * 1000; // 20 minutes
private static final Flag[] PERMANENT_FLAGS = { Flag.DELETED, Flag.SEEN };
private static final String CAPABILITY_IDLE = "IDLE";
private static final String COMMAND_IDLE = "IDLE";
private static final String CAPABILITY_NAMESPACE = "NAMESPACE";
private static final String COMMAND_NAMESPACE = "NAMESPACE";
private String mHost;
private int mPort;
private String mUsername;
private String mPassword;
private int mConnectionSecurity;
private String mPathPrefix;
private String mPathDelimeter;
private volatile String mPathPrefix;
private volatile String mCombinedPrefix = null;
private volatile String mPathDelimeter;
private LinkedList<ImapConnection> mConnections =
new LinkedList<ImapConnection>();
@ -196,6 +203,10 @@ public class ImapStore extends Store
if ((uri.getPath() != null) && (uri.getPath().length() > 0))
{
mPathPrefix = uri.getPath().substring(1);
if (mPathPrefix != null && mPathPrefix.trim().length() == 0)
{
mPathPrefix = null;
}
}
mModifiedUtf7Charset = new CharsetProvider().charsetForName("X-RFC-3501");
@ -217,6 +228,34 @@ public class ImapStore extends Store
return folder;
}
private String getCombinedPrefix()
{
if (mCombinedPrefix == null)
{
if (mPathPrefix != null)
{
String tmpPrefix = mPathPrefix.trim();
String tmpDelim = (mPathDelimeter != null ? mPathDelimeter.trim() : "");
if (tmpPrefix.endsWith(tmpDelim))
{
mCombinedPrefix = tmpPrefix;
}
else if (tmpPrefix.length() > 0)
{
mCombinedPrefix = tmpPrefix + tmpDelim;
}
else
{
mCombinedPrefix = "";
}
}
else
{
mCombinedPrefix = "";
}
}
return mCombinedPrefix;
}
@Override
public Folder[] getPersonalNamespaces() throws MessagingException
@ -225,13 +264,10 @@ public class ImapStore extends Store
try
{
ArrayList<Folder> folders = new ArrayList<Folder>();
if (mPathPrefix == null)
{
mPathPrefix = "";
}
List<ImapResponse> responses =
connection.executeSimpleCommand(String.format("LIST \"\" \"%s*\"",
mPathPrefix));
getCombinedPrefix()));
for (ImapResponse response : responses)
{
@ -243,6 +279,7 @@ public class ImapStore extends Store
if (mPathDelimeter == null)
{
mPathDelimeter = response.getString(2);
mCombinedPrefix = null;
}
if (folder.equalsIgnoreCase(Email.INBOX))
@ -251,13 +288,14 @@ public class ImapStore extends Store
}
else
{
if (mPathPrefix.length() > 0)
if (getCombinedPrefix().length() > 0)
{
if (folder.length() >= mPathPrefix.length() + 1)
if (folder.length() >= getCombinedPrefix().length())
{
folder = folder.substring(mPathPrefix.length() + 1);
folder = folder.substring(getCombinedPrefix().length());
}
if (!decodeFolderName(response.getString(3)).equals(mPathPrefix + mPathDelimeter + folder))
if (!decodeFolderName(response.getString(3)).equals(getCombinedPrefix() + folder))
{
includeFolder = false;
}
@ -406,12 +444,7 @@ public class ImapStore extends Store
return true;
}
@Override
public Pusher getPusher(PushReceiver receiver, List<String> names)
{
return new ImapPusher(this, receiver, names);
}
class ImapFolder extends Folder
{
private String mName;
@ -433,18 +466,7 @@ public class ImapStore extends Store
String prefixedName = "";
if (!Email.INBOX.equalsIgnoreCase(mName))
{
String prefix = mPathPrefix;
String delim = mPathDelimeter;
if (prefix != null && delim != null)
{
prefix = prefix.trim();
delim = delim.trim();
if (prefix.length() > 0 && delim.length() > 0)
{
prefixedName += mPathPrefix + mPathDelimeter;
}
}
prefixedName = getCombinedPrefix();
}
prefixedName += mName;
@ -503,7 +525,7 @@ public class ImapStore extends Store
// 2 OK [READ-WRITE] Select completed.
try
{
if (mPathDelimeter == null)
{
List<ImapResponse> nameResponses =
@ -512,7 +534,7 @@ public class ImapStore extends Store
{
if (response.get(0).equals("LIST"))
{
mPathDelimeter = nameResponses.get(0).getString(2);
mPathDelimeter = response.getString(2);
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Got path delimeter '" + mPathDelimeter + "' for " + getLogId());
@ -1168,6 +1190,37 @@ public class ImapStore extends Store
}
return responses;
}
protected void handlePossibleUidNext(ImapResponse response)
{
if (response.get(0).equals("OK") && response.size() > 1)
{
Object bracketedObj = response.get(1);
if (bracketedObj instanceof ImapList)
{
ImapList bracketed = (ImapList)bracketedObj;
if (bracketed.size() > 1)
{
Object keyObj = bracketed.get(0);
if (keyObj instanceof String)
{
String key = (String)keyObj;
if ("UIDNEXT".equals(key))
{
uidNext = bracketed.getNumber(1);
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Got UidNext = " + uidNext + " for " + getLogId());
}
}
}
}
}
}
}
/**
* Handle an untagged response that the caller doesn't care to handle themselves.
@ -1186,34 +1239,9 @@ public class ImapStore extends Store
Log.d(Email.LOG_TAG, "Got untagged EXISTS with value " + mMessageCount + " for " + getLogId());
}
}
if (response.get(0).equals("OK") && response.size() > 1)
{
Object bracketedObj = response.get(1);
if (bracketedObj instanceof ImapList)
{
ImapList bracketed = (ImapList)bracketedObj;
if (bracketed.size() > 1)
{
Object keyObj = bracketed.get(0);
if (keyObj instanceof String)
{
String key = (String)keyObj;
if ("UIDNEXT".equals(key))
{
uidNext = bracketed.getNumber(1);
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Got UidNext = " + uidNext + " for " + getLogId());
}
}
}
}
}
}
else if (response.get(1).equals("EXPUNGE") && mMessageCount > 0)
handlePossibleUidNext(response);
if (response.get(1).equals("EXPUNGE") && mMessageCount > 0)
{
mMessageCount--;
if (Email.DEBUG)
@ -1873,6 +1901,61 @@ public class ImapStore extends Store
{
throw new AuthenticationFailedException(null, me);
}
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "NAMESPACE = " + hasCapability(CAPABILITY_NAMESPACE)
+ ", mPathPrefix = " + mPathPrefix);
}
if (mPathPrefix == null)
{
if (hasCapability(CAPABILITY_NAMESPACE))
{
Log.i(Email.LOG_TAG, "mPathPrefix is unset and server has NAMESPACE capability");
List<ImapResponse> namespaceResponses =
executeSimpleCommand(COMMAND_NAMESPACE);
for (ImapResponse response : namespaceResponses)
{
if (response.get(0).equals(COMMAND_NAMESPACE))
{
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Got NAMESPACE response " + response + " on " + getLogId());
}
Object personalNamespaces = response.get(1);
if (personalNamespaces != null && personalNamespaces instanceof ImapList)
{
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Got personal namespaces: " + personalNamespaces);
}
ImapList bracketed = (ImapList)personalNamespaces;
Object firstNamespace = bracketed.get(0);
if (firstNamespace != null && firstNamespace instanceof ImapList)
{
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Got first personal namespaces: " + firstNamespace);
}
bracketed = (ImapList)firstNamespace;
mPathPrefix = bracketed.getString(0);
mPathDelimeter = bracketed.getString(1);
mCombinedPrefix = null;
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Got path '" + mPathPrefix + "' and separator '" + mPathDelimeter + "'");
}
}
}
}
}
}
else
{
Log.i(Email.LOG_TAG, "mPathPrefix is unset but server does not have NAMESPACE capability");
mPathPrefix = "";
}
}
}
catch (SSLException e)
{
@ -1922,7 +2005,12 @@ public class ImapStore extends Store
// Log.v(Email.LOG_TAG, "Have capability '" + capability + "' for " + getLogId());
// }
}
return capabilities.contains("IDLE");
return capabilities.contains(CAPABILITY_IDLE);
}
protected boolean hasCapability(String capability)
{
return capabilities.contains(capability);
}
private boolean isOpen()
@ -2287,7 +2375,7 @@ public class ImapStore extends Store
}
}
public void start() throws MessagingException
public void start()
{
Runnable runner = new Runnable()
{
@ -2297,7 +2385,6 @@ public class ImapStore extends Store
Log.i(Email.LOG_TAG, "Pusher starting for " + getLogId());
while (stop.get() != true)
{
try
{
int oldUidNext = -1;
@ -2332,17 +2419,17 @@ public class ImapStore extends Store
{
handleUntaggedResponses(responses);
}
if (uidNext > oldUidNext)
int startUid = oldUidNext;
if (startUid < uidNext - 10)
{
startUid = uidNext - 10;
}
if (startUid < 1)
{
startUid = 1;
}
if (uidNext > startUid)
{
int startUid = oldUidNext;
if (startUid < uidNext - 100)
{
startUid = uidNext - 100;
}
if (startUid < 1)
{
startUid = 1;
}
Log.i(Email.LOG_TAG, "Needs sync from uid " + startUid + " to " + uidNext + " for " + getLogId());
List<Message> messages = new ArrayList<Message>();
@ -2359,7 +2446,7 @@ public class ImapStore extends Store
}
else
{
if (stop.get() != true)
if (stop.get() == false)
{
List<ImapResponse> untaggedResponses = null;
if (storedUntaggedResponses.size() > 0)
@ -2378,8 +2465,11 @@ public class ImapStore extends Store
idling.set(false);
}
storedUntaggedResponses.clear();
processUntaggedResponses(untaggedResponses);
if (stop.get() == false)
{
storedUntaggedResponses.clear();
processUntaggedResponses(untaggedResponses);
}
delayTime.set(NORMAL_DELAY_TIME);
}
}
@ -2404,6 +2494,7 @@ public class ImapStore extends Store
}
else
{
receiver.pushError("Push error: " + e.getMessage(), null);
Log.e(Email.LOG_TAG, "Got exception while idling for " + getLogId(), e);
int delayTimeInt = delayTime.get();
receiver.sleep(delayTimeInt);
@ -2453,25 +2544,34 @@ public class ImapStore extends Store
}
storedUntaggedResponses.add(response);
}
handlePossibleUidNext(response);
}
}
protected void processUntaggedResponses(List<ImapResponse> responses)
{
boolean skipSync = false;
int oldMessageCount = mMessageCount;
if (oldMessageCount == -1)
{
skipSync = true;
}
List<Integer> flagSyncMsgSeqs = new ArrayList<Integer>();
for (ImapResponse response : responses)
{
oldMessageCount += processUntaggedResponse(oldMessageCount, response, flagSyncMsgSeqs);
}
if (oldMessageCount < 0)
if (skipSync == false)
{
oldMessageCount = 0;
}
if (mMessageCount > oldMessageCount)
{
syncMessages(oldMessageCount + 1, mMessageCount, true);
if (oldMessageCount < 0)
{
oldMessageCount = 0;
}
if (mMessageCount > oldMessageCount)
{
syncMessages(oldMessageCount + 1, mMessageCount, true);
}
}
if (Email.DEBUG)
{
@ -2610,10 +2710,13 @@ public class ImapStore extends Store
}
}
public void stop() throws MessagingException
public void stop()
{
stop.set(true);
if (listeningThread != null)
{
listeningThread.interrupt();
}
if (mConnection != null)
{
if (Email.DEBUG)
@ -2634,109 +2737,143 @@ public class ImapStore extends Store
{
Log.v(Email.LOG_TAG, "Got async response: " + response);
}
if (response.mTag == null)
if (stop.get() == true)
{
if (response.size() > 1)
if (Email.DEBUG)
{
boolean started = false;
Object responseType = response.get(1);
if ("EXISTS".equals(responseType) || "EXPUNGE".equals(responseType) ||
"FETCH".equals(responseType))
Log.d(Email.LOG_TAG, "Got async untagged response: " + response + ", but stop is set for " + getLogId());
}
try
{
sendDone();
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Exception while sending DONE for " + getLogId(), e);
}
}
else
{
if (response.mTag == null)
{
if (response.size() > 1)
{
if (started == false)
boolean started = false;
Object responseType = response.get(1);
if ("EXISTS".equals(responseType) || "EXPUNGE".equals(responseType) ||
"FETCH".equals(responseType))
{
receiver.acquireWakeLock();
started = true;
}
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Got useful async untagged response: " + response + " for " + getLogId());
}
try
{
sendDone();
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Exception while sending DONE for " + getLogId(), e);
if (started == false)
{
receiver.acquireWakeLock();
started = true;
}
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Got useful async untagged response: " + response + " for " + getLogId());
}
try
{
sendDone();
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Exception while sending DONE for " + getLogId(), e);
}
}
}
}
else if (response.size() > 0)
{
if ("idling".equals(response.get(0)))
else if (response.size() > 0)
{
if (Email.DEBUG)
if ("idling".equals(response.get(0)))
{
Log.d(Email.LOG_TAG, "Idling " + getLogId());
if (Email.DEBUG)
{
Log.d(Email.LOG_TAG, "Idling " + getLogId());
}
receiver.releaseWakeLock();
}
receiver.releaseWakeLock();
}
}
}
}
}
@Override
public Pusher getPusher(PushReceiver receiver)
{
return new ImapPusher(this, receiver);
}
public class ImapPusher implements Pusher
{
List<ImapFolderPusher> folderPushers = new ArrayList<ImapFolderPusher>();
final ImapStore mStore;
final PushReceiver mReceiver;
HashMap<String, ImapFolderPusher> folderPushers = new HashMap<String, ImapFolderPusher>();
public ImapPusher(ImapStore store, PushReceiver receiver, List<String> folderNames)
public ImapPusher(ImapStore store, PushReceiver receiver)
{
for (String folderName : folderNames)
mStore = store;
mReceiver = receiver;
}
@Override
public void start(List<String> folderNames)
{
stop();
synchronized(folderPushers)
{
ImapFolderPusher pusher = new ImapFolderPusher(store, folderName, receiver);
folderPushers.add(pusher);
for (String folderName : folderNames)
{
ImapFolderPusher pusher = folderPushers.get(folderName);
if (pusher == null)
{
pusher = new ImapFolderPusher(mStore, folderName, mReceiver);
folderPushers.put(folderName, pusher);
pusher.start();
}
}
}
}
@Override
public void refresh()
{
for (ImapFolderPusher folderPusher : folderPushers)
synchronized(folderPushers)
{
try
for (ImapFolderPusher folderPusher : folderPushers.values())
{
folderPusher.refresh();
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Got exception while refreshing for " + folderPusher.getName(), e);
}
}
}
public void start()
{
for (ImapFolderPusher folderPusher : folderPushers)
{
try
{
folderPusher.start();
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Got exception while starting " + folderPusher.getName(), e);
try
{
folderPusher.refresh();
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Got exception while refreshing for " + folderPusher.getName(), e);
}
}
}
}
@Override
public void stop()
{
Log.i(Email.LOG_TAG, "Requested stop of IMAP pusher");
for (ImapFolderPusher folderPusher : folderPushers)
synchronized(folderPushers)
{
try
for (ImapFolderPusher folderPusher : folderPushers.values())
{
Log.i(Email.LOG_TAG, "Requesting stop of IMAP folderPusher " + folderPusher.getName());
folderPusher.stop();
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Got exception while stopping " + folderPusher.getName(), e);
try
{
Log.i(Email.LOG_TAG, "Requesting stop of IMAP folderPusher " + folderPusher.getName());
folderPusher.stop();
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Got exception while stopping " + folderPusher.getName(), e);
}
}
folderPushers.clear();
}
folderPushers.clear();
}
public int getRefreshInterval()

View file

@ -69,8 +69,8 @@ public class BootReceiver extends BroadcastReceiver
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction()))
{
Email.setServicesEnabled(context, tmpWakeLockId);
tmpWakeLockId = null;
//Email.setServicesEnabled(context, tmpWakeLockId);
//tmpWakeLockId = null;
}
else if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(intent.getAction()))
{

View file

@ -361,13 +361,7 @@ public class MailService extends CoreService
for (Account account : Preferences.getPreferences(MailService.this).getAccounts())
{
Log.i(Email.LOG_TAG, "Setting up pushers for account " + account.getDescription());
Pusher pusher = MessagingController.getInstance(getApplication()).setupPushing(account);
if (pusher != null)
{
pushing = true;
Log.i(Email.LOG_TAG, "Starting configured pusher for account " + account.getDescription());
pusher.start();
}
pushing |= MessagingController.getInstance(getApplication()).setupPushing(account);
}
if (pushing)
{