1bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler/* 2bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * Copyright (C) 2009 The Android Open Source Project 3bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * 4bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * Licensed under the Apache License, Version 2.0 (the "License"); 5bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * you may not use this file except in compliance with the License. 6bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * You may obtain a copy of the License at 7bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * 8bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * http://www.apache.org/licenses/LICENSE-2.0 9bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * 10bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * Unless required by applicable law or agreed to in writing, software 11bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * distributed under the License is distributed on an "AS IS" BASIS, 12bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * See the License for the specific language governing permissions and 14bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * limitations under the License. 15bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler */ 16bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler 17bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadlerpackage com.android.email; 18bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler 1985e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blankimport android.app.Service; 2085e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blankimport android.content.ContentResolver; 2185e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blankimport android.content.ContentUris; 2285e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blankimport android.content.ContentValues; 2385e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blankimport android.content.Context; 2485e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blankimport android.content.Intent; 2585e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blankimport android.database.Cursor; 2685e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blankimport android.net.Uri; 2785e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blankimport android.os.Bundle; 2885e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blankimport android.os.IBinder; 2985e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blankimport android.os.RemoteCallbackList; 3085e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blankimport android.os.RemoteException; 3185e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blankimport android.util.Log; 3285e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blank 33391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blankimport com.android.email.mail.store.Pop3Store.Pop3Message; 340993190cafebc107bd27a26996b5d63d4a4ede10Marc Blankimport com.android.email.provider.AccountBackupRestore; 3566a47b8dac5e97e37c30b928bc5a227d74baada9Marc Blankimport com.android.email.service.EmailServiceUtils; 364e4aba9ebc43c6a83190f3a883fa05bb7d5100b3Marc Blankimport com.android.email.service.MailService; 370d4fc55861ed4393aa82f124f2865695ef564641Marc Blankimport com.android.emailcommon.Api; 3831d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blankimport com.android.emailcommon.Logging; 392193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.AuthenticationFailedException; 402193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.Folder.MessageRetrievalListener; 413a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blankimport com.android.emailcommon.mail.MessagingException; 42f5418f1f93b02e7fab9f15eb201800b65510998eMarc Blankimport com.android.emailcommon.provider.Account; 43a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent; 44a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.Attachment; 45a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.Body; 46a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.MailboxColumns; 47a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.Message; 48a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.MessageColumns; 4985e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blankimport com.android.emailcommon.provider.HostAuth; 5053ea83ebf91f820692e8fa8e781f5cc982dd94dbBen Komaloimport com.android.emailcommon.provider.Mailbox; 510d4fc55861ed4393aa82f124f2865695ef564641Marc Blankimport com.android.emailcommon.service.EmailServiceStatus; 520d4fc55861ed4393aa82f124f2865695ef564641Marc Blankimport com.android.emailcommon.service.IEmailService; 530d4fc55861ed4393aa82f124f2865695ef564641Marc Blankimport com.android.emailcommon.service.IEmailServiceCallback; 5475a754660e33c5e18cacffff193983ba22a7b9b0Marc Blankimport com.android.emailcommon.service.SearchParams; 558a574694606f0e5d781334d0d426fc379c51f3edMarc Blankimport com.android.emailcommon.utility.AttachmentUtilities; 56e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedyimport com.android.emailcommon.utility.EmailAsyncTask; 5731d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blankimport com.android.emailcommon.utility.Utility; 58aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blankimport com.google.common.annotations.VisibleForTesting; 59bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler 60391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blankimport java.io.FileNotFoundException; 61391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blankimport java.io.IOException; 62391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blankimport java.io.InputStream; 63c4cdb11d24c19428dd39f986b00c1a29e75e1505Todd Kennedyimport java.util.ArrayList; 64086aac2386a575a0e2c78b1fa8dd8ea13825ae2bMakoto Onukiimport java.util.Collection; 65ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blankimport java.util.HashMap; 66bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadlerimport java.util.HashSet; 67768aff4c88a13c1663b1c33b1ab03637e5ce375bMakoto Onukiimport java.util.concurrent.ConcurrentHashMap; 68bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler 69bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler/** 70bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * New central controller/dispatcher for Email activities that may require remote operations. 71bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * Handles disambiguating between legacy MessagingController operations and newer provider/sync 727894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank * based code. We implement Service to allow loadAttachment calls to be sent in a consistent manner 737894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank * to IMAP, POP3, and EAS by AttachmentDownloadService 74bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler */ 7545f530ba5553dcbe3e548930945c40e13736deb3Makoto Onukipublic class Controller { 767894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank private static final String TAG = "Controller"; 77b3f7dd0169a35221184b9327c8ce337b09dc6d1fMakoto Onuki private static Controller sInstance; 78c184f36c2df16431693d7709e28ded593efc3da7Marc Blank private final Context mContext; 797c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler private Context mProviderContext; 80c184f36c2df16431693d7709e28ded593efc3da7Marc Blank private final MessagingController mLegacyController; 81b3f7dd0169a35221184b9327c8ce337b09dc6d1fMakoto Onuki private final LegacyListener mLegacyListener = new LegacyListener(); 82b3f7dd0169a35221184b9327c8ce337b09dc6d1fMakoto Onuki private final ServiceCallback mServiceCallback = new ServiceCallback(); 83b3f7dd0169a35221184b9327c8ce337b09dc6d1fMakoto Onuki private final HashSet<Result> mListeners = new HashSet<Result>(); 848d8f86e899165772a7d91250b98dfc3c0d78b538Marc Blank /*package*/ final ConcurrentHashMap<Long, Boolean> mLegacyControllerMap = 858d8f86e899165772a7d91250b98dfc3c0d78b538Marc Blank new ConcurrentHashMap<Long, Boolean>(); 867b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler 87391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank // Note that 0 is a syntactically valid account key; however there can never be an account 88391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank // with id = 0, so attempts to restore the account will return null. Null values are 89391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank // handled properly within the code, so this won't cause any issues. 90c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank private static final long GLOBAL_MAILBOX_ACCOUNT_KEY = 0; 91391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank /*package*/ static final String ATTACHMENT_MAILBOX_SERVER_ID = "__attachment_mailbox__"; 92391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank /*package*/ static final String ATTACHMENT_MESSAGE_UID_PREFIX = "__attachment_message__"; 93c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank /*package*/ static final String SEARCH_MAILBOX_SERVER_ID = "__search_mailbox__"; 94391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank private static final String WHERE_TYPE_ATTACHMENT = 95391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank MailboxColumns.TYPE + "=" + Mailbox.TYPE_ATTACHMENT; 96391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank private static final String WHERE_MAILBOX_KEY = MessageColumns.MAILBOX_KEY + "=?"; 97391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank 987894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank private static final String[] MESSAGEID_TO_ACCOUNTID_PROJECTION = new String[] { 997c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler EmailContent.RECORD_ID, 1007c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler EmailContent.MessageColumns.ACCOUNT_KEY 1017c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler }; 1027894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank private static final int MESSAGEID_TO_ACCOUNTID_COLUMN_ACCOUNTID = 1; 1037894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 1047894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank private static final String[] BODY_SOURCE_KEY_PROJECTION = 1057894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank new String[] {Body.SOURCE_MESSAGE_KEY}; 1067894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank private static final int BODY_SOURCE_KEY_COLUMN = 0; 1077894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank private static final String WHERE_MESSAGE_KEY = Body.MESSAGE_KEY + "=?"; 1087c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler 109e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler private static final String MAILBOXES_FOR_ACCOUNT_SELECTION = MailboxColumns.ACCOUNT_KEY + "=?"; 11069af769688acc28a20cdbad046cea2565456801cMarc Blank private static final String MAILBOXES_FOR_ACCOUNT_EXCEPT_ACCOUNT_MAILBOX_SELECTION = 11169af769688acc28a20cdbad046cea2565456801cMarc Blank MAILBOXES_FOR_ACCOUNT_SELECTION + " AND " + MailboxColumns.TYPE + "!=" + 11269af769688acc28a20cdbad046cea2565456801cMarc Blank Mailbox.TYPE_EAS_ACCOUNT_MAILBOX; 113d3a9ab946caef4cdc8ef81f7fd8f445fdba3782fAndy Stadler private static final String MESSAGES_FOR_ACCOUNT_SELECTION = MessageColumns.ACCOUNT_KEY + "=?"; 1147894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 1157894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank // Service callbacks as set up via setCallback 1167894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank private static RemoteCallbackList<IEmailServiceCallback> sCallbackList = 1177894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank new RemoteCallbackList<IEmailServiceCallback>(); 118f9ab857a5599faac2896394180fcd4ed56b09941Andrew Stadler 1191ecfb5311b0315edf86a450398a8712dbfd86772Ben Komalo private volatile boolean mInUnitTests = false; 1201ecfb5311b0315edf86a450398a8712dbfd86772Ben Komalo 121c184f36c2df16431693d7709e28ded593efc3da7Marc Blank protected Controller(Context _context) { 122c184f36c2df16431693d7709e28ded593efc3da7Marc Blank mContext = _context.getApplicationContext(); 123c184f36c2df16431693d7709e28ded593efc3da7Marc Blank mProviderContext = _context; 1247894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank mLegacyController = MessagingController.getInstance(mProviderContext, this); 12546d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler mLegacyController.addListener(mLegacyListener); 126bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler } 127bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler 128bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler /** 1291ecfb5311b0315edf86a450398a8712dbfd86772Ben Komalo * Mark this controller as being in use in a unit test. 1301ecfb5311b0315edf86a450398a8712dbfd86772Ben Komalo * This is a kludge vs having proper mocks and dependency injection; since the Controller is a 1311ecfb5311b0315edf86a450398a8712dbfd86772Ben Komalo * global singleton there isn't much else we can do. 1321ecfb5311b0315edf86a450398a8712dbfd86772Ben Komalo */ 133cb1d65c47825dc7a45c7954cd93669296b35305eBen Komalo public void markForTest(boolean inUnitTests) { 1341ecfb5311b0315edf86a450398a8712dbfd86772Ben Komalo mInUnitTests = inUnitTests; 1351ecfb5311b0315edf86a450398a8712dbfd86772Ben Komalo } 1361ecfb5311b0315edf86a450398a8712dbfd86772Ben Komalo 1371ecfb5311b0315edf86a450398a8712dbfd86772Ben Komalo /** 1384be3bc1ec8a52308ee1998f0a31d7e491e06b3c1Makoto Onuki * Cleanup for test. Mustn't be called for the regular {@link Controller}, as it's a 1394be3bc1ec8a52308ee1998f0a31d7e491e06b3c1Makoto Onuki * singleton and lives till the process finishes. 1404be3bc1ec8a52308ee1998f0a31d7e491e06b3c1Makoto Onuki * 1414be3bc1ec8a52308ee1998f0a31d7e491e06b3c1Makoto Onuki * <p>However, this method MUST be called for mock instances. 1424be3bc1ec8a52308ee1998f0a31d7e491e06b3c1Makoto Onuki */ 1434be3bc1ec8a52308ee1998f0a31d7e491e06b3c1Makoto Onuki public void cleanupForTest() { 1444be3bc1ec8a52308ee1998f0a31d7e491e06b3c1Makoto Onuki mLegacyController.removeListener(mLegacyListener); 1454be3bc1ec8a52308ee1998f0a31d7e491e06b3c1Makoto Onuki } 1464be3bc1ec8a52308ee1998f0a31d7e491e06b3c1Makoto Onuki 1474be3bc1ec8a52308ee1998f0a31d7e491e06b3c1Makoto Onuki /** 148c184f36c2df16431693d7709e28ded593efc3da7Marc Blank * Gets or creates the singleton instance of Controller. 149c184f36c2df16431693d7709e28ded593efc3da7Marc Blank */ 150c184f36c2df16431693d7709e28ded593efc3da7Marc Blank public synchronized static Controller getInstance(Context _context) { 151c184f36c2df16431693d7709e28ded593efc3da7Marc Blank if (sInstance == null) { 152c184f36c2df16431693d7709e28ded593efc3da7Marc Blank sInstance = new Controller(_context); 153c184f36c2df16431693d7709e28ded593efc3da7Marc Blank } 154c184f36c2df16431693d7709e28ded593efc3da7Marc Blank return sInstance; 155c184f36c2df16431693d7709e28ded593efc3da7Marc Blank } 156c184f36c2df16431693d7709e28ded593efc3da7Marc Blank 157c184f36c2df16431693d7709e28ded593efc3da7Marc Blank /** 158ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki * Inject a mock controller. Used only for testing. Affects future calls to getInstance(). 159ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki * 160ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki * Tests that use this method MUST clean it up by calling this method again with null. 161ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki */ 162ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki public synchronized static void injectMockControllerForTest(Controller mockController) { 163ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki sInstance = mockController; 164ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki } 165ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki 166ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki /** 1677c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler * For testing only: Inject a different context for provider access. This will be 1687c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler * used internally for access the underlying provider (e.g. getContentResolver().query()). 1697c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler * @param providerContext the provider context to be used by this instance 1707c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler */ 1717c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler public void setProviderContext(Context providerContext) { 1727c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler mProviderContext = providerContext; 1737c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler } 1747c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler 1757c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler /** 176bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * Any UI code that wishes for callback results (on async ops) should register their callback 177bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * here (typically from onResume()). Unregistered callbacks will never be called, to prevent 178bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * problems when the command completes and the activity has already paused or finished. 179bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * @param listener The callback that may be used in action methods 180bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler */ 181bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler public void addResultCallback(Result listener) { 182bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler synchronized (mListeners) { 183e069246d48bf5f90dfe20dacd709d495173ebb47Makoto Onuki listener.setRegistered(true); 184bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler mListeners.add(listener); 185bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler } 186bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler } 187bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler 188bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler /** 189bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * Any UI code that no longer wishes for callback results (on async ops) should unregister 190bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * their callback here (typically from onPause()). Unregistered callbacks will never be called, 191bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * to prevent problems when the command completes and the activity has already paused or 192bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * finished. 193bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * @param listener The callback that may no longer be used 194bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler */ 195bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler public void removeResultCallback(Result listener) { 196bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler synchronized (mListeners) { 197e069246d48bf5f90dfe20dacd709d495173ebb47Makoto Onuki listener.setRegistered(false); 198bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler mListeners.remove(listener); 199bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler } 200bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler } 2017b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler 202086aac2386a575a0e2c78b1fa8dd8ea13825ae2bMakoto Onuki public Collection<Result> getResultCallbacksForTest() { 203086aac2386a575a0e2c78b1fa8dd8ea13825ae2bMakoto Onuki return mListeners; 204086aac2386a575a0e2c78b1fa8dd8ea13825ae2bMakoto Onuki } 205086aac2386a575a0e2c78b1fa8dd8ea13825ae2bMakoto Onuki 206bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler /** 207391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank * Delete all Messages that live in the attachment mailbox 208391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank */ 209391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank public void deleteAttachmentMessages() { 210391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank // Note: There should only be one attachment mailbox at present 211391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank ContentResolver resolver = mProviderContext.getContentResolver(); 212391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank Cursor c = null; 213391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank try { 214391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank c = resolver.query(Mailbox.CONTENT_URI, EmailContent.ID_PROJECTION, 215391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank WHERE_TYPE_ATTACHMENT, null, null); 216391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank while (c.moveToNext()) { 217391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank long mailboxId = c.getLong(EmailContent.ID_PROJECTION_COLUMN); 218391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank // Must delete attachments BEFORE messages 2198a574694606f0e5d781334d0d426fc379c51f3edMarc Blank AttachmentUtilities.deleteAllMailboxAttachmentFiles(mProviderContext, 0, 2208a574694606f0e5d781334d0d426fc379c51f3edMarc Blank mailboxId); 221391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank resolver.delete(Message.CONTENT_URI, WHERE_MAILBOX_KEY, 222391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank new String[] {Long.toString(mailboxId)}); 223391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank } 224391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank } finally { 225391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank if (c != null) { 226391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank c.close(); 227391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank } 228391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank } 229391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank } 230391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank 231391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank /** 232c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank * Get a mailbox based on a sqlite WHERE clause 233391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank */ 234c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank private Mailbox getGlobalMailboxWhere(String where) { 235391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank Cursor c = mProviderContext.getContentResolver().query(Mailbox.CONTENT_URI, 236c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank Mailbox.CONTENT_PROJECTION, where, null, null); 237391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank try { 238391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank if (c.moveToFirst()) { 2395e39f90e9d4665713eba38586b08546f1d581adbTodd Kennedy Mailbox m = new Mailbox(); 2405e39f90e9d4665713eba38586b08546f1d581adbTodd Kennedy m.restore(c); 2415e39f90e9d4665713eba38586b08546f1d581adbTodd Kennedy return m; 242391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank } 243391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank } finally { 244391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank c.close(); 245391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank } 246c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank return null; 247c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank } 248c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank 249c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank /** 250c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank * Returns the attachment mailbox (where we store eml attachment Emails), creating one 251c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank * if necessary 252c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank * @return the global attachment mailbox 253c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank */ 254c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank public Mailbox getAttachmentMailbox() { 255c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank Mailbox m = getGlobalMailboxWhere(WHERE_TYPE_ATTACHMENT); 256c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank if (m == null) { 257c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank m = new Mailbox(); 258c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank m.mAccountKey = GLOBAL_MAILBOX_ACCOUNT_KEY; 259c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank m.mServerId = ATTACHMENT_MAILBOX_SERVER_ID; 260c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank m.mFlagVisible = false; 261c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank m.mDisplayName = ATTACHMENT_MAILBOX_SERVER_ID; 262c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank m.mSyncInterval = Mailbox.CHECK_INTERVAL_NEVER; 263c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank m.mType = Mailbox.TYPE_ATTACHMENT; 264c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank m.save(mProviderContext); 265c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank } 266c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank return m; 267c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank } 268c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank 269c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank /** 270c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank * Returns the search mailbox for the specified account, creating one if necessary 271c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank * @return the search mailbox for the passed in account 272c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank */ 273c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank public Mailbox getSearchMailbox(long accountId) { 274c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank Mailbox m = Mailbox.restoreMailboxOfType(mContext, accountId, Mailbox.TYPE_SEARCH); 275c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank if (m == null) { 276c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank m = new Mailbox(); 277c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank m.mAccountKey = accountId; 278c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank m.mServerId = SEARCH_MAILBOX_SERVER_ID; 27929c89ad17a0983ddc4eb2b4922c93a53aff2d735Ben Komalo m.mFlagVisible = false; 280c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank m.mDisplayName = SEARCH_MAILBOX_SERVER_ID; 281c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank m.mSyncInterval = Mailbox.CHECK_INTERVAL_NEVER; 282c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank m.mType = Mailbox.TYPE_SEARCH; 283c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank m.mFlags = Mailbox.FLAG_HOLDS_MAIL; 284f62fd3fd177a79579cde30e43a85eb9709eb348bBen Komalo m.mParentKey = Mailbox.NO_MAILBOX; 285c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank m.save(mProviderContext); 286c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank } 287391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank return m; 288391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank } 289391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank 290391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank /** 291391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank * Create a Message from the Uri and store it in the attachment mailbox 292391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank * @param uri the uri containing message content 293391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank * @return the Message or null 294391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank */ 295391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank public Message loadMessageFromUri(Uri uri) { 296391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank Mailbox mailbox = getAttachmentMailbox(); 297391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank if (mailbox == null) return null; 298391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank try { 299391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank InputStream is = mProviderContext.getContentResolver().openInputStream(uri); 300391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank try { 301391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank // First, create a Pop3Message from the attachment and then parse it 302391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank Pop3Message pop3Message = new Pop3Message( 303391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank ATTACHMENT_MESSAGE_UID_PREFIX + System.currentTimeMillis(), null); 304391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank pop3Message.parse(is); 305391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank // Now, pull out the header fields 306391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank Message msg = new Message(); 307391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank LegacyConversions.updateMessageFields(msg, pop3Message, 0, mailbox.mId); 308391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank // Commit the message to the local store 309391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank msg.save(mProviderContext); 310391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank // Setup the rest of the message and mark it completely loaded 311391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank mLegacyController.copyOneMessageToProvider(pop3Message, msg, 312391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank Message.FLAG_LOADED_COMPLETE, mProviderContext); 313391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank // Restore the complete message and return it 314391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank return Message.restoreMessageWithId(mProviderContext, msg.mId); 315391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank } catch (MessagingException e) { 316391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank } catch (IOException e) { 317391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank } 318391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank } catch (FileNotFoundException e) { 319391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank } 320391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank return null; 321391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank } 322391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank 323391ae25c43a38829cc0990af18c36bdc7cc374cfMarc Blank /** 3243a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank * Set logging flags for external sync services 325f00dccd32125c727cc18d837b59c15c95f5d78bcMarc Blank * 32677898e14e96feb5d107c4e69b5241169e7425058Andrew Stadler * Generally this should be called by anybody who changes Email.DEBUG 32777898e14e96feb5d107c4e69b5241169e7425058Andrew Stadler */ 3283a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank public void serviceLogging(int debugFlags) { 32966a47b8dac5e97e37c30b928bc5a227d74baada9Marc Blank IEmailService service = EmailServiceUtils.getExchangeService(mContext, mServiceCallback); 33077898e14e96feb5d107c4e69b5241169e7425058Andrew Stadler try { 3313a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank service.setLogging(debugFlags); 33277898e14e96feb5d107c4e69b5241169e7425058Andrew Stadler } catch (RemoteException e) { 33377898e14e96feb5d107c4e69b5241169e7425058Andrew Stadler // TODO Change exception handling to be consistent with however this method 33477898e14e96feb5d107c4e69b5241169e7425058Andrew Stadler // is implemented for other protocols 3353a5c1fb274a9ce72d708d88509bf2607cb018dddMarc Blank Log.d("setLogging", "RemoteException" + e); 33677898e14e96feb5d107c4e69b5241169e7425058Andrew Stadler } 33777898e14e96feb5d107c4e69b5241169e7425058Andrew Stadler } 33877898e14e96feb5d107c4e69b5241169e7425058Andrew Stadler 33977898e14e96feb5d107c4e69b5241169e7425058Andrew Stadler /** 340bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * Request a remote update of mailboxes for an account. 341bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler */ 3423f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki public void updateMailboxList(final long accountId) { 343ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki Utility.runAsync(new Runnable() { 344ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki @Override 345ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki public void run() { 346ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki final IEmailService service = getServiceForAccount(accountId); 347ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki if (service != null) { 348ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki // Service implementation 349ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki try { 350ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki service.updateFolderList(accountId); 351ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki } catch (RemoteException e) { 352ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki // TODO Change exception handling to be consistent with however this method 353ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki // is implemented for other protocols 354ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki Log.d("updateMailboxList", "RemoteException" + e); 355ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki } 356ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki } else { 357ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki // MessagingController implementation 35846d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler mLegacyController.listFolders(accountId, mLegacyListener); 35946d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler } 360ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki } 361ec15f2356e47d621584cc3fc84c9c02557e0a0dfMakoto Onuki }); 36246d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler } 36346d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler 36446d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler /** 36546d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler * Request a remote update of a mailbox. For use by the timed service. 36646d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler * 36746d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler * Functionally this is quite similar to updateMailbox(), but it's a separate API and 36846d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler * separate callback in order to keep UI callbacks from affecting the service loop. 36946d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler */ 3703f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki public void serviceCheckMail(final long accountId, final long mailboxId, final long tag) { 37146d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler IEmailService service = getServiceForAccount(accountId); 37246d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler if (service != null) { 37346d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler // Service implementation 37446d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler// try { 375d366346a640c93d70b78ddadfbc3a3b74944359bMarc Blank // TODO this isn't quite going to work, because we're going to get the 37646d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler // generic (UI) callbacks and not the ones we need to restart the ol' service. 37746d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler // service.startSync(mailboxId, tag); 3783f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki mLegacyListener.checkMailFinished(mContext, accountId, mailboxId, tag); 37946d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler// } catch (RemoteException e) { 38046d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler // TODO Change exception handling to be consistent with however this method 38146d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler // is implemented for other protocols 38246d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler// Log.d("updateMailbox", "RemoteException" + e); 38346d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler// } 38446d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler } else { 38546d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler // MessagingController implementation 3863f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki Utility.runAsync(new Runnable() { 38746d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler public void run() { 38846d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler mLegacyController.checkMail(accountId, tag, mLegacyListener); 3898f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler } 3903f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki }); 391bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler } 392bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler } 3937b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler 3947b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler /** 3957b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler * Request a remote update of a mailbox. 3967b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler * 3977b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler * The contract here should be to try and update the headers ASAP, in order to populate 3987b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler * a simple message list. We should also at this point queue up a background task of 3997b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler * downloading some/all of the messages in this mailbox, but that should be interruptable. 4007b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler */ 401cbdd9f78b2605e87e45e4f6761b0a8c444a8cd4cMarc Blank public void updateMailbox(final long accountId, final long mailboxId, boolean userRequest) { 4027b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler 4038f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler IEmailService service = getServiceForAccount(accountId); 4048f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler if (service != null) { 405ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blank try { 406cbdd9f78b2605e87e45e4f6761b0a8c444a8cd4cMarc Blank service.startSync(mailboxId, userRequest); 4078f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler } catch (RemoteException e) { 4088f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler // TODO Change exception handling to be consistent with however this method 4098f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler // is implemented for other protocols 4108f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler Log.d("updateMailbox", "RemoteException" + e); 4117b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler } 4128f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler } else { 4138f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler // MessagingController implementation 4143f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki Utility.runAsync(new Runnable() { 4158f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler public void run() { 41646d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler // TODO shouldn't be passing fully-build accounts & mailboxes into APIs 4178f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler Account account = 418f5418f1f93b02e7fab9f15eb201800b65510998eMarc Blank Account.restoreAccountWithId(mProviderContext, accountId); 41946d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler Mailbox mailbox = 42053ea83ebf91f820692e8fa8e781f5cc982dd94dbBen Komalo Mailbox.restoreMailboxWithId(mProviderContext, mailboxId); 421ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blank if (account == null || mailbox == null || 422ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blank mailbox.mType == Mailbox.TYPE_SEARCH) { 42322d29c67dacf4e8155a588d59815f1f97ecf0588Makoto Onuki return; 42422d29c67dacf4e8155a588d59815f1f97ecf0588Makoto Onuki } 42546d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler mLegacyController.synchronizeMailbox(account, mailbox, mLegacyListener); 4268f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler } 4273f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki }); 4287b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler } 4297b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler } 4307b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler 431bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler /** 432df86adf87328a439347260331592509787020420Andrew Stadler * Request that any final work necessary be done, to load a message. 433df86adf87328a439347260331592509787020420Andrew Stadler * 434df86adf87328a439347260331592509787020420Andrew Stadler * Note, this assumes that the caller has already checked message.mFlagLoaded and that 435df86adf87328a439347260331592509787020420Andrew Stadler * additional work is needed. There is no optimization here for a message which is already 436df86adf87328a439347260331592509787020420Andrew Stadler * loaded. 437df86adf87328a439347260331592509787020420Andrew Stadler * 438df86adf87328a439347260331592509787020420Andrew Stadler * @param messageId the message to load 439df86adf87328a439347260331592509787020420Andrew Stadler * @param callback the Controller callback by which results will be reported 440df86adf87328a439347260331592509787020420Andrew Stadler */ 4413f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki public void loadMessageForView(final long messageId) { 442df86adf87328a439347260331592509787020420Andrew Stadler 443df86adf87328a439347260331592509787020420Andrew Stadler // Split here for target type (Service or MessagingController) 444df86adf87328a439347260331592509787020420Andrew Stadler IEmailService service = getServiceForMessage(messageId); 445df86adf87328a439347260331592509787020420Andrew Stadler if (service != null) { 446df86adf87328a439347260331592509787020420Andrew Stadler // There is no service implementation, so we'll just jam the value, log the error, 447df86adf87328a439347260331592509787020420Andrew Stadler // and get out of here. 448df86adf87328a439347260331592509787020420Andrew Stadler Uri uri = ContentUris.withAppendedId(Message.CONTENT_URI, messageId); 449df86adf87328a439347260331592509787020420Andrew Stadler ContentValues cv = new ContentValues(); 4506c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler cv.put(MessageColumns.FLAG_LOADED, Message.FLAG_LOADED_COMPLETE); 451fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler mProviderContext.getContentResolver().update(uri, cv, null, null); 45231d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank Log.d(Logging.LOG_TAG, "Unexpected loadMessageForView() for service-based message."); 453aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki final long accountId = Account.getAccountIdForMessageId(mProviderContext, messageId); 454df86adf87328a439347260331592509787020420Andrew Stadler synchronized (mListeners) { 455df86adf87328a439347260331592509787020420Andrew Stadler for (Result listener : mListeners) { 456aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki listener.loadMessageForViewCallback(null, accountId, messageId, 100); 457df86adf87328a439347260331592509787020420Andrew Stadler } 458df86adf87328a439347260331592509787020420Andrew Stadler } 459df86adf87328a439347260331592509787020420Andrew Stadler } else { 460df86adf87328a439347260331592509787020420Andrew Stadler // MessagingController implementation 4613f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki Utility.runAsync(new Runnable() { 462df86adf87328a439347260331592509787020420Andrew Stadler public void run() { 463df86adf87328a439347260331592509787020420Andrew Stadler mLegacyController.loadMessageForView(messageId, mLegacyListener); 464df86adf87328a439347260331592509787020420Andrew Stadler } 4653f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki }); 466df86adf87328a439347260331592509787020420Andrew Stadler } 467df86adf87328a439347260331592509787020420Andrew Stadler } 468df86adf87328a439347260331592509787020420Andrew Stadler 469df86adf87328a439347260331592509787020420Andrew Stadler 470df86adf87328a439347260331592509787020420Andrew Stadler /** 471c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda * Saves the message to a mailbox of given type. 4722917e895c7e7c33407a77c76232569d4bd4905cfMihai Preda * This is a synchronous operation taking place in the same thread as the caller. 4732917e895c7e7c33407a77c76232569d4bd4905cfMihai Preda * Upon return the message.mId is set. 474c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda * @param message the message (must have the mAccountId set). 475c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda * @param mailboxType the mailbox type (e.g. Mailbox.TYPE_DRAFTS). 476c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda */ 477c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda public void saveToMailbox(final EmailContent.Message message, final int mailboxType) { 4782917e895c7e7c33407a77c76232569d4bd4905cfMihai Preda long accountId = message.mAccountKey; 4792917e895c7e7c33407a77c76232569d4bd4905cfMihai Preda long mailboxId = findOrCreateMailboxOfType(accountId, mailboxType); 4802917e895c7e7c33407a77c76232569d4bd4905cfMihai Preda message.mMailboxKey = mailboxId; 481fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler message.save(mProviderContext); 482c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda } 483c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda 484c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda /** 4851ecfb5311b0315edf86a450398a8712dbfd86772Ben Komalo * Look for a specific system mailbox, creating it if necessary, and return the mailbox id. 486900021dbeeb93409c069a04a740c2436e30d1b2aAndy Stadler * This is a blocking operation and should not be called from the UI thread. 487900021dbeeb93409c069a04a740c2436e30d1b2aAndy Stadler * 488900021dbeeb93409c069a04a740c2436e30d1b2aAndy Stadler * Synchronized so multiple threads can call it (and not risk creating duplicate boxes). 489900021dbeeb93409c069a04a740c2436e30d1b2aAndy Stadler * 490c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda * @param accountId the account id 491c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda * @param mailboxType the mailbox type (e.g. EmailContent.Mailbox.TYPE_TRASH) 492c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda * @return the id of the mailbox. The mailbox is created if not existing. 493c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda * Returns Mailbox.NO_MAILBOX if the accountId or mailboxType are negative. 494c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda * Does not validate the input in other ways (e.g. does not verify the existence of account). 495c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda */ 496900021dbeeb93409c069a04a740c2436e30d1b2aAndy Stadler public synchronized long findOrCreateMailboxOfType(long accountId, int mailboxType) { 497c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda if (accountId < 0 || mailboxType < 0) { 498c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda return Mailbox.NO_MAILBOX; 499c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda } 500c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda long mailboxId = 501c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda Mailbox.findMailboxOfType(mProviderContext, accountId, mailboxType); 502c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda return mailboxId == Mailbox.NO_MAILBOX ? createMailbox(accountId, mailboxType) : mailboxId; 503c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda } 504c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda 505c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda /** 506fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler * Returns the server-side name for a specific mailbox. 507fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler * 508c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda * @return the resource string corresponding to the mailbox type, empty if not found. 509c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda */ 510e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo public static String getMailboxServerName(Context context, int mailboxType) { 511c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda int resId = -1; 512c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda switch (mailboxType) { 5136ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler case Mailbox.TYPE_INBOX: 514fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler resId = R.string.mailbox_name_server_inbox; 5156ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler break; 5166ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler case Mailbox.TYPE_OUTBOX: 517fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler resId = R.string.mailbox_name_server_outbox; 5186ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler break; 5196ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler case Mailbox.TYPE_DRAFTS: 520fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler resId = R.string.mailbox_name_server_drafts; 5216ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler break; 5226ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler case Mailbox.TYPE_TRASH: 523fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler resId = R.string.mailbox_name_server_trash; 5246ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler break; 5256ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler case Mailbox.TYPE_SENT: 526fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler resId = R.string.mailbox_name_server_sent; 527fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler break; 528fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler case Mailbox.TYPE_JUNK: 529fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler resId = R.string.mailbox_name_server_junk; 5306ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler break; 531c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda } 532e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo return resId != -1 ? context.getString(resId) : ""; 533c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda } 534c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda 535c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda /** 536c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda * Create a mailbox given the account and mailboxType. 537c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda * TODO: Does this need to be signaled explicitly to the sync engines? 538c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda */ 5399d2dae67506983c64f72350a4fb5967cfd85b9a8Todd Kennedy @VisibleForTesting 5409d2dae67506983c64f72350a4fb5967cfd85b9a8Todd Kennedy long createMailbox(long accountId, int mailboxType) { 541c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda if (accountId < 0 || mailboxType < 0) { 542c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda String mes = "Invalid arguments " + accountId + ' ' + mailboxType; 54331d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank Log.e(Logging.LOG_TAG, mes); 544f00dccd32125c727cc18d837b59c15c95f5d78bcMarc Blank throw new RuntimeException(mes); 545c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda } 546e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo Mailbox box = Mailbox.newSystemMailbox( 547e71a19a52313a0fb615700e52a336b65f3c305daBen Komalo accountId, mailboxType, getMailboxServerName(mContext, mailboxType)); 5489e2c6bd5f21f2d19eef7ebfe30e6fdf94ede0857Andrew Stadler box.save(mProviderContext); 549c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda return box.mId; 550c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda } 551c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda 552c6893ddf0fc1a647ca13a2b3aac2c68ca345de37Mihai Preda /** 553334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda * Send a message: 554334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda * - move the message to Outbox (the message is assumed to be in Drafts). 5554b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler * - EAS service will take it from there 5567891106a7d6b4c406792a8a9144e5148e6bf5ddbBen Komalo * - mark reply/forward state in source message (if any) 5574b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler * - trigger send for POP/IMAP 5587891106a7d6b4c406792a8a9144e5148e6bf5ddbBen Komalo * @param message the fully populated Message (usually retrieved from the Draft box). Note that 5597891106a7d6b4c406792a8a9144e5148e6bf5ddbBen Komalo * all transient fields (e.g. Body related fields) are also expected to be fully loaded 560334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda */ 5617891106a7d6b4c406792a8a9144e5148e6bf5ddbBen Komalo public void sendMessage(Message message) { 562334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda ContentResolver resolver = mProviderContext.getContentResolver(); 5637891106a7d6b4c406792a8a9144e5148e6bf5ddbBen Komalo long accountId = message.mAccountKey; 5647891106a7d6b4c406792a8a9144e5148e6bf5ddbBen Komalo long messageId = message.mId; 5657891106a7d6b4c406792a8a9144e5148e6bf5ddbBen Komalo if (accountId == Account.NO_ACCOUNT) { 566334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda accountId = lookupAccountForMessage(messageId); 567334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda } 5687891106a7d6b4c406792a8a9144e5148e6bf5ddbBen Komalo if (accountId == Account.NO_ACCOUNT) { 569334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda // probably the message was not found 570bfac9f2e8a13f6c719608a6948203bbef921c99fMakoto Onuki if (Logging.LOGD) { 571334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda Email.log("no account found for message " + messageId); 572334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda } 573334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda return; 574334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda } 575334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda 576334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda // Move to Outbox 577334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda long outboxId = findOrCreateMailboxOfType(accountId, Mailbox.TYPE_OUTBOX); 578334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda ContentValues cv = new ContentValues(); 579334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda cv.put(EmailContent.MessageColumns.MAILBOX_KEY, outboxId); 580334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda 581334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda // does this need to be SYNCED_CONTENT_URI instead? 5827891106a7d6b4c406792a8a9144e5148e6bf5ddbBen Komalo Uri uri = ContentUris.withAppendedId(Message.CONTENT_URI, messageId); 583334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda resolver.update(uri, cv, null, null); 584334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda 5857891106a7d6b4c406792a8a9144e5148e6bf5ddbBen Komalo // If this is a reply/forward, indicate it as such on the source. 5867891106a7d6b4c406792a8a9144e5148e6bf5ddbBen Komalo long sourceKey = message.mSourceKey; 5877891106a7d6b4c406792a8a9144e5148e6bf5ddbBen Komalo if (sourceKey != Message.NO_MESSAGE) { 58850a092c3d6155fcd704990450640cf159072b1a2Marc Blank boolean isReply = (message.mFlags & Message.FLAG_TYPE_REPLY) != 0; 58950a092c3d6155fcd704990450640cf159072b1a2Marc Blank int flagUpdate = isReply ? Message.FLAG_REPLIED_TO : Message.FLAG_FORWARDED; 59050a092c3d6155fcd704990450640cf159072b1a2Marc Blank setMessageAnsweredOrForwarded(sourceKey, flagUpdate); 5917891106a7d6b4c406792a8a9144e5148e6bf5ddbBen Komalo } 5927891106a7d6b4c406792a8a9144e5148e6bf5ddbBen Komalo 5937894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank sendPendingMessages(accountId); 5947894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 5957894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 5967894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank private void sendPendingMessagesSmtp(long accountId) { 5977894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank // for IMAP & POP only, (attempt to) send the message now 598f5418f1f93b02e7fab9f15eb201800b65510998eMarc Blank final Account account = 599f5418f1f93b02e7fab9f15eb201800b65510998eMarc Blank Account.restoreAccountWithId(mProviderContext, accountId); 6007894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank if (account == null) { 6017894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank return; 6024b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler } 6037894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank final long sentboxId = findOrCreateMailboxOfType(accountId, Mailbox.TYPE_SENT); 6047894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank Utility.runAsync(new Runnable() { 6057894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank public void run() { 6067894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank mLegacyController.sendPendingMessages(account, sentboxId, mLegacyListener); 6077894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 6087894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank }); 609334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda } 610334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda 611334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda /** 612e346193f06c6c3ffd8412ce151109df8b7f45999Andrew Stadler * Try to send all pending messages for a given account 613d366346a640c93d70b78ddadfbc3a3b74944359bMarc Blank * 6147894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank * @param accountId the account for which to send messages 615e346193f06c6c3ffd8412ce151109df8b7f45999Andrew Stadler */ 6163f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki public void sendPendingMessages(long accountId) { 6174b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler // 1. make sure we even have an outbox, exit early if not 6184b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler final long outboxId = 6194b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler Mailbox.findMailboxOfType(mProviderContext, accountId, Mailbox.TYPE_OUTBOX); 6204b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler if (outboxId == Mailbox.NO_MAILBOX) { 6214b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler return; 6224b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler } 6234b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler 6244b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler // 2. dispatch as necessary 6254b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler IEmailService service = getServiceForAccount(accountId); 6264b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler if (service != null) { 6274b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler // Service implementation 6284b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler try { 629cbdd9f78b2605e87e45e4f6761b0a8c444a8cd4cMarc Blank service.startSync(outboxId, false); 6304b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler } catch (RemoteException e) { 6314b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler // TODO Change exception handling to be consistent with however this method 6324b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler // is implemented for other protocols 6334b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler Log.d("updateMailbox", "RemoteException" + e); 6344b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler } 6354b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler } else { 6364b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler // MessagingController implementation 6377894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank sendPendingMessagesSmtp(accountId); 6384b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler } 639e346193f06c6c3ffd8412ce151109df8b7f45999Andrew Stadler } 640e346193f06c6c3ffd8412ce151109df8b7f45999Andrew Stadler 641e346193f06c6c3ffd8412ce151109df8b7f45999Andrew Stadler /** 64277398c42899a383680005b92955a29ab3d872c5cAndrew Stadler * Reset visible limits for all accounts. 64377398c42899a383680005b92955a29ab3d872c5cAndrew Stadler * For each account: 64477398c42899a383680005b92955a29ab3d872c5cAndrew Stadler * look up limit 64577398c42899a383680005b92955a29ab3d872c5cAndrew Stadler * write limit into all mailboxes for that account 64677398c42899a383680005b92955a29ab3d872c5cAndrew Stadler */ 64777398c42899a383680005b92955a29ab3d872c5cAndrew Stadler public void resetVisibleLimits() { 6483f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki Utility.runAsync(new Runnable() { 64977398c42899a383680005b92955a29ab3d872c5cAndrew Stadler public void run() { 650fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler ContentResolver resolver = mProviderContext.getContentResolver(); 65177398c42899a383680005b92955a29ab3d872c5cAndrew Stadler Cursor c = null; 65277398c42899a383680005b92955a29ab3d872c5cAndrew Stadler try { 65377398c42899a383680005b92955a29ab3d872c5cAndrew Stadler c = resolver.query( 65477398c42899a383680005b92955a29ab3d872c5cAndrew Stadler Account.CONTENT_URI, 65577398c42899a383680005b92955a29ab3d872c5cAndrew Stadler Account.ID_PROJECTION, 65677398c42899a383680005b92955a29ab3d872c5cAndrew Stadler null, null, null); 65777398c42899a383680005b92955a29ab3d872c5cAndrew Stadler while (c.moveToNext()) { 65877398c42899a383680005b92955a29ab3d872c5cAndrew Stadler long accountId = c.getLong(Account.ID_PROJECTION_COLUMN); 65985e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blank String protocol = Account.getProtocol(mProviderContext, accountId); 66085e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blank if (!HostAuth.SCHEME_EAS.equals(protocol)) { 66185e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blank ContentValues cv = new ContentValues(); 66285e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blank cv.put(MailboxColumns.VISIBLE_LIMIT, Email.VISIBLE_LIMIT_DEFAULT); 66385e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blank resolver.update(Mailbox.CONTENT_URI, cv, 66485e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blank MailboxColumns.ACCOUNT_KEY + "=?", 66585e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blank new String[] { Long.toString(accountId) }); 66677398c42899a383680005b92955a29ab3d872c5cAndrew Stadler } 66777398c42899a383680005b92955a29ab3d872c5cAndrew Stadler } 66877398c42899a383680005b92955a29ab3d872c5cAndrew Stadler } finally { 669f5c3db12de89365c6d52c6d75c7b684e2c0d16ffMarc Blank if (c != null) { 670f5c3db12de89365c6d52c6d75c7b684e2c0d16ffMarc Blank c.close(); 671f5c3db12de89365c6d52c6d75c7b684e2c0d16ffMarc Blank } 67277398c42899a383680005b92955a29ab3d872c5cAndrew Stadler } 67377398c42899a383680005b92955a29ab3d872c5cAndrew Stadler } 6743f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki }); 67577398c42899a383680005b92955a29ab3d872c5cAndrew Stadler } 67677398c42899a383680005b92955a29ab3d872c5cAndrew Stadler 67777398c42899a383680005b92955a29ab3d872c5cAndrew Stadler /** 678e346193f06c6c3ffd8412ce151109df8b7f45999Andrew Stadler * Increase the load count for a given mailbox, and trigger a refresh. Applies only to 679bad39b2e00dcd9127f5e0aed96ab31cf0817be76Marc Blank * IMAP and POP mailboxes, with the exception of the EAS search mailbox. 680e346193f06c6c3ffd8412ce151109df8b7f45999Andrew Stadler * 681e346193f06c6c3ffd8412ce151109df8b7f45999Andrew Stadler * @param mailboxId the mailbox 682e346193f06c6c3ffd8412ce151109df8b7f45999Andrew Stadler */ 6833f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki public void loadMoreMessages(final long mailboxId) { 684ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blank EmailAsyncTask.runAsyncParallel(new Runnable() { 68577398c42899a383680005b92955a29ab3d872c5cAndrew Stadler public void run() { 686fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler Mailbox mailbox = Mailbox.restoreMailboxWithId(mProviderContext, mailboxId); 68777398c42899a383680005b92955a29ab3d872c5cAndrew Stadler if (mailbox == null) { 68877398c42899a383680005b92955a29ab3d872c5cAndrew Stadler return; 68977398c42899a383680005b92955a29ab3d872c5cAndrew Stadler } 690ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blank if (mailbox.mType == Mailbox.TYPE_SEARCH) { 691ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blank try { 692ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blank searchMore(mailbox.mAccountKey); 693ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blank } catch (MessagingException e) { 694ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blank // Nothing to be done 695ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blank } 696ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blank return; 697ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blank } 698fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler Account account = Account.restoreAccountWithId(mProviderContext, 699fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler mailbox.mAccountKey); 70077398c42899a383680005b92955a29ab3d872c5cAndrew Stadler if (account == null) { 70177398c42899a383680005b92955a29ab3d872c5cAndrew Stadler return; 70277398c42899a383680005b92955a29ab3d872c5cAndrew Stadler } 70385e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blank // Use provider math to increment the field 70485e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blank ContentValues cv = new ContentValues();; 70585e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blank cv.put(EmailContent.FIELD_COLUMN_NAME, MailboxColumns.VISIBLE_LIMIT); 70685e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blank cv.put(EmailContent.ADD_COLUMN_NAME, Email.VISIBLE_LIMIT_INCREMENT); 70785e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blank Uri uri = ContentUris.withAppendedId(Mailbox.ADD_TO_FIELD_URI, mailboxId); 70885e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blank mProviderContext.getContentResolver().update(uri, cv, null, null); 70985e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blank // Trigger a refresh using the new, longer limit 71085e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blank mailbox.mVisibleLimit += Email.VISIBLE_LIMIT_INCREMENT; 71185e4c101b014857fe40f87c3837b82564cfc5b6cMarc Blank mLegacyController.synchronizeMailbox(account, mailbox, mLegacyListener); 71277398c42899a383680005b92955a29ab3d872c5cAndrew Stadler } 7133f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki }); 714e346193f06c6c3ffd8412ce151109df8b7f45999Andrew Stadler } 715e346193f06c6c3ffd8412ce151109df8b7f45999Andrew Stadler 716e346193f06c6c3ffd8412ce151109df8b7f45999Andrew Stadler /** 717334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda * @param messageId the id of message 718334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda * @return the accountId corresponding to the given messageId, or -1 if not found. 719334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda */ 720334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda private long lookupAccountForMessage(long messageId) { 721334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda ContentResolver resolver = mProviderContext.getContentResolver(); 722334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda Cursor c = resolver.query(EmailContent.Message.CONTENT_URI, 723334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda MESSAGEID_TO_ACCOUNTID_PROJECTION, EmailContent.RECORD_ID + "=?", 724334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda new String[] { Long.toString(messageId) }, null); 725334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda try { 726334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda return c.moveToFirst() 727334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda ? c.getLong(MESSAGEID_TO_ACCOUNTID_COLUMN_ACCOUNTID) 728334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda : -1; 729334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda } finally { 730334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda c.close(); 731334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda } 732334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda } 733334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda 734334903369e1ea8f032d7ffd67f57f4e7004dc2cfMihai Preda /** 7357768ce276ede4ee979df28ee514ddca79bdb90abMihai Preda * Delete a single attachment entry from the DB given its id. 7365de54008e58ff63d388e4d448b50a47950990e22Marc Blank * Does not delete any eventual associated files. 7377768ce276ede4ee979df28ee514ddca79bdb90abMihai Preda */ 7387768ce276ede4ee979df28ee514ddca79bdb90abMihai Preda public void deleteAttachment(long attachmentId) { 7397768ce276ede4ee979df28ee514ddca79bdb90abMihai Preda ContentResolver resolver = mProviderContext.getContentResolver(); 7407768ce276ede4ee979df28ee514ddca79bdb90abMihai Preda Uri uri = ContentUris.withAppendedId(Attachment.CONTENT_URI, attachmentId); 7417768ce276ede4ee979df28ee514ddca79bdb90abMihai Preda resolver.delete(uri, null, null); 7427768ce276ede4ee979df28ee514ddca79bdb90abMihai Preda } 7437768ce276ede4ee979df28ee514ddca79bdb90abMihai Preda 7447768ce276ede4ee979df28ee514ddca79bdb90abMihai Preda /** 7453096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki * Async version of {@link #deleteMessageSync}. 7467c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler */ 7473096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki public void deleteMessage(final long messageId) { 7483096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki EmailAsyncTask.runAsyncParallel(new Runnable() { 7493096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki public void run() { 7503096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki deleteMessageSync(messageId); 7513096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki } 7523096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki }); 7533096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki } 7543096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki 7553096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki /** 7563096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki * Batch & async version of {@link #deleteMessageSync}. 7573096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki */ 7583096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki public void deleteMessages(final long[] messageIds) { 7593096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki if (messageIds == null || messageIds.length == 0) { 7603096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki throw new IllegalArgumentException(); 7613096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki } 7623096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki EmailAsyncTask.runAsyncParallel(new Runnable() { 763b53b1501055cbf5040bfd7b88a9cda084574c398Marc Blank public void run() { 7643096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki for (long messageId: messageIds) { 7653096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki deleteMessageSync(messageId); 7663096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki } 76777aabd951992057a543f1699150971bf1f2d4394Makoto Onuki } 76877aabd951992057a543f1699150971bf1f2d4394Makoto Onuki }); 76977aabd951992057a543f1699150971bf1f2d4394Makoto Onuki } 7707c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler 77177aabd951992057a543f1699150971bf1f2d4394Makoto Onuki /** 7723096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki * Delete a single message by moving it to the trash, or really delete it if it's already in 7733096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki * trash or a draft message. 7743096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki * 7753096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki * This function has no callback, no result reporting, because the desired outcome 7763096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki * is reflected entirely by changes to one or more cursors. 7773096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki * 7783096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki * @param messageId The id of the message to "delete". 77977aabd951992057a543f1699150971bf1f2d4394Makoto Onuki */ 7803096b4ae18f55c9ebf04d83c534da4d5e3370932Makoto Onuki /* package */ void deleteMessageSync(long messageId) { 78177aabd951992057a543f1699150971bf1f2d4394Makoto Onuki // 1. Get the message's account 78277aabd951992057a543f1699150971bf1f2d4394Makoto Onuki Account account = Account.getAccountForMessageId(mProviderContext, messageId); 7837c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler 7841daf8766937e0d8dda6a35870b3e27435c92df9aMakoto Onuki if (account == null) return; 7851daf8766937e0d8dda6a35870b3e27435c92df9aMakoto Onuki 78677aabd951992057a543f1699150971bf1f2d4394Makoto Onuki // 2. Confirm that there is a trash mailbox available. If not, create one 78777aabd951992057a543f1699150971bf1f2d4394Makoto Onuki long trashMailboxId = findOrCreateMailboxOfType(account.mId, Mailbox.TYPE_TRASH); 7887c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler 78977aabd951992057a543f1699150971bf1f2d4394Makoto Onuki // 3. Get the message's original mailbox 79077aabd951992057a543f1699150971bf1f2d4394Makoto Onuki Mailbox mailbox = Mailbox.getMailboxForMessageId(mProviderContext, messageId); 7917c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler 7921daf8766937e0d8dda6a35870b3e27435c92df9aMakoto Onuki if (mailbox == null) return; 7931daf8766937e0d8dda6a35870b3e27435c92df9aMakoto Onuki 79477aabd951992057a543f1699150971bf1f2d4394Makoto Onuki // 4. Drop non-essential data for the message (e.g. attachment files) 7958a574694606f0e5d781334d0d426fc379c51f3edMarc Blank AttachmentUtilities.deleteAllAttachmentFiles(mProviderContext, account.mId, 79677aabd951992057a543f1699150971bf1f2d4394Makoto Onuki messageId); 7977c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler 79877aabd951992057a543f1699150971bf1f2d4394Makoto Onuki Uri uri = ContentUris.withAppendedId(EmailContent.Message.SYNCED_CONTENT_URI, 79977aabd951992057a543f1699150971bf1f2d4394Makoto Onuki messageId); 80077aabd951992057a543f1699150971bf1f2d4394Makoto Onuki ContentResolver resolver = mProviderContext.getContentResolver(); 801f9ab857a5599faac2896394180fcd4ed56b09941Andrew Stadler 80277aabd951992057a543f1699150971bf1f2d4394Makoto Onuki // 5. Perform "delete" as appropriate 80377aabd951992057a543f1699150971bf1f2d4394Makoto Onuki if ((mailbox.mId == trashMailboxId) || (mailbox.mType == Mailbox.TYPE_DRAFTS)) { 80477aabd951992057a543f1699150971bf1f2d4394Makoto Onuki // 5a. Really delete it 80577aabd951992057a543f1699150971bf1f2d4394Makoto Onuki resolver.delete(uri, null, null); 80677aabd951992057a543f1699150971bf1f2d4394Makoto Onuki } else { 80777aabd951992057a543f1699150971bf1f2d4394Makoto Onuki // 5b. Move to trash 80877aabd951992057a543f1699150971bf1f2d4394Makoto Onuki ContentValues cv = new ContentValues(); 80977aabd951992057a543f1699150971bf1f2d4394Makoto Onuki cv.put(EmailContent.MessageColumns.MAILBOX_KEY, trashMailboxId); 81077aabd951992057a543f1699150971bf1f2d4394Makoto Onuki resolver.update(uri, cv, null, null); 81177aabd951992057a543f1699150971bf1f2d4394Makoto Onuki } 81277aabd951992057a543f1699150971bf1f2d4394Makoto Onuki 81377aabd951992057a543f1699150971bf1f2d4394Makoto Onuki if (isMessagingController(account)) { 81477aabd951992057a543f1699150971bf1f2d4394Makoto Onuki mLegacyController.processPendingActions(account.mId); 81577aabd951992057a543f1699150971bf1f2d4394Makoto Onuki } 816b53b1501055cbf5040bfd7b88a9cda084574c398Marc Blank } 817f9ab857a5599faac2896394180fcd4ed56b09941Andrew Stadler 818b53b1501055cbf5040bfd7b88a9cda084574c398Marc Blank /** 819e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy * Moves messages to a new mailbox. 820b53b1501055cbf5040bfd7b88a9cda084574c398Marc Blank * 821b53b1501055cbf5040bfd7b88a9cda084574c398Marc Blank * This function has no callback, no result reporting, because the desired outcome 822b53b1501055cbf5040bfd7b88a9cda084574c398Marc Blank * is reflected entirely by changes to one or more cursors. 823b53b1501055cbf5040bfd7b88a9cda084574c398Marc Blank * 824e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy * Note this method assumes all of the given message and mailbox IDs belong to the same 82511aea1efe45b23c1217b31be029a527c9dc460b8Makoto Onuki * account. 82611aea1efe45b23c1217b31be029a527c9dc460b8Makoto Onuki * 827e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy * @param messageIds IDs of the messages that are to be moved 828e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy * @param newMailboxId ID of the new mailbox that the messages will be moved to 829e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy * @return an asynchronous task that executes the move (for testing only) 830b53b1501055cbf5040bfd7b88a9cda084574c398Marc Blank */ 831e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy public EmailAsyncTask<Void, Void, Void> moveMessages(final long[] messageIds, 83211aea1efe45b23c1217b31be029a527c9dc460b8Makoto Onuki final long newMailboxId) { 83311aea1efe45b23c1217b31be029a527c9dc460b8Makoto Onuki if (messageIds == null || messageIds.length == 0) { 83454c91f00d7f967690a80b992062e75c40182d088Makoto Onuki throw new IllegalArgumentException(); 83511aea1efe45b23c1217b31be029a527c9dc460b8Makoto Onuki } 836e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy return EmailAsyncTask.runAsyncParallel(new Runnable() { 837b53b1501055cbf5040bfd7b88a9cda084574c398Marc Blank public void run() { 83811aea1efe45b23c1217b31be029a527c9dc460b8Makoto Onuki Account account = Account.getAccountForMessageId(mProviderContext, messageIds[0]); 839b53b1501055cbf5040bfd7b88a9cda084574c398Marc Blank if (account != null) { 840b53b1501055cbf5040bfd7b88a9cda084574c398Marc Blank ContentValues cv = new ContentValues(); 84111aea1efe45b23c1217b31be029a527c9dc460b8Makoto Onuki cv.put(EmailContent.MessageColumns.MAILBOX_KEY, newMailboxId); 84211aea1efe45b23c1217b31be029a527c9dc460b8Makoto Onuki ContentResolver resolver = mProviderContext.getContentResolver(); 84311aea1efe45b23c1217b31be029a527c9dc460b8Makoto Onuki for (long messageId : messageIds) { 84411aea1efe45b23c1217b31be029a527c9dc460b8Makoto Onuki Uri uri = ContentUris.withAppendedId( 84511aea1efe45b23c1217b31be029a527c9dc460b8Makoto Onuki EmailContent.Message.SYNCED_CONTENT_URI, messageId); 84611aea1efe45b23c1217b31be029a527c9dc460b8Makoto Onuki resolver.update(uri, cv, null, null); 84711aea1efe45b23c1217b31be029a527c9dc460b8Makoto Onuki } 848b53b1501055cbf5040bfd7b88a9cda084574c398Marc Blank if (isMessagingController(account)) { 849b53b1501055cbf5040bfd7b88a9cda084574c398Marc Blank mLegacyController.processPendingActions(account.mId); 850b53b1501055cbf5040bfd7b88a9cda084574c398Marc Blank } 8516c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler } 852b53b1501055cbf5040bfd7b88a9cda084574c398Marc Blank } 853b53b1501055cbf5040bfd7b88a9cda084574c398Marc Blank }); 8547c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler } 8557c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler 8567c3cca80a0b4dacb7bcb48c65a9999138b5df82bAndrew Stadler /** 8576ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * Set/clear the unread status of a message 8586ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * 8596ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * @param messageId the message to update 8606ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * @param isRead the new value for the isRead flag 8616ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler */ 862b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank public void setMessageReadSync(long messageId, boolean isRead) { 863b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank setMessageBooleanSync(messageId, EmailContent.MessageColumns.FLAG_READ, isRead); 864b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank } 865b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank 866b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank /** 867b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank * Set/clear the unread status of a message from UI thread 868b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank * 869b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank * @param messageId the message to update 870b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank * @param isRead the new value for the isRead flag 871b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank * @return the EmailAsyncTask created 872b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank */ 873b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank public EmailAsyncTask<Void, Void, Void> setMessageRead(final long messageId, 874b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank final boolean isRead) { 875b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank return EmailAsyncTask.runAsyncParallel(new Runnable() { 876b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank @Override 877b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank public void run() { 878b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank setMessageBooleanSync(messageId, EmailContent.MessageColumns.FLAG_READ, isRead); 879b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank }}); 8806ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler } 8816ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler 8826ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler /** 88350a092c3d6155fcd704990450640cf159072b1a2Marc Blank * Update a message record and ping MessagingController, if necessary 88450a092c3d6155fcd704990450640cf159072b1a2Marc Blank * 88550a092c3d6155fcd704990450640cf159072b1a2Marc Blank * @param messageId the message to update 88650a092c3d6155fcd704990450640cf159072b1a2Marc Blank * @param cv the ContentValues used in the update 88750a092c3d6155fcd704990450640cf159072b1a2Marc Blank */ 88850a092c3d6155fcd704990450640cf159072b1a2Marc Blank private void updateMessageSync(long messageId, ContentValues cv) { 88950a092c3d6155fcd704990450640cf159072b1a2Marc Blank Uri uri = ContentUris.withAppendedId(EmailContent.Message.SYNCED_CONTENT_URI, messageId); 89050a092c3d6155fcd704990450640cf159072b1a2Marc Blank mProviderContext.getContentResolver().update(uri, cv, null, null); 89150a092c3d6155fcd704990450640cf159072b1a2Marc Blank 89250a092c3d6155fcd704990450640cf159072b1a2Marc Blank // Service runs automatically, MessagingController needs a kick 89350a092c3d6155fcd704990450640cf159072b1a2Marc Blank long accountId = Account.getAccountIdForMessageId(mProviderContext, messageId); 89450a092c3d6155fcd704990450640cf159072b1a2Marc Blank if (accountId == Account.NO_ACCOUNT) return; 89550a092c3d6155fcd704990450640cf159072b1a2Marc Blank if (isMessagingController(accountId)) { 89650a092c3d6155fcd704990450640cf159072b1a2Marc Blank mLegacyController.processPendingActions(accountId); 89750a092c3d6155fcd704990450640cf159072b1a2Marc Blank } 89850a092c3d6155fcd704990450640cf159072b1a2Marc Blank } 89950a092c3d6155fcd704990450640cf159072b1a2Marc Blank 90050a092c3d6155fcd704990450640cf159072b1a2Marc Blank /** 90150a092c3d6155fcd704990450640cf159072b1a2Marc Blank * Set the answered status of a message 90250a092c3d6155fcd704990450640cf159072b1a2Marc Blank * 90350a092c3d6155fcd704990450640cf159072b1a2Marc Blank * @param messageId the message to update 90450a092c3d6155fcd704990450640cf159072b1a2Marc Blank * @return the AsyncTask that will execute the changes (for testing only) 90550a092c3d6155fcd704990450640cf159072b1a2Marc Blank */ 90650a092c3d6155fcd704990450640cf159072b1a2Marc Blank public void setMessageAnsweredOrForwarded(final long messageId, 90750a092c3d6155fcd704990450640cf159072b1a2Marc Blank final int flag) { 90850a092c3d6155fcd704990450640cf159072b1a2Marc Blank EmailAsyncTask.runAsyncParallel(new Runnable() { 90950a092c3d6155fcd704990450640cf159072b1a2Marc Blank public void run() { 91050a092c3d6155fcd704990450640cf159072b1a2Marc Blank Message msg = Message.restoreMessageWithId(mProviderContext, messageId); 91150a092c3d6155fcd704990450640cf159072b1a2Marc Blank if (msg == null) { 91250a092c3d6155fcd704990450640cf159072b1a2Marc Blank Log.w(Logging.LOG_TAG, "Unable to find source message for a reply/forward"); 91350a092c3d6155fcd704990450640cf159072b1a2Marc Blank return; 91450a092c3d6155fcd704990450640cf159072b1a2Marc Blank } 91550a092c3d6155fcd704990450640cf159072b1a2Marc Blank ContentValues cv = new ContentValues(); 91650a092c3d6155fcd704990450640cf159072b1a2Marc Blank cv.put(MessageColumns.FLAGS, msg.mFlags | flag); 91750a092c3d6155fcd704990450640cf159072b1a2Marc Blank updateMessageSync(messageId, cv); 91850a092c3d6155fcd704990450640cf159072b1a2Marc Blank } 91950a092c3d6155fcd704990450640cf159072b1a2Marc Blank }); 92050a092c3d6155fcd704990450640cf159072b1a2Marc Blank } 92150a092c3d6155fcd704990450640cf159072b1a2Marc Blank 92250a092c3d6155fcd704990450640cf159072b1a2Marc Blank /** 923b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank * Set/clear the favorite status of a message from UI thread 9246ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * 9256ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * @param messageId the message to update 9266ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * @param isFavorite the new value for the isFavorite flag 927b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank * @return the EmailAsyncTask created 9286ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler */ 929b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank public EmailAsyncTask<Void, Void, Void> setMessageFavorite(final long messageId, 9303b1cccf234cd95c3e1c4c568bc588ab06b06d3aaAndy Stadler final boolean isFavorite) { 931b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank return EmailAsyncTask.runAsyncParallel(new Runnable() { 932b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank @Override 933b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank public void run() { 934b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank setMessageBooleanSync(messageId, EmailContent.MessageColumns.FLAG_FAVORITE, 935b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank isFavorite); 936b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank }}); 937b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank } 938b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank /** 939b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank * Set/clear the favorite status of a message 940b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank * 941b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank * @param messageId the message to update 942b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank * @param isFavorite the new value for the isFavorite flag 943b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank */ 944b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank public void setMessageFavoriteSync(long messageId, boolean isFavorite) { 945b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank setMessageBooleanSync(messageId, EmailContent.MessageColumns.FLAG_FAVORITE, isFavorite); 9463b1cccf234cd95c3e1c4c568bc588ab06b06d3aaAndy Stadler } 947423206653fc1841153f6c6c00599a65d5c5f2191Andrew Stadler 9483b1cccf234cd95c3e1c4c568bc588ab06b06d3aaAndy Stadler /** 9493b1cccf234cd95c3e1c4c568bc588ab06b06d3aaAndy Stadler * Set/clear boolean columns of a message 9503b1cccf234cd95c3e1c4c568bc588ab06b06d3aaAndy Stadler * 9513b1cccf234cd95c3e1c4c568bc588ab06b06d3aaAndy Stadler * @param messageId the message to update 9523b1cccf234cd95c3e1c4c568bc588ab06b06d3aaAndy Stadler * @param columnName the column to update 9533b1cccf234cd95c3e1c4c568bc588ab06b06d3aaAndy Stadler * @param columnValue the new value for the column 9543b1cccf234cd95c3e1c4c568bc588ab06b06d3aaAndy Stadler */ 955b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank private void setMessageBooleanSync(long messageId, String columnName, boolean columnValue) { 956b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank ContentValues cv = new ContentValues(); 957b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank cv.put(columnName, columnValue); 958b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank updateMessageSync(messageId, cv); 9596ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler } 9606ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler 961b81a31b29b22b1b11e8ad636638d2b8213e9f199Marc Blank 962ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blank private static final HashMap<Long, SearchParams> sSearchParamsMap = 963ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blank new HashMap<Long, SearchParams>(); 96429c89ad17a0983ddc4eb2b4922c93a53aff2d735Ben Komalo 965ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blank public void searchMore(long accountId) throws MessagingException { 966ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blank SearchParams params = sSearchParamsMap.get(accountId); 967ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blank if (params == null) return; 968ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blank params.mOffset += params.mLimit; 969ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blank searchMessages(accountId, params); 970ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blank } 97129c89ad17a0983ddc4eb2b4922c93a53aff2d735Ben Komalo 9726ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler /** 973627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blank * Search for messages on the (IMAP) server; do not call this on the UI thread! 974627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blank * @param accountId the id of the account to be searched 975627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blank * @param searchParams the parameters for this search 976627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blank * @throws MessagingException 977627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blank */ 9785a9c95f94eaaed326d3116b539b7005ab4f3f8c7Marc Blank public int searchMessages(final long accountId, final SearchParams searchParams) 979627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blank throws MessagingException { 980627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blank // Find/create our search mailbox 981627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blank Mailbox searchMailbox = getSearchMailbox(accountId); 9825a9c95f94eaaed326d3116b539b7005ab4f3f8c7Marc Blank if (searchMailbox == null) return 0; 983627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blank final long searchMailboxId = searchMailbox.mId; 984ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blank // Save this away (per account) 985ed1dc9ee72410e07de24bc4a072d066981611a48Marc Blank sSearchParamsMap.put(accountId, searchParams); 986bad39b2e00dcd9127f5e0aed96ab31cf0817be76Marc Blank 987bad39b2e00dcd9127f5e0aed96ab31cf0817be76Marc Blank if (searchParams.mOffset == 0) { 988bad39b2e00dcd9127f5e0aed96ab31cf0817be76Marc Blank // Delete existing contents of search mailbox 989bad39b2e00dcd9127f5e0aed96ab31cf0817be76Marc Blank ContentResolver resolver = mContext.getContentResolver(); 990bad39b2e00dcd9127f5e0aed96ab31cf0817be76Marc Blank resolver.delete(Message.CONTENT_URI, Message.MAILBOX_KEY + "=" + searchMailboxId, 991bad39b2e00dcd9127f5e0aed96ab31cf0817be76Marc Blank null); 992bad39b2e00dcd9127f5e0aed96ab31cf0817be76Marc Blank ContentValues cv = new ContentValues(); 993bad39b2e00dcd9127f5e0aed96ab31cf0817be76Marc Blank // For now, use the actual query as the name of the mailbox 994bad39b2e00dcd9127f5e0aed96ab31cf0817be76Marc Blank cv.put(Mailbox.DISPLAY_NAME, searchParams.mFilter); 995bad39b2e00dcd9127f5e0aed96ab31cf0817be76Marc Blank resolver.update(ContentUris.withAppendedId(Mailbox.CONTENT_URI, searchMailboxId), 996bad39b2e00dcd9127f5e0aed96ab31cf0817be76Marc Blank cv, null, null); 997bad39b2e00dcd9127f5e0aed96ab31cf0817be76Marc Blank } 998bad39b2e00dcd9127f5e0aed96ab31cf0817be76Marc Blank 999c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank IEmailService service = getServiceForAccount(accountId); 1000c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank if (service != null) { 1001c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank // Service implementation 1002c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank try { 10035a9c95f94eaaed326d3116b539b7005ab4f3f8c7Marc Blank return service.searchMessages(accountId, searchParams, searchMailboxId); 1004c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank } catch (RemoteException e) { 1005c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank // TODO Change exception handling to be consistent with however this method 1006c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank // is implemented for other protocols 100778684ccc795c0d5211dfc04a834cb452dccb1058Marc Blank Log.e("searchMessages", "RemoteException", e); 10085a9c95f94eaaed326d3116b539b7005ab4f3f8c7Marc Blank return 0; 1009c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank } 1010627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blank } else { 1011627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blank // This is the actual mailbox we'll be searching 1012627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blank Mailbox actualMailbox = Mailbox.restoreMailboxWithId(mContext, searchParams.mMailboxId); 1013f62fd3fd177a79579cde30e43a85eb9709eb348bBen Komalo if (actualMailbox == null) { 1014f62fd3fd177a79579cde30e43a85eb9709eb348bBen Komalo Log.e(Logging.LOG_TAG, "Unable to find mailbox " + searchParams.mMailboxId 1015f62fd3fd177a79579cde30e43a85eb9709eb348bBen Komalo + " to search in with " + searchParams); 10165a9c95f94eaaed326d3116b539b7005ab4f3f8c7Marc Blank return 0; 1017f62fd3fd177a79579cde30e43a85eb9709eb348bBen Komalo } 1018627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blank // Do the search 1019627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blank if (Email.DEBUG) { 1020627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blank Log.d(Logging.LOG_TAG, "Search: " + searchParams.mFilter); 1021627bc6ed57ee06cc588e64ff959bfd7870b659b6Marc Blank } 10225a9c95f94eaaed326d3116b539b7005ab4f3f8c7Marc Blank return mLegacyController.searchMailbox(accountId, searchParams, searchMailboxId); 1023c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank } 1024c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank } 1025c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank 1026c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank /** 10275de54008e58ff63d388e4d448b50a47950990e22Marc Blank * Respond to a meeting invitation. 10285de54008e58ff63d388e4d448b50a47950990e22Marc Blank * 10295de54008e58ff63d388e4d448b50a47950990e22Marc Blank * @param messageId the id of the invitation being responded to 10305de54008e58ff63d388e4d448b50a47950990e22Marc Blank * @param response the code representing the response to the invitation 10315de54008e58ff63d388e4d448b50a47950990e22Marc Blank */ 10323f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki public void sendMeetingResponse(final long messageId, final int response) { 10335de54008e58ff63d388e4d448b50a47950990e22Marc Blank // Split here for target type (Service or MessagingController) 10345de54008e58ff63d388e4d448b50a47950990e22Marc Blank IEmailService service = getServiceForMessage(messageId); 10355de54008e58ff63d388e4d448b50a47950990e22Marc Blank if (service != null) { 10365de54008e58ff63d388e4d448b50a47950990e22Marc Blank // Service implementation 10375de54008e58ff63d388e4d448b50a47950990e22Marc Blank try { 10385de54008e58ff63d388e4d448b50a47950990e22Marc Blank service.sendMeetingResponse(messageId, response); 10395de54008e58ff63d388e4d448b50a47950990e22Marc Blank } catch (RemoteException e) { 10405de54008e58ff63d388e4d448b50a47950990e22Marc Blank // TODO Change exception handling to be consistent with however this method 10415de54008e58ff63d388e4d448b50a47950990e22Marc Blank // is implemented for other protocols 10425de54008e58ff63d388e4d448b50a47950990e22Marc Blank Log.e("onDownloadAttachment", "RemoteException", e); 10435de54008e58ff63d388e4d448b50a47950990e22Marc Blank } 10445de54008e58ff63d388e4d448b50a47950990e22Marc Blank } 10455de54008e58ff63d388e4d448b50a47950990e22Marc Blank } 10465de54008e58ff63d388e4d448b50a47950990e22Marc Blank 10475de54008e58ff63d388e4d448b50a47950990e22Marc Blank /** 1048a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler * Request that an attachment be loaded. It will be stored at a location controlled 1049a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler * by the AttachmentProvider. 10506ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * 10516ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * @param attachmentId the attachment to load 10526ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * @param messageId the owner message 1053a98de7e55e91229c35352b496fad3fbb108a9609Andrew Stadler * @param accountId the owner account 10546ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler */ 1055b8efc2d048175f4d12630a036f9aed4e9be0f982Makoto Onuki public void loadAttachment(final long attachmentId, final long messageId, 10563f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki final long accountId) { 10579ef6f645f57d869a600113f555389b5d5e368c21Mihai Preda Attachment attachInfo = Attachment.restoreAttachmentWithId(mProviderContext, attachmentId); 1058edd1c9ac7e92da3ca5459f4c7c3154b98ff68eacTodd Kennedy if (attachInfo == null) { 1059edd1c9ac7e92da3ca5459f4c7c3154b98ff68eacTodd Kennedy return; 1060edd1c9ac7e92da3ca5459f4c7c3154b98ff68eacTodd Kennedy } 1061edd1c9ac7e92da3ca5459f4c7c3154b98ff68eacTodd Kennedy 10624dcb1c5fdaacc40309b77af2a32532bc60218523Marc Blank if (Utility.attachmentExists(mProviderContext, attachInfo)) { 10633f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler // The attachment has already been downloaded, so we will just "pretend" to download it 10647894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank // This presumably is for POP3 messages 10653f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler synchronized (mListeners) { 10663f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler for (Result listener : mListeners) { 1067aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki listener.loadAttachmentCallback(null, accountId, messageId, attachmentId, 0); 10683f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler } 10693f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler for (Result listener : mListeners) { 1070aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki listener.loadAttachmentCallback(null, accountId, messageId, attachmentId, 100); 10713f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler } 10723f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler } 10733f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler return; 10743f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler } 10753f1ac4da947f426775c9546f2e37206f58ce1a6eAndrew Stadler 10767894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank // Flag the attachment as needing download at the user's request 10777894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank ContentValues cv = new ContentValues(); 10787894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank cv.put(Attachment.FLAGS, attachInfo.mFlags | Attachment.FLAG_DOWNLOAD_USER_REQUEST); 1079e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler attachInfo.update(mProviderContext, cv); 10806ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler } 10816ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler 10826ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler /** 10836ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * For a given message id, return a service proxy if applicable, or null. 10846ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * 10856ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * @param messageId the message of interest 10866ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * @result service proxy, or null if n/a 10876ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler */ 10886ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler private IEmailService getServiceForMessage(long messageId) { 10896ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler // TODO make this more efficient, caching the account, smaller lookup here, etc. 10906ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler Message message = Message.restoreMessageWithId(mProviderContext, messageId); 10917e1de3c484ad0faa5f2d789649c1b4979e071044Makoto Onuki if (message == null) { 10927e1de3c484ad0faa5f2d789649c1b4979e071044Makoto Onuki return null; 10937e1de3c484ad0faa5f2d789649c1b4979e071044Makoto Onuki } 10948f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler return getServiceForAccount(message.mAccountKey); 10958f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler } 10968f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler 10978f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler /** 10988f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler * For a given account id, return a service proxy if applicable, or null. 10998f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler * 11008f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler * @param accountId the message of interest 11018f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler * @result service proxy, or null if n/a 11028f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler */ 11038f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler private IEmailService getServiceForAccount(long accountId) { 11048d8f86e899165772a7d91250b98dfc3c0d78b538Marc Blank if (isMessagingController(accountId)) return null; 11058d8f86e899165772a7d91250b98dfc3c0d78b538Marc Blank return getExchangeEmailService(); 11066ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler } 11076ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler 1108c7b6145c125cf0f9bdd6426db11ee796fe8b1cf1Makoto Onuki private IEmailService getExchangeEmailService() { 110966a47b8dac5e97e37c30b928bc5a227d74baada9Marc Blank return EmailServiceUtils.getExchangeService(mContext, mServiceCallback); 1110c7b6145c125cf0f9bdd6426db11ee796fe8b1cf1Makoto Onuki } 1111c7b6145c125cf0f9bdd6426db11ee796fe8b1cf1Makoto Onuki 11126ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler /** 1113bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * Simple helper to determine if legacy MessagingController should be used 1114bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler */ 1115f5418f1f93b02e7fab9f15eb201800b65510998eMarc Blank public boolean isMessagingController(Account account) { 1116e892f6f978c18d1d43f94681f4d73f36d5f8a2cdMarc Blank if (account == null) return false; 11178d8f86e899165772a7d91250b98dfc3c0d78b538Marc Blank return isMessagingController(account.mId); 11188d8f86e899165772a7d91250b98dfc3c0d78b538Marc Blank } 11197b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler 11208d8f86e899165772a7d91250b98dfc3c0d78b538Marc Blank public boolean isMessagingController(long accountId) { 11218d8f86e899165772a7d91250b98dfc3c0d78b538Marc Blank Boolean isLegacyController = mLegacyControllerMap.get(accountId); 11228d8f86e899165772a7d91250b98dfc3c0d78b538Marc Blank if (isLegacyController == null) { 11238d8f86e899165772a7d91250b98dfc3c0d78b538Marc Blank String protocol = Account.getProtocol(mProviderContext, accountId); 11248d8f86e899165772a7d91250b98dfc3c0d78b538Marc Blank isLegacyController = ("pop3".equals(protocol) || "imap".equals(protocol)); 11258d8f86e899165772a7d91250b98dfc3c0d78b538Marc Blank mLegacyControllerMap.put(accountId, isLegacyController); 11268d8f86e899165772a7d91250b98dfc3c0d78b538Marc Blank } 11278d8f86e899165772a7d91250b98dfc3c0d78b538Marc Blank return isLegacyController; 1128bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler } 11297b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler 1130bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler /** 1131954bcd45b0c9febfb41bb0dc3dde2eca7559a290Makoto Onuki * Delete an account. 1132768aff4c88a13c1663b1c33b1ab03637e5ce375bMakoto Onuki */ 1133954bcd45b0c9febfb41bb0dc3dde2eca7559a290Makoto Onuki public void deleteAccount(final long accountId) { 11344e4aba9ebc43c6a83190f3a883fa05bb7d5100b3Marc Blank EmailAsyncTask.runAsyncParallel(new Runnable() { 11354e4aba9ebc43c6a83190f3a883fa05bb7d5100b3Marc Blank @Override 1136954bcd45b0c9febfb41bb0dc3dde2eca7559a290Makoto Onuki public void run() { 1137e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler deleteAccountSync(accountId, mProviderContext); 1138291b90fb24214f767485c427739d25842936dff7Makoto Onuki } 1139291b90fb24214f767485c427739d25842936dff7Makoto Onuki }); 1140291b90fb24214f767485c427739d25842936dff7Makoto Onuki } 1141291b90fb24214f767485c427739d25842936dff7Makoto Onuki 1142291b90fb24214f767485c427739d25842936dff7Makoto Onuki /** 1143a50fc99b0c433f0cde31ba1c7ab87fb9ea86345dTodd Kennedy * Delete an account synchronously. 1144291b90fb24214f767485c427739d25842936dff7Makoto Onuki */ 114502d59d21949a77c60859b615312f02e6d8003490Marc Blank public void deleteAccountSync(long accountId, Context context) { 1146291b90fb24214f767485c427739d25842936dff7Makoto Onuki try { 11478d8f86e899165772a7d91250b98dfc3c0d78b538Marc Blank mLegacyControllerMap.remove(accountId); 1148291b90fb24214f767485c427739d25842936dff7Makoto Onuki // Get the account URI. 114902d59d21949a77c60859b615312f02e6d8003490Marc Blank final Account account = Account.restoreAccountWithId(context, accountId); 1150291b90fb24214f767485c427739d25842936dff7Makoto Onuki if (account == null) { 1151291b90fb24214f767485c427739d25842936dff7Makoto Onuki return; // Already deleted? 1152291b90fb24214f767485c427739d25842936dff7Makoto Onuki } 1153954bcd45b0c9febfb41bb0dc3dde2eca7559a290Makoto Onuki 11542a33dde4d16f0468890a4852f5e4017a973a2342Marc Blank // Delete account data, attachments, PIM data, etc. 11552a33dde4d16f0468890a4852f5e4017a973a2342Marc Blank deleteSyncedDataSync(accountId); 11562a33dde4d16f0468890a4852f5e4017a973a2342Marc Blank 11572a33dde4d16f0468890a4852f5e4017a973a2342Marc Blank // Now delete the account itself 11582a33dde4d16f0468890a4852f5e4017a973a2342Marc Blank Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, accountId); 1159e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler context.getContentResolver().delete(uri, null, null); 1160954bcd45b0c9febfb41bb0dc3dde2eca7559a290Makoto Onuki 11611ecfb5311b0315edf86a450398a8712dbfd86772Ben Komalo // For unit tests, don't run backup, security, and ui pieces. 11621ecfb5311b0315edf86a450398a8712dbfd86772Ben Komalo if (mInUnitTests) { 11631ecfb5311b0315edf86a450398a8712dbfd86772Ben Komalo return; 11641ecfb5311b0315edf86a450398a8712dbfd86772Ben Komalo } 1165954bcd45b0c9febfb41bb0dc3dde2eca7559a290Makoto Onuki 11664e4aba9ebc43c6a83190f3a883fa05bb7d5100b3Marc Blank // Clean up 11674e4aba9ebc43c6a83190f3a883fa05bb7d5100b3Marc Blank AccountBackupRestore.backup(context); 116802d59d21949a77c60859b615312f02e6d8003490Marc Blank SecurityPolicy.getInstance(context).reducePolicies(); 11692959a7e073c87e2fa5fab42ec543b352a91cf187Andy Stadler Email.setServicesEnabledSync(context); 11704e4aba9ebc43c6a83190f3a883fa05bb7d5100b3Marc Blank Email.setNotifyUiAccountsChanged(true); 11714e4aba9ebc43c6a83190f3a883fa05bb7d5100b3Marc Blank MailService.actionReschedule(context); 1172291b90fb24214f767485c427739d25842936dff7Makoto Onuki } catch (Exception e) { 117331d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank Log.w(Logging.LOG_TAG, "Exception while deleting account", e); 1174291b90fb24214f767485c427739d25842936dff7Makoto Onuki } 1175768aff4c88a13c1663b1c33b1ab03637e5ce375bMakoto Onuki } 1176768aff4c88a13c1663b1c33b1ab03637e5ce375bMakoto Onuki 1177768aff4c88a13c1663b1c33b1ab03637e5ce375bMakoto Onuki /** 1178e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler * Delete all synced data, but don't delete the actual account. This is used when security 1179e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler * policy requirements are not met, and we don't want to reveal any synced data, but we do 1180e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler * wish to keep the account configured (e.g. to accept remote wipe commands). 1181e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler * 118269af769688acc28a20cdbad046cea2565456801cMarc Blank * The only mailbox not deleted is the account mailbox (if any) 118369af769688acc28a20cdbad046cea2565456801cMarc Blank * Also, clear the sync keys on the remaining account, since the data is gone. 1184d3a9ab946caef4cdc8ef81f7fd8f445fdba3782fAndy Stadler * 1185e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler * SYNCHRONOUS - do not call from UI thread. 1186e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler * 1187e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler * @param accountId The account to wipe. 1188e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler */ 1189e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler public void deleteSyncedDataSync(long accountId) { 1190e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler try { 1191e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler // Delete synced attachments 11928a574694606f0e5d781334d0d426fc379c51f3edMarc Blank AttachmentUtilities.deleteAllAccountAttachmentFiles(mProviderContext, 11938a574694606f0e5d781334d0d426fc379c51f3edMarc Blank accountId); 1194d3a9ab946caef4cdc8ef81f7fd8f445fdba3782fAndy Stadler 1195d3a9ab946caef4cdc8ef81f7fd8f445fdba3782fAndy Stadler // Delete synced email, leaving only an empty inbox. We do this in two phases: 1196d3a9ab946caef4cdc8ef81f7fd8f445fdba3782fAndy Stadler // 1. Delete all non-inbox mailboxes (which will delete all of their messages) 1197d3a9ab946caef4cdc8ef81f7fd8f445fdba3782fAndy Stadler // 2. Delete all remaining messages (which will be the inbox messages) 1198d3a9ab946caef4cdc8ef81f7fd8f445fdba3782fAndy Stadler ContentResolver resolver = mProviderContext.getContentResolver(); 1199d3a9ab946caef4cdc8ef81f7fd8f445fdba3782fAndy Stadler String[] accountIdArgs = new String[] { Long.toString(accountId) }; 120069af769688acc28a20cdbad046cea2565456801cMarc Blank resolver.delete(Mailbox.CONTENT_URI, 120169af769688acc28a20cdbad046cea2565456801cMarc Blank MAILBOXES_FOR_ACCOUNT_EXCEPT_ACCOUNT_MAILBOX_SELECTION, 1202d3a9ab946caef4cdc8ef81f7fd8f445fdba3782fAndy Stadler accountIdArgs); 1203d3a9ab946caef4cdc8ef81f7fd8f445fdba3782fAndy Stadler resolver.delete(Message.CONTENT_URI, MESSAGES_FOR_ACCOUNT_SELECTION, accountIdArgs); 1204d3a9ab946caef4cdc8ef81f7fd8f445fdba3782fAndy Stadler 1205d3a9ab946caef4cdc8ef81f7fd8f445fdba3782fAndy Stadler // Delete sync keys on remaining items 1206d3a9ab946caef4cdc8ef81f7fd8f445fdba3782fAndy Stadler ContentValues cv = new ContentValues(); 1207d3a9ab946caef4cdc8ef81f7fd8f445fdba3782fAndy Stadler cv.putNull(Account.SYNC_KEY); 1208d3a9ab946caef4cdc8ef81f7fd8f445fdba3782fAndy Stadler resolver.update(Account.CONTENT_URI, cv, Account.ID_SELECTION, accountIdArgs); 1209d3a9ab946caef4cdc8ef81f7fd8f445fdba3782fAndy Stadler cv.clear(); 1210d3a9ab946caef4cdc8ef81f7fd8f445fdba3782fAndy Stadler cv.putNull(Mailbox.SYNC_KEY); 1211d3a9ab946caef4cdc8ef81f7fd8f445fdba3782fAndy Stadler resolver.update(Mailbox.CONTENT_URI, cv, 1212d3a9ab946caef4cdc8ef81f7fd8f445fdba3782fAndy Stadler MAILBOXES_FOR_ACCOUNT_SELECTION, accountIdArgs); 1213d3a9ab946caef4cdc8ef81f7fd8f445fdba3782fAndy Stadler 121469af769688acc28a20cdbad046cea2565456801cMarc Blank // Delete PIM data (contacts, calendar), stop syncs, etc. if applicable 1215e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler IEmailService service = getServiceForAccount(accountId); 1216e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler if (service != null) { 1217e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler service.deleteAccountPIMData(accountId); 1218e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler } 1219e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler } catch (Exception e) { 122031d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank Log.w(Logging.LOG_TAG, "Exception while deleting account synced data", e); 1221e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler } 1222e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler } 1223e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler 1224e29189e3eeea9c629777b3deed6ea2be67caa737Andy Stadler /** 1225bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * Simple callback for synchronous commands. For many commands, this can be largely ignored 1226bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * and the result is observed via provider cursors. The callback will *not* necessarily be 1227bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * made from the UI thread, so you may need further handlers to safely make UI updates. 1228bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler */ 12293f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki public static abstract class Result { 1230e069246d48bf5f90dfe20dacd709d495173ebb47Makoto Onuki private volatile boolean mRegistered; 1231e069246d48bf5f90dfe20dacd709d495173ebb47Makoto Onuki 123245e04b009d570235c542f3c97eaa7e1d00e6cc7bMakoto Onuki protected void setRegistered(boolean registered) { 1233e069246d48bf5f90dfe20dacd709d495173ebb47Makoto Onuki mRegistered = registered; 1234e069246d48bf5f90dfe20dacd709d495173ebb47Makoto Onuki } 1235e069246d48bf5f90dfe20dacd709d495173ebb47Makoto Onuki 1236e069246d48bf5f90dfe20dacd709d495173ebb47Makoto Onuki protected final boolean isRegistered() { 1237e069246d48bf5f90dfe20dacd709d495173ebb47Makoto Onuki return mRegistered; 1238e069246d48bf5f90dfe20dacd709d495173ebb47Makoto Onuki } 1239e069246d48bf5f90dfe20dacd709d495173ebb47Makoto Onuki 12407b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler /** 12417b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler * Callback for updateMailboxList 12427b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler * 12437b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler * @param result If null, the operation completed without error 12446ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * @param accountId The account being operated on 12458f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler * @param progress 0 for "starting", 1..99 for updates (if needed in UI), 100 for complete 12467b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler */ 12478f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler public void updateMailboxListCallback(MessagingException result, long accountId, 12483f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki int progress) { 12493f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki } 12507b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler 1251bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler /** 125246d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler * Callback for updateMailbox. Note: This looks a lot like checkMailCallback, but 125346d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler * it's a separate call used only by UI's, so we can keep things separate. 12547b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler * 1255bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler * @param result If null, the operation completed without error 12566ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * @param accountId The account being operated on 12576ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * @param mailboxId The mailbox being operated on 12588f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler * @param progress 0 for "starting", 1..99 for updates (if needed in UI), 100 for complete 125946d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler * @param numNewMessages the number of new messages delivered 1260bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler */ 12616ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler public void updateMailboxCallback(MessagingException result, long accountId, 1262c4cdb11d24c19428dd39f986b00c1a29e75e1505Todd Kennedy long mailboxId, int progress, int numNewMessages, ArrayList<Long> addedMessages) { 12633f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki } 12646ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler 12656ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler /** 1266df86adf87328a439347260331592509787020420Andrew Stadler * Callback for loadMessageForView 1267df86adf87328a439347260331592509787020420Andrew Stadler * 1268df86adf87328a439347260331592509787020420Andrew Stadler * @param result if null, the attachment completed - if non-null, terminating with failure 1269df86adf87328a439347260331592509787020420Andrew Stadler * @param messageId the message which contains the attachment 1270df86adf87328a439347260331592509787020420Andrew Stadler * @param progress 0 for "starting", 1..99 for updates (if needed in UI), 100 for complete 1271df86adf87328a439347260331592509787020420Andrew Stadler */ 1272aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki public void loadMessageForViewCallback(MessagingException result, long accountId, 1273aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki long messageId, int progress) { 12743f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki } 1275df86adf87328a439347260331592509787020420Andrew Stadler 1276df86adf87328a439347260331592509787020420Andrew Stadler /** 12776ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * Callback for loadAttachment 12786ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * 12796ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * @param result if null, the attachment completed - if non-null, terminating with failure 12806ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * @param messageId the message which contains the attachment 12816ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * @param attachmentId the attachment being loaded 12826ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler * @param progress 0 for "starting", 1..99 for updates (if needed in UI), 100 for complete 12836ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler */ 1284aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki public void loadAttachmentCallback(MessagingException result, long accountId, 1285aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki long messageId, long attachmentId, int progress) { 12863f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki } 128746d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler 128846d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler /** 128946d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler * Callback for checkmail. Note: This looks a lot like updateMailboxCallback, but 129046d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler * it's a separate call used only by the automatic checker service, so we can keep 129146d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler * things separate. 129246d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler * 129346d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler * @param result If null, the operation completed without error 129446d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler * @param accountId The account being operated on 129546d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler * @param mailboxId The mailbox being operated on (may be unknown at start) 129646d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler * @param progress 0 for "starting", no updates, 100 for complete 129746d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler * @param tag the same tag that was passed to serviceCheckMail() 129846d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler */ 129946d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler public void serviceCheckMailCallback(MessagingException result, long accountId, 13003f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki long mailboxId, int progress, long tag) { 13013f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki } 13024b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler 13034b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler /** 13044b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler * Callback for sending pending messages. This will be called once to start the 13054b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler * group, multiple times for messages, and once to complete the group. 13064b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler * 1307be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * Unfortunately this callback works differently on SMTP and EAS. 1308be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * 1309be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * On SMTP: 1310be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * 1311be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * First, we get this. 1312be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * result == null, messageId == -1, progress == 0: start batch send 1313be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * 1314be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * Then we get these callbacks per message. 1315be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * (Exchange backend may skip "start sending one message".) 1316be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * result == null, messageId == xx, progress == 0: start sending one message 1317be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * result == xxxx, messageId == xx, progress == 0; failed sending one message 1318be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * 1319be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * Finally we get this. 1320be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * result == null, messageId == -1, progres == 100; finish sending batch 1321be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * 1322be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * On EAS: Almost same as above, except: 1323be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * 1324be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * - There's no first ("start batch send") callback. 1325be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * - accountId is always -1. 1326be1aa37dc516a9c3dd4af65b11f92a5951f5c5c3Makoto Onuki * 13274b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler * @param result If null, the operation completed without error 13284b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler * @param accountId The account being operated on 13294b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler * @param messageId The being sent (may be unknown at start) 13304b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler * @param progress 0 for "starting", 100 for complete 13314b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler */ 13324b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler public void sendMailCallback(MessagingException result, long accountId, 13333f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki long messageId, int progress) { 13343f545a4060982b8a5d715905c7818d59056c1ee0Makoto Onuki } 1335bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler } 13367b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler 1337bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler /** 1338aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki * Bridge to intercept {@link MessageRetrievalListener#loadAttachmentProgress} and 1339aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki * pass down to {@link Result}. 1340bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler */ 1341aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki public class MessageRetrievalListenerBridge implements MessageRetrievalListener { 1342aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki private final long mMessageId; 1343aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki private final long mAttachmentId; 1344aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki private final long mAccountId; 1345aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki 1346aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki public MessageRetrievalListenerBridge(long messageId, long attachmentId) { 1347aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki mMessageId = messageId; 1348aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki mAttachmentId = attachmentId; 1349aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki mAccountId = Account.getAccountIdForMessageId(mProviderContext, mMessageId); 13507894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 13517894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 1352aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki @Override 1353aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki public void loadAttachmentProgress(int progress) { 1354aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki synchronized (mListeners) { 1355aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki for (Result listener : mListeners) { 1356aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki listener.loadAttachmentCallback(null, mAccountId, mMessageId, mAttachmentId, 1357aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki progress); 1358aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki } 1359aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki } 1360aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki } 1361aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki 1362aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki @Override 13632193962ca2b3157e79f731736afa2a0c972e778aMarc Blank public void messageRetrieved(com.android.emailcommon.mail.Message message) { 1364aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki } 1365aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki } 1366aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki 1367aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki /** 1368aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki * Support for receiving callbacks from MessagingController and dealing with UI going 1369aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki * out of scope. 1370aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki */ 1371aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki public class LegacyListener extends MessagingListener { 13727894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank public LegacyListener() { 13737894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 13747b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler 1375bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler @Override 13760c4dc85190028f389f0dcbc3dbed0b344d20a313Andrew Stadler public void listFoldersStarted(long accountId) { 137746d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler synchronized (mListeners) { 137846d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler for (Result l : mListeners) { 13790c4dc85190028f389f0dcbc3dbed0b344d20a313Andrew Stadler l.updateMailboxListCallback(null, accountId, 0); 138046d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler } 13818f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler } 13828f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler } 13838f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler 13848f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler @Override 13850c4dc85190028f389f0dcbc3dbed0b344d20a313Andrew Stadler public void listFoldersFailed(long accountId, String message) { 138646d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler synchronized (mListeners) { 138746d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler for (Result l : mListeners) { 13880c4dc85190028f389f0dcbc3dbed0b344d20a313Andrew Stadler l.updateMailboxListCallback(new MessagingException(message), accountId, 0); 138946d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler } 1390bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler } 1391bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler } 1392bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler 1393bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler @Override 13940c4dc85190028f389f0dcbc3dbed0b344d20a313Andrew Stadler public void listFoldersFinished(long accountId) { 139546d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler synchronized (mListeners) { 139646d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler for (Result l : mListeners) { 13970c4dc85190028f389f0dcbc3dbed0b344d20a313Andrew Stadler l.updateMailboxListCallback(null, accountId, 100); 139846d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler } 13997b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler } 14007b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler } 14017b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler 14027b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler @Override 14030c4dc85190028f389f0dcbc3dbed0b344d20a313Andrew Stadler public void synchronizeMailboxStarted(long accountId, long mailboxId) { 140446d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler synchronized (mListeners) { 140546d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler for (Result l : mListeners) { 1406c4cdb11d24c19428dd39f986b00c1a29e75e1505Todd Kennedy l.updateMailboxCallback(null, accountId, mailboxId, 0, 0, null); 140746d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler } 14088f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler } 14098f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler } 14108f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler 14118f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler @Override 14120c4dc85190028f389f0dcbc3dbed0b344d20a313Andrew Stadler public void synchronizeMailboxFinished(long accountId, long mailboxId, 1413c4cdb11d24c19428dd39f986b00c1a29e75e1505Todd Kennedy int totalMessagesInMailbox, int numNewMessages, ArrayList<Long> addedMessages) { 141446d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler synchronized (mListeners) { 141546d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler for (Result l : mListeners) { 1416c4cdb11d24c19428dd39f986b00c1a29e75e1505Todd Kennedy l.updateMailboxCallback(null, accountId, mailboxId, 100, numNewMessages, 1417c4cdb11d24c19428dd39f986b00c1a29e75e1505Todd Kennedy addedMessages); 141846d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler } 14197b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler } 14207b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler } 14217b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler 14227b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler @Override 14230c4dc85190028f389f0dcbc3dbed0b344d20a313Andrew Stadler public void synchronizeMailboxFailed(long accountId, long mailboxId, Exception e) { 14240d1078363581db8caded06cf94e729e88a88761aAndrew Stadler MessagingException me; 14250d1078363581db8caded06cf94e729e88a88761aAndrew Stadler if (e instanceof MessagingException) { 14260d1078363581db8caded06cf94e729e88a88761aAndrew Stadler me = (MessagingException) e; 14270d1078363581db8caded06cf94e729e88a88761aAndrew Stadler } else { 14280d1078363581db8caded06cf94e729e88a88761aAndrew Stadler me = new MessagingException(e.toString()); 14290d1078363581db8caded06cf94e729e88a88761aAndrew Stadler } 143046d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler synchronized (mListeners) { 143146d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler for (Result l : mListeners) { 1432c4cdb11d24c19428dd39f986b00c1a29e75e1505Todd Kennedy l.updateMailboxCallback(me, accountId, mailboxId, 0, 0, null); 14337b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler } 1434bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler } 1435bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler } 14367b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler 143746d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler @Override 143846d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler public void checkMailStarted(Context context, long accountId, long tag) { 143946d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler synchronized (mListeners) { 144046d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler for (Result l : mListeners) { 144146d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler l.serviceCheckMailCallback(null, accountId, -1, 0, tag); 144246d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler } 144346d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler } 144446d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler } 14457b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler 144646d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler @Override 144746d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler public void checkMailFinished(Context context, long accountId, long folderId, long tag) { 144846d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler synchronized (mListeners) { 144946d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler for (Result l : mListeners) { 145046d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler l.serviceCheckMailCallback(null, accountId, folderId, 100, tag); 145146d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler } 145246d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler } 145346d7d7f1b6387d144c3f9e7c987418dc8f55fad4Andrew Stadler } 14540d1078363581db8caded06cf94e729e88a88761aAndrew Stadler 14550d1078363581db8caded06cf94e729e88a88761aAndrew Stadler @Override 1456df86adf87328a439347260331592509787020420Andrew Stadler public void loadMessageForViewStarted(long messageId) { 1457aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki final long accountId = Account.getAccountIdForMessageId(mProviderContext, messageId); 1458df86adf87328a439347260331592509787020420Andrew Stadler synchronized (mListeners) { 1459df86adf87328a439347260331592509787020420Andrew Stadler for (Result listener : mListeners) { 1460aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki listener.loadMessageForViewCallback(null, accountId, messageId, 0); 1461df86adf87328a439347260331592509787020420Andrew Stadler } 1462df86adf87328a439347260331592509787020420Andrew Stadler } 1463df86adf87328a439347260331592509787020420Andrew Stadler } 1464df86adf87328a439347260331592509787020420Andrew Stadler 1465df86adf87328a439347260331592509787020420Andrew Stadler @Override 1466df86adf87328a439347260331592509787020420Andrew Stadler public void loadMessageForViewFinished(long messageId) { 1467aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki final long accountId = Account.getAccountIdForMessageId(mProviderContext, messageId); 1468df86adf87328a439347260331592509787020420Andrew Stadler synchronized (mListeners) { 1469df86adf87328a439347260331592509787020420Andrew Stadler for (Result listener : mListeners) { 1470aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki listener.loadMessageForViewCallback(null, accountId, messageId, 100); 1471df86adf87328a439347260331592509787020420Andrew Stadler } 1472df86adf87328a439347260331592509787020420Andrew Stadler } 1473df86adf87328a439347260331592509787020420Andrew Stadler } 1474df86adf87328a439347260331592509787020420Andrew Stadler 1475df86adf87328a439347260331592509787020420Andrew Stadler @Override 1476df86adf87328a439347260331592509787020420Andrew Stadler public void loadMessageForViewFailed(long messageId, String message) { 1477aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki final long accountId = Account.getAccountIdForMessageId(mProviderContext, messageId); 1478df86adf87328a439347260331592509787020420Andrew Stadler synchronized (mListeners) { 1479df86adf87328a439347260331592509787020420Andrew Stadler for (Result listener : mListeners) { 1480df86adf87328a439347260331592509787020420Andrew Stadler listener.loadMessageForViewCallback(new MessagingException(message), 1481aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki accountId, messageId, 0); 1482df86adf87328a439347260331592509787020420Andrew Stadler } 1483df86adf87328a439347260331592509787020420Andrew Stadler } 1484df86adf87328a439347260331592509787020420Andrew Stadler } 1485df86adf87328a439347260331592509787020420Andrew Stadler 1486df86adf87328a439347260331592509787020420Andrew Stadler @Override 14870d1078363581db8caded06cf94e729e88a88761aAndrew Stadler public void loadAttachmentStarted(long accountId, long messageId, long attachmentId, 14880d1078363581db8caded06cf94e729e88a88761aAndrew Stadler boolean requiresDownload) { 14897894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank try { 14907894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank mCallbackProxy.loadAttachmentStatus(messageId, attachmentId, 14917894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank EmailServiceStatus.IN_PROGRESS, 0); 14927894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } catch (RemoteException e) { 14937894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 14940d1078363581db8caded06cf94e729e88a88761aAndrew Stadler synchronized (mListeners) { 14950d1078363581db8caded06cf94e729e88a88761aAndrew Stadler for (Result listener : mListeners) { 1496aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki listener.loadAttachmentCallback(null, accountId, messageId, attachmentId, 0); 14970d1078363581db8caded06cf94e729e88a88761aAndrew Stadler } 14980d1078363581db8caded06cf94e729e88a88761aAndrew Stadler } 14990d1078363581db8caded06cf94e729e88a88761aAndrew Stadler } 15000d1078363581db8caded06cf94e729e88a88761aAndrew Stadler 15010d1078363581db8caded06cf94e729e88a88761aAndrew Stadler @Override 15020d1078363581db8caded06cf94e729e88a88761aAndrew Stadler public void loadAttachmentFinished(long accountId, long messageId, long attachmentId) { 15037894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank try { 15047894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank mCallbackProxy.loadAttachmentStatus(messageId, attachmentId, 15057894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank EmailServiceStatus.SUCCESS, 100); 15067894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } catch (RemoteException e) { 15077894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 15080d1078363581db8caded06cf94e729e88a88761aAndrew Stadler synchronized (mListeners) { 15090d1078363581db8caded06cf94e729e88a88761aAndrew Stadler for (Result listener : mListeners) { 1510aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki listener.loadAttachmentCallback(null, accountId, messageId, attachmentId, 100); 15110d1078363581db8caded06cf94e729e88a88761aAndrew Stadler } 15120d1078363581db8caded06cf94e729e88a88761aAndrew Stadler } 15130d1078363581db8caded06cf94e729e88a88761aAndrew Stadler } 15140d1078363581db8caded06cf94e729e88a88761aAndrew Stadler 15150d1078363581db8caded06cf94e729e88a88761aAndrew Stadler @Override 15160d1078363581db8caded06cf94e729e88a88761aAndrew Stadler public void loadAttachmentFailed(long accountId, long messageId, long attachmentId, 1517f92dd2bf3ea445db9b9a0eb9a447b5cbdb1a6e05Todd Kennedy MessagingException me, boolean background) { 15187894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank try { 15197894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank // If the cause of the MessagingException is an IOException, we send a status of 15207894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank // CONNECTION_ERROR; in this case, AttachmentDownloadService will try again to 15217894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank // download the attachment. Otherwise, the error is considered non-recoverable. 15227894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank int status = EmailServiceStatus.ATTACHMENT_NOT_FOUND; 1523f92dd2bf3ea445db9b9a0eb9a447b5cbdb1a6e05Todd Kennedy if (me != null && me.getCause() instanceof IOException) { 15247894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank status = EmailServiceStatus.CONNECTION_ERROR; 15257894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 15267894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank mCallbackProxy.loadAttachmentStatus(messageId, attachmentId, status, 0); 15277894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } catch (RemoteException e) { 15287894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 15290d1078363581db8caded06cf94e729e88a88761aAndrew Stadler synchronized (mListeners) { 15300d1078363581db8caded06cf94e729e88a88761aAndrew Stadler for (Result listener : mListeners) { 1531f92dd2bf3ea445db9b9a0eb9a447b5cbdb1a6e05Todd Kennedy // TODO We are overloading the exception here. The UI listens for this 1532f92dd2bf3ea445db9b9a0eb9a447b5cbdb1a6e05Todd Kennedy // callback and displays a toast if the exception is not null. Since we 1533f92dd2bf3ea445db9b9a0eb9a447b5cbdb1a6e05Todd Kennedy // want to avoid displaying toast for background operations, we force 1534f92dd2bf3ea445db9b9a0eb9a447b5cbdb1a6e05Todd Kennedy // the exception to be null. This needs to be re-worked so the UI will 1535f92dd2bf3ea445db9b9a0eb9a447b5cbdb1a6e05Todd Kennedy // only receive (or at least pays attention to) responses for requests 1536f92dd2bf3ea445db9b9a0eb9a447b5cbdb1a6e05Todd Kennedy // it explicitly cares about. Then we would not need to overload the 1537f92dd2bf3ea445db9b9a0eb9a447b5cbdb1a6e05Todd Kennedy // exception parameter. 1538f92dd2bf3ea445db9b9a0eb9a447b5cbdb1a6e05Todd Kennedy listener.loadAttachmentCallback(background ? null : me, accountId, messageId, 1539f92dd2bf3ea445db9b9a0eb9a447b5cbdb1a6e05Todd Kennedy attachmentId, 0); 15400d1078363581db8caded06cf94e729e88a88761aAndrew Stadler } 15410d1078363581db8caded06cf94e729e88a88761aAndrew Stadler } 15420d1078363581db8caded06cf94e729e88a88761aAndrew Stadler } 15434b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler 15444b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler @Override 15454b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler synchronized public void sendPendingMessagesStarted(long accountId, long messageId) { 15464b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler synchronized (mListeners) { 15474b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler for (Result listener : mListeners) { 15484b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler listener.sendMailCallback(null, accountId, messageId, 0); 15494b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler } 15504b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler } 15514b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler } 15524b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler 15534b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler @Override 15544b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler synchronized public void sendPendingMessagesCompleted(long accountId) { 15554b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler synchronized (mListeners) { 15564b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler for (Result listener : mListeners) { 15574b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler listener.sendMailCallback(null, accountId, -1, 100); 15584b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler } 15594b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler } 15604b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler } 15614b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler 15624b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler @Override 15634b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler synchronized public void sendPendingMessagesFailed(long accountId, long messageId, 15644b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler Exception reason) { 15654b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler MessagingException me; 15664b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler if (reason instanceof MessagingException) { 15674b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler me = (MessagingException) reason; 15684b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler } else { 15694b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler me = new MessagingException(reason.toString()); 15704b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler } 15714b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler synchronized (mListeners) { 15724b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler for (Result listener : mListeners) { 15734b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler listener.sendMailCallback(me, accountId, messageId, 0); 15744b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler } 15754b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler } 15764b41bae270ea4c49ec8403084db43ee9b37cdda4Andrew Stadler } 1577bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler } 15787b0b463477ef7172bd4b9e19c6338634ebedd8eeAndrew Stadler 15796ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler /** 15808f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler * Service callback for service operations 15816ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler */ 1582ea69fc40d75f5fcf38872f836cdea9fb3aa9c991Andrew Stadler private class ServiceCallback extends IEmailServiceCallback.Stub { 15836ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler 15846ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler private final static boolean DEBUG_FAIL_DOWNLOADS = false; // do not check in "true" 1585bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler 1586ea69fc40d75f5fcf38872f836cdea9fb3aa9c991Andrew Stadler public void loadAttachmentStatus(long messageId, long attachmentId, int statusCode, 15878f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler int progress) { 15889312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler MessagingException result = mapStatusToException(statusCode); 1589ea69fc40d75f5fcf38872f836cdea9fb3aa9c991Andrew Stadler switch (statusCode) { 1590ea69fc40d75f5fcf38872f836cdea9fb3aa9c991Andrew Stadler case EmailServiceStatus.SUCCESS: 1591ea69fc40d75f5fcf38872f836cdea9fb3aa9c991Andrew Stadler progress = 100; 15926ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler break; 1593ea69fc40d75f5fcf38872f836cdea9fb3aa9c991Andrew Stadler case EmailServiceStatus.IN_PROGRESS: 1594ea69fc40d75f5fcf38872f836cdea9fb3aa9c991Andrew Stadler if (DEBUG_FAIL_DOWNLOADS && progress > 75) { 1595ea69fc40d75f5fcf38872f836cdea9fb3aa9c991Andrew Stadler result = new MessagingException( 1596ea69fc40d75f5fcf38872f836cdea9fb3aa9c991Andrew Stadler String.valueOf(EmailServiceStatus.CONNECTION_ERROR)); 1597ea69fc40d75f5fcf38872f836cdea9fb3aa9c991Andrew Stadler } 1598ea69fc40d75f5fcf38872f836cdea9fb3aa9c991Andrew Stadler // discard progress reports that look like sentinels 1599ea69fc40d75f5fcf38872f836cdea9fb3aa9c991Andrew Stadler if (progress < 0 || progress >= 100) { 1600ea69fc40d75f5fcf38872f836cdea9fb3aa9c991Andrew Stadler return; 1601ea69fc40d75f5fcf38872f836cdea9fb3aa9c991Andrew Stadler } 1602ea69fc40d75f5fcf38872f836cdea9fb3aa9c991Andrew Stadler break; 1603ea69fc40d75f5fcf38872f836cdea9fb3aa9c991Andrew Stadler } 1604aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki final long accountId = Account.getAccountIdForMessageId(mProviderContext, messageId); 1605ea69fc40d75f5fcf38872f836cdea9fb3aa9c991Andrew Stadler synchronized (mListeners) { 1606ea69fc40d75f5fcf38872f836cdea9fb3aa9c991Andrew Stadler for (Result listener : mListeners) { 1607aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki listener.loadAttachmentCallback(result, accountId, messageId, attachmentId, 1608aef9515ee70f1f0b6cc4fa601078597b55831331Makoto Onuki progress); 16096ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler } 16106ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler } 16116ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler } 1612c449cba5101f083d4cef8acd9972bc05598bad44Marc Blank 1613f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler /** 1614f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler * Note, this is an incomplete implementation of this callback, because we are 1615f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler * not getting things back from Service in quite the same way as from MessagingController. 1616f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler * However, this is sufficient for basic "progress=100" notification that message send 1617f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler * has just completed. 1618f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler */ 1619d366346a640c93d70b78ddadfbc3a3b74944359bMarc Blank public void sendMessageStatus(long messageId, String subject, int statusCode, 1620d366346a640c93d70b78ddadfbc3a3b74944359bMarc Blank int progress) { 1621f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler long accountId = -1; // This should be in the callback 1622f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler MessagingException result = mapStatusToException(statusCode); 1623f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler switch (statusCode) { 1624f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler case EmailServiceStatus.SUCCESS: 1625f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler progress = 100; 1626f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler break; 1627f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler case EmailServiceStatus.IN_PROGRESS: 1628f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler // discard progress reports that look like sentinels 1629f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler if (progress < 0 || progress >= 100) { 1630f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler return; 1631f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler } 1632f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler break; 1633f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler } 1634f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler synchronized(mListeners) { 1635f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler for (Result listener : mListeners) { 1636f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler listener.sendMailCallback(result, accountId, messageId, progress); 1637f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler } 1638f9ccc0ba88e00c4175f6720aca07876d50b9f22fAndrew Stadler } 1639c449cba5101f083d4cef8acd9972bc05598bad44Marc Blank } 1640c449cba5101f083d4cef8acd9972bc05598bad44Marc Blank 16418f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler public void syncMailboxListStatus(long accountId, int statusCode, int progress) { 16429312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler MessagingException result = mapStatusToException(statusCode); 16438f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler switch (statusCode) { 16448f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler case EmailServiceStatus.SUCCESS: 16458f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler progress = 100; 16468f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler break; 16478f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler case EmailServiceStatus.IN_PROGRESS: 16488f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler // discard progress reports that look like sentinels 16498f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler if (progress < 0 || progress >= 100) { 16508f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler return; 16518f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler } 16528f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler break; 16538f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler } 16548f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler synchronized(mListeners) { 16558f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler for (Result listener : mListeners) { 16568f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler listener.updateMailboxListCallback(result, accountId, progress); 16578f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler } 16588f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler } 1659c449cba5101f083d4cef8acd9972bc05598bad44Marc Blank } 1660c449cba5101f083d4cef8acd9972bc05598bad44Marc Blank 16618f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler public void syncMailboxStatus(long mailboxId, int statusCode, int progress) { 16629312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler MessagingException result = mapStatusToException(statusCode); 16638f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler switch (statusCode) { 16648f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler case EmailServiceStatus.SUCCESS: 16658f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler progress = 100; 16668f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler break; 16678f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler case EmailServiceStatus.IN_PROGRESS: 16688f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler // discard progress reports that look like sentinels 16698f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler if (progress < 0 || progress >= 100) { 16708f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler return; 16718f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler } 16728f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler break; 16738f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler } 16748f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler // TODO should pass this back instead of looking it up here 1675fa52e6c95674aef6461a5cfc670a052e1c5b7f2fAndrew Stadler Mailbox mbx = Mailbox.restoreMailboxWithId(mProviderContext, mailboxId); 1676f00dccd32125c727cc18d837b59c15c95f5d78bcMarc Blank // The mailbox could have disappeared if the server commanded it 1677f00dccd32125c727cc18d837b59c15c95f5d78bcMarc Blank if (mbx == null) return; 16788f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler long accountId = mbx.mAccountKey; 16798f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler synchronized(mListeners) { 16808f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler for (Result listener : mListeners) { 1681c4cdb11d24c19428dd39f986b00c1a29e75e1505Todd Kennedy listener.updateMailboxCallback(result, accountId, mailboxId, progress, 0, null); 16828f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler } 16838f7f93a7b36d873d5adba65f4da54819880c0285Andrew Stadler } 1684c449cba5101f083d4cef8acd9972bc05598bad44Marc Blank } 16859312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler 16869312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler private MessagingException mapStatusToException(int statusCode) { 16879312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler switch (statusCode) { 16889312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler case EmailServiceStatus.SUCCESS: 16899312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler case EmailServiceStatus.IN_PROGRESS: 1690aeea97275d27f42d724b17e37aed2d0302271007Marc Blank // Don't generate error if the account is uninitialized 1691aeea97275d27f42d724b17e37aed2d0302271007Marc Blank case EmailServiceStatus.ACCOUNT_UNINITIALIZED: 16929312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler return null; 16939312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler 16949312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler case EmailServiceStatus.LOGIN_FAILED: 16959312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler return new AuthenticationFailedException(""); 16969312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler 16979312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler case EmailServiceStatus.CONNECTION_ERROR: 16989312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler return new MessagingException(MessagingException.IOERROR); 16999312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler 1700605371e793c7038cf24c15ca5090f27ab431ce79Andrew Stadler case EmailServiceStatus.SECURITY_FAILURE: 1701605371e793c7038cf24c15ca5090f27ab431ce79Andrew Stadler return new MessagingException(MessagingException.SECURITY_POLICIES_REQUIRED); 1702605371e793c7038cf24c15ca5090f27ab431ce79Andrew Stadler 1703d2fd1252d504fa61db9eb8362442cf20f1198e0fMarc Blank case EmailServiceStatus.ACCESS_DENIED: 1704d2fd1252d504fa61db9eb8362442cf20f1198e0fMarc Blank return new MessagingException(MessagingException.ACCESS_DENIED); 1705d2fd1252d504fa61db9eb8362442cf20f1198e0fMarc Blank 17069312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler case EmailServiceStatus.ATTACHMENT_NOT_FOUND: 1707b221cbc785d7c868a69a144da31756c50c0e11b4Marc Blank return new MessagingException(MessagingException.ATTACHMENT_NOT_FOUND); 1708b221cbc785d7c868a69a144da31756c50c0e11b4Marc Blank 1709cb24e515b7983133133ca38bd3e3e6354daaab76Ben Komalo case EmailServiceStatus.CLIENT_CERTIFICATE_ERROR: 1710cb24e515b7983133133ca38bd3e3e6354daaab76Ben Komalo return new MessagingException(MessagingException.CLIENT_CERTIFICATE_ERROR); 1711cb24e515b7983133133ca38bd3e3e6354daaab76Ben Komalo 1712b221cbc785d7c868a69a144da31756c50c0e11b4Marc Blank case EmailServiceStatus.MESSAGE_NOT_FOUND: 17139312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler case EmailServiceStatus.FOLDER_NOT_DELETED: 17149312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler case EmailServiceStatus.FOLDER_NOT_RENAMED: 17159312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler case EmailServiceStatus.FOLDER_NOT_CREATED: 17169312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler case EmailServiceStatus.REMOTE_EXCEPTION: 17179312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler // TODO: define exception code(s) & UI string(s) for server-side errors 17189312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler default: 17199312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler return new MessagingException(String.valueOf(statusCode)); 17209312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler } 17219312faea437854f075df57b9ec23a5d57cb8db0cAndrew Stadler } 17226ae38e4a3937898c5d3fec11a9dc2fb4bab8eab6Andrew Stadler } 17237894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 17247894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank private interface ServiceCallbackWrapper { 17257894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank public void call(IEmailServiceCallback cb) throws RemoteException; 17267894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 17277894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 17287894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank /** 17297894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank * Proxy that can be used to broadcast service callbacks; we currently use this only for 17307894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank * loadAttachment callbacks 17317894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank */ 17327894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank private final IEmailServiceCallback.Stub mCallbackProxy = 17337894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank new IEmailServiceCallback.Stub() { 17347894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 17357894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank /** 17367894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank * Broadcast a callback to the everyone that's registered 17377894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank * 17387894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank * @param wrapper the ServiceCallbackWrapper used in the broadcast 17397894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank */ 17407894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank private synchronized void broadcastCallback(ServiceCallbackWrapper wrapper) { 17417894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank if (sCallbackList != null) { 17427894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank // Call everyone on our callback list 17437894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank // Exceptions can be safely ignored 17447894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank int count = sCallbackList.beginBroadcast(); 17457894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank for (int i = 0; i < count; i++) { 17467894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank try { 17477894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank wrapper.call(sCallbackList.getBroadcastItem(i)); 17487894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } catch (RemoteException e) { 17497894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 17507894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 17517894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank sCallbackList.finishBroadcast(); 17527894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 17537894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 17547894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 17557894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank public void loadAttachmentStatus(final long messageId, final long attachmentId, 17567894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank final int status, final int progress) { 17577894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank broadcastCallback(new ServiceCallbackWrapper() { 17587894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank @Override 17597894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank public void call(IEmailServiceCallback cb) throws RemoteException { 17607894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank cb.loadAttachmentStatus(messageId, attachmentId, status, progress); 17617894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 17627894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank }); 17637894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 17647894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 17657894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank @Override 1766e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy public void sendMessageStatus(long messageId, String subject, int statusCode, int progress){ 17677894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 17687894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 17697894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank @Override 1770e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy public void syncMailboxListStatus(long accountId, int statusCode, int progress) { 17717894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 17727894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 17737894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank @Override 1774e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy public void syncMailboxStatus(long mailboxId, int statusCode, int progress) { 17757894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 17767894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank }; 17777894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 177845f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki public static class ControllerService extends Service { 177945f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki /** 17803b1cccf234cd95c3e1c4c568bc588ab06b06d3aaAndy Stadler * Create our EmailService implementation here. For now, only loadAttachment is supported; 17813b1cccf234cd95c3e1c4c568bc588ab06b06d3aaAndy Stadler * the intention, however, is to move more functionality to the service interface 178245f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki */ 178345f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki private final IEmailService.Stub mBinder = new IEmailService.Stub() { 17847894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 178522409fcffae4c6e551fb3e6ead4cdc92e33fded1Ben Komalo public Bundle validate(HostAuth hostAuth) { 178645f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki return null; 178745f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki } 17887894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 1789e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy public Bundle autoDiscover(String userName, String password) { 179045f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki return null; 179145f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki } 17927894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 1793e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy public void startSync(long mailboxId, boolean userRequest) { 179445f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki } 17957894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 1796e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy public void stopSync(long mailboxId) { 17977894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 179845f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki 1799dc78a769fce18d259eccc602c4623fa74cdf5319Marc Blank public void loadAttachment(long attachmentId, boolean background) 1800dc78a769fce18d259eccc602c4623fa74cdf5319Marc Blank throws RemoteException { 180145f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki Attachment att = Attachment.restoreAttachmentWithId(ControllerService.this, 180245f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki attachmentId); 180345f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki if (att != null) { 1804dc78a769fce18d259eccc602c4623fa74cdf5319Marc Blank if (Email.DEBUG) { 1805dc78a769fce18d259eccc602c4623fa74cdf5319Marc Blank Log.d(TAG, "loadAttachment " + attachmentId + ": " + att.mFileName); 1806dc78a769fce18d259eccc602c4623fa74cdf5319Marc Blank } 180745f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki Message msg = Message.restoreMessageWithId(ControllerService.this, 180845f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki att.mMessageKey); 180945f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki if (msg != null) { 181045f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki // If the message is a forward and the attachment needs downloading, we need 181145f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki // to retrieve the message from the source, rather than from the message 181245f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki // itself 181345f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki if ((msg.mFlags & Message.FLAG_TYPE_FORWARD) != 0) { 181445f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki String[] cols = Utility.getRowColumns(ControllerService.this, 181545f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki Body.CONTENT_URI, BODY_SOURCE_KEY_PROJECTION, WHERE_MESSAGE_KEY, 181645f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki new String[] {Long.toString(msg.mId)}); 181745f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki if (cols != null) { 181845f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki msg = Message.restoreMessageWithId(ControllerService.this, 181945f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki Long.parseLong(cols[BODY_SOURCE_KEY_COLUMN])); 182045f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki if (msg == null) { 18213b1cccf234cd95c3e1c4c568bc588ab06b06d3aaAndy Stadler // TODO: We can try restoring from the deleted table here... 182245f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki return; 182345f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki } 18247894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 18257894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 182645f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki MessagingController legacyController = sInstance.mLegacyController; 182745f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki LegacyListener legacyListener = sInstance.mLegacyListener; 182845f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki legacyController.loadAttachment(msg.mAccountKey, msg.mId, msg.mMailboxKey, 1829f92dd2bf3ea445db9b9a0eb9a447b5cbdb1a6e05Todd Kennedy attachmentId, legacyListener, background); 18302ac18339439631f2539a4cd35056b8ae65d5a24fMarc Blank } else { 18312ac18339439631f2539a4cd35056b8ae65d5a24fMarc Blank // Send back the specific error status for this case 18322ac18339439631f2539a4cd35056b8ae65d5a24fMarc Blank sInstance.mCallbackProxy.loadAttachmentStatus(att.mMessageKey, attachmentId, 18332ac18339439631f2539a4cd35056b8ae65d5a24fMarc Blank EmailServiceStatus.MESSAGE_NOT_FOUND, 0); 18347894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 18357894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 18367894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 18377894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 1838e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy public void updateFolderList(long accountId) { 183945f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki } 18407894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 1841e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy public void hostChanged(long accountId) { 184245f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki } 18437894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 1844e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy public void setLogging(int flags) { 184545f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki } 18467894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 1847e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy public void sendMeetingResponse(long messageId, int response) { 184845f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki } 18497894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 1850e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy public void loadMore(long messageId) { 185145f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki } 18527894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 185345f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki // The following three methods are not implemented in this version 1854e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy public boolean createFolder(long accountId, String name) { 185545f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki return false; 185645f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki } 18577894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 1858e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy public boolean deleteFolder(long accountId, String name) { 185945f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki return false; 186045f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki } 18617894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 1862e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy public boolean renameFolder(long accountId, String oldName, String newName) { 186345f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki return false; 186445f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki } 18657894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 1866e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy public void setCallback(IEmailServiceCallback cb) { 186745f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki sCallbackList.register(cb); 186845f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki } 186964dcd7700e134d112c3bd7460539fc1c97a13eb2Marc Blank 1870e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy public void deleteAccountPIMData(long accountId) { 1871cf3fb71bc6fd795c10dc1d7467292532c19041aeMarc Blank } 18720d4fc55861ed4393aa82f124f2865695ef564641Marc Blank 187375a754660e33c5e18cacffff193983ba22a7b9b0Marc Blank public int searchMessages(long accountId, SearchParams searchParams, 187475a754660e33c5e18cacffff193983ba22a7b9b0Marc Blank long destMailboxId) { 1875c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank return 0; 1876c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank } 1877c60b8d0529168edecf2376a6f421a0ae1e10fe29Marc Blank 18780d4fc55861ed4393aa82f124f2865695ef564641Marc Blank @Override 1879e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5Todd Kennedy public int getApiLevel() { 18800d4fc55861ed4393aa82f124f2865695ef564641Marc Blank return Api.LEVEL; 18810d4fc55861ed4393aa82f124f2865695ef564641Marc Blank } 188245f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki }; 18837894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank 188445f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki @Override 188545f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki public IBinder onBind(Intent intent) { 188645f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki return mBinder; 188745f530ba5553dcbe3e548930945c40e13736deb3Makoto Onuki } 18887894ee82b3a9f22d460a0c6f79e87be27686a649Marc Blank } 1889bcec088320fc56cd5b5e1bbc706e4b7e304b95bfAndrew Stadler} 1890