Rework/cleanup of "refresh".
Added RefreshManager, which is responsible for getting refresh requests from UI and keeping track of what is being refreshed. Conceptually it's a part of Controller, but extracted for easier testing. - Now sendPendingMessagesForAllAccounts() is owned by RefreshManager rather than Controller. - Also updateMailboxRefreshTime/mailboxRequiresRefresh have been moved in from the Email class. - Now MessagingException implements a method to return an error message for the UI. The refresh button on 2-pane doesn't work as intended yet, because the spec is a bit too complicated (as described in the TODO in MessageListXLFragmentManager.onRefhres()). This change touches many file mostly because it cleans up a lot of code duplication. Change-Id: I058ab745ccff10f6e574f6ec4569c84ac4a3e10e
This commit is contained in:
parent
f513fbd8cb
commit
21efedb67f
32
src/com/android/email/Clock.java
Normal file
32
src/com/android/email/Clock.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
@ -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:
|
||||
|
@ -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.
|
||||
*
|
||||
* <p>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<T extends Result> extends Result {
|
||||
private final Handler mHandler;
|
||||
@ -38,10 +41,18 @@ public class ControllerResultUiThreadWrapper<T extends Result> 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<T extends Result> 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<T extends Result> 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<T extends Result> 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<T extends Result> 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<T extends Result> 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<T extends Result> extends Result {
|
||||
|
||||
@Override
|
||||
public void deleteAccountCallback(final long accountId) {
|
||||
mHandler.post(new Runnable() {
|
||||
run(new Runnable() {
|
||||
public void run() {
|
||||
mWrappee.deleteAccountCallback(accountId);
|
||||
}
|
||||
|
@ -141,9 +141,6 @@ public class Email extends Application {
|
||||
*/
|
||||
public static final int MAX_ATTACHMENT_UPLOAD_SIZE = (5 * 1024 * 1024);
|
||||
|
||||
private static HashMap<Long, Long> sMailboxSyncTimes = new HashMap<Long, Long>();
|
||||
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.
|
||||
|
@ -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
|
||||
*/
|
||||
|
443
src/com/android/email/RefreshManager.java
Normal file
443
src/com/android/email/RefreshManager.java
Normal file
@ -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.
|
||||
*
|
||||
* <p>This class is responsible for two things:
|
||||
* <ul>
|
||||
* <li>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.
|
||||
* <li>Keeping track of which mailbox list/message list is actually being refreshed.
|
||||
* </ul>
|
||||
* Refresh requests will be ignored if a request to the same target is already requested, or is
|
||||
* already being refreshed.
|
||||
*
|
||||
* <p>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<Listener> mListeners = new ArrayList<Listener>();
|
||||
|
||||
/**
|
||||
* 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<Long, Status> mMap = new HashMap<Long, Status>();
|
||||
|
||||
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<ControllerResult>(
|
||||
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<Listener> 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
* </ul>
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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.
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -16,6 +16,10 @@
|
||||
|
||||
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.
|
||||
*
|
||||
@ -97,4 +101,32 @@ public class MessagingException extends Exception {
|
||||
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
|
||||
}
|
||||
}
|
@ -655,8 +655,6 @@ public class MailService extends Service {
|
||||
updateAccountReport(accountId, -1);
|
||||
}
|
||||
}
|
||||
// Call the global refresh tracker for all mailboxes
|
||||
Email.updateMailboxRefreshTime(mailboxId);
|
||||
}
|
||||
}
|
||||
|
||||
|
32
tests/src/com/android/email/MockClock.java
Normal file
32
tests/src/com/android/email/MockClock.java
Normal file
@ -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++;
|
||||
}
|
||||
}
|
532
tests/src/com/android/email/RefreshManagerTest.java
Normal file
532
tests/src/com/android/email/RefreshManagerTest.java
Normal file
@ -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<Long> mAccountIds = new ArrayList<Long>();
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user