RefreshManager.java revision 54c91f00d7f967690a80b992062e75c40182d088
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 1931d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blankimport com.android.emailcommon.Logging; 202193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.MessagingException; 2131d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blankimport com.android.emailcommon.utility.Utility; 2221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 2321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onukiimport android.content.Context; 2421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onukiimport android.os.Handler; 2521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onukiimport android.util.Log; 2621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 2721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onukiimport java.util.ArrayList; 2821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onukiimport java.util.Collection; 2921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onukiimport java.util.HashMap; 3021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 3121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki/** 3221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Class that handles "refresh" (and "send pending messages" for outboxes) related functionalities. 3321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * 3421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * <p>This class is responsible for two things: 3521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * <ul> 3621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * <li>Taking refresh requests of mailbox-lists and message-lists and the "send outgoing 3721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * messages" requests from UI, and calls appropriate methods of {@link Controller}. 3821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Note at this point the timer-based refresh 3921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * (by {@link com.android.email.service.MailService}) uses {@link Controller} directly. 4021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * <li>Keeping track of which mailbox list/message list is actually being refreshed. 4121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * </ul> 4221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Refresh requests will be ignored if a request to the same target is already requested, or is 4321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * already being refreshed. 4421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * 4521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * <p>Conceptually it can be a part of {@link Controller}, but extracted for easy testing. 46715a19be28723908dbf332b9a9029993510dad0eMakoto Onuki * 47e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki * (All public methods must be called on the UI thread. All callbacks will be called on the UI 48715a19be28723908dbf332b9a9029993510dad0eMakoto Onuki * thread.) 4921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 5021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onukipublic class RefreshManager { 51295297581c8af9b6ee0a41487b7fded08739890cMakoto Onuki private static final boolean LOG_ENABLED = false; // DONT SUBMIT WITH TRUE 5221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private static final long MAILBOX_AUTO_REFRESH_INTERVAL = 5 * 60 * 1000; // in milliseconds 536993130a7cb089da642ee689603a2f8487b3fd39Makoto Onuki private static final long MAILBOX_LIST_AUTO_REFRESH_INTERVAL = 5 * 60 * 1000; // in milliseconds 5421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 5521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private static RefreshManager sInstance; 5621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 5721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private final Clock mClock; 5821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private final Context mContext; 5921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private final Controller mController; 6021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private final Controller.Result mControllerResult; 6121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 6221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** Last error message */ 6321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private String mErrorMessage; 6421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 6521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public interface Listener { 66be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki /** 67be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * Refresh status of a mailbox list or a message list has changed. 68be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * 69be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * @param accountId ID of the account. 70be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * @param mailboxId -1 if it's about the mailbox list, or the ID of the mailbox list in 71be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * question. 72be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki */ 7321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public void onRefreshStatusChanged(long accountId, long mailboxId); 74be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki 75be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki /** 76be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * Error callback. 77be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * 78be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * @param accountId ID of the account, or -1 if unknown. 79be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * @param mailboxId ID of the mailbox, or -1 if unknown. 80be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * @param message error message which can be shown to the user. 81be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki */ 8221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public void onMessagingError(long accountId, long mailboxId, String message); 8321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 8421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 8521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private final ArrayList<Listener> mListeners = new ArrayList<Listener>(); 8621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 8721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 8821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Status of a mailbox list/message list. 8921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 9021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /* package */ static class Status { 9121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 9221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * True if a refresh of the mailbox is requested, and not finished yet. 9321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 9421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private boolean mIsRefreshRequested; 9521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 9621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 9721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * True if the mailbox is being refreshed. 9821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * 9921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Set true when {@link #onRefreshRequested} is called, i.e. refresh is requested by UI. 10021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Note refresh can occur without a request from UI as well (e.g. timer based refresh). 10121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * In which case, {@link #mIsRefreshing} will be true with {@link #mIsRefreshRequested} 10221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * being false. 10321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 10421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private boolean mIsRefreshing; 10521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 10621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private long mLastRefreshTime; 10721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 10821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean isRefreshing() { 10921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mIsRefreshRequested || mIsRefreshing; 11021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 11121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 11221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean canRefresh() { 11321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return !isRefreshing(); 11421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 11521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 11621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public void onRefreshRequested() { 11721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mIsRefreshRequested = true; 11821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 11921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 12021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public long getLastRefreshTime() { 12121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mLastRefreshTime; 12221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 12321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 12421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public void onCallback(MessagingException exception, int progress, Clock clock) { 12521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (exception == null && progress == 0) { 12621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki // Refresh started 12721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mIsRefreshing = true; 12821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } else if (exception != null || progress == 100) { 12921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki // Refresh finished 13021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mIsRefreshing = false; 13121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mIsRefreshRequested = false; 13221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mLastRefreshTime = clock.getTime(); 13321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 13421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 13521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 13621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 13721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 13821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Map of accounts/mailboxes to {@link Status}. 13921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 14021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private static class RefreshStatusMap { 14121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private final HashMap<Long, Status> mMap = new HashMap<Long, Status>(); 14221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 14321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public Status get(long id) { 14421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki Status s = mMap.get(id); 14521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (s == null) { 14621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki s = new Status(); 14721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mMap.put(id, s); 14821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 14921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return s; 15021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 15121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 15221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean isRefreshingAny() { 15321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki for (Status s : mMap.values()) { 15421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (s.isRefreshing()) { 15521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return true; 15621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 15721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 15821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return false; 15921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 16021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 16121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 16221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private final RefreshStatusMap mMailboxListStatus = new RefreshStatusMap(); 16321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private final RefreshStatusMap mMessageListStatus = new RefreshStatusMap(); 16421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 16521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 16621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * @return the singleton instance. 16721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 16821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public static synchronized RefreshManager getInstance(Context context) { 16921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (sInstance == null) { 170c184f36c2df16431693d7709e28ded593efc3da7Marc Blank sInstance = new RefreshManager(context, Controller.getInstance(context), 17121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki Clock.INSTANCE, new Handler()); 17221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 17321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return sInstance; 17421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 17521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 176e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki protected RefreshManager(Context context, Controller controller, Clock clock, 17721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki Handler handler) { 17821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mClock = clock; 17921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mContext = context.getApplicationContext(); 18021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mController = controller; 18121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mControllerResult = new ControllerResultUiThreadWrapper<ControllerResult>( 18221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki handler, new ControllerResult()); 18321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mController.addResultCallback(mControllerResult); 18421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 18521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 186e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki /** 187e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki * MUST be called for mock instances. (The actual instance is a singleton, so no cleanup 188e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki * is necessary.) 189e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki */ 190e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki public void cleanUpForTest() { 191e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki mController.removeResultCallback(mControllerResult); 192e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki } 193e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki 19421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public void registerListener(Listener listener) { 19521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (listener == null) { 19654c91f00d7f967690a80b992062e75c40182d088Makoto Onuki throw new IllegalArgumentException(); 19721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 19821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mListeners.add(listener); 19921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 20021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 20121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public void unregisterListener(Listener listener) { 20221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (listener == null) { 20354c91f00d7f967690a80b992062e75c40182d088Makoto Onuki throw new IllegalArgumentException(); 20421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 20521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mListeners.remove(listener); 20621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 20721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 20821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 20921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Refresh the mailbox list of an account. 21021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 21121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean refreshMailboxList(long accountId) { 21221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki final Status status = mMailboxListStatus.get(accountId); 21321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (!status.canRefresh()) return false; 21421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 215295297581c8af9b6ee0a41487b7fded08739890cMakoto Onuki if (LOG_ENABLED) { 21631d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank Log.d(Logging.LOG_TAG, "refreshMailboxList " + accountId); 217295297581c8af9b6ee0a41487b7fded08739890cMakoto Onuki } 21821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki status.onRefreshRequested(); 21921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki notifyRefreshStatusChanged(accountId, -1); 22021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mController.updateMailboxList(accountId); 22121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return true; 22221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 22321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 22421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean isMailboxStale(long mailboxId) { 22521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mClock.getTime() >= (mMessageListStatus.get(mailboxId).getLastRefreshTime() 22621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki + MAILBOX_AUTO_REFRESH_INTERVAL); 22721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 22821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 2296993130a7cb089da642ee689603a2f8487b3fd39Makoto Onuki public boolean isMailboxListStale(long accountId) { 2306993130a7cb089da642ee689603a2f8487b3fd39Makoto Onuki return mClock.getTime() >= (mMailboxListStatus.get(accountId).getLastRefreshTime() 2316993130a7cb089da642ee689603a2f8487b3fd39Makoto Onuki + MAILBOX_LIST_AUTO_REFRESH_INTERVAL); 2326993130a7cb089da642ee689603a2f8487b3fd39Makoto Onuki } 2336993130a7cb089da642ee689603a2f8487b3fd39Makoto Onuki 23421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 23521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Refresh messages in a mailbox. 23621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 237cbdd9f78b2605e87e45e4f6761b0a8c444a8cd4cMarc Blank public boolean refreshMessageList(long accountId, long mailboxId, boolean userRequest) { 238cbdd9f78b2605e87e45e4f6761b0a8c444a8cd4cMarc Blank return refreshMessageList(accountId, mailboxId, false, userRequest); 23921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 24021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 24121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 24221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * "load more messages" in a mailbox. 24321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 24421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean loadMoreMessages(long accountId, long mailboxId) { 245a796fbab0237c094aa943de68f85d201dd22503bMakoto Onuki return refreshMessageList(accountId, mailboxId, true, true); 24621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 24721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 248cbdd9f78b2605e87e45e4f6761b0a8c444a8cd4cMarc Blank private boolean refreshMessageList(long accountId, long mailboxId, boolean loadMoreMessages, 249cbdd9f78b2605e87e45e4f6761b0a8c444a8cd4cMarc Blank boolean userRequest) { 25021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki final Status status = mMessageListStatus.get(mailboxId); 25121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (!status.canRefresh()) return false; 25221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 253295297581c8af9b6ee0a41487b7fded08739890cMakoto Onuki if (LOG_ENABLED) { 25431d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank Log.d(Logging.LOG_TAG, "refreshMessageList " + accountId + ", " + mailboxId + ", " 255295297581c8af9b6ee0a41487b7fded08739890cMakoto Onuki + loadMoreMessages); 256295297581c8af9b6ee0a41487b7fded08739890cMakoto Onuki } 25721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki status.onRefreshRequested(); 25821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki notifyRefreshStatusChanged(accountId, mailboxId); 2590d21aa395ae21857fb5ab74db7c284eda49729d4Makoto Onuki if (loadMoreMessages) { 2600d21aa395ae21857fb5ab74db7c284eda49729d4Makoto Onuki mController.loadMoreMessages(mailboxId); 2610d21aa395ae21857fb5ab74db7c284eda49729d4Makoto Onuki } else { 262cbdd9f78b2605e87e45e4f6761b0a8c444a8cd4cMarc Blank mController.updateMailbox(accountId, mailboxId, userRequest); 2630d21aa395ae21857fb5ab74db7c284eda49729d4Makoto Onuki } 26421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return true; 26521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 26621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 26721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 26821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Send pending messages. 26921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 27021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean sendPendingMessages(long accountId) { 271295297581c8af9b6ee0a41487b7fded08739890cMakoto Onuki if (LOG_ENABLED) { 27231d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank Log.d(Logging.LOG_TAG, "sendPendingMessages " + accountId); 273295297581c8af9b6ee0a41487b7fded08739890cMakoto Onuki } 27421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki notifyRefreshStatusChanged(accountId, -1); 27521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mController.sendPendingMessages(accountId); 27621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return true; 27721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 27821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 27921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 28021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Call {@link #sendPendingMessages} for all accounts. 28121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 28221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public void sendPendingMessagesForAllAccounts() { 283295297581c8af9b6ee0a41487b7fded08739890cMakoto Onuki if (LOG_ENABLED) { 28431d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank Log.d(Logging.LOG_TAG, "sendPendingMessagesForAllAccounts"); 285295297581c8af9b6ee0a41487b7fded08739890cMakoto Onuki } 286f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki new SendPendingMessagesForAllAccountsImpl().execute(); 28721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 28821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 289f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki private class SendPendingMessagesForAllAccountsImpl extends Utility.ForEachAccount { 290f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki public SendPendingMessagesForAllAccountsImpl() { 291f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki super(mContext); 292f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki } 293f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki 294f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki @Override 295f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki protected void performAction(long accountId) { 296f52afae9424fe41071cc34a8d6cbcb82b992a411Makoto Onuki sendPendingMessages(accountId); 29721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 29821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 29921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 300e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki public long getLastMailboxListRefreshTime(long accountId) { 301e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki return mMailboxListStatus.get(accountId).getLastRefreshTime(); 302e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki } 303e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki 304e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki public long getLastMessageListRefreshTime(long mailboxId) { 305e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki return mMessageListStatus.get(mailboxId).getLastRefreshTime(); 306e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki } 307e357f5879187124c7af5c2ece5d7d3e4f60f07d2Makoto Onuki 30821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean isMailboxListRefreshing(long accountId) { 30921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mMailboxListStatus.get(accountId).isRefreshing(); 31021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 31121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 31221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public boolean isMessageListRefreshing(long mailboxId) { 31321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mMessageListStatus.get(mailboxId).isRefreshing(); 31421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 31521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 316c1e8c95d053464e0821d45347704bd6c27e7e546Andy Stadler public boolean isRefreshingAnyMailboxListForTest() { 31721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mMailboxListStatus.isRefreshingAny(); 31821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 31921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 320c1e8c95d053464e0821d45347704bd6c27e7e546Andy Stadler public boolean isRefreshingAnyMessageListForTest() { 32121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mMessageListStatus.isRefreshingAny(); 32221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 32321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 32421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public String getErrorMessage() { 32521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mErrorMessage; 32621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 32721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 32821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private void notifyRefreshStatusChanged(long accountId, long mailboxId) { 32921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki for (Listener l : mListeners) { 33021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki l.onRefreshStatusChanged(accountId, mailboxId); 33121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 33221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 33321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 33421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private void reportError(long accountId, long mailboxId, String errorMessage) { 33521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mErrorMessage = errorMessage; 33621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki for (Listener l : mListeners) { 33721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki l.onMessagingError(accountId, mailboxId, mErrorMessage); 33821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 33921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 34021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 34121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /* package */ Collection<Listener> getListenersForTest() { 34221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mListeners; 34321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 34421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 34521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /* package */ Status getMailboxListStatusForTest(long accountId) { 34621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mMailboxListStatus.get(accountId); 34721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 34821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 34921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /* package */ Status getMessageListStatusForTest(long mailboxId) { 35021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return mMessageListStatus.get(mailboxId); 35121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 35221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 35321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private class ControllerResult extends Controller.Result { 35421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private boolean mSendMailExceptionReported = false; 35521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 35621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private String exceptionToString(MessagingException exception) { 35721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (exception == null) { 35821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki return "(no exception)"; 35921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } else { 36031d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank return MessagingExceptionStrings.getErrorString(mContext, exception); 36121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 36221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 36321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 36421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 36521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Callback for mailbox list refresh. 36621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 36721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki @Override 36821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public void updateMailboxListCallback(MessagingException exception, long accountId, 36921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki int progress) { 370295297581c8af9b6ee0a41487b7fded08739890cMakoto Onuki if (LOG_ENABLED) { 37131d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank Log.d(Logging.LOG_TAG, "updateMailboxListCallback " + accountId + ", " + progress 37221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki + ", " + exceptionToString(exception)); 37321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 37421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mMailboxListStatus.get(accountId).onCallback(exception, progress, mClock); 37521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (exception != null) { 37631d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank reportError(accountId, -1, 37731d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank MessagingExceptionStrings.getErrorString(mContext, exception)); 37821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 37921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki notifyRefreshStatusChanged(accountId, -1); 38021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 38121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 38221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 38321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Callback for explicit (user-driven) mailbox refresh. 38421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 38521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki @Override 38621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public void updateMailboxCallback(MessagingException exception, long accountId, 387c4cdb11d24c19428dd39f986b00c1a29e75e1505Todd Kennedy long mailboxId, int progress, int dontUseNumNewMessages, 388c4cdb11d24c19428dd39f986b00c1a29e75e1505Todd Kennedy ArrayList<Long> addedMessages) { 389295297581c8af9b6ee0a41487b7fded08739890cMakoto Onuki if (LOG_ENABLED) { 39031d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank Log.d(Logging.LOG_TAG, "updateMailboxCallback " + accountId + ", " 39121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki + mailboxId + ", " + progress + ", " + exceptionToString(exception)); 39221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 39321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki updateMailboxCallbackInternal(exception, accountId, mailboxId, progress, 0); 39421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 39521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 39621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 39721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Callback for implicit (timer-based) mailbox refresh. 39821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * 39921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Do the same as {@link #updateMailboxCallback}. 40021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * TODO: Figure out if it's really okay to do the same as updateMailboxCallback. 40121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * If both the explicit refresh and the implicit refresh can run at the same time, 40221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * we need to keep track of their status separately. 40321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 40421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki @Override 40521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public void serviceCheckMailCallback( 40621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki MessagingException exception, long accountId, long mailboxId, int progress, 40721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki long tag) { 408295297581c8af9b6ee0a41487b7fded08739890cMakoto Onuki if (LOG_ENABLED) { 40931d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank Log.d(Logging.LOG_TAG, "serviceCheckMailCallback " + accountId + ", " 41021efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki + mailboxId + ", " + progress + ", " + exceptionToString(exception)); 41121efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 41221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki updateMailboxCallbackInternal(exception, accountId, mailboxId, progress, 0); 41321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 41421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 41521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki private void updateMailboxCallbackInternal(MessagingException exception, long accountId, 41621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki long mailboxId, int progress, int dontUseNumNewMessages) { 41721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki // Don't use dontUseNumNewMessages. serviceCheckMailCallback() don't set it. 41821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mMessageListStatus.get(mailboxId).onCallback(exception, progress, mClock); 41921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki if (exception != null) { 42031d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank reportError(accountId, mailboxId, 42131d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank MessagingExceptionStrings.getErrorString(mContext, exception)); 42221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 42321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki notifyRefreshStatusChanged(accountId, mailboxId); 42421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 42521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 42621efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki 42721efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki /** 42821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * Send message progress callback. 42921efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki * 430be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * We don't keep track of the status of outboxes, but we monitor this to catch 431be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * errors. 43221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki */ 43321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki @Override 43421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki public void sendMailCallback(MessagingException exception, long accountId, long messageId, 43521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki int progress) { 436295297581c8af9b6ee0a41487b7fded08739890cMakoto Onuki if (LOG_ENABLED) { 43731d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank Log.d(Logging.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 (exception != null && !mSendMailExceptionReported) { 44421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki // Only the first error in a batch will be reported. 44521efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki mSendMailExceptionReported = true; 44631d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank reportError(accountId, messageId, 44731d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank MessagingExceptionStrings.getErrorString(mContext, exception)); 44821efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 449be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki if (progress == 100) { 450be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki mSendMailExceptionReported = false; 451be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki } 45221efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 45321efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki } 45421efedb67fdfff208cef3a18804771fd1d1fff30Makoto Onuki} 455