RefreshManager.java revision e357f5879187124c7af5c2ece5d7d3e4f60f07d2
121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki/* 221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Copyright (C) 2010 The Android Open Source Project 321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * 421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Licensed under the Apache License, Version 2.0 (the "License"); 521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * you may not use this file except in compliance with the License. 621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * You may obtain a copy of the License at 721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * 821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * http://www.apache.org/licenses/LICENSE-2.0 921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * 1021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Unless required by applicable law or agreed to in writing, software 1121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * distributed under the License is distributed on an "AS IS" BASIS, 1221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * See the License for the specific language governing permissions and 1421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * limitations under the License. 1521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 1621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 1721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onukipackage com.android.email; 1821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 1921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onukiimport com.android.email.mail.MessagingException; 2021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 2121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onukiimport android.content.Context; 2221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onukiimport android.os.Handler; 2321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onukiimport android.util.Log; 2421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 2521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onukiimport java.security.InvalidParameterException; 2621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onukiimport java.util.ArrayList; 2721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onukiimport java.util.Collection; 2821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onukiimport java.util.HashMap; 2921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 3021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki/** 3121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Class that handles "refresh" (and "send pending messages" for outboxes) related functionalities. 3221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * 3321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * <p>This class is responsible for two things: 3421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * <ul> 3521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * <li>Taking refresh requests of mailbox-lists and message-lists and the "send outgoing 3621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * messages" requests from UI, and calls appropriate methods of {@link Controller}. 3721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Note at this point the timer-based refresh 3821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * (by {@link com.android.email.service.MailService}) uses {@link Controller} directly. 3921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * <li>Keeping track of which mailbox list/message list is actually being refreshed. 4021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * </ul> 4121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Refresh requests will be ignored if a request to the same target is already requested, or is 4221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * already being refreshed. 4321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * 4421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * <p>Conceptually it can be a part of {@link Controller}, but extracted for easy testing. 45715a19be28723908dbf332b9a9029993510dad0eMakoto Onuki * 46e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki * (All public methods must be called on the UI thread. All callbacks will be called on the UI 47715a19be28723908dbf332b9a9029993510dad0eMakoto Onuki * thread.) 4821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 4921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onukipublic class RefreshManager { 5021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private static final boolean DEBUG_CALLBACK_LOG = true; 5121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private static final long MAILBOX_AUTO_REFRESH_INTERVAL = 5 * 60 * 1000; // in milliseconds 5221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 5321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private static RefreshManager sInstance; 5421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 5521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private final Clock mClock; 5621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private final Context mContext; 5721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private final Controller mController; 5821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private final Controller.Result mControllerResult; 5921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 6021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** Last error message */ 6121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private String mErrorMessage; 6221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 6321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public interface Listener { 6421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public void onRefreshStatusChanged(long accountId, long mailboxId); 6521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public void onMessagingError(long accountId, long mailboxId, String message); 6621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 6721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 6821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private final ArrayList<Listener> mListeners = new ArrayList<Listener>(); 6921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 7021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 7121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Status of a mailbox list/message list. 7221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 7321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /* package */ static class Status { 7421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 7521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * True if a refresh of the mailbox is requested, and not finished yet. 7621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 7721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private boolean mIsRefreshRequested; 7821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 7921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 8021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * True if the mailbox is being refreshed. 8121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * 8221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Set true when {@link #onRefreshRequested} is called, i.e. refresh is requested by UI. 8321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Note refresh can occur without a request from UI as well (e.g. timer based refresh). 8421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * In which case, {@link #mIsRefreshing} will be true with {@link #mIsRefreshRequested} 8521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * being false. 8621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 8721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private boolean mIsRefreshing; 8821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 8921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private long mLastRefreshTime; 9021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 9121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean isRefreshing() { 9221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mIsRefreshRequested || mIsRefreshing; 9321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 9421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 9521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean canRefresh() { 9621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return !isRefreshing(); 9721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 9821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 9921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public void onRefreshRequested() { 10021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mIsRefreshRequested = true; 10121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 10221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 10321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public long getLastRefreshTime() { 10421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mLastRefreshTime; 10521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 10621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 10721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public void onCallback(MessagingException exception, int progress, Clock clock) { 10821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (exception == null && progress == 0) { 10921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki // Refresh started 11021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mIsRefreshing = true; 11121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } else if (exception != null || progress == 100) { 11221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki // Refresh finished 11321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mIsRefreshing = false; 11421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mIsRefreshRequested = false; 11521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mLastRefreshTime = clock.getTime(); 11621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 11721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 11821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 11921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 12021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 12121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Map of accounts/mailboxes to {@link Status}. 12221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 12321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private static class RefreshStatusMap { 12421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private final HashMap<Long, Status> mMap = new HashMap<Long, Status>(); 12521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 12621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public Status get(long id) { 12721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki Status s = mMap.get(id); 12821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (s == null) { 12921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki s = new Status(); 13021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mMap.put(id, s); 13121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 13221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return s; 13321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 13421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 13521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean isRefreshingAny() { 13621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki for (Status s : mMap.values()) { 13721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (s.isRefreshing()) { 13821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return true; 13921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 14021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 14121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return false; 14221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 14321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 14421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 14521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private final RefreshStatusMap mMailboxListStatus = new RefreshStatusMap(); 14621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private final RefreshStatusMap mMessageListStatus = new RefreshStatusMap(); 14721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private final RefreshStatusMap mOutboxStatus = new RefreshStatusMap(); 14821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 14921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 15021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * @return the singleton instance. 15121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 15221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public static synchronized RefreshManager getInstance(Context context) { 15321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (sInstance == null) { 154c184f36c2df16431693d7709e28ded593efc3da7Marc Blank sInstance = new RefreshManager(context, Controller.getInstance(context), 15521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki Clock.INSTANCE, new Handler()); 15621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 15721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return sInstance; 15821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 15921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 160e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki protected RefreshManager(Context context, Controller controller, Clock clock, 16121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki Handler handler) { 16221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mClock = clock; 16321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mContext = context.getApplicationContext(); 16421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mController = controller; 16521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mControllerResult = new ControllerResultUiThreadWrapper<ControllerResult>( 16621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki handler, new ControllerResult()); 16721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mController.addResultCallback(mControllerResult); 16821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 16921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 170e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki /** 171e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki * MUST be called for mock instances. (The actual instance is a singleton, so no cleanup 172e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki * is necessary.) 173e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki */ 174e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki public void cleanUpForTest() { 175e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki mController.removeResultCallback(mControllerResult); 176e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki } 177e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki 17821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public void registerListener(Listener listener) { 17921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (listener == null) { 18021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki throw new InvalidParameterException(); 18121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 18221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mListeners.add(listener); 18321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 18421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 18521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public void unregisterListener(Listener listener) { 18621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (listener == null) { 18721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki throw new InvalidParameterException(); 18821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 18921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mListeners.remove(listener); 19021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 19121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 19221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 19321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Refresh the mailbox list of an account. 19421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 19521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean refreshMailboxList(long accountId) { 19621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki final Status status = mMailboxListStatus.get(accountId); 19721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (!status.canRefresh()) return false; 19821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 19921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki Log.i(Email.LOG_TAG, "refreshMailboxList " + accountId); 20021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki status.onRefreshRequested(); 20121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki notifyRefreshStatusChanged(accountId, -1); 20221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mController.updateMailboxList(accountId); 20321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return true; 20421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 20521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 20621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean isMailboxStale(long mailboxId) { 20721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mClock.getTime() >= (mMessageListStatus.get(mailboxId).getLastRefreshTime() 20821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki + MAILBOX_AUTO_REFRESH_INTERVAL); 20921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 21021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 21121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 21221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Refresh messages in a mailbox. 21321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 21421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean refreshMessageList(long accountId, long mailboxId) { 21521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return refreshMessageList(accountId, mailboxId, false); 21621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 21721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 21821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 21921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * "load more messages" in a mailbox. 22021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 22121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean loadMoreMessages(long accountId, long mailboxId) { 22221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return refreshMessageList(accountId, mailboxId, true); 22321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 22421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 22521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private boolean refreshMessageList(long accountId, long mailboxId, boolean loadMoreMessages) { 22621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki final Status status = mMessageListStatus.get(mailboxId); 22721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (!status.canRefresh()) return false; 22821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 22921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki Log.i(Email.LOG_TAG, "refreshMessageList " + accountId + ", " + mailboxId + ", " 23021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki + loadMoreMessages); 23121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki status.onRefreshRequested(); 23221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki notifyRefreshStatusChanged(accountId, mailboxId); 23321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mController.updateMailbox(accountId, mailboxId); 23421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return true; 23521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 23621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 23721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 23821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Send pending messages. 23921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 24021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean sendPendingMessages(long accountId) { 24121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki final Status status = mOutboxStatus.get(accountId); 24221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (!status.canRefresh()) return false; 24321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 24421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki Log.i(Email.LOG_TAG, "sendPendingMessages " + accountId); 24521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki status.onRefreshRequested(); 24621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki notifyRefreshStatusChanged(accountId, -1); 24721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mController.sendPendingMessages(accountId); 24821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return true; 24921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 25021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 25121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 25221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Call {@link #sendPendingMessages} for all accounts. 25321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 25421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public void sendPendingMessagesForAllAccounts() { 25521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki Log.i(Email.LOG_TAG, "sendPendingMessagesForAllAccounts"); 256f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki new SendPendingMessagesForAllAccountsImpl().execute(); 25721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 25821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 259f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki private class SendPendingMessagesForAllAccountsImpl extends Utility.ForEachAccount { 260f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki public SendPendingMessagesForAllAccountsImpl() { 261f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki super(mContext); 262f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki } 263f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki 264f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki @Override 265f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki protected void performAction(long accountId) { 266f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki sendPendingMessages(accountId); 26721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 26821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 26921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 270e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki public long getLastMailboxListRefreshTime(long accountId) { 271e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki return mMailboxListStatus.get(accountId).getLastRefreshTime(); 272e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki } 273e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki 274e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki public long getLastMessageListRefreshTime(long mailboxId) { 275e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki return mMessageListStatus.get(mailboxId).getLastRefreshTime(); 276e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki } 277e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki 278e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki public long getLastSendMessageTime(long accountId) { 279e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki return mOutboxStatus.get(accountId).getLastRefreshTime(); 280e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki } 281e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki 28221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean isMailboxListRefreshing(long accountId) { 28321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mMailboxListStatus.get(accountId).isRefreshing(); 28421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 28521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 28621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean isMessageListRefreshing(long mailboxId) { 28721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mMessageListStatus.get(mailboxId).isRefreshing(); 28821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 28921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 29021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean isSendingMessage(long accountId) { 29121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mOutboxStatus.get(accountId).isRefreshing(); 29221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 29321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 29421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean isRefreshingAnyMailboxList() { 29521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mMailboxListStatus.isRefreshingAny(); 29621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 29721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 29821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean isRefreshingAnyMessageList() { 29921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mMessageListStatus.isRefreshingAny(); 30021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 30121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 30221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean isSendingAnyMessage() { 30321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mOutboxStatus.isRefreshingAny(); 30421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 30521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 30621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean isRefreshingOrSendingAny() { 30721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return isRefreshingAnyMailboxList() || isRefreshingAnyMessageList() 30821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki || isSendingAnyMessage(); 30921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 31021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 31121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public String getErrorMessage() { 31221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mErrorMessage; 31321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 31421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 31521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private void notifyRefreshStatusChanged(long accountId, long mailboxId) { 31621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki for (Listener l : mListeners) { 31721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki l.onRefreshStatusChanged(accountId, mailboxId); 31821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 31921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 32021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 32121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private void reportError(long accountId, long mailboxId, String errorMessage) { 32221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mErrorMessage = errorMessage; 32321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki for (Listener l : mListeners) { 32421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki l.onMessagingError(accountId, mailboxId, mErrorMessage); 32521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 32621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 32721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 32821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /* package */ Collection<Listener> getListenersForTest() { 32921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mListeners; 33021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 33121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 33221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /* package */ Status getMailboxListStatusForTest(long accountId) { 33321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mMailboxListStatus.get(accountId); 33421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 33521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 33621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /* package */ Status getMessageListStatusForTest(long mailboxId) { 33721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mMessageListStatus.get(mailboxId); 33821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 33921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 34021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /* package */ Status getOutboxStatusForTest(long acountId) { 34121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mOutboxStatus.get(acountId); 34221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 34321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 34421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private class ControllerResult extends Controller.Result { 34521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private boolean mSendMailExceptionReported = false; 34621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 34721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private String exceptionToString(MessagingException exception) { 34821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (exception == null) { 34921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return "(no exception)"; 35021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } else { 35121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return exception.getUiErrorMessage(mContext); 35221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 35321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 35421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 35521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 35621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Callback for mailbox list refresh. 35721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 35821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki @Override 35921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public void updateMailboxListCallback(MessagingException exception, long accountId, 36021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki int progress) { 36121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (Email.DEBUG && DEBUG_CALLBACK_LOG) { 36221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki Log.d(Email.LOG_TAG, "updateMailboxListCallback " + accountId + ", " + progress 36321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki + ", " + exceptionToString(exception)); 36421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 36521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mMailboxListStatus.get(accountId).onCallback(exception, progress, mClock); 36621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (exception != null) { 36721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki reportError(accountId, -1, exception.getUiErrorMessage(mContext)); 36821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 36921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki notifyRefreshStatusChanged(accountId, -1); 37021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 37121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 37221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 37321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Callback for explicit (user-driven) mailbox refresh. 37421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 37521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki @Override 37621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public void updateMailboxCallback(MessagingException exception, long accountId, 37721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki long mailboxId, int progress, int dontUseNumNewMessages) { 37821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (Email.DEBUG && DEBUG_CALLBACK_LOG) { 37921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki Log.d(Email.LOG_TAG, "updateMailboxCallback " + accountId + ", " 38021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki + mailboxId + ", " + progress + ", " + exceptionToString(exception)); 38121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 38221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki updateMailboxCallbackInternal(exception, accountId, mailboxId, progress, 0); 38321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 38421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 38521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 38621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Callback for implicit (timer-based) mailbox refresh. 38721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * 38821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Do the same as {@link #updateMailboxCallback}. 38921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * TODO: Figure out if it's really okay to do the same as updateMailboxCallback. 39021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * If both the explicit refresh and the implicit refresh can run at the same time, 39121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * we need to keep track of their status separately. 39221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 39321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki @Override 39421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public void serviceCheckMailCallback( 39521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki MessagingException exception, long accountId, long mailboxId, int progress, 39621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki long tag) { 39721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (Email.DEBUG && DEBUG_CALLBACK_LOG) { 39821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki Log.d(Email.LOG_TAG, "serviceCheckMailCallback " + accountId + ", " 39921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki + mailboxId + ", " + progress + ", " + exceptionToString(exception)); 40021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 40121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki updateMailboxCallbackInternal(exception, accountId, mailboxId, progress, 0); 40221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 40321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 40421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private void updateMailboxCallbackInternal(MessagingException exception, long accountId, 40521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki long mailboxId, int progress, int dontUseNumNewMessages) { 40621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki // Don't use dontUseNumNewMessages. serviceCheckMailCallback() don't set it. 40721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mMessageListStatus.get(mailboxId).onCallback(exception, progress, mClock); 40821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (exception != null) { 40921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki reportError(accountId, mailboxId, exception.getUiErrorMessage(mContext)); 41021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 41121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki notifyRefreshStatusChanged(accountId, mailboxId); 41221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 41321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 41421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 41521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 41621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Send message progress callback. 41721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * 41821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * This callback is overly overloaded: 41921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * 42021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * First, we get this. 42121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * result == null, messageId == -1, progress == 0: start batch send 42221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * 42321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Then we get these callbacks per message. 42421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * (Exchange backend may skip "start sending one message".) 42521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * result == null, messageId == xx, progress == 0: start sending one message 42621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * result == xxxx, messageId == xx, progress == 0; failed sending one message 42721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * 42821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Finally we get this. 42921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * result == null, messageId == -1, progres == 100; finish sending batch 43021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * 43121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * So, let's just report the first exception we get, and ignore the rest. 43221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 43321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki @Override 43421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public void sendMailCallback(MessagingException exception, long accountId, long messageId, 43521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki int progress) { 43621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (Email.DEBUG && DEBUG_CALLBACK_LOG) { 43721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki Log.d(Email.LOG_TAG, "sendMailCallback " + accountId + ", " 43821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki + messageId + ", " + progress + ", " + exceptionToString(exception)); 43921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 44021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (progress == 0 && messageId == -1) { 44121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mSendMailExceptionReported = false; 44221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 44321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (messageId == -1) { 44421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki // Update the status only for the batch start/end. 44521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki // (i.e. don't report for each message.) 44621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mOutboxStatus.get(accountId).onCallback(exception, progress, mClock); 44721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki notifyRefreshStatusChanged(accountId, -1); 44821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 44921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (exception != null && !mSendMailExceptionReported) { 45021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki // Only the first error in a batch will be reported. 45121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mSendMailExceptionReported = true; 45221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki reportError(accountId, messageId, exception.getUiErrorMessage(mContext)); 45321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 45421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 45521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 45621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki} 457