diff --git a/src/com/android/email/Clock.java b/src/com/android/email/Clock.java
new file mode 100644
index 000000000..a2b44bb9b
--- /dev/null
+++ b/src/com/android/email/Clock.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.email;
+
+/**
+ * A class provide the current time (like {@link System#currentTimeMillis()}).
+ * It's intended to be mocked out for unit tests.
+ */
+public class Clock {
+ public static final Clock INSTANCE = new Clock();
+
+ protected Clock() {
+ }
+
+ public long getTime() {
+ return System.currentTimeMillis();
+ }
+}
diff --git a/src/com/android/email/Controller.java b/src/com/android/email/Controller.java
index 9bdb333fc..c3192a458 100644
--- a/src/com/android/email/Controller.java
+++ b/src/com/android/email/Controller.java
@@ -571,26 +571,6 @@ public class Controller {
}
}
- /**
- * Call {@link #sendPendingMessages} for all accounts.
- */
- public void sendPendingMessagesForAllAccounts(final Context context) {
- Utility.runAsync(new Runnable() {
- public void run() {
- Cursor c = context.getContentResolver().query(Account.CONTENT_URI,
- Account.ID_PROJECTION, null, null, null);
- try {
- while (c.moveToNext()) {
- long accountId = c.getLong(Account.ID_PROJECTION_COLUMN);
- sendPendingMessages(accountId);
- }
- } finally {
- c.close();
- }
- }
- });
- }
-
/**
* Reset visible limits for all accounts.
* For each account:
diff --git a/src/com/android/email/ControllerResultUiThreadWrapper.java b/src/com/android/email/ControllerResultUiThreadWrapper.java
index a2c9cce9d..d4e5fd9cc 100644
--- a/src/com/android/email/ControllerResultUiThreadWrapper.java
+++ b/src/com/android/email/ControllerResultUiThreadWrapper.java
@@ -24,6 +24,9 @@ import android.os.Handler;
/**
* A {@link Result} that wraps another {@link Result} and makes sure methods gets called back
* on the UI thread.
+ *
+ *
Optionally it supports the "synchronous" mode, if you pass null for the {@code handler}
+ * parameter, which allows unit tests to run synchronously.
*/
public class ControllerResultUiThreadWrapper extends Result {
private final Handler mHandler;
@@ -38,10 +41,18 @@ public class ControllerResultUiThreadWrapper extends Result {
return mWrappee;
}
+ private void run(Runnable runnable) {
+ if (mHandler == null) {
+ runnable.run();
+ } else {
+ mHandler.post(runnable);
+ }
+ }
+
@Override
public void loadAttachmentCallback(final MessagingException result, final long messageId,
final long attachmentId, final int progress) {
- mHandler.post(new Runnable() {
+ run(new Runnable() {
public void run() {
mWrappee.loadAttachmentCallback(result, messageId, attachmentId, progress);
}
@@ -51,7 +62,7 @@ public class ControllerResultUiThreadWrapper extends Result {
@Override
public void loadMessageForViewCallback(final MessagingException result,
final long messageId, final int progress) {
- mHandler.post(new Runnable() {
+ run(new Runnable() {
public void run() {
mWrappee.loadMessageForViewCallback(result, messageId, progress);
}
@@ -61,7 +72,7 @@ public class ControllerResultUiThreadWrapper extends Result {
@Override
public void sendMailCallback(final MessagingException result, final long accountId,
final long messageId, final int progress) {
- mHandler.post(new Runnable() {
+ run(new Runnable() {
public void run() {
mWrappee.sendMailCallback(result, accountId, messageId, progress);
}
@@ -71,7 +82,7 @@ public class ControllerResultUiThreadWrapper extends Result {
@Override
public void serviceCheckMailCallback(final MessagingException result, final long accountId,
final long mailboxId, final int progress, final long tag) {
- mHandler.post(new Runnable() {
+ run(new Runnable() {
public void run() {
mWrappee.serviceCheckMailCallback(result, accountId, mailboxId, progress, tag);
}
@@ -81,7 +92,7 @@ public class ControllerResultUiThreadWrapper extends Result {
@Override
public void updateMailboxCallback(final MessagingException result, final long accountId,
final long mailboxId, final int progress, final int numNewMessages) {
- mHandler.post(new Runnable() {
+ run(new Runnable() {
public void run() {
mWrappee.updateMailboxCallback(result, accountId, mailboxId, progress,
numNewMessages);
@@ -92,7 +103,7 @@ public class ControllerResultUiThreadWrapper extends Result {
@Override
public void updateMailboxListCallback(final MessagingException result, final long accountId,
final int progress) {
- mHandler.post(new Runnable() {
+ run(new Runnable() {
public void run() {
mWrappee.updateMailboxListCallback(result, accountId, progress);
}
@@ -101,7 +112,7 @@ public class ControllerResultUiThreadWrapper extends Result {
@Override
public void deleteAccountCallback(final long accountId) {
- mHandler.post(new Runnable() {
+ run(new Runnable() {
public void run() {
mWrappee.deleteAccountCallback(accountId);
}
diff --git a/src/com/android/email/Email.java b/src/com/android/email/Email.java
index dae5f2123..0beb01c80 100644
--- a/src/com/android/email/Email.java
+++ b/src/com/android/email/Email.java
@@ -141,9 +141,6 @@ public class Email extends Application {
*/
public static final int MAX_ATTACHMENT_UPLOAD_SIZE = (5 * 1024 * 1024);
- private static HashMap sMailboxSyncTimes = new HashMap();
- private static final long UPDATE_INTERVAL = 5 * DateUtils.MINUTE_IN_MILLIS;
-
/**
* This is used to force stacked UI to return to the "welcome" screen any time we change
* the accounts list (e.g. deleting accounts in the Account Manager preferences.)
@@ -271,6 +268,8 @@ public class Email extends Application {
DEBUG = prefs.getEnableDebugLogging();
setTempDirectory(this);
+ // Tie MailRefreshManager to the Controller.
+ RefreshManager.getInstance(this);
// Reset all accounts to default visible window
Controller.getInstance(this).resetVisibleLimits();
@@ -286,30 +285,6 @@ public class Email extends Application {
Log.d(LOG_TAG, message);
}
- /**
- * Update the time when the mailbox is refreshed
- * @param mailboxId mailbox which need to be updated
- */
- public static void updateMailboxRefreshTime(long mailboxId) {
- synchronized (sMailboxSyncTimes) {
- sMailboxSyncTimes.put(mailboxId, System.currentTimeMillis());
- }
- }
-
- /**
- * Check if the mailbox is need to be refreshed
- * @param mailboxId mailbox checked the need of refreshing
- * @return the need of refreshing
- */
- public static boolean mailboxRequiresRefresh(long mailboxId) {
- synchronized (sMailboxSyncTimes) {
- return
- !sMailboxSyncTimes.containsKey(mailboxId)
- || (System.currentTimeMillis() - sMailboxSyncTimes.get(mailboxId)
- > UPDATE_INTERVAL);
- }
- }
-
/**
* Called by the accounts reconciler to notify that accounts have changed, or by "Welcome"
* to clear the flag.
diff --git a/src/com/android/email/MessagingController.java b/src/com/android/email/MessagingController.java
index 769bc18ea..906cce811 100644
--- a/src/com/android/email/MessagingController.java
+++ b/src/com/android/email/MessagingController.java
@@ -2026,14 +2026,13 @@ public class MessagingController implements Runnable {
}
/**
- * Checks mail for one or multiple accounts. If account is null all accounts
- * are checked. This entry point is for use by the mail checking service only, because it
+ * Checks mail for an account.
+ * This entry point is for use by the mail checking service only, because it
* gives slightly different callbacks (so the service doesn't get confused by callbacks
* triggered by/for the foreground UI.
*
* TODO clean up the execution model which is unnecessarily threaded due to legacy code
*
- * @param context
* @param accountId the account to check
* @param listener
*/
diff --git a/src/com/android/email/RefreshManager.java b/src/com/android/email/RefreshManager.java
new file mode 100644
index 000000000..19f98f53f
--- /dev/null
+++ b/src/com/android/email/RefreshManager.java
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.email;
+
+import com.android.email.mail.MessagingException;
+import com.android.email.provider.EmailContent;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.os.Handler;
+import android.util.Log;
+
+import java.security.InvalidParameterException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+
+/**
+ * Class that handles "refresh" (and "send pending messages" for outboxes) related functionalities.
+ *
+ * This class is responsible for two things:
+ *
+ * - Taking refresh requests of mailbox-lists and message-lists and the "send outgoing
+ * messages" requests from UI, and calls appropriate methods of {@link Controller}.
+ * Note at this point the timer-based refresh
+ * (by {@link com.android.email.service.MailService}) uses {@link Controller} directly.
+ *
- Keeping track of which mailbox list/message list is actually being refreshed.
+ *
+ * Refresh requests will be ignored if a request to the same target is already requested, or is
+ * already being refreshed.
+ *
+ * Conceptually it can be a part of {@link Controller}, but extracted for easy testing.
+ */
+public class RefreshManager {
+ private static final boolean DEBUG_CALLBACK_LOG = true;
+ private static final long MAILBOX_AUTO_REFRESH_INTERVAL = 5 * 60 * 1000; // in milliseconds
+
+ private static RefreshManager sInstance;
+
+ private final Clock mClock;
+ private final Context mContext;
+ private final Controller mController;
+ private final Controller.Result mControllerResult;
+
+ /** Last error message */
+ private String mErrorMessage;
+
+ public interface Listener {
+ public void onRefreshStatusChanged(long accountId, long mailboxId);
+ public void onMessagingError(long accountId, long mailboxId, String message);
+ }
+
+ private final ArrayList mListeners = new ArrayList();
+
+ /**
+ * Status of a mailbox list/message list.
+ */
+ /* package */ static class Status {
+ /**
+ * True if a refresh of the mailbox is requested, and not finished yet.
+ */
+ private boolean mIsRefreshRequested;
+
+ /**
+ * True if the mailbox is being refreshed.
+ *
+ * Set true when {@link #onRefreshRequested} is called, i.e. refresh is requested by UI.
+ * Note refresh can occur without a request from UI as well (e.g. timer based refresh).
+ * In which case, {@link #mIsRefreshing} will be true with {@link #mIsRefreshRequested}
+ * being false.
+ */
+ private boolean mIsRefreshing;
+
+ private long mLastRefreshTime;
+
+ public boolean isRefreshing() {
+ return mIsRefreshRequested || mIsRefreshing;
+ }
+
+ public boolean canRefresh() {
+ return !isRefreshing();
+ }
+
+ public void onRefreshRequested() {
+ mIsRefreshRequested = true;
+ }
+
+ public long getLastRefreshTime() {
+ return mLastRefreshTime;
+ }
+
+ public void onCallback(MessagingException exception, int progress, Clock clock) {
+ if (exception == null && progress == 0) {
+ // Refresh started
+ mIsRefreshing = true;
+ } else if (exception != null || progress == 100) {
+ // Refresh finished
+ mIsRefreshing = false;
+ mIsRefreshRequested = false;
+ mLastRefreshTime = clock.getTime();
+ }
+ }
+ }
+
+ /**
+ * Map of accounts/mailboxes to {@link Status}.
+ */
+ private static class RefreshStatusMap {
+ private final HashMap mMap = new HashMap();
+
+ public Status get(long id) {
+ Status s = mMap.get(id);
+ if (s == null) {
+ s = new Status();
+ mMap.put(id, s);
+ }
+ return s;
+ }
+
+ public boolean isRefreshingAny() {
+ for (Status s : mMap.values()) {
+ if (s.isRefreshing()) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ private final RefreshStatusMap mMailboxListStatus = new RefreshStatusMap();
+ private final RefreshStatusMap mMessageListStatus = new RefreshStatusMap();
+ private final RefreshStatusMap mOutboxStatus = new RefreshStatusMap();
+
+ /**
+ * @return the singleton instance.
+ */
+ public static synchronized RefreshManager getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new RefreshManager(context, Controller.getInstance(context),
+ Clock.INSTANCE, new Handler());
+ }
+ return sInstance;
+ }
+
+ /* package */ RefreshManager(Context context, Controller controller, Clock clock,
+ Handler handler) {
+ mClock = clock;
+ mContext = context.getApplicationContext();
+ mController = controller;
+ mControllerResult = new ControllerResultUiThreadWrapper(
+ handler, new ControllerResult());
+ mController.addResultCallback(mControllerResult);
+ }
+
+ public void registerListener(Listener listener) {
+ if (listener == null) {
+ throw new InvalidParameterException();
+ }
+ mListeners.add(listener);
+ }
+
+ public void unregisterListener(Listener listener) {
+ if (listener == null) {
+ throw new InvalidParameterException();
+ }
+ mListeners.remove(listener);
+ }
+
+ /**
+ * Refresh the mailbox list of an account.
+ */
+ public boolean refreshMailboxList(long accountId) {
+ final Status status = mMailboxListStatus.get(accountId);
+ if (!status.canRefresh()) return false;
+
+ Log.i(Email.LOG_TAG, "refreshMailboxList " + accountId);
+ status.onRefreshRequested();
+ notifyRefreshStatusChanged(accountId, -1);
+ mController.updateMailboxList(accountId);
+ return true;
+ }
+
+ public boolean isMailboxStale(long mailboxId) {
+ return mClock.getTime() >= (mMessageListStatus.get(mailboxId).getLastRefreshTime()
+ + MAILBOX_AUTO_REFRESH_INTERVAL);
+ }
+
+ /**
+ * Refresh messages in a mailbox.
+ */
+ public boolean refreshMessageList(long accountId, long mailboxId) {
+ return refreshMessageList(accountId, mailboxId, false);
+ }
+
+ /**
+ * "load more messages" in a mailbox.
+ */
+ public boolean loadMoreMessages(long accountId, long mailboxId) {
+ return refreshMessageList(accountId, mailboxId, true);
+ }
+
+ private boolean refreshMessageList(long accountId, long mailboxId, boolean loadMoreMessages) {
+ final Status status = mMessageListStatus.get(mailboxId);
+ if (!status.canRefresh()) return false;
+
+ Log.i(Email.LOG_TAG, "refreshMessageList " + accountId + ", " + mailboxId + ", "
+ + loadMoreMessages);
+ status.onRefreshRequested();
+ notifyRefreshStatusChanged(accountId, mailboxId);
+ mController.updateMailbox(accountId, mailboxId);
+ return true;
+ }
+
+ /**
+ * Send pending messages.
+ */
+ public boolean sendPendingMessages(long accountId) {
+ final Status status = mOutboxStatus.get(accountId);
+ if (!status.canRefresh()) return false;
+
+ Log.i(Email.LOG_TAG, "sendPendingMessages " + accountId);
+ status.onRefreshRequested();
+ notifyRefreshStatusChanged(accountId, -1);
+ mController.sendPendingMessages(accountId);
+ return true;
+ }
+
+ /**
+ * Call {@link #sendPendingMessages} for all accounts.
+ */
+ public void sendPendingMessagesForAllAccounts() {
+ Log.i(Email.LOG_TAG, "sendPendingMessagesForAllAccounts");
+ Utility.runAsync(new Runnable() {
+ public void run() {
+ sendPendingMessagesForAllAccountsSync();
+ }
+ });
+ }
+
+ /**
+ * Synced internal method for {@link #sendPendingMessagesForAllAccounts} for testing.
+ */
+ /* package */ void sendPendingMessagesForAllAccountsSync() {
+ Cursor c = mContext.getContentResolver().query(EmailContent.Account.CONTENT_URI,
+ EmailContent.Account.ID_PROJECTION, null, null, null);
+ try {
+ while (c.moveToNext()) {
+ sendPendingMessages(c.getLong(EmailContent.Account.ID_PROJECTION_COLUMN));
+ }
+ } finally {
+ c.close();
+ }
+ }
+
+ public boolean isMailboxListRefreshing(long accountId) {
+ return mMailboxListStatus.get(accountId).isRefreshing();
+ }
+
+ public boolean isMessageListRefreshing(long mailboxId) {
+ return mMessageListStatus.get(mailboxId).isRefreshing();
+ }
+
+ public boolean isSendingMessage(long accountId) {
+ return mOutboxStatus.get(accountId).isRefreshing();
+ }
+
+ public boolean isRefreshingAnyMailboxList() {
+ return mMailboxListStatus.isRefreshingAny();
+ }
+
+ public boolean isRefreshingAnyMessageList() {
+ return mMessageListStatus.isRefreshingAny();
+ }
+
+ public boolean isSendingAnyMessage() {
+ return mOutboxStatus.isRefreshingAny();
+ }
+
+ public boolean isRefreshingOrSendingAny() {
+ return isRefreshingAnyMailboxList() || isRefreshingAnyMessageList()
+ || isSendingAnyMessage();
+ }
+
+ public String getErrorMessage() {
+ return mErrorMessage;
+ }
+
+ private void notifyRefreshStatusChanged(long accountId, long mailboxId) {
+ for (Listener l : mListeners) {
+ l.onRefreshStatusChanged(accountId, mailboxId);
+ }
+ }
+
+ private void reportError(long accountId, long mailboxId, String errorMessage) {
+ mErrorMessage = errorMessage;
+ for (Listener l : mListeners) {
+ l.onMessagingError(accountId, mailboxId, mErrorMessage);
+ }
+ }
+
+ /* package */ Collection getListenersForTest() {
+ return mListeners;
+ }
+
+ /* package */ Status getMailboxListStatusForTest(long accountId) {
+ return mMailboxListStatus.get(accountId);
+ }
+
+ /* package */ Status getMessageListStatusForTest(long mailboxId) {
+ return mMessageListStatus.get(mailboxId);
+ }
+
+ /* package */ Status getOutboxStatusForTest(long acountId) {
+ return mOutboxStatus.get(acountId);
+ }
+
+ private class ControllerResult extends Controller.Result {
+ private boolean mSendMailExceptionReported = false;
+
+ private String exceptionToString(MessagingException exception) {
+ if (exception == null) {
+ return "(no exception)";
+ } else {
+ return exception.getUiErrorMessage(mContext);
+ }
+ }
+
+ /**
+ * Callback for mailbox list refresh.
+ */
+ @Override
+ public void updateMailboxListCallback(MessagingException exception, long accountId,
+ int progress) {
+ if (Email.DEBUG && DEBUG_CALLBACK_LOG) {
+ Log.d(Email.LOG_TAG, "updateMailboxListCallback " + accountId + ", " + progress
+ + ", " + exceptionToString(exception));
+ }
+ mMailboxListStatus.get(accountId).onCallback(exception, progress, mClock);
+ if (exception != null) {
+ reportError(accountId, -1, exception.getUiErrorMessage(mContext));
+ }
+ notifyRefreshStatusChanged(accountId, -1);
+ }
+
+ /**
+ * Callback for explicit (user-driven) mailbox refresh.
+ */
+ @Override
+ public void updateMailboxCallback(MessagingException exception, long accountId,
+ long mailboxId, int progress, int dontUseNumNewMessages) {
+ if (Email.DEBUG && DEBUG_CALLBACK_LOG) {
+ Log.d(Email.LOG_TAG, "updateMailboxCallback " + accountId + ", "
+ + mailboxId + ", " + progress + ", " + exceptionToString(exception));
+ }
+ updateMailboxCallbackInternal(exception, accountId, mailboxId, progress, 0);
+ }
+
+ /**
+ * Callback for implicit (timer-based) mailbox refresh.
+ *
+ * Do the same as {@link #updateMailboxCallback}.
+ * TODO: Figure out if it's really okay to do the same as updateMailboxCallback.
+ * If both the explicit refresh and the implicit refresh can run at the same time,
+ * we need to keep track of their status separately.
+ */
+ @Override
+ public void serviceCheckMailCallback(
+ MessagingException exception, long accountId, long mailboxId, int progress,
+ long tag) {
+ if (Email.DEBUG && DEBUG_CALLBACK_LOG) {
+ Log.d(Email.LOG_TAG, "serviceCheckMailCallback " + accountId + ", "
+ + mailboxId + ", " + progress + ", " + exceptionToString(exception));
+ }
+ updateMailboxCallbackInternal(exception, accountId, mailboxId, progress, 0);
+ }
+
+ private void updateMailboxCallbackInternal(MessagingException exception, long accountId,
+ long mailboxId, int progress, int dontUseNumNewMessages) {
+ // Don't use dontUseNumNewMessages. serviceCheckMailCallback() don't set it.
+ mMessageListStatus.get(mailboxId).onCallback(exception, progress, mClock);
+ if (exception != null) {
+ reportError(accountId, mailboxId, exception.getUiErrorMessage(mContext));
+ }
+ notifyRefreshStatusChanged(accountId, mailboxId);
+ }
+
+
+ /**
+ * Send message progress callback.
+ *
+ * This callback is overly overloaded:
+ *
+ * First, we get this.
+ * result == null, messageId == -1, progress == 0: start batch send
+ *
+ * Then we get these callbacks per message.
+ * (Exchange backend may skip "start sending one message".)
+ * result == null, messageId == xx, progress == 0: start sending one message
+ * result == xxxx, messageId == xx, progress == 0; failed sending one message
+ *
+ * Finally we get this.
+ * result == null, messageId == -1, progres == 100; finish sending batch
+ *
+ * So, let's just report the first exception we get, and ignore the rest.
+ */
+ @Override
+ public void sendMailCallback(MessagingException exception, long accountId, long messageId,
+ int progress) {
+ if (Email.DEBUG && DEBUG_CALLBACK_LOG) {
+ Log.d(Email.LOG_TAG, "sendMailCallback " + accountId + ", "
+ + messageId + ", " + progress + ", " + exceptionToString(exception));
+ }
+ if (progress == 0 && messageId == -1) {
+ mSendMailExceptionReported = false;
+ }
+ if (messageId == -1) {
+ // Update the status only for the batch start/end.
+ // (i.e. don't report for each message.)
+ mOutboxStatus.get(accountId).onCallback(exception, progress, mClock);
+ notifyRefreshStatusChanged(accountId, -1);
+ }
+ if (exception != null && !mSendMailExceptionReported) {
+ // Only the first error in a batch will be reported.
+ mSendMailExceptionReported = true;
+ reportError(accountId, messageId, exception.getUiErrorMessage(mContext));
+ }
+ }
+ }
+}
diff --git a/src/com/android/email/activity/AccountFolderList.java b/src/com/android/email/activity/AccountFolderList.java
index 972bf1cc9..fcecbaedb 100644
--- a/src/com/android/email/activity/AccountFolderList.java
+++ b/src/com/android/email/activity/AccountFolderList.java
@@ -322,9 +322,6 @@ public class AccountFolderList extends Activity implements AccountFolderListFrag
@Override
public void updateMailboxCallback(MessagingException result, long accountKey,
long mailboxKey, int progress, int numNewMessages) {
- if (result != null || progress == 100) {
- Email.updateMailboxRefreshTime(mailboxKey);
- }
updateProgress(result, progress);
}
diff --git a/src/com/android/email/activity/MailboxList.java b/src/com/android/email/activity/MailboxList.java
index 37cad67e4..6592da771 100644
--- a/src/com/android/email/activity/MailboxList.java
+++ b/src/com/android/email/activity/MailboxList.java
@@ -22,8 +22,6 @@ import com.android.email.Email;
import com.android.email.R;
import com.android.email.Utility;
import com.android.email.activity.setup.AccountSettings;
-import com.android.email.mail.AuthenticationFailedException;
-import com.android.email.mail.CertificateValidationException;
import com.android.email.mail.MessagingException;
import com.android.email.provider.EmailContent.Account;
import com.android.email.provider.EmailContent.AccountColumns;
@@ -189,7 +187,7 @@ public class MailboxList extends Activity implements MailboxListFragment.Callbac
onAccounts();
return true;
case R.id.refresh:
- onRefresh(-1);
+ onRefresh();
return true;
case R.id.compose:
onCompose();
@@ -210,17 +208,12 @@ public class MailboxList extends Activity implements MailboxListFragment.Callbac
}
/**
- * Refresh the mailbox list, or a single mailbox
- * @param mailboxId -1 for all
+ * Refresh the mailbox list
*/
- private void onRefresh(long mailboxId) {
+ private void onRefresh() {
Controller controller = Controller.getInstance(getApplication());
showProgressIcon(true);
- if (mailboxId >= 0) {
- controller.updateMailbox(mAccountId, mailboxId);
- } else {
- controller.updateMailboxList(mAccountId);
- }
+ mListFragment.onRefresh();
}
private void onAccounts() {
@@ -274,7 +267,6 @@ public class MailboxList extends Activity implements MailboxListFragment.Callbac
*/
private class ControllerResults extends Controller.Result {
- // TODO report errors into UI
@Override
public void updateMailboxListCallback(MessagingException result, long accountKey,
int progress) {
@@ -284,13 +276,9 @@ public class MailboxList extends Activity implements MailboxListFragment.Callbac
}
}
- // TODO report errors into UI
@Override
public void updateMailboxCallback(MessagingException result, long accountKey,
long mailboxKey, int progress, int numNewMessages) {
- if (result != null || progress == 100) {
- Email.updateMailboxRefreshTime(mailboxKey);
- }
if (accountKey == mAccountId) {
updateBanner(result, progress);
updateProgress(result, progress);
@@ -321,28 +309,7 @@ public class MailboxList extends Activity implements MailboxListFragment.Callbac
*/
private void updateBanner(MessagingException result, int progress) {
if (result != null) {
- int id = R.string.status_network_error;
- if (result instanceof AuthenticationFailedException) {
- id = R.string.account_setup_failed_dlg_auth_message;
- } else if (result instanceof CertificateValidationException) {
- id = R.string.account_setup_failed_dlg_certificate_message;
- } else {
- switch (result.getExceptionType()) {
- case MessagingException.IOERROR:
- id = R.string.account_setup_failed_ioerror;
- break;
- case MessagingException.TLS_REQUIRED:
- id = R.string.account_setup_failed_tls_required;
- break;
- case MessagingException.AUTH_REQUIRED:
- id = R.string.account_setup_failed_auth_required;
- break;
- case MessagingException.GENERAL_SECURITY:
- id = R.string.account_setup_failed_security;
- break;
- }
- }
- showErrorBanner(getString(id));
+ showErrorBanner(result.getUiErrorMessage(MailboxList.this));
} else if (progress > 0) {
showErrorBanner(null);
}
diff --git a/src/com/android/email/activity/MailboxListFragment.java b/src/com/android/email/activity/MailboxListFragment.java
index bbbf89778..4b2c91270 100644
--- a/src/com/android/email/activity/MailboxListFragment.java
+++ b/src/com/android/email/activity/MailboxListFragment.java
@@ -16,7 +16,9 @@
package com.android.email.activity;
+import com.android.email.Controller;
import com.android.email.Email;
+import com.android.email.RefreshManager;
import com.android.email.Utility;
import android.app.Activity;
@@ -238,4 +240,10 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
public void onItemClick(AdapterView> parent, View view, int position, long id) {
mCallback.onMailboxSelected(mAccountId, id);
}
+
+ public void onRefresh() {
+ if (mAccountId != -1) {
+ RefreshManager.getInstance(getActivity()).refreshMailboxList(mAccountId);
+ }
+ }
}
diff --git a/src/com/android/email/activity/MessageCompose.java b/src/com/android/email/activity/MessageCompose.java
index 0b954b80b..b23cb9e80 100644
--- a/src/com/android/email/activity/MessageCompose.java
+++ b/src/com/android/email/activity/MessageCompose.java
@@ -145,7 +145,6 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus
private TextView mRightTitle;
private Controller mController;
- private Listener mListener;
private boolean mDraftNeedsSaving;
private boolean mMessageLoaded;
private AsyncTask mLoadAttachmentsTask;
@@ -270,7 +269,6 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.list_title);
mController = Controller.getInstance(getApplication());
- mListener = new Listener();
initViews();
setDraftNeedsSaving(false);
@@ -342,7 +340,6 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus
@Override
public void onResume() {
super.onResume();
- mController.addResultCallback(mListener);
// Exit immediately if the accounts list has changed (e.g. externally deleted)
if (Email.getNotifyUiAccountsChanged()) {
@@ -356,7 +353,6 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus
public void onPause() {
super.onPause();
saveIfNeeded();
- mController.removeResultCallback(mListener);
}
/**
@@ -1523,14 +1519,4 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus
setMessageContentSelection((mAccount != null) ? mAccount.mSignature : null);
}
}
-
- private class Listener extends Controller.Result {
- @Override
- public void updateMailboxCallback(MessagingException result, long accountId,
- long mailboxId, int progress, int numNewMessages) {
- if (result != null || progress == 100) {
- Email.updateMailboxRefreshTime(mailboxId);
- }
- }
- }
}
diff --git a/src/com/android/email/activity/MessageList.java b/src/com/android/email/activity/MessageList.java
index cfbd0da20..5b7a0d3c9 100644
--- a/src/com/android/email/activity/MessageList.java
+++ b/src/com/android/email/activity/MessageList.java
@@ -23,8 +23,6 @@ import com.android.email.R;
import com.android.email.Utility;
import com.android.email.activity.setup.AccountSecurity;
import com.android.email.activity.setup.AccountSettings;
-import com.android.email.mail.AuthenticationFailedException;
-import com.android.email.mail.CertificateValidationException;
import com.android.email.mail.MessagingException;
import com.android.email.provider.EmailContent;
import com.android.email.provider.EmailContent.Account;
@@ -542,7 +540,6 @@ public class MessageList extends Activity implements OnClickListener,
private void showProgressIcon(boolean show) {
int visibility = show ? View.VISIBLE : View.GONE;
mProgressIcon.setVisibility(visibility);
- mListFragment.showProgressIcon(show);
}
private void showErrorBanner(String message) {
@@ -579,9 +576,6 @@ public class MessageList extends Activity implements OnClickListener,
public void updateMailboxCallback(MessagingException result, long accountKey,
long mailboxKey, int progress, int numNewMessages) {
updateBanner(result, progress, mailboxKey);
- if (result != null || progress == 100) {
- Email.updateMailboxRefreshTime(mailboxKey);
- }
updateProgress(result, progress);
}
@@ -632,33 +626,7 @@ public class MessageList extends Activity implements OnClickListener,
return;
}
if (result != null) {
- int id = R.string.status_network_error;
- if (result instanceof AuthenticationFailedException) {
- id = R.string.account_setup_failed_dlg_auth_message;
- } else if (result instanceof CertificateValidationException) {
- id = R.string.account_setup_failed_dlg_certificate_message;
- } else {
- switch (result.getExceptionType()) {
- case MessagingException.IOERROR:
- id = R.string.account_setup_failed_ioerror;
- break;
- case MessagingException.TLS_REQUIRED:
- id = R.string.account_setup_failed_tls_required;
- break;
- case MessagingException.AUTH_REQUIRED:
- id = R.string.account_setup_failed_auth_required;
- break;
- case MessagingException.GENERAL_SECURITY:
- id = R.string.account_setup_failed_security;
- break;
- // TODO Generate a unique string for this case, which is the case
- // where the security policy needs to be updated.
- case MessagingException.SECURITY_POLICIES_REQUIRED:
- id = R.string.account_setup_failed_security;
- break;
- }
- }
- showErrorBanner(getString(id));
+ showErrorBanner(result.getUiErrorMessage(MessageList.this));
} else if (progress > 0) {
showErrorBanner(null);
}
diff --git a/src/com/android/email/activity/MessageListFragment.java b/src/com/android/email/activity/MessageListFragment.java
index 3eea957ae..28a64b417 100644
--- a/src/com/android/email/activity/MessageListFragment.java
+++ b/src/com/android/email/activity/MessageListFragment.java
@@ -18,6 +18,7 @@ package com.android.email.activity;
import com.android.email.Controller;
import com.android.email.Email;
+import com.android.email.RefreshManager;
import com.android.email.R;
import com.android.email.Utility;
import com.android.email.data.MailboxAccountLoader;
@@ -62,6 +63,8 @@ import java.util.Set;
*
* We run them sequentially. i.e. First starts {@link MailboxAccountLoader}, and when it finishes
* starts the other.
+ *
+ * TODO Add "send all messages" button to outboxes
*/
public class MessageListFragment extends ListFragment
implements OnItemClickListener, OnItemLongClickListener, MessagesAdapter.Callback {
@@ -90,6 +93,8 @@ public class MessageListFragment extends ListFragment
// Controller access
private Controller mController;
+ private RefreshManager mRefreshManager;
+ private RefreshListener mRefreshListener = new RefreshListener();
// Misc members
private boolean mDoAutoRefresh;
@@ -151,6 +156,8 @@ public class MessageListFragment extends ListFragment
super.onCreate(savedInstanceState);
mActivity = getActivity();
mController = Controller.getInstance(mActivity);
+ mRefreshManager = RefreshManager.getInstance(mActivity);
+ mRefreshManager.registerListener(mRefreshListener);
}
@Override
@@ -218,7 +225,7 @@ public class MessageListFragment extends ListFragment
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Email.LOG_TAG, "MessageListFragment onDestroy");
}
-
+ mRefreshManager.unregisterListener(mRefreshListener);
super.onDestroy();
}
@@ -391,9 +398,9 @@ public class MessageListFragment extends ListFragment
* Refresh the list. NOOP for special mailboxes (e.g. combined inbox).
*/
public void onRefresh() {
- final long accountId = getAccountId();
+ long accountId = getAccountId();
if (accountId != -1) {
- mController.updateMailbox(accountId, mMailboxId);
+ mRefreshManager.refreshMessageList(accountId, mMailboxId);
}
}
@@ -410,16 +417,18 @@ public class MessageListFragment extends ListFragment
* Load more messages. NOOP for special mailboxes (e.g. combined inbox).
*/
private void onLoadMoreMessages() {
- if (!isMagicMailbox()) {
- mController.loadMoreMessages(mMailboxId);
+ long accountId = getAccountId();
+ if (accountId != -1) {
+ mRefreshManager.loadMoreMessages(accountId, mMailboxId);
}
}
public void onSendPendingMessages() {
+ RefreshManager rm = RefreshManager.getInstance(mActivity);
if (getMailboxId() == Mailbox.QUERY_ALL_OUTBOX) {
- mController.sendPendingMessagesForAllAccounts(mActivity);
+ rm.sendPendingMessagesForAllAccounts();
} else if (!isMagicMailbox()) { // Magic boxes don't have a specific account id.
- mController.sendPendingMessages(getAccountId());
+ rm.sendPendingMessages(getAccountId());
}
}
@@ -618,24 +627,12 @@ public class MessageListFragment extends ListFragment
return;
}
mDoAutoRefresh = false;
- if (!Email.mailboxRequiresRefresh(mMailboxId)) {
+ if (!mRefreshManager.isMailboxStale(mMailboxId)) {
return;
}
onRefresh();
}
- /**
- * Show/hide the progress icon on the list footer. It's called by the host activity.
- * TODO: It might be cleaner if the fragment listen to the controller events and show it by
- * itself, rather than letting the activity controll this.
- */
- public void showProgressIcon(boolean show) {
- if (mListFooterProgress != null) {
- mListFooterProgress.setVisibility(show ? View.VISIBLE : View.GONE);
- }
- updateListFooterText(show);
- }
-
/** Implements {@link MessagesAdapter.Callback} */
@Override
public void onAdapterFavoriteChanged(MessageListItem itemView, boolean newFavorite) {
@@ -651,6 +648,10 @@ public class MessageListFragment extends ListFragment
private void determineFooterMode() {
mListFooterMode = LIST_FOOTER_MODE_NONE;
+ if ((mMailbox == null) || (mMailbox.mType == Mailbox.TYPE_OUTBOX)
+ || (mMailbox.mType == Mailbox.TYPE_DRAFTS)) {
+ return; // No footer
+ }
if (mAccount != null && !mAccount.isEasAccount()) {
// IMAP, POP has "load more"
mListFooterMode = LIST_FOOTER_MODE_MORE;
@@ -658,12 +659,12 @@ public class MessageListFragment extends ListFragment
}
private void addFooterView() {
+ ListView lv = getListView();
+ if (mListFooterView != null) {
+ lv.removeFooterView(mListFooterView);
+ }
determineFooterMode();
if (mListFooterMode != LIST_FOOTER_MODE_NONE) {
- ListView lv = getListView();
- if (mListFooterView != null) {
- lv.removeFooterView(mListFooterView);
- }
lv.addFooterView(mListFooterView);
lv.setAdapter(mListAdapter);
@@ -671,22 +672,22 @@ public class MessageListFragment extends ListFragment
mListFooterProgress = mListFooterView.findViewById(R.id.progress);
mListFooterText = (TextView) mListFooterView.findViewById(R.id.main_text);
- // TODO We don't know if it's really "inactive". Someone has to
- // remember all sync status.
- updateListFooterText(false);
+ updateListFooter();
}
}
/**
- * Set the list footer text based on mode and "network active" status
+ * Set the list footer text based on mode and the current "network active" status
*/
- private void updateListFooterText(boolean networkActive) {
+ private void updateListFooter() {
if (mListFooterMode != LIST_FOOTER_MODE_NONE) {
int footerTextId = 0;
switch (mListFooterMode) {
case LIST_FOOTER_MODE_MORE:
- footerTextId = networkActive ? R.string.status_loading_messages
+ boolean active = mRefreshManager.isMessageListRefreshing(mMailboxId);
+ footerTextId = active ? R.string.status_loading_messages
: R.string.message_list_load_more_messages_action;
+ mListFooterProgress.setVisibility(active ? View.VISIBLE : View.GONE);
break;
}
mListFooterText.setText(footerTextId);
@@ -914,4 +915,15 @@ public class MessageListFragment extends ListFragment
mSelectionMode = null;
}
}
-}
+
+ private class RefreshListener implements RefreshManager.Listener {
+ @Override
+ public void onMessagingError(long accountId, long mailboxId, String message) {
+ }
+
+ @Override
+ public void onRefreshStatusChanged(long accountId, long mailboxId) {
+ updateListFooter();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/email/activity/MessageListXL.java b/src/com/android/email/activity/MessageListXL.java
index d6cebcd27..1350f4d2f 100644
--- a/src/com/android/email/activity/MessageListXL.java
+++ b/src/com/android/email/activity/MessageListXL.java
@@ -17,6 +17,7 @@
package com.android.email.activity;
import com.android.email.Email;
+import com.android.email.RefreshManager;
import com.android.email.R;
import com.android.email.Utility;
import com.android.email.activity.setup.AccountSettings;
@@ -54,6 +55,9 @@ public class MessageListXL extends Activity implements View.OnClickListener,
private static final int LOADER_ID_ACCOUNT_LIST = 0;
private Context mContext;
+ private RefreshManager mRefreshManager;
+ private final RefreshListener mMailRefreshManagerListener
+ = new RefreshListener();
private View mMessageViewButtonPanel;
private View mMoveToNewerButton;
@@ -91,6 +95,8 @@ public class MessageListXL extends Activity implements View.OnClickListener,
final boolean isRestoring = (savedInstanceState != null);
mContext = getApplicationContext();
+ mRefreshManager = RefreshManager.getInstance(this);
+ mRefreshManager.registerListener(mMailRefreshManagerListener);
mFragmentManager.setMailboxListFragmentCallback(new MailboxListFragmentCallback());
mFragmentManager.setMessageListFragmentCallback(new MessageListFragmentCallback());
@@ -171,6 +177,7 @@ public class MessageListXL extends Activity implements View.OnClickListener,
@Override
protected void onDestroy() {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) Log.d(Email.LOG_TAG, "MessageListXL onDestroy");
+ mRefreshManager.unregisterListener(mMailRefreshManagerListener);
super.onDestroy();
}
@@ -492,6 +499,26 @@ public class MessageListXL extends Activity implements View.OnClickListener,
}
}
+ private class RefreshListener
+ implements RefreshManager.Listener {
+ @Override
+ public void onMessagingError(long accountId, long mailboxId, String message) {
+ Utility.showToast(MessageListXL.this, message); // STOPSHIP temporary UI
+ invalidateOptionsMenu();
+ }
+
+ @Override
+ public void onRefreshStatusChanged(long accountId, long mailboxId) {
+ invalidateOptionsMenu();
+ }
+ }
+
+ private boolean isProgressActive() {
+ final long mailboxId = mFragmentManager.getMailboxId();
+ return (mailboxId >= 0) && mRefreshManager.isMessageListRefreshing(mailboxId);
+
+ }
+
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
@@ -499,13 +526,26 @@ public class MessageListXL extends Activity implements View.OnClickListener,
return true;
}
+ // STOPSHIP - this is a placeholder if/until there's support for progress in actionbar
+ // Remove it, or replace with a better icon
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ MenuItem item = menu.findItem(R.id.refresh);
+ if (isProgressActive()) {
+ item.setIcon(android.R.drawable.progress_indeterminate_horizontal);
+ } else {
+ item.setIcon(R.drawable.ic_menu_refresh);
+ }
+ return super.onPrepareOptionsMenu(menu);
+ }
+
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.compose:
return onCompose();
case R.id.refresh:
- // TODO Implement this
+ onRefresh();
return true;
case R.id.account_settings:
return onAccountSettings();
@@ -539,6 +579,27 @@ public class MessageListXL extends Activity implements View.OnClickListener,
return true;
}
+ private void onRefresh() {
+ // Temporary implementation
+ if (mFragmentManager.isMailboxSelected()) {
+ mRefreshManager.refreshMessageList(mFragmentManager.getAccountId(),
+ mFragmentManager.getMailboxId());
+ }
+
+ // TODO implement this
+ // - Refresh mailbox list. But don't do that always; implement a min interval.
+ //
+ // - Refresh the selected mailbox, if it's supported.
+ // (regardless if the right-pane is MessageList or MessageView)
+ // - If not suppoted (e.g. outbox, draft, or push mailboxes), refresh the inbox of the
+ // current account.
+
+ // To do that, we need a way to tell the type of the currently selected mailbox.
+ // We can do this with MessageListFragment, but it's gone it if a message is being viewed.
+ // Maybe we should always have a MessageListFragment instance?
+ // That way it'll be easier to restore the scroll position.
+ }
+
/**
* STOPSHIP: Remove this.
* Rotate screen when the R key is pressed. Workaround for auto-orientation not working.
diff --git a/src/com/android/email/activity/MessageViewFragmentBase.java b/src/com/android/email/activity/MessageViewFragmentBase.java
index 50e98e208..25d70b18d 100644
--- a/src/com/android/email/activity/MessageViewFragmentBase.java
+++ b/src/com/android/email/activity/MessageViewFragmentBase.java
@@ -1024,14 +1024,6 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O
attachment.downloadButton.setEnabled(enable);
}
}
-
- @Override
- public void updateMailboxCallback(MessagingException result, long accountId,
- long mailboxId, int progress, int numNewMessages) {
- if (result != null || progress == 100) {
- Email.updateMailboxRefreshTime(mailboxId);
- }
- }
}
public boolean isMessageLoadedForTest() {
diff --git a/src/com/android/email/mail/AuthenticationFailedException.java b/src/com/android/email/mail/AuthenticationFailedException.java
index 2bcd606d5..7a767657f 100644
--- a/src/com/android/email/mail/AuthenticationFailedException.java
+++ b/src/com/android/email/mail/AuthenticationFailedException.java
@@ -16,6 +16,8 @@
package com.android.email.mail;
+import com.android.email.R;
+
public class AuthenticationFailedException extends MessagingException {
public static final long serialVersionUID = -1;
@@ -29,5 +31,10 @@ public class AuthenticationFailedException extends MessagingException {
public AuthenticationFailedException(String message, Throwable throwable) {
super(MessagingException.AUTHENTICATION_FAILED, message, throwable);
- }
+ }
+
+ @Override
+ public int getUiErrorMessageResourceId() {
+ return R.string.account_setup_failed_dlg_auth_message;
+ }
}
diff --git a/src/com/android/email/mail/CertificateValidationException.java b/src/com/android/email/mail/CertificateValidationException.java
index 6f8f43fc5..6f8fa85fe 100644
--- a/src/com/android/email/mail/CertificateValidationException.java
+++ b/src/com/android/email/mail/CertificateValidationException.java
@@ -16,6 +16,8 @@
package com.android.email.mail;
+import com.android.email.R;
+
public class CertificateValidationException extends MessagingException {
public static final long serialVersionUID = -1;
@@ -26,4 +28,9 @@ public class CertificateValidationException extends MessagingException {
public CertificateValidationException(String message, Throwable throwable) {
super(MessagingException.CERTIFICATE_VALIDATION_ERROR, message, throwable);
}
+
+ @Override
+ public int getUiErrorMessageResourceId() {
+ return R.string.account_setup_failed_dlg_certificate_message;
+ }
}
\ No newline at end of file
diff --git a/src/com/android/email/mail/MessagingException.java b/src/com/android/email/mail/MessagingException.java
index e8fa83704..981d01148 100644
--- a/src/com/android/email/mail/MessagingException.java
+++ b/src/com/android/email/mail/MessagingException.java
@@ -16,18 +16,22 @@
package com.android.email.mail;
+import com.android.email.R;
+
+import android.content.Context;
+
/**
* This exception is used for most types of failures that occur during server interactions.
- *
+ *
* Data passed through this exception should be considered non-localized. Any strings should
* either be internal-only (for debugging) or server-generated.
- *
+ *
* TO DO: Does it make sense to further collapse AuthenticationFailedException and
* CertificateValidationException and any others into this?
*/
public class MessagingException extends Exception {
public static final long serialVersionUID = -1;
-
+
public static final int NO_ERROR = -1;
/** Any exception that does not specify a specific issue */
public static final int UNSPECIFIED_EXCEPTION = 0;
@@ -53,9 +57,9 @@ public class MessagingException extends Exception {
public static final int CERTIFICATE_VALIDATION_ERROR = 10;
/** Authentication failed during autodiscover */
public static final int AUTODISCOVER_AUTHENTICATION_FAILED = 11;
-
+
protected int mExceptionType;
-
+
public MessagingException(String message) {
super(message);
mExceptionType = UNSPECIFIED_EXCEPTION;
@@ -70,7 +74,7 @@ public class MessagingException extends Exception {
super(message, throwable);
mExceptionType = exceptionType;
}
-
+
/**
* Constructs a MessagingException with an exceptionType and a null message.
* @param exceptionType The exception type to set for this exception.
@@ -79,7 +83,7 @@ public class MessagingException extends Exception {
super();
mExceptionType = exceptionType;
}
-
+
/**
* Constructs a MessagingException with an exceptionType and a message.
* @param exceptionType The exception type to set for this exception.
@@ -88,13 +92,41 @@ public class MessagingException extends Exception {
super(message);
mExceptionType = exceptionType;
}
-
+
/**
* Return the exception type. Will be OTHER_EXCEPTION if not explicitly set.
- *
+ *
* @return Returns the exception type.
*/
public int getExceptionType() {
return mExceptionType;
}
-}
+
+ /**
+ * @return the error message associated with this exception.
+ */
+ public final String getUiErrorMessage(Context context) {
+ return context.getResources().getString(getUiErrorMessageResourceId());
+ }
+
+ /**
+ * @return the resource ID of the error message associated with this exception.
+ */
+ public int getUiErrorMessageResourceId() {
+ switch (getExceptionType()) {
+ case MessagingException.IOERROR:
+ return R.string.account_setup_failed_ioerror;
+ case MessagingException.TLS_REQUIRED:
+ return R.string.account_setup_failed_tls_required;
+ case MessagingException.AUTH_REQUIRED:
+ return R.string.account_setup_failed_auth_required;
+ case MessagingException.GENERAL_SECURITY:
+ return R.string.account_setup_failed_security;
+ // TODO Generate a unique string for this case, which is the case
+ // where the security policy needs to be updated.
+ case MessagingException.SECURITY_POLICIES_REQUIRED:
+ return R.string.account_setup_failed_security;
+ }
+ return R.string.status_network_error; // default
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/email/service/MailService.java b/src/com/android/email/service/MailService.java
index e4066dacd..52d5a4521 100644
--- a/src/com/android/email/service/MailService.java
+++ b/src/com/android/email/service/MailService.java
@@ -655,8 +655,6 @@ public class MailService extends Service {
updateAccountReport(accountId, -1);
}
}
- // Call the global refresh tracker for all mailboxes
- Email.updateMailboxRefreshTime(mailboxId);
}
}
diff --git a/tests/src/com/android/email/MockClock.java b/tests/src/com/android/email/MockClock.java
new file mode 100644
index 000000000..2d80dc56e
--- /dev/null
+++ b/tests/src/com/android/email/MockClock.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.email;
+
+public class MockClock extends Clock {
+ public static final long DEFAULT_TIME = 10000; // Arbitrary value
+
+ public long mTime = DEFAULT_TIME;
+
+ @Override
+ public long getTime() {
+ return mTime;
+ }
+
+ public void advance() {
+ mTime++;
+ }
+}
diff --git a/tests/src/com/android/email/RefreshManagerTest.java b/tests/src/com/android/email/RefreshManagerTest.java
new file mode 100644
index 000000000..42230e5ed
--- /dev/null
+++ b/tests/src/com/android/email/RefreshManagerTest.java
@@ -0,0 +1,532 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.email;
+
+import com.android.email.mail.MessagingException;
+import com.android.email.provider.EmailContent.Account;
+import com.android.email.provider.EmailProvider;
+import com.android.email.provider.ProviderTestUtils;
+
+import android.content.Context;
+import android.test.AndroidTestCase;
+import android.test.MoreAsserts;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+import junit.framework.Assert;
+
+public class RefreshManagerTest extends AndroidTestCase {
+ private MockClock mClock;
+ private MockController mController;
+ private RefreshManager mTarget;
+ private RefreshListener mListener;
+
+ // Isolated Context for providers.
+ private Context mProviderContext;
+
+ private static final MessagingException EXCEPTION = new MessagingException("test");
+
+ // Looks silly, but it'll make it more readable.
+ private static final long ACCOUNT_1 = 1;
+ private static final long ACCOUNT_2 = 2;
+ private static final long MAILBOX_1 = 3;
+ private static final long MAILBOX_2 = 4;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mClock = new MockClock();
+ mController = new MockController(getContext());
+ mListener = new RefreshListener();
+ mProviderContext = DBTestHelper.ProviderContextSetupHelper.getProviderContext(
+ mContext, EmailProvider.class);
+ mTarget = new RefreshManager(mProviderContext, mController, mClock, null);
+ mTarget.registerListener(mListener);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ mController.cleanupForTest();
+ }
+
+ public void testRegisterUnregisterListener() {
+ // mListener is already registered
+ assertEquals(1, mTarget.getListenersForTest().size());
+
+ mTarget.unregisterListener(mListener);
+ assertEquals(0, mTarget.getListenersForTest().size());
+ }
+
+ public void testRefreshStatus() {
+ RefreshManager.Status s = new RefreshManager.Status();
+ assertFalse(s.isRefreshing());
+ assertTrue(s.canRefresh());
+ assertEquals(0, s.getLastRefreshTime());
+
+ // Request refresh
+ s.onRefreshRequested();
+ assertTrue(s.isRefreshing());
+ assertFalse(s.canRefresh());
+ assertEquals(0, s.getLastRefreshTime());
+
+ // Refresh start
+ s.onCallback(null, 0, mClock);
+ assertTrue(s.isRefreshing());
+ assertFalse(s.canRefresh());
+ assertEquals(0, s.getLastRefreshTime());
+
+ // Refresh 50% done -- nothing changes
+ s.onCallback(null, 50, mClock);
+ assertTrue(s.isRefreshing());
+ assertFalse(s.canRefresh());
+ assertEquals(0, s.getLastRefreshTime());
+
+ // Refresh finish
+ s.onCallback(null, 100, mClock);
+ assertFalse(s.isRefreshing());
+ assertTrue(s.canRefresh());
+ assertEquals(mClock.mTime, s.getLastRefreshTime());
+
+ // Refresh start without request
+ s.onCallback(null, 0, mClock);
+ assertTrue(s.isRefreshing());
+ assertFalse(s.canRefresh());
+ assertEquals(mClock.mTime, s.getLastRefreshTime());
+
+ mClock.advance();
+
+ // Refresh finish with error.
+ s.onCallback(EXCEPTION, 0, mClock);
+ assertFalse(s.isRefreshing());
+ assertTrue(s.canRefresh());
+ assertEquals(mClock.mTime, s.getLastRefreshTime());
+ }
+
+ public void testRefreshMailboxList() {
+ // request refresh for account 1
+ assertTrue(mTarget.refreshMailboxList(ACCOUNT_1));
+
+ assertTrue(mListener.mCalledOnRefreshStatusChanged);
+ assertFalse(mListener.mCalledOnConnectionError);
+ assertEquals(ACCOUNT_1, mListener.mAccountId);
+ assertEquals(-1, mListener.mMailboxId);
+ mListener.reset();
+ assertTrue(mController.mCalledUpdateMailboxList);
+ assertEquals(ACCOUNT_1, mController.mAccountId);
+ assertEquals(-1, mController.mMailboxId);
+ mController.reset();
+ assertTrue(mTarget.isMailboxListRefreshing(ACCOUNT_1));
+ assertTrue(mTarget.isRefreshingAnyMailboxList());
+
+ // Request again -- shouldn't be accepted.
+ assertFalse(mTarget.refreshMailboxList(ACCOUNT_1));
+
+ assertFalse(mListener.mCalledOnRefreshStatusChanged);
+ assertFalse(mListener.mCalledOnConnectionError);
+ mListener.reset();
+ assertFalse(mController.mCalledUpdateMailboxList);
+ mController.reset();
+
+ // request refresh for account 2
+ assertTrue(mTarget.refreshMailboxList(ACCOUNT_2));
+
+ assertTrue(mListener.mCalledOnRefreshStatusChanged);
+ assertFalse(mListener.mCalledOnConnectionError);
+ assertEquals(ACCOUNT_2, mListener.mAccountId);
+ assertEquals(-1, mListener.mMailboxId);
+ mListener.reset();
+ assertTrue(mController.mCalledUpdateMailboxList);
+ assertEquals(ACCOUNT_2, mController.mAccountId);
+ assertEquals(-1, mController.mMailboxId);
+ mController.reset();
+ assertTrue(mTarget.isMailboxListRefreshing(ACCOUNT_2));
+ assertTrue(mTarget.isRefreshingAnyMailboxList());
+
+ // Refreshing for account 1...
+ mController.mListener.updateMailboxListCallback(null, ACCOUNT_1, 0);
+
+ assertTrue(mListener.mCalledOnRefreshStatusChanged);
+ assertFalse(mListener.mCalledOnConnectionError);
+ assertEquals(ACCOUNT_1, mListener.mAccountId);
+ assertEquals(-1, mListener.mMailboxId);
+ mListener.reset();
+ assertTrue(mTarget.isMailboxListRefreshing(ACCOUNT_1));
+ assertEquals(0, mTarget.getMailboxListStatusForTest(ACCOUNT_1).getLastRefreshTime());
+
+ // Done.
+ Log.w(Email.LOG_TAG, "" + mController.mListener.getClass());
+ mController.mListener.updateMailboxListCallback(null, ACCOUNT_1, 100);
+
+ assertTrue(mListener.mCalledOnRefreshStatusChanged);
+ assertFalse(mListener.mCalledOnConnectionError);
+ assertEquals(ACCOUNT_1, mListener.mAccountId);
+ assertEquals(-1, mListener.mMailboxId);
+ mListener.reset();
+ assertFalse(mTarget.isMailboxListRefreshing(ACCOUNT_1));
+ assertEquals(mClock.mTime, mTarget.getMailboxListStatusForTest(ACCOUNT_1)
+ .getLastRefreshTime());
+
+ // Check "any" method.
+ assertTrue(mTarget.isRefreshingAnyMailboxList()); // still refreshing account 2
+
+ // Refreshing for account 2...
+ mClock.advance();
+
+ mController.mListener.updateMailboxListCallback(null, ACCOUNT_2, 0);
+
+ assertTrue(mListener.mCalledOnRefreshStatusChanged);
+ assertFalse(mListener.mCalledOnConnectionError);
+ assertEquals(ACCOUNT_2, mListener.mAccountId);
+ assertEquals(-1, mListener.mMailboxId);
+ mListener.reset();
+ assertTrue(mTarget.isMailboxListRefreshing(ACCOUNT_2));
+ assertEquals(0, mTarget.getMailboxListStatusForTest(ACCOUNT_2).getLastRefreshTime());
+
+ // Done with exception.
+ mController.mListener.updateMailboxListCallback(EXCEPTION, ACCOUNT_2, 0);
+
+ assertTrue(mListener.mCalledOnRefreshStatusChanged);
+ assertTrue(mListener.mCalledOnConnectionError);
+ assertEquals(ACCOUNT_2, mListener.mAccountId);
+ assertEquals(-1, mListener.mMailboxId);
+ assertEquals(EXCEPTION.getUiErrorMessage(mContext), mListener.mMessage);
+ mListener.reset();
+ assertFalse(mTarget.isMailboxListRefreshing(ACCOUNT_2));
+ assertEquals(mClock.mTime, mTarget.getMailboxListStatusForTest(ACCOUNT_2)
+ .getLastRefreshTime());
+
+ // Check "any" method.
+ assertFalse(mTarget.isRefreshingAnyMailboxList());
+ }
+
+ public void testRefreshMessageList() {
+ // request refresh mailbox 1
+ assertTrue(mTarget.refreshMessageList(ACCOUNT_1, MAILBOX_1));
+
+ assertTrue(mListener.mCalledOnRefreshStatusChanged);
+ assertFalse(mListener.mCalledOnConnectionError);
+ assertEquals(ACCOUNT_1, mListener.mAccountId);
+ assertEquals(MAILBOX_1, mListener.mMailboxId);
+ mListener.reset();
+ assertTrue(mController.mCalledUpdateMailbox);
+ assertEquals(ACCOUNT_1, mController.mAccountId);
+ assertEquals(MAILBOX_1, mController.mMailboxId);
+ mController.reset();
+ assertTrue(mTarget.isMessageListRefreshing(MAILBOX_1));
+ assertTrue(mTarget.isRefreshingAnyMessageList());
+
+ // Request again -- shouldn't be accepted.
+ assertFalse(mTarget.refreshMessageList(ACCOUNT_1, MAILBOX_1));
+
+ assertFalse(mListener.mCalledOnRefreshStatusChanged);
+ assertFalse(mListener.mCalledOnConnectionError);
+ mListener.reset();
+ assertFalse(mController.mCalledUpdateMailbox);
+ mController.reset();
+
+ // request refresh mailbox 2
+ assertTrue(mTarget.refreshMessageList(ACCOUNT_2, MAILBOX_2));
+
+ assertTrue(mListener.mCalledOnRefreshStatusChanged);
+ assertFalse(mListener.mCalledOnConnectionError);
+ assertEquals(ACCOUNT_2, mListener.mAccountId);
+ assertEquals(MAILBOX_2, mListener.mMailboxId);
+ mListener.reset();
+ assertTrue(mController.mCalledUpdateMailbox);
+ assertEquals(ACCOUNT_2, mController.mAccountId);
+ assertEquals(MAILBOX_2, mController.mMailboxId);
+ mController.reset();
+ assertTrue(mTarget.isMessageListRefreshing(MAILBOX_2));
+ assertTrue(mTarget.isRefreshingAnyMessageList());
+
+ // Refreshing mailbox 1...
+ mController.mListener.updateMailboxCallback(null, ACCOUNT_1, MAILBOX_1, 0, 0);
+
+ assertTrue(mListener.mCalledOnRefreshStatusChanged);
+ assertFalse(mListener.mCalledOnConnectionError);
+ assertEquals(ACCOUNT_1, mListener.mAccountId);
+ assertEquals(MAILBOX_1, mListener.mMailboxId);
+ mListener.reset();
+ assertTrue(mTarget.isMessageListRefreshing(MAILBOX_1));
+ assertEquals(0, mTarget.getMessageListStatusForTest(MAILBOX_1).getLastRefreshTime());
+
+ // Done.
+ Log.w(Email.LOG_TAG, "" + mController.mListener.getClass());
+ mController.mListener.updateMailboxCallback(null, ACCOUNT_1, MAILBOX_1, 100, 0);
+
+ assertTrue(mListener.mCalledOnRefreshStatusChanged);
+ assertFalse(mListener.mCalledOnConnectionError);
+ assertEquals(ACCOUNT_1, mListener.mAccountId);
+ assertEquals(MAILBOX_1, mListener.mMailboxId);
+ mListener.reset();
+ assertFalse(mTarget.isMessageListRefreshing(MAILBOX_1));
+ assertEquals(mClock.mTime, mTarget.getMessageListStatusForTest(MAILBOX_1)
+ .getLastRefreshTime());
+
+ // Check "any" method.
+ assertTrue(mTarget.isRefreshingAnyMessageList()); // still refreshing mailbox 2
+
+ // Refreshing mailbox 2...
+ mClock.advance();
+
+ mController.mListener.updateMailboxCallback(null, ACCOUNT_2, MAILBOX_2, 0, 0);
+
+ assertTrue(mListener.mCalledOnRefreshStatusChanged);
+ assertFalse(mListener.mCalledOnConnectionError);
+ assertEquals(ACCOUNT_2, mListener.mAccountId);
+ assertEquals(MAILBOX_2, mListener.mMailboxId);
+ mListener.reset();
+ assertTrue(mTarget.isMessageListRefreshing(MAILBOX_2));
+ assertEquals(0, mTarget.getMessageListStatusForTest(MAILBOX_2).getLastRefreshTime());
+
+ // Done with exception.
+ mController.mListener.updateMailboxCallback(EXCEPTION, ACCOUNT_2, MAILBOX_2, 0, 0);
+
+ assertTrue(mListener.mCalledOnRefreshStatusChanged);
+ assertTrue(mListener.mCalledOnConnectionError);
+ assertEquals(ACCOUNT_2, mListener.mAccountId);
+ assertEquals(MAILBOX_2, mListener.mMailboxId);
+ assertEquals(EXCEPTION.getUiErrorMessage(mContext), mListener.mMessage);
+ mListener.reset();
+ assertFalse(mTarget.isMessageListRefreshing(MAILBOX_2));
+ assertEquals(mClock.mTime, mTarget.getMessageListStatusForTest(MAILBOX_2)
+ .getLastRefreshTime());
+
+ // Check "any" method.
+ assertFalse(mTarget.isRefreshingAnyMessageList());
+ }
+
+ public void testSendPendingMessages() {
+ // request sending for account 1
+ assertTrue(mTarget.sendPendingMessages(ACCOUNT_1));
+
+ assertTrue(mListener.mCalledOnRefreshStatusChanged);
+ assertFalse(mListener.mCalledOnConnectionError);
+ assertEquals(ACCOUNT_1, mListener.mAccountId);
+ assertEquals(-1, mListener.mMailboxId);
+ mListener.reset();
+ assertTrue(mController.mCalledSendPendingMessages);
+ assertEquals(ACCOUNT_1, mController.mAccountId);
+ assertEquals(-1, mController.mMailboxId);
+ mController.reset();
+ assertTrue(mTarget.isSendingMessage(ACCOUNT_1));
+ assertTrue(mTarget.isSendingAnyMessage());
+
+ // Request again -- shouldn't be accepted.
+ assertFalse(mTarget.sendPendingMessages(ACCOUNT_1));
+
+ assertFalse(mListener.mCalledOnRefreshStatusChanged);
+ assertFalse(mListener.mCalledOnConnectionError);
+ mListener.reset();
+ assertFalse(mController.mCalledSendPendingMessages);
+ mController.reset();
+
+ // request sending for account 2
+ assertTrue(mTarget.sendPendingMessages(ACCOUNT_2));
+
+ assertTrue(mListener.mCalledOnRefreshStatusChanged);
+ assertFalse(mListener.mCalledOnConnectionError);
+ assertEquals(ACCOUNT_2, mListener.mAccountId);
+ assertEquals(-1, mListener.mMailboxId);
+ mListener.reset();
+ assertTrue(mController.mCalledSendPendingMessages);
+ assertEquals(ACCOUNT_2, mController.mAccountId);
+ assertEquals(-1, mController.mMailboxId);
+ mController.reset();
+ assertTrue(mTarget.isSendingMessage(ACCOUNT_2));
+ assertTrue(mTarget.isSendingAnyMessage());
+
+ // sending for account 1...
+ mController.mListener.sendMailCallback(null, ACCOUNT_1, -1, 0);
+
+ assertTrue(mListener.mCalledOnRefreshStatusChanged);
+ assertFalse(mListener.mCalledOnConnectionError);
+ assertEquals(ACCOUNT_1, mListener.mAccountId);
+ assertEquals(-1, mListener.mMailboxId);
+ mListener.reset();
+ assertTrue(mTarget.isSendingMessage(ACCOUNT_1));
+ assertEquals(0, mTarget.getOutboxStatusForTest(ACCOUNT_1).getLastRefreshTime());
+
+ // Per message callback (1)
+ mController.mListener.sendMailCallback(null, ACCOUNT_1, 100, 0);
+ mController.mListener.sendMailCallback(null, ACCOUNT_1, 101, 0);
+
+ // No callback per message
+ assertFalse(mListener.mCalledOnRefreshStatusChanged);
+ assertFalse(mListener.mCalledOnConnectionError);
+ mListener.reset();
+
+ // Exception -- first error will be reported.
+ mController.mListener.sendMailCallback(EXCEPTION, ACCOUNT_1, 102, 0);
+
+ assertFalse(mListener.mCalledOnRefreshStatusChanged);
+ assertTrue(mListener.mCalledOnConnectionError);
+ assertEquals(EXCEPTION.getUiErrorMessage(mContext), mListener.mMessage);
+ mListener.reset();
+
+ // Exception again -- no more error callbacks
+ mController.mListener.sendMailCallback(null, ACCOUNT_1, 103, 0);
+ mController.mListener.sendMailCallback(EXCEPTION, ACCOUNT_1, 104, 0);
+
+ assertFalse(mListener.mCalledOnRefreshStatusChanged);
+ assertFalse(mListener.mCalledOnConnectionError);
+ mListener.reset();
+
+ // Done.
+ Log.w(Email.LOG_TAG, "" + mController.mListener.getClass());
+ mController.mListener.sendMailCallback(null, ACCOUNT_1, -1, 100);
+
+ assertTrue(mListener.mCalledOnRefreshStatusChanged);
+ assertFalse(mListener.mCalledOnConnectionError);
+ assertEquals(ACCOUNT_1, mListener.mAccountId);
+ assertEquals(-1, mListener.mMailboxId);
+ mListener.reset();
+ assertFalse(mTarget.isSendingMessage(ACCOUNT_1));
+ assertEquals(mClock.mTime, mTarget.getOutboxStatusForTest(ACCOUNT_1)
+ .getLastRefreshTime());
+
+ // Check "any" method.
+ assertTrue(mTarget.isSendingAnyMessage()); // still sending for account 2
+
+ // sending for account 2...
+ mClock.advance();
+
+ mController.mListener.sendMailCallback(null, ACCOUNT_2, -1, 0);
+
+ assertTrue(mListener.mCalledOnRefreshStatusChanged);
+ assertFalse(mListener.mCalledOnConnectionError);
+ assertEquals(ACCOUNT_2, mListener.mAccountId);
+ assertEquals(-1, mListener.mMailboxId);
+ mListener.reset();
+ assertTrue(mTarget.isSendingMessage(ACCOUNT_2));
+ assertEquals(0, mTarget.getOutboxStatusForTest(ACCOUNT_2).getLastRefreshTime());
+
+ // Done with exception.
+ mController.mListener.sendMailCallback(EXCEPTION, ACCOUNT_2, -1, 0);
+
+ assertTrue(mListener.mCalledOnRefreshStatusChanged);
+ assertTrue(mListener.mCalledOnConnectionError);
+ assertEquals(ACCOUNT_2, mListener.mAccountId);
+ assertEquals(-1, mListener.mMailboxId);
+ assertEquals(EXCEPTION.getUiErrorMessage(mContext), mListener.mMessage);
+ mListener.reset();
+ assertFalse(mTarget.isSendingMessage(ACCOUNT_2));
+ assertEquals(mClock.mTime, mTarget.getOutboxStatusForTest(ACCOUNT_2)
+ .getLastRefreshTime());
+
+ // Check "any" method.
+ assertFalse(mTarget.isSendingAnyMessage());
+ }
+
+ public void testSendPendingMessagesForAllAccounts() {
+ Account acct1 = ProviderTestUtils.setupAccount("acct1", true, mProviderContext);
+ Account acct2 = ProviderTestUtils.setupAccount("acct2", true, mProviderContext);
+
+ mTarget.sendPendingMessagesForAllAccountsSync();
+ assertTrue(mController.mCalledSendPendingMessages);
+
+ MoreAsserts.assertEquals(new Long[] {acct1.mId, acct2.mId}, mListener.getAccountIds());
+ }
+
+ private static class MockController extends Controller {
+ public long mAccountId = -1;
+ public long mMailboxId = -1;
+ public boolean mCalledSendPendingMessages;
+ public boolean mCalledUpdateMailbox;
+ public boolean mCalledUpdateMailboxList;
+ public Result mListener;
+
+ protected MockController(Context context) {
+ super(context);
+ }
+
+ public void reset() {
+ mAccountId = -1;
+ mMailboxId = -1;
+ mCalledSendPendingMessages = false;
+ mCalledUpdateMailbox = false;
+ mCalledUpdateMailboxList = false;
+ }
+
+ @Override
+ public void sendPendingMessages(long accountId) {
+ mCalledSendPendingMessages = true;
+ mAccountId = accountId;
+ }
+
+ @Override
+ public void updateMailbox(long accountId, long mailboxId) {
+ mCalledUpdateMailbox = true;
+ mAccountId = accountId;
+ mMailboxId = mailboxId;
+ }
+
+ @Override
+ public void updateMailboxList(long accountId) {
+ mCalledUpdateMailboxList = true;
+ mAccountId = accountId;
+ }
+
+ @Override
+ public void addResultCallback(Result listener) {
+ Assert.assertTrue(mListener == null);
+ mListener = listener;
+ }
+ }
+
+ private static class RefreshListener implements RefreshManager.Listener {
+ public long mAccountId = -1;
+ public long mMailboxId = -1;
+ public String mMessage;
+ public boolean mCalledOnConnectionError;
+ public boolean mCalledOnRefreshStatusChanged;
+ private final ArrayList mAccountIds = new ArrayList();
+
+ public void reset() {
+ mAccountId = -1;
+ mMailboxId = -1;
+ mMessage = null;
+ mAccountIds.clear();
+ mCalledOnConnectionError = false;
+ mCalledOnRefreshStatusChanged = false;
+ }
+
+ @Override
+ public void onRefreshStatusChanged(long accountId, long mailboxId) {
+ mAccountId = accountId;
+ mMailboxId = mailboxId;
+ mAccountIds.add(mAccountId);
+ mCalledOnRefreshStatusChanged = true;
+ }
+
+ @Override
+ public void onMessagingError(long accountId, long mailboxId, String message) {
+ mAccountId = accountId;
+ mMailboxId = mailboxId;
+ mMessage = message;
+ mAccountIds.add(mAccountId);
+ mCalledOnConnectionError = true;
+ }
+
+ public Long[] getAccountIds() {
+ return mAccountIds.toArray(new Long[0]);
+ }
+ }
+}