1f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler/* 2f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler * Copyright (C) 2009 The Android Open Source Project 3f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler * 4f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler * Licensed under the Apache License, Version 2.0 (the "License"); 5f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler * you may not use this file except in compliance with the License. 6f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler * You may obtain a copy of the License at 7f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler * 8f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler * http://www.apache.org/licenses/LICENSE-2.0 9f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler * 10f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler * Unless required by applicable law or agreed to in writing, software 11f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler * distributed under the License is distributed on an "AS IS" BASIS, 12f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler * See the License for the specific language governing permissions and 14f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler * limitations under the License. 15f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler */ 16f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 17f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadlerpackage com.android.email.provider; 18f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 1982a207132b34377d532f19882f5bfc70bc657da0Tony Mantlerimport android.accounts.AccountManager; 20f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport android.appwidget.AppWidgetManager; 2103dc3f22d151d0cddc6487429786a708de813d67Tony Mantlerimport android.content.ComponentCallbacks; 22f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport android.content.ComponentName; 236e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport android.content.ContentProvider; 246e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport android.content.ContentProviderOperation; 256e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport android.content.ContentProviderResult; 266e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport android.content.ContentResolver; 276e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport android.content.ContentUris; 286e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport android.content.ContentValues; 2903cd72805dab0379ed255d151f1c17cc60655fc3Marc Blankimport android.content.Context; 30f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport android.content.Intent; 316e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport android.content.OperationApplicationException; 32e669f28b0866e66c629103698ad14b22a204442fYu Ping Huimport android.content.PeriodicSync; 33c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantlerimport android.content.SharedPreferences; 346e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport android.content.UriMatcher; 3503dc3f22d151d0cddc6487429786a708de813d67Tony Mantlerimport android.content.pm.ActivityInfo; 3603dc3f22d151d0cddc6487429786a708de813d67Tony Mantlerimport android.content.res.Configuration; 375a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrookimport android.content.res.Resources; 386e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport android.database.ContentObserver; 396e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport android.database.Cursor; 40f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport android.database.CursorWrapper; 41901faf1bfb3473b4e40ccd82dab3f3f99eb599bbYu Ping Huimport android.database.DatabaseUtils; 426e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport android.database.MatrixCursor; 43f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport android.database.MergeCursor; 446e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport android.database.sqlite.SQLiteDatabase; 456e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport android.database.sqlite.SQLiteException; 462f288864b621cfb5aee44eda27df463460d33dd3Tony Mantlerimport android.database.sqlite.SQLiteStatement; 476e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport android.net.Uri; 489d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrookimport android.os.AsyncTask; 495a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrookimport android.os.Binder; 505181cd6d4a60ed0b7dbed022484d299a3e91f0daYu Ping Huimport android.os.Build; 51f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport android.os.Bundle; 52feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albertimport android.os.Handler; 53feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albertimport android.os.Handler.Callback; 54e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantlerimport android.os.Looper; 55f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport android.os.Parcel; 565a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrookimport android.os.ParcelFileDescriptor; 57f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport android.os.RemoteException; 58f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport android.provider.BaseColumns; 596e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport android.text.TextUtils; 6064cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Huimport android.text.format.DateUtils; 619b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Huimport android.util.Base64; 62feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albertimport android.util.Log; 63c6953b77552d4cb71776cf0537dc226029381628Tony Mantlerimport android.util.SparseArray; 646e418aa41a17136be0dddb816d843428a0a1e722Marc Blank 65f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.common.content.ProjectionMap; 669dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onukiimport com.android.email.Preferences; 67f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.email.R; 68f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.email.SecurityPolicy; 69876c8e1408c119f6dd771fdf13a9b95ea62f704aTony Mantlerimport com.android.email.activity.setup.AccountSettingsFragment; 7082a207132b34377d532f19882f5bfc70bc657da0Tony Mantlerimport com.android.email.activity.setup.AccountSettingsUtils; 718c03e2af9f439c6e0c6abb38b0c371da7ccdb72aTony Mantlerimport com.android.email.activity.setup.HeadlessAccountSettingsLoader; 723d16e5d4b994d92db51962c8c461c53bee04309fAnthony Leeimport com.android.email.service.AttachmentService; 73f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.email.service.EmailServiceUtils; 74f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.email.service.EmailServiceUtils.EmailServiceInfo; 75f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.email2.ui.MailActivityEmail; 76bfac9f2e8a13f6c719608a6948203bbef921c99fMakoto Onukiimport com.android.emailcommon.Logging; 77f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.emailcommon.mail.Address; 78f5418f1f93b02e7fab9f15eb201800b65510998eMarc Blankimport com.android.emailcommon.provider.Account; 790b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdonimport com.android.emailcommon.provider.Credential; 80a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent; 81a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.AccountColumns; 82a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.Attachment; 83a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.AttachmentColumns; 84a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.Body; 85a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.BodyColumns; 86feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albertimport com.android.emailcommon.provider.EmailContent.HostAuthColumns; 87a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.MailboxColumns; 88a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.Message; 89a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.MessageColumns; 90aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blankimport com.android.emailcommon.provider.EmailContent.PolicyColumns; 913dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantlerimport com.android.emailcommon.provider.EmailContent.QuickResponseColumns; 92a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.SyncColumns; 9312b82d9374947c9268217f45befe8a74bd9b60d7Ben Komaloimport com.android.emailcommon.provider.HostAuth; 9453ea83ebf91f820692e8fa8e781f5cc982dd94dbBen Komaloimport com.android.emailcommon.provider.Mailbox; 95f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdonimport com.android.emailcommon.provider.MailboxUtilities; 96ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Huimport com.android.emailcommon.provider.MessageChangeLogTable; 97ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Huimport com.android.emailcommon.provider.MessageMove; 98ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Huimport com.android.emailcommon.provider.MessageStateChange; 99aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blankimport com.android.emailcommon.provider.Policy; 1006e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport com.android.emailcommon.provider.QuickResponse; 101f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.emailcommon.service.EmailServiceProxy; 10271737836e6be308f752cb95c955a03146b039a9cYu Ping Huimport com.android.emailcommon.service.EmailServiceStatus; 103f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.emailcommon.service.IEmailService; 104f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.emailcommon.service.SearchParams; 105f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.emailcommon.utility.AttachmentUtilities; 1063f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdonimport com.android.emailcommon.utility.EmailAsyncTask; 107f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.emailcommon.utility.Utility; 1086eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sappersteinimport com.android.ex.photo.provider.PhotoContract; 1092f9c66d08b13c1ed4eb7d2f70baa98116ac5fcfbScott Kennedyimport com.android.mail.preferences.MailPrefs; 110c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantlerimport com.android.mail.preferences.MailPrefs.PreferenceKeys; 111709b4633eda47f81a689c3be623660d74cdad904Mindy Pereiraimport com.android.mail.providers.Folder; 11268a3607895963854637215a405145f190d6458f0Andy Huangimport com.android.mail.providers.FolderList; 11324a489c3de70a02bccbf2cfc54b36a385d72c337Alice Yangimport com.android.mail.providers.Settings; 114f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.mail.providers.UIProvider; 115f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.mail.providers.UIProvider.AccountCapabilities; 116b7e0834121d564982c0389c87df775ba311429d4Tony Mantlerimport com.android.mail.providers.UIProvider.AccountColumns.SettingsColumns; 117f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.mail.providers.UIProvider.AccountCursorExtraKeys; 118f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.mail.providers.UIProvider.ConversationPriority; 119f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.mail.providers.UIProvider.ConversationSendingState; 120f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.mail.providers.UIProvider.DraftType; 1219a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrookimport com.android.mail.utils.AttachmentUtils; 122560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedyimport com.android.mail.utils.LogTag; 123f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.mail.utils.LogUtils; 1247fdde9bb4a24e931618a7a64227e2194c89034daScott Kennedyimport com.android.mail.utils.MatrixCursorWithCachedColumns; 125f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.mail.utils.MatrixCursorWithExtra; 12611472650d1fce7548939d311c4434128930c18baPaul Westbrookimport com.android.mail.utils.MimeType; 127f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.mail.utils.Utils; 128f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.mail.widget.BaseWidgetProvider; 129b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrookimport com.google.common.collect.ImmutableMap; 13051693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrookimport com.google.common.collect.ImmutableSet; 13105649dca2f59f28cd4295e041045a605badddb15Tony Mantlerimport com.google.common.collect.Sets; 132f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 1330e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blankimport java.io.File; 134af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blankimport java.io.FileDescriptor; 1355a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrookimport java.io.FileNotFoundException; 1367525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantlerimport java.io.FileWriter; 1372f288864b621cfb5aee44eda27df463460d33dd3Tony Mantlerimport java.io.IOException; 138af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blankimport java.io.PrintWriter; 13984969fb580f569c0e3625a3c59a71d2909ae198dFred Quintanaimport java.util.ArrayList; 1406e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport java.util.Arrays; 14182a207132b34377d532f19882f5bfc70bc657da0Tony Mantlerimport java.util.Collection; 142feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albertimport java.util.HashSet; 1435d7ff8577d7efd938390ddc5d5476717203d0a55Marc Blankimport java.util.List; 144ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Huimport java.util.Locale; 1456e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport java.util.Map; 14651693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrookimport java.util.Set; 147f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport java.util.regex.Pattern; 14884969fb580f569c0e3625a3c59a71d2909ae198dFred Quintana 149c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantlerpublic class EmailProvider extends ContentProvider 150c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler implements SharedPreferences.OnSharedPreferenceChangeListener { 151f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 152560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy private static final String TAG = LogTag.getLogTag(); 153f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 154feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // Time to delay upsync requests. 155feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert public static final long SYNC_DELAY_MILLIS = 30 * DateUtils.SECOND_IN_MILLIS; 156feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert 1577e5df63fc9771c7950d3f95da17cfb112ebbf7f3Marc Blank public static String EMAIL_APP_MIME_TYPE; 158f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 15917d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie // exposed for testing 16017d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie public static final String DATABASE_NAME = "EmailProvider.db"; 16117d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie public static final String BODY_DATABASE_NAME = "EmailProviderBody.db"; 16217d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie 16382a207132b34377d532f19882f5bfc70bc657da0Tony Mantler // We don't back up to the backup database anymore, just keep this constant here so we can 16482a207132b34377d532f19882f5bfc70bc657da0Tony Mantler // delete the old backups and trigger a new backup to the account manager 16582a207132b34377d532f19882f5bfc70bc657da0Tony Mantler @Deprecated 166b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static final String BACKUP_DATABASE_NAME = "EmailProviderBackup.db"; 16782a207132b34377d532f19882f5bfc70bc657da0Tony Mantler private static final String ACCOUNT_MANAGER_JSON_TAG = "accountJson"; 16809fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank 16907676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook /** 17007676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook * Notifies that changes happened. Certain UI components, e.g., widgets, can register for this 17107676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook * {@link android.content.Intent} and update accordingly. However, this can be very broad and 17207676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook * is NOT the preferred way of getting notification. 17307676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook */ 174b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static final String ACTION_NOTIFY_MESSAGE_LIST_DATASET_CHANGED = 175f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "com.android.email.MESSAGE_LIST_DATASET_CHANGED"; 17607676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook 177b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static final String EMAIL_MESSAGE_MIME_TYPE = 178c81bef672089654e6da3babbeb0172bd636564b2Marc Blank "vnd.android.cursor.item/email-message"; 179b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static final String EMAIL_ATTACHMENT_MIME_TYPE = 18009fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank "vnd.android.cursor.item/email-attachment"; 18109fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank 182bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy /** Appended to the notification URI for delete operations */ 183b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static final String NOTIFICATION_OP_DELETE = "delete"; 184bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy /** Appended to the notification URI for insert operations */ 185b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static final String NOTIFICATION_OP_INSERT = "insert"; 186bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy /** Appended to the notification URI for update operations */ 187b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static final String NOTIFICATION_OP_UPDATE = "update"; 188bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy 18964cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu /** The query string to trigger a folder refresh. */ 1900053401d07cd11f19c63dfbc3942d027b4067de8Tony Mantler protected static String QUERY_UIREFRESH = "uirefresh"; 19164cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu 192ef83299b99288c00b9d661260d19715e73e6889cMarc Blank // Definitions for our queries looking for orphaned messages 193ef83299b99288c00b9d661260d19715e73e6889cMarc Blank private static final String[] ORPHANS_PROJECTION 1943dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler = new String[] {MessageColumns._ID, MessageColumns.MAILBOX_KEY}; 195ef83299b99288c00b9d661260d19715e73e6889cMarc Blank private static final int ORPHANS_ID = 0; 196ef83299b99288c00b9d661260d19715e73e6889cMarc Blank private static final int ORPHANS_MAILBOX_KEY = 1; 197ef83299b99288c00b9d661260d19715e73e6889cMarc Blank 1983dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler private static final String WHERE_ID = BaseColumns._ID + "=?"; 199f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 200f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int ACCOUNT_BASE = 0; 201f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int ACCOUNT = ACCOUNT_BASE; 2027bcf1882bcb33b690f0b104f7605c9a6da39f344Makoto Onuki private static final int ACCOUNT_ID = ACCOUNT_BASE + 1; 20382a207132b34377d532f19882f5bfc70bc657da0Tony Mantler private static final int ACCOUNT_CHECK = ACCOUNT_BASE + 2; 20482a207132b34377d532f19882f5bfc70bc657da0Tony Mantler private static final int ACCOUNT_PICK_TRASH_FOLDER = ACCOUNT_BASE + 3; 20582a207132b34377d532f19882f5bfc70bc657da0Tony Mantler private static final int ACCOUNT_PICK_SENT_FOLDER = ACCOUNT_BASE + 4; 206f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 207f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int MAILBOX_BASE = 0x1000; 208f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int MAILBOX = MAILBOX_BASE; 2097bcf1882bcb33b690f0b104f7605c9a6da39f344Makoto Onuki private static final int MAILBOX_ID = MAILBOX_BASE + 1; 210503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu private static final int MAILBOX_NOTIFICATION = MAILBOX_BASE + 2; 211503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu private static final int MAILBOX_MOST_RECENT_MESSAGE = MAILBOX_BASE + 3; 212503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu private static final int MAILBOX_MESSAGE_COUNT = MAILBOX_BASE + 4; 213f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 214f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int MESSAGE_BASE = 0x2000; 215f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int MESSAGE = MESSAGE_BASE; 2164119218e2fd64341ac946fb8f2cbdb796a444cb8Andrew Stadler private static final int MESSAGE_ID = MESSAGE_BASE + 1; 2174119218e2fd64341ac946fb8f2cbdb796a444cb8Andrew Stadler private static final int SYNCED_MESSAGE_ID = MESSAGE_BASE + 2; 21800287c4d8f54ae07c89bb3893f440acdca09d728Marc Blank private static final int MESSAGE_SELECTION = MESSAGE_BASE + 3; 219ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu private static final int MESSAGE_MOVE = MESSAGE_BASE + 4; 220ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu private static final int MESSAGE_STATE_CHANGE = MESSAGE_BASE + 5; 221f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 222f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int ATTACHMENT_BASE = 0x3000; 223f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int ATTACHMENT = ATTACHMENT_BASE; 2247bcf1882bcb33b690f0b104f7605c9a6da39f344Makoto Onuki private static final int ATTACHMENT_ID = ATTACHMENT_BASE + 1; 2257bcf1882bcb33b690f0b104f7605c9a6da39f344Makoto Onuki private static final int ATTACHMENTS_MESSAGE_ID = ATTACHMENT_BASE + 2; 2265a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook private static final int ATTACHMENTS_CACHED_FILE_ACCESS = ATTACHMENT_BASE + 3; 227f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 228f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int HOSTAUTH_BASE = 0x4000; 229f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int HOSTAUTH = HOSTAUTH_BASE; 230f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int HOSTAUTH_ID = HOSTAUTH_BASE + 1; 231f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 232e34525d0f026a7467cee1cb5fddcf25ba6f35207Marc Blank private static final int UPDATED_MESSAGE_BASE = 0x5000; 233e34525d0f026a7467cee1cb5fddcf25ba6f35207Marc Blank private static final int UPDATED_MESSAGE = UPDATED_MESSAGE_BASE; 234f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank private static final int UPDATED_MESSAGE_ID = UPDATED_MESSAGE_BASE + 1; 235f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 236f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank private static final int DELETED_MESSAGE_BASE = 0x6000; 237f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank private static final int DELETED_MESSAGE = DELETED_MESSAGE_BASE; 238f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank private static final int DELETED_MESSAGE_ID = DELETED_MESSAGE_BASE + 1; 239f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 240aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank private static final int POLICY_BASE = 0x7000; 241aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank private static final int POLICY = POLICY_BASE; 242aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank private static final int POLICY_ID = POLICY_BASE + 1; 243aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank 2445a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo private static final int QUICK_RESPONSE_BASE = 0x8000; 2455a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo private static final int QUICK_RESPONSE = QUICK_RESPONSE_BASE; 2465a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo private static final int QUICK_RESPONSE_ID = QUICK_RESPONSE_BASE + 1; 2475a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo private static final int QUICK_RESPONSE_ACCOUNT_ID = QUICK_RESPONSE_BASE + 2; 2485a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo 249f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final int UI_BASE = 0x9000; 250f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final int UI_FOLDERS = UI_BASE; 251f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final int UI_SUBFOLDERS = UI_BASE + 1; 252f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final int UI_MESSAGES = UI_BASE + 2; 253f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final int UI_MESSAGE = UI_BASE + 3; 2548e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu private static final int UI_UNDO = UI_BASE + 4; 2558e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu private static final int UI_FOLDER_REFRESH = UI_BASE + 5; 2568e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu private static final int UI_FOLDER = UI_BASE + 6; 2578e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu private static final int UI_ACCOUNT = UI_BASE + 7; 2588e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu private static final int UI_ACCTS = UI_BASE + 8; 2598e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu private static final int UI_ATTACHMENTS = UI_BASE + 9; 2608e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu private static final int UI_ATTACHMENT = UI_BASE + 10; 2618cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private static final int UI_ATTACHMENT_BY_CID = UI_BASE + 11; 2628cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private static final int UI_SEARCH = UI_BASE + 12; 2638cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private static final int UI_ACCOUNT_DATA = UI_BASE + 13; 2648cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private static final int UI_FOLDER_LOAD_MORE = UI_BASE + 14; 2658cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private static final int UI_CONVERSATION = UI_BASE + 15; 2668cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private static final int UI_RECENT_FOLDERS = UI_BASE + 16; 2678cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private static final int UI_DEFAULT_RECENT_FOLDERS = UI_BASE + 17; 2688cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private static final int UI_FULL_FOLDERS = UI_BASE + 18; 2698cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private static final int UI_ALL_FOLDERS = UI_BASE + 19; 2708cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private static final int UI_PURGE_FOLDER = UI_BASE + 20; 271f837c474a44f421b4f02bcb5cf3a67fccbced2d2Tony Mantler private static final int UI_INBOX = UI_BASE + 21; 272b7e0834121d564982c0389c87df775ba311429d4Tony Mantler private static final int UI_ACCTSETTINGS = UI_BASE + 22; 273f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 274c6953b77552d4cb71776cf0537dc226029381628Tony Mantler private static final int BODY_BASE = 0xA000; 275f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int BODY = BODY_BASE; 276f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int BODY_ID = BODY_BASE + 1; 2772f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler private static final int BODY_HTML = BODY_BASE + 2; 2782f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler private static final int BODY_TEXT = BODY_BASE + 3; 279f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 2800b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon private static final int CREDENTIAL_BASE = 0xB000; 2810b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon private static final int CREDENTIAL = CREDENTIAL_BASE; 2820b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon private static final int CREDENTIAL_ID = CREDENTIAL_BASE + 1; 2830b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon 284f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int BASE_SHIFT = 12; // 12 bits to the base type: 0, 0x1000, 0x2000, etc. 285f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 286c6953b77552d4cb71776cf0537dc226029381628Tony Mantler private static final SparseArray<String> TABLE_NAMES; 287c6953b77552d4cb71776cf0537dc226029381628Tony Mantler static { 288c6953b77552d4cb71776cf0537dc226029381628Tony Mantler SparseArray<String> array = new SparseArray<String>(11); 289c6953b77552d4cb71776cf0537dc226029381628Tony Mantler array.put(ACCOUNT_BASE >> BASE_SHIFT, Account.TABLE_NAME); 290c6953b77552d4cb71776cf0537dc226029381628Tony Mantler array.put(MAILBOX_BASE >> BASE_SHIFT, Mailbox.TABLE_NAME); 291c6953b77552d4cb71776cf0537dc226029381628Tony Mantler array.put(MESSAGE_BASE >> BASE_SHIFT, Message.TABLE_NAME); 292c6953b77552d4cb71776cf0537dc226029381628Tony Mantler array.put(ATTACHMENT_BASE >> BASE_SHIFT, Attachment.TABLE_NAME); 293c6953b77552d4cb71776cf0537dc226029381628Tony Mantler array.put(HOSTAUTH_BASE >> BASE_SHIFT, HostAuth.TABLE_NAME); 294c6953b77552d4cb71776cf0537dc226029381628Tony Mantler array.put(UPDATED_MESSAGE_BASE >> BASE_SHIFT, Message.UPDATED_TABLE_NAME); 295c6953b77552d4cb71776cf0537dc226029381628Tony Mantler array.put(DELETED_MESSAGE_BASE >> BASE_SHIFT, Message.DELETED_TABLE_NAME); 296c6953b77552d4cb71776cf0537dc226029381628Tony Mantler array.put(POLICY_BASE >> BASE_SHIFT, Policy.TABLE_NAME); 297c6953b77552d4cb71776cf0537dc226029381628Tony Mantler array.put(QUICK_RESPONSE_BASE >> BASE_SHIFT, QuickResponse.TABLE_NAME); 298c6953b77552d4cb71776cf0537dc226029381628Tony Mantler array.put(UI_BASE >> BASE_SHIFT, null); 299c6953b77552d4cb71776cf0537dc226029381628Tony Mantler array.put(BODY_BASE >> BASE_SHIFT, Body.TABLE_NAME); 3000b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon array.put(CREDENTIAL_BASE >> BASE_SHIFT, Credential.TABLE_NAME); 301c6953b77552d4cb71776cf0537dc226029381628Tony Mantler TABLE_NAMES = array; 302c6953b77552d4cb71776cf0537dc226029381628Tony Mantler } 303f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 3044525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH); 3054525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu 3064525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu /** 3074525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu * Functions which manipulate the database connection or files synchronize on this. 3084525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu * It's static because there can be multiple provider objects. 3094525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu * TODO: Do we actually need to synchronize across all DB access, not just connection creation? 3104525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu */ 3114525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu private static final Object sDatabaseLock = new Object(); 312f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 313f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank /** 314f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank * Let's only generate these SQL strings once, as they are used frequently 315f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank * Note that this isn't relevant for table creation strings, since they are used only once 316f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank */ 317f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank private static final String UPDATED_MESSAGE_INSERT = "insert or ignore into " + 318f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank Message.UPDATED_TABLE_NAME + " select * from " + Message.TABLE_NAME + " where " + 3193dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler BaseColumns._ID + '='; 320f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 321f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank private static final String UPDATED_MESSAGE_DELETE = "delete from " + 3223dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler Message.UPDATED_TABLE_NAME + " where " + BaseColumns._ID + '='; 323f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 324f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank private static final String DELETED_MESSAGE_INSERT = "insert or replace into " + 325f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank Message.DELETED_TABLE_NAME + " select * from " + Message.TABLE_NAME + " where " + 3263dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler BaseColumns._ID + '='; 327f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 3287525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler private static final String ORPHAN_BODY_MESSAGE_ID_SELECT = 3297525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler "select " + BodyColumns.MESSAGE_KEY + " from " + Body.TABLE_NAME + 3307525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler " except select " + BaseColumns._ID + " from " + Message.TABLE_NAME; 3317525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler 332f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank private static final String DELETE_ORPHAN_BODIES = "delete from " + Body.TABLE_NAME + 3337525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler " where " + BodyColumns.MESSAGE_KEY + " in " + '(' + ORPHAN_BODY_MESSAGE_ID_SELECT + ')'; 334f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 335f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank private static final String DELETE_BODY = "delete from " + Body.TABLE_NAME + 336fb7974f5bfb6275fb856b0f7ff386ef10680c83aMihai Preda " where " + BodyColumns.MESSAGE_KEY + '='; 337f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 338f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final ContentValues EMPTY_CONTENT_VALUES = new ContentValues(); 339261d6c3f0c97a12256519a2c3b131a56e57ab45fMakoto Onuki 340b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static final String MESSAGE_URI_PARAMETER_MAILBOX_ID = "mailboxId"; 341c81bef672089654e6da3babbeb0172bd636564b2Marc Blank 342f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // For undo handling 343f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private int mLastSequence = -1; 344ea2edb637036a7368b6ef82a0aafdb1a790e26e9Mark Wei private final ArrayList<ContentProviderOperation> mLastSequenceOps = 345f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank new ArrayList<ContentProviderOperation>(); 346f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 347f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Query parameter indicating the command came from UIProvider 348f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String IS_UIPROVIDER = "is_uiprovider"; 349f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 35071737836e6be308f752cb95c955a03146b039a9cYu Ping Hu private static final String SYNC_STATUS_CALLBACK_METHOD = "sync_status"; 35171737836e6be308f752cb95c955a03146b039a9cYu Ping Hu 352e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank /** 353e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank * Wrap the UriMatcher call so we can throw a runtime exception if an unknown Uri is passed in 354e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank * @param uri the Uri to match 355e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank * @return the match value 356e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank */ 357e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank private static int findMatch(Uri uri, String methodName) { 358e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank int match = sURIMatcher.match(uri); 359e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank if (match < 0) { 3601c1bd6a3eb2b7d99e30713648616c807ae20cbb5Marc Blank throw new IllegalArgumentException("Unknown uri: " + uri); 361bfac9f2e8a13f6c719608a6948203bbef921c99fMakoto Onuki } else if (Logging.LOGD) { 362560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.v(TAG, methodName + ": uri=" + uri + ", match is " + match); 363e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank } 364e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank return match; 365e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank } 366e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank 36717d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie // exposed for testing 36817d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie public static Uri INTEGRITY_CHECK_URI; 36917d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie 370e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank public static Uri ACCOUNT_BACKUP_URI; 371b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static Uri FOLDER_STATUS_URI; 372e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank 373f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private SQLiteDatabase mDatabase; 374f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private SQLiteDatabase mBodyDatabase; 375ebb79619e8ed3c9f0c051e7f323e3971bce7508dMarc Blank 376feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert private Handler mDelayedSyncHandler; 377feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert private final Set<SyncRequestMessage> mDelayedSyncRequests = new HashSet<SyncRequestMessage>(); 378feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert 3793f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon private static void reconcileAccountsAsync(final Context context) { 38050591a7be4fe59cc7063acddcb1f61833ba2f100James Lemieux if (context.getResources().getBoolean(R.bool.reconcile_accounts)) { 38150591a7be4fe59cc7063acddcb1f61833ba2f100James Lemieux EmailAsyncTask.runAsyncParallel(new Runnable() { 38250591a7be4fe59cc7063acddcb1f61833ba2f100James Lemieux @Override 38350591a7be4fe59cc7063acddcb1f61833ba2f100James Lemieux public void run() { 38450591a7be4fe59cc7063acddcb1f61833ba2f100James Lemieux AccountReconciler.reconcileAccounts(context); 38550591a7be4fe59cc7063acddcb1f61833ba2f100James Lemieux } 38650591a7be4fe59cc7063acddcb1f61833ba2f100James Lemieux }); 38750591a7be4fe59cc7063acddcb1f61833ba2f100James Lemieux } 3883f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon } 3893f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon 390f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank public static Uri uiUri(String type, long id) { 391f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return Uri.parse(uiUriString(type, id)); 392ebb79619e8ed3c9f0c051e7f323e3971bce7508dMarc Blank } 393ebb79619e8ed3c9f0c051e7f323e3971bce7508dMarc Blank 394f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 395f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Creates a URI string from a database ID (guaranteed to be unique). 396f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param type of the resource: uifolder, message, etc. 397f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param id the id of the resource. 398582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler * @return uri string 399f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 400f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank public static String uiUriString(String type, long id) { 401f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return "content://" + EmailContent.AUTHORITY + "/" + type + ((id == -1) ? "" : ("/" + id)); 40203cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank } 40303cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank 4042bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank /** 4052bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank * Orphan record deletion utility. Generates a sqlite statement like: 4062bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank * delete from <table> where <column> not in (select <foreignColumn> from <foreignTable>) 40717d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie * Exposed for testing. 4082bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank * @param db the EmailProvider database 4092bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank * @param table the table whose orphans are to be removed 4102bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank * @param column the column deletion will be based on 4112bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank * @param foreignColumn the column in the foreign table whose absence will trigger the deletion 4122bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank * @param foreignTable the foreign table 4132bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank */ 41417d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie public static void deleteUnlinked(SQLiteDatabase db, String table, String column, 415b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy String foreignColumn, String foreignTable) { 4162bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank int count = db.delete(table, column + " not in (select " + foreignColumn + " from " + 4172bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank foreignTable + ")", null); 4182bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank if (count > 0) { 419560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.w(TAG, "Found " + count + " orphaned row(s) in " + table); 4202bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank } 4212bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank } 4222bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank 423f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon 424f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon /** 425f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon * Make sure that parentKeys match with parentServerId. 426f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon * When we sync folders, we do two passes: First to create the mailbox rows, and second 427f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon * to set the parentKeys. Two passes are needed because we won't know the parent's Id 428f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon * until that row is inserted, and the order in which the rows are given is arbitrary. 429f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon * If we crash while this operation is in progress, the parent keys can be left uninitialized. 4300053401d07cd11f19c63dfbc3942d027b4067de8Tony Mantler * @param db SQLiteDatabase to modify 431f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon */ 432f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon private void fixParentKeys(SQLiteDatabase db) { 433f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon LogUtils.d(TAG, "Fixing parent keys"); 434f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon 435f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // Update the parentKey for each mailbox row to match the _id of the row whose 436f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // serverId matches our parentServerId. This will leave parentKey blank for any 437f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // row that does not have a parentServerId 438f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon 439f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // This is kind of a confusing sql statement, so here's the actual text of it, 440f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // for reference: 441f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // 442f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // update mailbox set parentKey = (select _id from mailbox as b where 443f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // mailbox.parentServerId=b.serverId and mailbox.parentServerId not null and 444f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // mailbox.accountKey=b.accountKey) 445f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon db.execSQL("update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.PARENT_KEY + "=" 4463dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + "(select " + Mailbox._ID + " from " + Mailbox.TABLE_NAME + " as b where " 447f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon + Mailbox.TABLE_NAME + "." + MailboxColumns.PARENT_SERVER_ID + "=" 448f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon + "b." + MailboxColumns.SERVER_ID + " and " 449f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon + Mailbox.TABLE_NAME + "." + MailboxColumns.PARENT_SERVER_ID + " not null and " 450f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon + Mailbox.TABLE_NAME + "." + MailboxColumns.ACCOUNT_KEY 451f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon + "=b." + Mailbox.ACCOUNT_KEY + ")"); 452f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon 453f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // Top level folders can still have uninitialized parent keys. Update these 454f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // to indicate that the parent is -1. 455f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // 456f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // update mailbox set parentKey = -1 where parentKey=0 or parentKey is null; 457f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon db.execSQL("update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.PARENT_KEY 458f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon + "=" + Mailbox.NO_MAILBOX + " where " + MailboxColumns.PARENT_KEY 459f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon + "=" + Mailbox.PARENT_KEY_UNINITIALIZED + " or " + MailboxColumns.PARENT_KEY 460f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon + " is null"); 461f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon 462f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon } 463f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon 46417d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie // exposed for testing 46517d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie public SQLiteDatabase getDatabase(Context context) { 4664525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu synchronized (sDatabaseLock) { 4674525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // Always return the cached database, if we've got one 4684525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu if (mDatabase != null) { 4694525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu return mDatabase; 4704525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu } 4710e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank 4724525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // Whenever we create or re-cache the databases, make sure that we haven't lost one 4734525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // to corruption 4744525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu checkDatabases(); 4750e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank 4764525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu DBHelper.DatabaseHelper helper = new DBHelper.DatabaseHelper(context, DATABASE_NAME); 4774525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu mDatabase = helper.getWritableDatabase(); 4784525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu DBHelper.BodyDatabaseHelper bodyHelper = 4794525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu new DBHelper.BodyDatabaseHelper(context, BODY_DATABASE_NAME); 4804525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu mBodyDatabase = bodyHelper.getWritableDatabase(); 4814525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu if (mBodyDatabase != null) { 4824525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu String bodyFileName = mBodyDatabase.getPath(); 4834525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu mDatabase.execSQL("attach \"" + bodyFileName + "\" as BodyDatabase"); 4844525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu } 485ef83299b99288c00b9d661260d19715e73e6889cMarc Blank 4864525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // Restore accounts if the database is corrupted... 4874525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu restoreIfNeeded(context, mDatabase); 4884525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // Check for any orphaned Messages in the updated/deleted tables 4894525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu deleteMessageOrphans(mDatabase, Message.UPDATED_TABLE_NAME); 4904525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu deleteMessageOrphans(mDatabase, Message.DELETED_TABLE_NAME); 4914525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // Delete orphaned mailboxes/messages/policies (account no longer exists) 4924525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu deleteUnlinked(mDatabase, Mailbox.TABLE_NAME, MailboxColumns.ACCOUNT_KEY, 4933dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler AccountColumns._ID, Account.TABLE_NAME); 4944525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu deleteUnlinked(mDatabase, Message.TABLE_NAME, MessageColumns.ACCOUNT_KEY, 4953dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler AccountColumns._ID, Account.TABLE_NAME); 4963dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler deleteUnlinked(mDatabase, Policy.TABLE_NAME, PolicyColumns._ID, 4974525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu AccountColumns.POLICY_KEY, Account.TABLE_NAME); 498f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon fixParentKeys(mDatabase); 4994525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu initUiProvider(); 5004525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu return mDatabase; 5014525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu } 502f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 503f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 5046e418aa41a17136be0dddb816d843428a0a1e722Marc Blank /** 505f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Perform startup actions related to UI 506f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 507f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private void initUiProvider() { 508f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Clear mailbox sync status 509f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mDatabase.execSQL("update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.UI_SYNC_STATUS + 510f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "=" + UIProvider.SyncStatus.NO_SYNC); 511f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 512f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 513f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 5149dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki * Restore user Account and HostAuth data from our backup database 5159dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki */ 516b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static void restoreIfNeeded(Context context, SQLiteDatabase mainDatabase) { 517f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (MailActivityEmail.DEBUG) { 518560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.w(TAG, "restoreIfNeeded..."); 5199dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki } 5209dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki // Check for legacy backup 5219dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki String legacyBackup = Preferences.getLegacyBackupPreference(context); 5229dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki // If there's a legacy backup, create a new-style backup and delete the legacy backup 5239dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki // In the 1:1000000000 chance that the user gets an app update just as his database becomes 5249dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki // corrupt, oh well... 5259dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki if (!TextUtils.isEmpty(legacyBackup)) { 5269dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki backupAccounts(context, mainDatabase); 5279dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki Preferences.clearLegacyBackupPreference(context); 528560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.w(TAG, "Created new EmailProvider backup database"); 5299dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki return; 5309dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki } 5319dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki 53282a207132b34377d532f19882f5bfc70bc657da0Tony Mantler // If there's a backup database (old style) delete it and trigger an account manager backup. 53382a207132b34377d532f19882f5bfc70bc657da0Tony Mantler // Roughly the same comment as above applies 53482a207132b34377d532f19882f5bfc70bc657da0Tony Mantler final File backupDb = context.getDatabasePath(BACKUP_DATABASE_NAME); 53582a207132b34377d532f19882f5bfc70bc657da0Tony Mantler if (backupDb.exists()) { 53682a207132b34377d532f19882f5bfc70bc657da0Tony Mantler backupAccounts(context, mainDatabase); 53782a207132b34377d532f19882f5bfc70bc657da0Tony Mantler context.deleteDatabase(BACKUP_DATABASE_NAME); 53882a207132b34377d532f19882f5bfc70bc657da0Tony Mantler LogUtils.w(TAG, "Migrated from backup database to account manager"); 53982a207132b34377d532f19882f5bfc70bc657da0Tony Mantler return; 54082a207132b34377d532f19882f5bfc70bc657da0Tony Mantler } 54182a207132b34377d532f19882f5bfc70bc657da0Tony Mantler 5429dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki // If we have accounts, we're done 543a6745514643f66741229a0cca3927931bdfa47b3yi.jang if (DatabaseUtils.longForQuery(mainDatabase, 544e743a06ddf7677706da7450100e19d0f4509a43cScott Kennedy "SELECT EXISTS (SELECT ? FROM " + Account.TABLE_NAME + " )", 545a6745514643f66741229a0cca3927931bdfa47b3yi.jang EmailContent.ID_PROJECTION) > 0) { 546874d25ff7073731a08c09b4528add58b720c4f6aMartin Hibdon if (MailActivityEmail.DEBUG) { 547874d25ff7073731a08c09b4528add58b720c4f6aMartin Hibdon LogUtils.w(TAG, "restoreIfNeeded: Account exists."); 548874d25ff7073731a08c09b4528add58b720c4f6aMartin Hibdon } 549874d25ff7073731a08c09b4528add58b720c4f6aMartin Hibdon return; 5509dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki } 55168a3607895963854637215a405145f190d6458f0Andy Huang 55282a207132b34377d532f19882f5bfc70bc657da0Tony Mantler restoreAccounts(context); 5539dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki } 5549dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki 5556c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki /** {@inheritDoc} */ 5566c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki @Override 5576c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki public void shutdown() { 5586c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki if (mDatabase != null) { 5596c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki mDatabase.close(); 5606c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki mDatabase = null; 5616c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki } 5626c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki if (mBodyDatabase != null) { 5636c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki mBodyDatabase.close(); 5646c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki mBodyDatabase = null; 5656c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki } 5666c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki } 5676c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki 56817d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie // exposed for testing 56917d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie public static void deleteMessageOrphans(SQLiteDatabase database, String tableName) { 570ef83299b99288c00b9d661260d19715e73e6889cMarc Blank if (database != null) { 571ef83299b99288c00b9d661260d19715e73e6889cMarc Blank // We'll look at all of the items in the table; there won't be many typically 572ef83299b99288c00b9d661260d19715e73e6889cMarc Blank Cursor c = database.query(tableName, ORPHANS_PROJECTION, null, null, null, null, null); 573ef83299b99288c00b9d661260d19715e73e6889cMarc Blank // Usually, there will be nothing in these tables, so make a quick check 574ef83299b99288c00b9d661260d19715e73e6889cMarc Blank try { 575ef83299b99288c00b9d661260d19715e73e6889cMarc Blank if (c.getCount() == 0) return; 576ef83299b99288c00b9d661260d19715e73e6889cMarc Blank ArrayList<Long> foundMailboxes = new ArrayList<Long>(); 577ef83299b99288c00b9d661260d19715e73e6889cMarc Blank ArrayList<Long> notFoundMailboxes = new ArrayList<Long>(); 578ef83299b99288c00b9d661260d19715e73e6889cMarc Blank ArrayList<Long> deleteList = new ArrayList<Long>(); 579ef83299b99288c00b9d661260d19715e73e6889cMarc Blank String[] bindArray = new String[1]; 580ef83299b99288c00b9d661260d19715e73e6889cMarc Blank while (c.moveToNext()) { 581ef83299b99288c00b9d661260d19715e73e6889cMarc Blank // Get the mailbox key and see if we've already found this mailbox 582ef83299b99288c00b9d661260d19715e73e6889cMarc Blank // If so, we're fine 583ef83299b99288c00b9d661260d19715e73e6889cMarc Blank long mailboxId = c.getLong(ORPHANS_MAILBOX_KEY); 584ef83299b99288c00b9d661260d19715e73e6889cMarc Blank // If we already know this mailbox doesn't exist, mark the message for deletion 585ef83299b99288c00b9d661260d19715e73e6889cMarc Blank if (notFoundMailboxes.contains(mailboxId)) { 586ef83299b99288c00b9d661260d19715e73e6889cMarc Blank deleteList.add(c.getLong(ORPHANS_ID)); 587ef83299b99288c00b9d661260d19715e73e6889cMarc Blank // If we don't know about this mailbox, we'll try to find it 588ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } else if (!foundMailboxes.contains(mailboxId)) { 589ef83299b99288c00b9d661260d19715e73e6889cMarc Blank bindArray[0] = Long.toString(mailboxId); 590ef83299b99288c00b9d661260d19715e73e6889cMarc Blank Cursor boxCursor = database.query(Mailbox.TABLE_NAME, 591ef83299b99288c00b9d661260d19715e73e6889cMarc Blank Mailbox.ID_PROJECTION, WHERE_ID, bindArray, null, null, null); 592ef83299b99288c00b9d661260d19715e73e6889cMarc Blank try { 593ef83299b99288c00b9d661260d19715e73e6889cMarc Blank // If it exists, we'll add it to the "found" mailboxes 594ef83299b99288c00b9d661260d19715e73e6889cMarc Blank if (boxCursor.moveToFirst()) { 595ef83299b99288c00b9d661260d19715e73e6889cMarc Blank foundMailboxes.add(mailboxId); 596ef83299b99288c00b9d661260d19715e73e6889cMarc Blank // Otherwise, we'll add to "not found" and mark the message for deletion 597ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } else { 598ef83299b99288c00b9d661260d19715e73e6889cMarc Blank notFoundMailboxes.add(mailboxId); 599ef83299b99288c00b9d661260d19715e73e6889cMarc Blank deleteList.add(c.getLong(ORPHANS_ID)); 600ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } 601ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } finally { 602ef83299b99288c00b9d661260d19715e73e6889cMarc Blank boxCursor.close(); 603ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } 604ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } 605ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } 606ef83299b99288c00b9d661260d19715e73e6889cMarc Blank // Now, delete the orphan messages 607ef83299b99288c00b9d661260d19715e73e6889cMarc Blank for (long messageId: deleteList) { 608ef83299b99288c00b9d661260d19715e73e6889cMarc Blank bindArray[0] = Long.toString(messageId); 609ef83299b99288c00b9d661260d19715e73e6889cMarc Blank database.delete(tableName, WHERE_ID, bindArray); 610ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } 611ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } finally { 612ef83299b99288c00b9d661260d19715e73e6889cMarc Blank c.close(); 613ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } 614ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } 615ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } 616ef83299b99288c00b9d661260d19715e73e6889cMarc Blank 617f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler @Override 618f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler public int delete(Uri uri, String selection, String[] selectionArgs) { 619feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert Log.d(TAG, "Delete: " + uri); 620e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank final int match = findMatch(uri, "delete"); 6212d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final Context context = getContext(); 622cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank // Pick the correct database for this operation 623cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank // If we're in a transaction already (which would happen during applyBatch), then the 624cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank // body database is already attached to the email database and any attempt to use the 625cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank // body database directly will result in a SQLiteException (the database is locked) 6262d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final SQLiteDatabase db = getDatabase(context); 6272d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final int table = match >> BASE_SHIFT; 6282c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank String id = "0"; 629cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank boolean messageDeletion = false; 630f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 6312d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final String tableName = TABLE_NAMES.valueAt(table); 632b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank int result = -1; 633f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 6342c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank try { 635f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (match == MESSAGE_ID || match == SYNCED_MESSAGE_ID) { 636f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (!uri.getBooleanQueryParameter(IS_UIPROVIDER, false)) { 637f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUIConversation(uri); 638f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 639f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6402c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank switch (match) { 641f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_MESSAGE: 642f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return uiDeleteMessage(uri); 643f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ACCOUNT_DATA: 644f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return uiDeleteAccountData(uri); 645f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ACCOUNT: 646f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return uiDeleteAccount(uri); 647e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler case UI_PURGE_FOLDER: 648e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler return uiPurgeFolder(uri); 64900287c4d8f54ae07c89bb3893f440acdca09d728Marc Blank case MESSAGE_SELECTION: 650c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank Cursor findCursor = db.query(tableName, Message.ID_COLUMN_PROJECTION, selection, 651c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank selectionArgs, null, null, null); 652c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank try { 653c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank if (findCursor.moveToFirst()) { 654c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank return delete(ContentUris.withAppendedId( 65500287c4d8f54ae07c89bb3893f440acdca09d728Marc Blank Message.CONTENT_URI, 656c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank findCursor.getLong(Message.ID_COLUMNS_ID_COLUMN)), 657c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank null, null); 658c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } else { 659c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank return 0; 660c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } 661c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } finally { 662c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank findCursor.close(); 663c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } 6642c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank // These are cases in which one or more Messages might get deleted, either by 6652c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank // cascade or explicitly 6662c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case MAILBOX_ID: 6672c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case MAILBOX: 6682c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case ACCOUNT_ID: 6692c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case ACCOUNT: 6702c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case MESSAGE: 671f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank case SYNCED_MESSAGE_ID: 6722c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case MESSAGE_ID: 6732c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank // Handle lost Body records here, since this cannot be done in a trigger 6742c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank // The process is: 675a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank // 1) Begin a transaction, ensuring that both databases are affected atomically 676a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank // 2) Do the requested deletion, with cascading deletions handled in triggers 677a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank // 3) End the transaction, committing all changes atomically 6786c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler // 6796c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler // Bodies are auto-deleted here; Attachments are auto-deleted via trigger 680cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank messageDeletion = true; 6818587aa61211d288d05b5fb2ddf02d69cabe6a9e2Marc Blank db.beginTransaction(); 6822c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank break; 6832c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank } 6842c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank switch (match) { 6852c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case BODY_ID: 686f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank case DELETED_MESSAGE_ID: 687f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank case SYNCED_MESSAGE_ID: 6882c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case MESSAGE_ID: 6892c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case UPDATED_MESSAGE_ID: 6902c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case ATTACHMENT_ID: 6912c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case MAILBOX_ID: 6922c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case ACCOUNT_ID: 6932c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case HOSTAUTH_ID: 694aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank case POLICY_ID: 6955a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo case QUICK_RESPONSE_ID: 6960b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon case CREDENTIAL_ID: 6972c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank id = uri.getPathSegments().get(1); 698f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank if (match == SYNCED_MESSAGE_ID) { 699f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank // For synced messages, first copy the old message to the deleted table and 700f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank // delete it from the updated table (in case it was updated first) 701f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank // Note that this is all within a transaction, for atomicity 702f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank db.execSQL(DELETED_MESSAGE_INSERT + id); 703f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank db.execSQL(UPDATED_MESSAGE_DELETE + id); 704f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank } 705503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu 706c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu final long accountId; 707c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu if (match == MAILBOX_ID) { 708c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu accountId = Mailbox.getAccountIdForMailbox(context, id); 709c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } else { 710c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu accountId = Account.NO_ACCOUNT; 711c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } 712c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu 713503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu result = db.delete(tableName, whereWithId(id, selection), selectionArgs); 714503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu 715f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (match == ACCOUNT_ID) { 716f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUI(UIPROVIDER_ACCOUNT_NOTIFIER, id); 71705649dca2f59f28cd4295e041045a605badddb15Tony Mantler notifyUI(UIPROVIDER_ALL_ACCOUNTS_NOTIFIER, null); 718f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else if (match == MAILBOX_ID) { 719c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu notifyUIFolder(id, accountId); 720f6db592c313c77190727c7cd72d3edda9d23a099Marc Blank } else if (match == ATTACHMENT_ID) { 721f6db592c313c77190727c7cd72d3edda9d23a099Marc Blank notifyUI(UIPROVIDER_ATTACHMENT_NOTIFIER, id); 722f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 7232c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank break; 7246c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler case ATTACHMENTS_MESSAGE_ID: 7256c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler // All attachments for the given message 7266c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler id = uri.getPathSegments().get(2); 727fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank result = db.delete(tableName, 7283dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler whereWith(AttachmentColumns.MESSAGE_KEY + "=" + id, selection), 7293dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler selectionArgs); 7306c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler break; 7316c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler 7322c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case BODY: 7332c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case MESSAGE: 734f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank case DELETED_MESSAGE: 7352c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case UPDATED_MESSAGE: 7362c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case ATTACHMENT: 7372c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case MAILBOX: 7382c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case ACCOUNT: 7392c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case HOSTAUTH: 740aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank case POLICY: 741fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank result = db.delete(tableName, selection, selectionArgs); 7422c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank break; 743ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu case MESSAGE_MOVE: 744ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu db.delete(MessageMove.TABLE_NAME, selection, selectionArgs); 745ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu break; 746ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu case MESSAGE_STATE_CHANGE: 747ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu db.delete(MessageStateChange.TABLE_NAME, selection, selectionArgs); 748ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu break; 7492c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank default: 7502c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank throw new IllegalArgumentException("Unknown URI " + uri); 7512c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank } 752cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank if (messageDeletion) { 753fb7974f5bfb6275fb856b0f7ff386ef10680c83aMihai Preda if (match == MESSAGE_ID) { 7545f4dbd64389cd6540a93cde1daed304bf9392a01Andrew Stadler // Delete the Body record associated with the deleted message 7557525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final ContentValues emptyValues = new ContentValues(2); 7567525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler emptyValues.putNull(BodyColumns.HTML_CONTENT); 7577525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler emptyValues.putNull(BodyColumns.TEXT_CONTENT); 7587525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final long messageId = Long.valueOf(id); 7597525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler try { 7607525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler writeBodyFiles(context, messageId, emptyValues); 7617525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } catch (final IllegalStateException e) { 7627525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler LogUtils.v(LogUtils.TAG, e, "Exception while deleting bodies"); 7637525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 764f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank db.execSQL(DELETE_BODY + id); 765fb7974f5bfb6275fb856b0f7ff386ef10680c83aMihai Preda } else { 766fb7974f5bfb6275fb856b0f7ff386ef10680c83aMihai Preda // Delete any orphaned Body records 7677525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final Cursor orphans = db.rawQuery(ORPHAN_BODY_MESSAGE_ID_SELECT, null); 7687525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler try { 7697525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final ContentValues emptyValues = new ContentValues(2); 7707525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler emptyValues.putNull(BodyColumns.HTML_CONTENT); 7717525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler emptyValues.putNull(BodyColumns.TEXT_CONTENT); 7727525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler while (orphans.moveToNext()) { 7737525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final long messageId = orphans.getLong(0); 7747525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler try { 7757525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler writeBodyFiles(context, messageId, emptyValues); 7767525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } catch (final IllegalStateException e) { 7777525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler LogUtils.v(LogUtils.TAG, e, "Exception while deleting bodies"); 7787525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 7797525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 7807525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } finally { 7817525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler orphans.close(); 7827525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 783fb7974f5bfb6275fb856b0f7ff386ef10680c83aMihai Preda db.execSQL(DELETE_ORPHAN_BODIES); 784cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank } 7858587aa61211d288d05b5fb2ddf02d69cabe6a9e2Marc Blank db.setTransactionSuccessful(); 7865f4dbd64389cd6540a93cde1daed304bf9392a01Andrew Stadler } 7870e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank } catch (SQLiteException e) { 7880e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank checkDatabases(); 7890e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank throw e; 7902c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank } finally { 791cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank if (messageDeletion) { 7928587aa61211d288d05b5fb2ddf02d69cabe6a9e2Marc Blank db.endTransaction(); 7935f4dbd64389cd6540a93cde1daed304bf9392a01Andrew Stadler } 794f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 795261d6c3f0c97a12256519a2c3b131a56e57ab45fMakoto Onuki 796bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy // Notify all notifier cursors 797e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy sendNotifierChange(getBaseNotificationUri(match), NOTIFICATION_OP_DELETE, id); 798bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy 799bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy // Notify all email content cursors 80005649dca2f59f28cd4295e041045a605badddb15Tony Mantler notifyUI(EmailContent.CONTENT_URI, null); 801626f3e48a4f14c38a973dd2bea2e2debea7637a5Andrew Stadler return result; 802f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 803f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 804f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler @Override 805f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler // Use the email- prefix because message, mailbox, and account are so generic (e.g. SMS, IM) 806f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler public String getType(Uri uri) { 807e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank int match = findMatch(uri, "getType"); 808f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler switch (match) { 809a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank case BODY_ID: 810a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank return "vnd.android.cursor.item/email-body"; 811a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank case BODY: 812c81bef672089654e6da3babbeb0172bd636564b2Marc Blank return "vnd.android.cursor.dir/email-body"; 813e34525d0f026a7467cee1cb5fddcf25ba6f35207Marc Blank case UPDATED_MESSAGE_ID: 814a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank case MESSAGE_ID: 815c81bef672089654e6da3babbeb0172bd636564b2Marc Blank // NOTE: According to the framework folks, we're supposed to invent mime types as 816c81bef672089654e6da3babbeb0172bd636564b2Marc Blank // a way of passing information to drag & drop recipients. 817c81bef672089654e6da3babbeb0172bd636564b2Marc Blank // If there's a mailboxId parameter in the url, we respond with a mime type that 818c81bef672089654e6da3babbeb0172bd636564b2Marc Blank // has -n appended, where n is the mailboxId of the message. The drag & drop code 819c81bef672089654e6da3babbeb0172bd636564b2Marc Blank // uses this information to know not to allow dragging the item to its own mailbox 820c81bef672089654e6da3babbeb0172bd636564b2Marc Blank String mimeType = EMAIL_MESSAGE_MIME_TYPE; 821c81bef672089654e6da3babbeb0172bd636564b2Marc Blank String mailboxId = uri.getQueryParameter(MESSAGE_URI_PARAMETER_MAILBOX_ID); 822c81bef672089654e6da3babbeb0172bd636564b2Marc Blank if (mailboxId != null) { 823c81bef672089654e6da3babbeb0172bd636564b2Marc Blank mimeType += "-" + mailboxId; 824c81bef672089654e6da3babbeb0172bd636564b2Marc Blank } 825c81bef672089654e6da3babbeb0172bd636564b2Marc Blank return mimeType; 826e34525d0f026a7467cee1cb5fddcf25ba6f35207Marc Blank case UPDATED_MESSAGE: 827fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank case MESSAGE: 828a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank return "vnd.android.cursor.dir/email-message"; 829fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank case MAILBOX: 830fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank return "vnd.android.cursor.dir/email-mailbox"; 831fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank case MAILBOX_ID: 832fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank return "vnd.android.cursor.item/email-mailbox"; 833fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank case ACCOUNT: 834fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank return "vnd.android.cursor.dir/email-account"; 835fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank case ACCOUNT_ID: 836fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank return "vnd.android.cursor.item/email-account"; 8374119218e2fd64341ac946fb8f2cbdb796a444cb8Andrew Stadler case ATTACHMENTS_MESSAGE_ID: 838fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank case ATTACHMENT: 839fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank return "vnd.android.cursor.dir/email-attachment"; 840fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank case ATTACHMENT_ID: 84109fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank return EMAIL_ATTACHMENT_MIME_TYPE; 842fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank case HOSTAUTH: 843fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank return "vnd.android.cursor.dir/email-hostauth"; 844fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank case HOSTAUTH_ID: 845fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank return "vnd.android.cursor.item/email-hostauth"; 846fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank default: 847f9fd4b6bb4a275d12548c250176b9be918619c7dYu Ping Hu return null; 848f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 849f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 850f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 851c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu // These URIs are used for specific UI notifications. We don't use EmailContent.CONTENT_URI 852c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu // as the base because that gets spammed. 853de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler // These can't be statically initialized because they depend on EmailContent.AUTHORITY 854de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler private static Uri UIPROVIDER_CONVERSATION_NOTIFIER; 855de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler private static Uri UIPROVIDER_FOLDER_NOTIFIER; 856de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler private static Uri UIPROVIDER_FOLDERLIST_NOTIFIER; 857de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler private static Uri UIPROVIDER_ACCOUNT_NOTIFIER; 8589e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler // Not currently used 859de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler //public static Uri UIPROVIDER_SETTINGS_NOTIFIER; 860de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler private static Uri UIPROVIDER_ATTACHMENT_NOTIFIER; 861de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler private static Uri UIPROVIDER_ATTACHMENTS_NOTIFIER; 862de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler public static Uri UIPROVIDER_ALL_ACCOUNTS_NOTIFIER; 863de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler private static Uri UIPROVIDER_MESSAGE_NOTIFIER; 864de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler private static Uri UIPROVIDER_RECENT_FOLDERS_NOTIFIER; 865f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 866f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler @Override 867f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler public Uri insert(Uri uri, ContentValues values) { 868feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert Log.d(TAG, "Insert: " + uri); 8692d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final int match = findMatch(uri, "insert"); 8702d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final Context context = getContext(); 8711b9337ea4f41c12cb108cbe67e0077169b1f0b8cMarc Blank 872cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank // See the comment at delete(), above 8732d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final SQLiteDatabase db = getDatabase(context); 8742d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final int table = match >> BASE_SHIFT; 875bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy String id = "0"; 876bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy long longId; 877f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 8785b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki // We do NOT allow setting of unreadCount/messageCount via the provider 8795b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki // These columns are maintained via triggers 8805b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki if (match == MAILBOX_ID || match == MAILBOX) { 8815b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki values.put(MailboxColumns.UNREAD_COUNT, 0); 8825b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki values.put(MailboxColumns.MESSAGE_COUNT, 0); 8835b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki } 884f678a8e67ace74ea285dcec9727d0117e23a5c73Makoto Onuki 8859e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler final Uri resultUri; 886f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 8870e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank try { 8880e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank switch (match) { 8897525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler case BODY: 8907525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final ContentValues dbValues = new ContentValues(values); 8917525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler // Prune out the content we don't want in the DB 8927525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler dbValues.remove(BodyColumns.HTML_CONTENT); 8937525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler dbValues.remove(BodyColumns.TEXT_CONTENT); 8947525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler // TODO: move this to the message table 8957525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler longId = db.insert(Body.TABLE_NAME, "foo", dbValues); 8967525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler resultUri = ContentUris.withAppendedId(uri, longId); 8977525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler // Write content to the filesystem where appropriate 8987525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler // This will look less ugly once the body table is folded into the message table 8997525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler // and we can just use longId instead 9007525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (!values.containsKey(BodyColumns.MESSAGE_KEY)) { 9017525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler throw new IllegalArgumentException( 9027525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler "Cannot insert body without MESSAGE_KEY"); 9037525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 9047525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final long messageId = values.getAsLong(BodyColumns.MESSAGE_KEY); 9057525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler writeBodyFiles(getContext(), messageId, values); 9067525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler break; 9076e418aa41a17136be0dddb816d843428a0a1e722Marc Blank // NOTE: It is NOT legal for production code to insert directly into UPDATED_MESSAGE 9086e418aa41a17136be0dddb816d843428a0a1e722Marc Blank // or DELETED_MESSAGE; see the comment below for details 9090e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case UPDATED_MESSAGE: 9100e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case DELETED_MESSAGE: 9116e418aa41a17136be0dddb816d843428a0a1e722Marc Blank case MESSAGE: 9125057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux decodeEmailAddresses(values); 9130e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ATTACHMENT: 9140e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case MAILBOX: 9150e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ACCOUNT: 9160e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case HOSTAUTH: 9170b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon case CREDENTIAL: 918aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank case POLICY: 9195a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo case QUICK_RESPONSE: 920c6953b77552d4cb71776cf0537dc226029381628Tony Mantler longId = db.insert(TABLE_NAMES.valueAt(table), "foo", values); 921bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy resultUri = ContentUris.withAppendedId(uri, longId); 9226e418aa41a17136be0dddb816d843428a0a1e722Marc Blank switch(match) { 923f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case MESSAGE: 9243dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler final long mailboxId = values.getAsLong(MessageColumns.MAILBOX_KEY); 925f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (!uri.getBooleanQueryParameter(IS_UIPROVIDER, false)) { 926c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu notifyUIConversationMailbox(mailboxId); 927f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 9283dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler notifyUIFolder(mailboxId, values.getAsLong(MessageColumns.ACCOUNT_KEY)); 929f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 9306e418aa41a17136be0dddb816d843428a0a1e722Marc Blank case MAILBOX: 9316e418aa41a17136be0dddb816d843428a0a1e722Marc Blank if (values.containsKey(MailboxColumns.TYPE)) { 932c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu if (values.getAsInteger(MailboxColumns.TYPE) < 933c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu Mailbox.TYPE_NOT_EMAIL) { 934c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu // Notify the account when a new mailbox is added 935c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu final Long accountId = 936c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu values.getAsLong(MailboxColumns.ACCOUNT_KEY); 9379e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler if (accountId != null && accountId > 0) { 938c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu notifyUI(UIPROVIDER_ACCOUNT_NOTIFIER, accountId); 939c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu notifyUI(UIPROVIDER_FOLDERLIST_NOTIFIER, accountId); 940c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } 9416e418aa41a17136be0dddb816d843428a0a1e722Marc Blank } 9426e418aa41a17136be0dddb816d843428a0a1e722Marc Blank } 943503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu break; 9446e418aa41a17136be0dddb816d843428a0a1e722Marc Blank case ACCOUNT: 945e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu updateAccountSyncInterval(longId, values); 946503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu if (!uri.getBooleanQueryParameter(IS_UIPROVIDER, false)) { 947503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu notifyUIAccount(longId); 9486e418aa41a17136be0dddb816d843428a0a1e722Marc Blank } 94905649dca2f59f28cd4295e041045a605badddb15Tony Mantler notifyUI(UIPROVIDER_ALL_ACCOUNTS_NOTIFIER, null); 950503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu break; 951503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu case UPDATED_MESSAGE: 952503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu case DELETED_MESSAGE: 953503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu throw new IllegalArgumentException("Unknown URL " + uri); 954503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu case ATTACHMENT: 955503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu int flags = 0; 9563dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler if (values.containsKey(AttachmentColumns.FLAGS)) { 9573dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler flags = values.getAsInteger(AttachmentColumns.FLAGS); 958503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu } 959503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu // Report all new attachments to the download service 9603dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler if (TextUtils.isEmpty(values.getAsString(AttachmentColumns.LOCATION))) { 9615ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon LogUtils.w(TAG, new Throwable(), "attachment with blank location"); 9625ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon } 963503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu mAttachmentService.attachmentChanged(getContext(), longId, flags); 9646e418aa41a17136be0dddb816d843428a0a1e722Marc Blank break; 96509fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank } 9660e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank break; 967c6953b77552d4cb71776cf0537dc226029381628Tony Mantler case QUICK_RESPONSE_ACCOUNT_ID: 968c6953b77552d4cb71776cf0537dc226029381628Tony Mantler longId = Long.parseLong(uri.getPathSegments().get(2)); 9693dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler values.put(QuickResponseColumns.ACCOUNT_KEY, longId); 970c6953b77552d4cb71776cf0537dc226029381628Tony Mantler return insert(QuickResponse.CONTENT_URI, values); 9710e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case MAILBOX_ID: 9720e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank // This implies adding a message to a mailbox 9730e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank // Hmm, a problem here is that we can't link the account as well, so it must be 9740e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank // already in the values... 975bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy longId = Long.parseLong(uri.getPathSegments().get(1)); 976bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy values.put(MessageColumns.MAILBOX_KEY, longId); 977261d6c3f0c97a12256519a2c3b131a56e57ab45fMakoto Onuki return insert(Message.CONTENT_URI, values); // Recurse 9780e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case MESSAGE_ID: 9790e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank // This implies adding an attachment to a message. 980bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy id = uri.getPathSegments().get(1); 981bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy longId = Long.parseLong(id); 982bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy values.put(AttachmentColumns.MESSAGE_KEY, longId); 983261d6c3f0c97a12256519a2c3b131a56e57ab45fMakoto Onuki return insert(Attachment.CONTENT_URI, values); // Recurse 9840e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ACCOUNT_ID: 9850e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank // This implies adding a mailbox to an account. 986bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy longId = Long.parseLong(uri.getPathSegments().get(1)); 987bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy values.put(MailboxColumns.ACCOUNT_KEY, longId); 988261d6c3f0c97a12256519a2c3b131a56e57ab45fMakoto Onuki return insert(Mailbox.CONTENT_URI, values); // Recurse 9890e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ATTACHMENTS_MESSAGE_ID: 990c6953b77552d4cb71776cf0537dc226029381628Tony Mantler longId = db.insert(TABLE_NAMES.valueAt(table), "foo", values); 991bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy resultUri = ContentUris.withAppendedId(Attachment.CONTENT_URI, longId); 9920e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank break; 9930e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank default: 994ef83299b99288c00b9d661260d19715e73e6889cMarc Blank throw new IllegalArgumentException("Unknown URL " + uri); 9950e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank } 9960e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank } catch (SQLiteException e) { 9970e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank checkDatabases(); 9980e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank throw e; 999f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 1000f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 1001bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy // Notify all notifier cursors 1002e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy sendNotifierChange(getBaseNotificationUri(match), NOTIFICATION_OP_INSERT, id); 1003bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy 1004261d6c3f0c97a12256519a2c3b131a56e57ab45fMakoto Onuki // Notify all existing cursors. 100505649dca2f59f28cd4295e041045a605badddb15Tony Mantler notifyUI(EmailContent.CONTENT_URI, null); 1006626f3e48a4f14c38a973dd2bea2e2debea7637a5Andrew Stadler return resultUri; 1007f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 1008f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 1009c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler @Override 1010c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler public boolean onCreate() { 1011c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler Context context = getContext(); 1012c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler EmailContent.init(context); 10134525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu init(context); 10144525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // Do this last, so that EmailContent/EmailProvider are initialized 10154525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu MailActivityEmail.setServicesEnabledAsync(context); 10163f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon reconcileAccountsAsync(context); 101702b9ac1b95947a2dc66bc0f6c770a1cb3ffdbbc9Tony Mantler 101802b9ac1b95947a2dc66bc0f6c770a1cb3ffdbbc9Tony Mantler // Update widgets 101902b9ac1b95947a2dc66bc0f6c770a1cb3ffdbbc9Tony Mantler final Intent updateAllWidgetsIntent = 102002b9ac1b95947a2dc66bc0f6c770a1cb3ffdbbc9Tony Mantler new Intent(com.android.mail.utils.Utils.ACTION_NOTIFY_DATASET_CHANGED); 102102b9ac1b95947a2dc66bc0f6c770a1cb3ffdbbc9Tony Mantler updateAllWidgetsIntent.putExtra(BaseWidgetProvider.EXTRA_UPDATE_ALL_WIDGETS, true); 102202b9ac1b95947a2dc66bc0f6c770a1cb3ffdbbc9Tony Mantler updateAllWidgetsIntent.setType(context.getString(R.string.application_mime_type)); 102302b9ac1b95947a2dc66bc0f6c770a1cb3ffdbbc9Tony Mantler context.sendBroadcast(updateAllWidgetsIntent); 102402b9ac1b95947a2dc66bc0f6c770a1cb3ffdbbc9Tony Mantler 102503dc3f22d151d0cddc6487429786a708de813d67Tony Mantler // The combined account name changes on locale changes 102603dc3f22d151d0cddc6487429786a708de813d67Tony Mantler final Configuration oldConfiguration = 102703dc3f22d151d0cddc6487429786a708de813d67Tony Mantler new Configuration(context.getResources().getConfiguration()); 102803dc3f22d151d0cddc6487429786a708de813d67Tony Mantler context.registerComponentCallbacks(new ComponentCallbacks() { 102903dc3f22d151d0cddc6487429786a708de813d67Tony Mantler @Override 103003dc3f22d151d0cddc6487429786a708de813d67Tony Mantler public void onConfigurationChanged(Configuration configuration) { 103103dc3f22d151d0cddc6487429786a708de813d67Tony Mantler int delta = oldConfiguration.updateFrom(configuration); 103203dc3f22d151d0cddc6487429786a708de813d67Tony Mantler if (Configuration.needNewResources(delta, ActivityInfo.CONFIG_LOCALE)) { 103303dc3f22d151d0cddc6487429786a708de813d67Tony Mantler notifyUIAccount(COMBINED_ACCOUNT_ID); 103403dc3f22d151d0cddc6487429786a708de813d67Tony Mantler } 103503dc3f22d151d0cddc6487429786a708de813d67Tony Mantler } 103603dc3f22d151d0cddc6487429786a708de813d67Tony Mantler 103703dc3f22d151d0cddc6487429786a708de813d67Tony Mantler @Override 103803dc3f22d151d0cddc6487429786a708de813d67Tony Mantler public void onLowMemory() {} 103903dc3f22d151d0cddc6487429786a708de813d67Tony Mantler }); 104003dc3f22d151d0cddc6487429786a708de813d67Tony Mantler 1041c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler MailPrefs.get(context).registerOnSharedPreferenceChangeListener(this); 1042c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler 10434525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu return false; 10444525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu } 10454525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu 10464525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu private static void init(final Context context) { 10474525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // Synchronize on the matcher rather than the class object to minimize risk of contention 10484525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // & deadlock. 10494525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu synchronized (sURIMatcher) { 10504525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // We use the existence of this variable as indicative of whether this function has 10514525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // already run. 10524525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu if (INTEGRITY_CHECK_URI != null) { 10534525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu return; 10544525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu } 1055c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler INTEGRITY_CHECK_URI = Uri.parse("content://" + EmailContent.AUTHORITY + 1056c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler "/integrityCheck"); 1057c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler ACCOUNT_BACKUP_URI = 1058c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler Uri.parse("content://" + EmailContent.AUTHORITY + "/accountBackup"); 1059c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler FOLDER_STATUS_URI = 1060c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler Uri.parse("content://" + EmailContent.AUTHORITY + "/status"); 1061c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler EMAIL_APP_MIME_TYPE = context.getString(R.string.application_mime_type); 1062c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 1063de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler final String uiNotificationAuthority = 1064de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler EmailContent.EMAIL_PACKAGE_NAME + ".uinotifications"; 1065de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler UIPROVIDER_CONVERSATION_NOTIFIER = 1066de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler Uri.parse("content://" + uiNotificationAuthority + "/uimessages"); 1067de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler UIPROVIDER_FOLDER_NOTIFIER = 1068de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler Uri.parse("content://" + uiNotificationAuthority + "/uifolder"); 1069de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler UIPROVIDER_FOLDERLIST_NOTIFIER = 1070de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler Uri.parse("content://" + uiNotificationAuthority + "/uifolders"); 1071de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler UIPROVIDER_ACCOUNT_NOTIFIER = 1072de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler Uri.parse("content://" + uiNotificationAuthority + "/uiaccount"); 1073de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler // Not currently used 1074de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler /* UIPROVIDER_SETTINGS_NOTIFIER = 1075de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler Uri.parse("content://" + uiNotificationAuthority + "/uisettings");*/ 1076de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler UIPROVIDER_ATTACHMENT_NOTIFIER = 1077de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler Uri.parse("content://" + uiNotificationAuthority + "/uiattachment"); 1078de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler UIPROVIDER_ATTACHMENTS_NOTIFIER = 1079de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler Uri.parse("content://" + uiNotificationAuthority + "/uiattachments"); 1080de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler UIPROVIDER_ALL_ACCOUNTS_NOTIFIER = 1081de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler Uri.parse("content://" + uiNotificationAuthority + "/uiaccts"); 1082de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler UIPROVIDER_MESSAGE_NOTIFIER = 1083de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler Uri.parse("content://" + uiNotificationAuthority + "/uimessage"); 1084de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler UIPROVIDER_RECENT_FOLDERS_NOTIFIER = 1085de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler Uri.parse("content://" + uiNotificationAuthority + "/uirecentfolders"); 1086de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler 1087c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // All accounts 10884525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "account", ACCOUNT); 1089c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // A specific account 1090c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // insert into this URI causes a mailbox to be added to the account 10914525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "account/#", ACCOUNT_ID); 10924525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "accountCheck/#", ACCOUNT_CHECK); 1093c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 1094c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // All mailboxes 10954525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "mailbox", MAILBOX); 1096c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // A specific mailbox 1097c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // insert into this URI causes a message to be added to the mailbox 1098c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // ** NOTE For now, the accountKey must be set manually in the values! 10994525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "mailbox/*", MAILBOX_ID); 11004525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "mailboxNotification/#", 11014525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu MAILBOX_NOTIFICATION); 11024525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "mailboxMostRecentMessage/#", 1103c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler MAILBOX_MOST_RECENT_MESSAGE); 11044525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "mailboxCount/#", MAILBOX_MESSAGE_COUNT); 1105c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 1106c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // All messages 11074525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "message", MESSAGE); 1108c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // A specific message 1109c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // insert into this URI causes an attachment to be added to the message 11104525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "message/#", MESSAGE_ID); 1111c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 1112c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // A specific attachment 11134525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "attachment", ATTACHMENT); 1114c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // A specific attachment (the header information) 11154525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "attachment/#", ATTACHMENT_ID); 1116c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // The attachments of a specific message (query only) (insert & delete TBD) 11174525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "attachment/message/#", 11184525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu ATTACHMENTS_MESSAGE_ID); 11194525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "attachment/cachedFile", 1120c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler ATTACHMENTS_CACHED_FILE_ACCESS); 1121c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 1122c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // All mail bodies 11234525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "body", BODY); 1124c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // A specific mail body 11254525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "body/#", BODY_ID); 11262f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler // A specific HTML body part, for openFile 11272f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler sURIMatcher.addURI(EmailContent.AUTHORITY, "bodyHtml/#", BODY_HTML); 11282f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler // A specific text body part, for openFile 11292f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler sURIMatcher.addURI(EmailContent.AUTHORITY, "bodyText/#", BODY_TEXT); 1130c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 1131c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // All hostauth records 11324525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "hostauth", HOSTAUTH); 1133c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // A specific hostauth 11344525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "hostauth/*", HOSTAUTH_ID); 1135c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 11360b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon // All credential records 11370b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon sURIMatcher.addURI(EmailContent.AUTHORITY, "credential", CREDENTIAL); 11380b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon // A specific credential 11390b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon sURIMatcher.addURI(EmailContent.AUTHORITY, "credential/*", CREDENTIAL_ID); 11400b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon 1141c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler /** 1142c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler * THIS URI HAS SPECIAL SEMANTICS 1143c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler * ITS USE IS INTENDED FOR THE UI TO MARK CHANGES THAT NEED TO BE SYNCED BACK 1144c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler * TO A SERVER VIA A SYNC ADAPTER 1145c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler */ 11464525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "syncedMessage/#", SYNCED_MESSAGE_ID); 11474525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "messageBySelection", MESSAGE_SELECTION); 1148c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 1149ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, MessageMove.PATH, MESSAGE_MOVE); 1150ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, MessageStateChange.PATH, 1151ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu MESSAGE_STATE_CHANGE); 1152336e65b6e1eb92fac8f03b5c39dde19361577cb4Yu Ping Hu 1153c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler /** 1154c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler * THE URIs BELOW THIS POINT ARE INTENDED TO BE USED BY SYNC ADAPTERS ONLY 1155c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler * THEY REFER TO DATA CREATED AND MAINTAINED BY CALLS TO THE SYNCED_MESSAGE_ID URI 1156c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler * BY THE UI APPLICATION 1157c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler */ 1158c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // All deleted messages 11594525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "deletedMessage", DELETED_MESSAGE); 1160c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // A specific deleted message 11614525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "deletedMessage/#", DELETED_MESSAGE_ID); 1162c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 1163c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // All updated messages 11644525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "updatedMessage", UPDATED_MESSAGE); 1165c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // A specific updated message 11664525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "updatedMessage/#", UPDATED_MESSAGE_ID); 1167c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 11684525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "policy", POLICY); 11694525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "policy/#", POLICY_ID); 1170c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 1171c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // All quick responses 11724525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "quickresponse", QUICK_RESPONSE); 1173c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // A specific quick response 11744525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "quickresponse/#", QUICK_RESPONSE_ID); 1175c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // All quick responses associated with a particular account id 11764525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "quickresponse/account/#", 1177c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler QUICK_RESPONSE_ACCOUNT_ID); 1178c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 11794525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uifolders/#", UI_FOLDERS); 118096192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler sURIMatcher.addURI(EmailContent.AUTHORITY, "uifullfolders/#", UI_FULL_FOLDERS); 11814525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uiallfolders/#", UI_ALL_FOLDERS); 11824525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uisubfolders/#", UI_SUBFOLDERS); 11834525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uimessages/#", UI_MESSAGES); 11844525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uimessage/#", UI_MESSAGE); 11854525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uiundo", UI_UNDO); 11864525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, QUERY_UIREFRESH + "/#", UI_FOLDER_REFRESH); 1187c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // We listen to everything trailing uifolder/ since there might be an appVersion 1188c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // as in Utils.appendVersionQueryParameter(). 11894525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uifolder/*", UI_FOLDER); 11900d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler sURIMatcher.addURI(EmailContent.AUTHORITY, "uiinbox/#", UI_INBOX); 11914525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uiaccount/#", UI_ACCOUNT); 11924525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uiaccts", UI_ACCTS); 1193b7e0834121d564982c0389c87df775ba311429d4Tony Mantler sURIMatcher.addURI(EmailContent.AUTHORITY, "uiacctsettings", UI_ACCTSETTINGS); 11944525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uiattachments/#", UI_ATTACHMENTS); 11954525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uiattachment/#", UI_ATTACHMENT); 1196b7e0834121d564982c0389c87df775ba311429d4Tony Mantler sURIMatcher.addURI(EmailContent.AUTHORITY, "uiattachmentbycid/#/*", 1197b7e0834121d564982c0389c87df775ba311429d4Tony Mantler UI_ATTACHMENT_BY_CID); 11984525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uisearch/#", UI_SEARCH); 11994525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uiaccountdata/#", UI_ACCOUNT_DATA); 12004525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uiloadmore/#", UI_FOLDER_LOAD_MORE); 12014525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uiconversation/#", UI_CONVERSATION); 12024525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uirecentfolders/#", UI_RECENT_FOLDERS); 12034525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uidefaultrecentfolders/#", 1204c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler UI_DEFAULT_RECENT_FOLDERS); 12054525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "pickTrashFolder/#", 12064525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu ACCOUNT_PICK_TRASH_FOLDER); 12074525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "pickSentFolder/#", 12084525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu ACCOUNT_PICK_SENT_FOLDER); 1209e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler sURIMatcher.addURI(EmailContent.AUTHORITY, "uipurgefolder/#", UI_PURGE_FOLDER); 1210c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler } 1211c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler } 1212f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 12130e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank /** 12140e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank * The idea here is that the two databases (EmailProvider.db and EmailProviderBody.db must 12150e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank * always be in sync (i.e. there are two database or NO databases). This code will delete 12160e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank * any "orphan" database, so that both will be created together. Note that an "orphan" database 12170e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank * will exist after either of the individual databases is deleted due to data corruption. 12180e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank */ 12194525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu public void checkDatabases() { 12204525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu synchronized (sDatabaseLock) { 12214525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // Uncache the databases 12224525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu if (mDatabase != null) { 12234525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu mDatabase = null; 12244525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu } 12254525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu if (mBodyDatabase != null) { 12264525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu mBodyDatabase = null; 12274525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu } 12284525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // Look for orphans, and delete as necessary; these must always be in sync 12294525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu final File databaseFile = getContext().getDatabasePath(DATABASE_NAME); 12304525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu final File bodyFile = getContext().getDatabasePath(BODY_DATABASE_NAME); 12314525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu 12324525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // TODO Make sure attachments are deleted 12334525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu if (databaseFile.exists() && !bodyFile.exists()) { 12344525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu LogUtils.w(TAG, "Deleting orphaned EmailProvider database..."); 12354525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu getContext().deleteDatabase(DATABASE_NAME); 12364525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu } else if (bodyFile.exists() && !databaseFile.exists()) { 12374525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu LogUtils.w(TAG, "Deleting orphaned EmailProviderBody database..."); 12384525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu getContext().deleteDatabase(BODY_DATABASE_NAME); 12394525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu } 12400e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank } 12410e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank } 12424525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu 1243f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler @Override 1244758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 1245fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank String sortOrder) { 1246f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler Cursor c = null; 1247d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank int match; 1248d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank try { 1249d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank match = findMatch(uri, "query"); 1250d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank } catch (IllegalArgumentException e) { 1251d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank String uriString = uri.toString(); 1252d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank // If we were passed an illegal uri, see if it ends in /-1 1253d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank // if so, and if substituting 0 for -1 results in a valid uri, return an empty cursor 1254d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank if (uriString != null && uriString.endsWith("/-1")) { 1255d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank uri = Uri.parse(uriString.substring(0, uriString.length() - 2) + "0"); 1256d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank match = findMatch(uri, "query"); 1257d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank switch (match) { 1258d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank case BODY_ID: 1259d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank case MESSAGE_ID: 1260d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank case DELETED_MESSAGE_ID: 1261d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank case UPDATED_MESSAGE_ID: 1262d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank case ATTACHMENT_ID: 1263d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank case MAILBOX_ID: 1264d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank case ACCOUNT_ID: 1265d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank case HOSTAUTH_ID: 1266e8eb6e659b5914eb7deab451c583e906010d0457Martin Hibdon case CREDENTIAL_ID: 1267aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank case POLICY_ID: 12687fdde9bb4a24e931618a7a64227e2194c89034daScott Kennedy return new MatrixCursorWithCachedColumns(projection, 0); 1269d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank } 1270d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank } 1271d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank throw e; 1272d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank } 1273a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank Context context = getContext(); 1274cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank // See the comment at delete(), above 1275a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank SQLiteDatabase db = getDatabase(context); 1276f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler int table = match >> BASE_SHIFT; 127707597e547bc02cd2247caa866d25b94745dcd448Marc Blank String limit = uri.getQueryParameter(EmailContent.PARAMETER_LIMIT); 1278f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler String id; 1279f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 1280c6953b77552d4cb71776cf0537dc226029381628Tony Mantler String tableName = TABLE_NAMES.valueAt(table); 1281fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank 12820e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank try { 12830e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank switch (match) { 12848cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux // First, dispatch queries from UnifiedEmail 1285f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_SEARCH: 1286c0e2b147e09dd0bf15f19e63807b1b3bab798f50Marc Blank c = uiSearch(uri, projection); 1287c0e2b147e09dd0bf15f19e63807b1b3bab798f50Marc Blank return c; 1288f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ACCTS: 12894038f464dee0a33f1e7a58102857c24edf7e0eb2Paul Westbrook final String suppressParam = 12904038f464dee0a33f1e7a58102857c24edf7e0eb2Paul Westbrook uri.getQueryParameter(EmailContent.SUPPRESS_COMBINED_ACCOUNT_PARAM); 12914038f464dee0a33f1e7a58102857c24edf7e0eb2Paul Westbrook final boolean suppressCombined = 12924038f464dee0a33f1e7a58102857c24edf7e0eb2Paul Westbrook suppressParam != null && Boolean.parseBoolean(suppressParam); 12934038f464dee0a33f1e7a58102857c24edf7e0eb2Paul Westbrook c = uiAccounts(projection, suppressCombined); 1294f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return c; 1295f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_UNDO: 1296f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return uiUndo(projection); 1297f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_SUBFOLDERS: 1298f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_MESSAGES: 1299f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_MESSAGE: 1300f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_FOLDER: 13010d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler case UI_INBOX: 1302f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ACCOUNT: 1303f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ATTACHMENT: 1304f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ATTACHMENTS: 13058cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux case UI_ATTACHMENT_BY_CID: 1306f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_CONVERSATION: 1307f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_RECENT_FOLDERS: 130896192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler case UI_FULL_FOLDERS: 1309f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ALL_FOLDERS: 1310f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // For now, we don't allow selection criteria within these queries 1311f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (selection != null || selectionArgs != null) { 1312f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank throw new IllegalArgumentException("UI queries can't have selection/args"); 1313f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 1314b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy 1315b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final String seenParam = uri.getQueryParameter(UIProvider.SEEN_QUERY_PARAMETER); 13169e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler final boolean unseenOnly = 13179e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler seenParam != null && Boolean.FALSE.toString().equals(seenParam); 1318b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy 1319b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy c = uiQuery(match, uri, projection, unseenOnly); 1320f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return c; 1321f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_FOLDERS: 1322f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c = uiFolders(uri, projection); 1323f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return c; 1324f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_FOLDER_LOAD_MORE: 132564cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu c = uiFolderLoadMore(getMailbox(uri)); 1326f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return c; 1327f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_FOLDER_REFRESH: 132864cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu c = uiFolderRefresh(getMailbox(uri), 0); 1329f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return c; 1330f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case MAILBOX_NOTIFICATION: 1331f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c = notificationQuery(uri); 1332f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return c; 1333f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case MAILBOX_MOST_RECENT_MESSAGE: 1334f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c = mostRecentMessageQuery(uri); 1335f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return c; 133617d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu case MAILBOX_MESSAGE_COUNT: 133717d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu c = getMailboxMessageCount(uri); 133817d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu return c; 1339ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu case MESSAGE_MOVE: 1340ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu return db.query(MessageMove.TABLE_NAME, projection, selection, selectionArgs, 1341ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu null, null, sortOrder, limit); 1342ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu case MESSAGE_STATE_CHANGE: 1343ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu return db.query(MessageStateChange.TABLE_NAME, projection, selection, 1344ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu selectionArgs, null, null, sortOrder, limit); 13450e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case MESSAGE: 13460e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case UPDATED_MESSAGE: 13470e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case DELETED_MESSAGE: 13480e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ATTACHMENT: 13490e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case MAILBOX: 13500e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ACCOUNT: 13510e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case HOSTAUTH: 1352e8eb6e659b5914eb7deab451c583e906010d0457Martin Hibdon case CREDENTIAL: 1353aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank case POLICY: 1354fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank c = db.query(tableName, projection, 13550efe738e05a31e0c1ebfba645bd2364a373a3f33Marc Blank selection, selectionArgs, null, null, sortOrder, limit); 13560e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank break; 1357c6953b77552d4cb71776cf0537dc226029381628Tony Mantler case QUICK_RESPONSE: 1358c6953b77552d4cb71776cf0537dc226029381628Tony Mantler c = uiQuickResponse(projection); 1359c6953b77552d4cb71776cf0537dc226029381628Tony Mantler break; 1360f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler case BODY: 1361f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler case BODY_ID: { 1362f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler final ProjectionMap map = new ProjectionMap.Builder() 1363f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler .addAll(projection) 1364f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler .build(); 13652f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler if (map.containsKey(BodyColumns.HTML_CONTENT) || 13662f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler map.containsKey(BodyColumns.TEXT_CONTENT)) { 13672f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler throw new IllegalArgumentException( 13682f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler "Body content cannot be returned in the cursor"); 13692f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler } 13702f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler 1371f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler final ContentValues cv = new ContentValues(2); 13722f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler cv.put(BodyColumns.HTML_CONTENT_URI, "@" + uriWithColumn("bodyHtml", 13732f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler BodyColumns.MESSAGE_KEY)); 13742f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler cv.put(BodyColumns.TEXT_CONTENT_URI, "@" + uriWithColumn("bodyText", 13752f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler BodyColumns.MESSAGE_KEY)); 13762f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler 1377f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler final StringBuilder sb = genSelect(map, projection, cv); 1378f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler sb.append(" FROM ").append(Body.TABLE_NAME); 1379f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler if (match == BODY_ID) { 1380f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler id = uri.getPathSegments().get(1); 1381f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler sb.append(" WHERE ").append(whereWithId(id, selection)); 1382f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler } else if (!TextUtils.isEmpty(selection)) { 1383f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler sb.append(" WHERE ").append(selection); 1384f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler } 1385f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler if (!TextUtils.isEmpty(sortOrder)) { 1386f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler sb.append(" ORDER BY ").append(sortOrder); 1387f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler } 1388f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler if (!TextUtils.isEmpty(limit)) { 1389f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler sb.append(" LIMIT ").append(limit); 1390f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler } 1391f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler c = db.rawQuery(sb.toString(), selectionArgs); 1392f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler break; 1393f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler } 13940e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case MESSAGE_ID: 13950e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case DELETED_MESSAGE_ID: 13960e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case UPDATED_MESSAGE_ID: 13970e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ATTACHMENT_ID: 13980e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case MAILBOX_ID: 13990e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ACCOUNT_ID: 14000e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case HOSTAUTH_ID: 1401e8eb6e659b5914eb7deab451c583e906010d0457Martin Hibdon case CREDENTIAL_ID: 1402aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank case POLICY_ID: 14030e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank id = uri.getPathSegments().get(1); 1404503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu c = db.query(tableName, projection, whereWithId(id, selection), 1405503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu selectionArgs, null, null, sortOrder, limit); 14060e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank break; 1407c6953b77552d4cb71776cf0537dc226029381628Tony Mantler case QUICK_RESPONSE_ID: 1408c6953b77552d4cb71776cf0537dc226029381628Tony Mantler id = uri.getPathSegments().get(1); 1409c6953b77552d4cb71776cf0537dc226029381628Tony Mantler c = uiQuickResponseId(projection, id); 1410c6953b77552d4cb71776cf0537dc226029381628Tony Mantler break; 14110e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ATTACHMENTS_MESSAGE_ID: 14120e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank // All attachments for the given message 14130e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank id = uri.getPathSegments().get(2); 14140e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank c = db.query(Attachment.TABLE_NAME, projection, 14153dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler whereWith(AttachmentColumns.MESSAGE_KEY + "=" + id, selection), 14160efe738e05a31e0c1ebfba645bd2364a373a3f33Marc Blank selectionArgs, null, null, sortOrder, limit); 14170e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank break; 14185a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo case QUICK_RESPONSE_ACCOUNT_ID: 14195a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo // All quick responses for the given account 14205a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo id = uri.getPathSegments().get(2); 1421c6953b77552d4cb71776cf0537dc226029381628Tony Mantler c = uiQuickResponseAccount(projection, id); 14225a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo break; 14230e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank default: 14240e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank throw new IllegalArgumentException("Unknown URI " + uri); 14250e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank } 14260e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank } catch (SQLiteException e) { 14270e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank checkDatabases(); 14280e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank throw e; 1429fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank } catch (RuntimeException e) { 1430fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank checkDatabases(); 1431fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank e.printStackTrace(); 1432fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank throw e; 1433fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank } finally { 14347390b187767b559f693666156b8ca5c7c25bcfe4Marc Blank if (c == null) { 14357390b187767b559f693666156b8ca5c7c25bcfe4Marc Blank // This should never happen, but let's be sure to log it... 143666eef4565dd0a8b99e927bed7b64c472d24c276dYu Ping Hu // TODO: There are actually cases where c == null is expected, for example 143766eef4565dd0a8b99e927bed7b64c472d24c276dYu Ping Hu // UI_FOLDER_LOAD_MORE. 143866eef4565dd0a8b99e927bed7b64c472d24c276dYu Ping Hu // Demoting this to a warning for now until we figure out what to do with it. 1439c9ee5a389a8e5f9db56742a2d41eae2c912e6612Martin Hibdon LogUtils.w(TAG, "Query returning null for uri: %s selection: %s", uri, selection); 14407390b187767b559f693666156b8ca5c7c25bcfe4Marc Blank } 1441f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 1442f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 1443f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler if ((c != null) && !isTemporary()) { 1444261d6c3f0c97a12256519a2c3b131a56e57ab45fMakoto Onuki c.setNotificationUri(getContext().getContentResolver(), uri); 1445f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 1446f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler return c; 1447f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 1448f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 1449b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static String whereWithId(String id, String selection) { 1450f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler StringBuilder sb = new StringBuilder(256); 1451f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler sb.append("_id="); 1452f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler sb.append(id); 1453f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler if (selection != null) { 14546c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler sb.append(" AND ("); 1455f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler sb.append(selection); 14566c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler sb.append(')'); 1457f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 1458f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler return sb.toString(); 1459f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 1460f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 14616c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler /** 14626c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler * Combine a locally-generated selection with a user-provided selection 14636c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler * 14646c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler * This introduces risk that the local selection might insert incorrect chars 14656c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler * into the SQL, so use caution. 14666c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler * 14676c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler * @param where locally-generated selection, must not be null 14686c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler * @param selection user-provided selection, may be null 14696c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler * @return a single selection string 14706c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler */ 1471b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static String whereWith(String where, String selection) { 14726c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler if (selection == null) { 14736c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler return where; 1474f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 14750053401d07cd11f19c63dfbc3942d027b4067de8Tony Mantler return where + " AND (" + selection + ")"; 1476f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 1477f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 14780993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank /** 14790993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank * Restore a HostAuth from a database, given its unique id 14800993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank * @param db the database 14810993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank * @param id the unique id (_id) of the row 14820993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank * @return a fully populated HostAuth or null if the row does not exist 14830993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank */ 14849dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki private static HostAuth restoreHostAuth(SQLiteDatabase db, long id) { 14850993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank Cursor c = db.query(HostAuth.TABLE_NAME, HostAuth.CONTENT_PROJECTION, 14863dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler HostAuthColumns._ID + "=?", new String[] {Long.toString(id)}, null, null, null); 14870993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank try { 14880993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank if (c.moveToFirst()) { 14890993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank HostAuth hostAuth = new HostAuth(); 14900993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank hostAuth.restore(c); 14910993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank return hostAuth; 14920993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 14930993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank return null; 14940993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } finally { 14950993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank c.close(); 14960993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 14970993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 14980993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank 14990993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank /** 15000993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank * Copy the Account and HostAuth tables from one database to another 15010993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank * @param fromDatabase the source database 15020993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank * @param toDatabase the destination database 15030993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank * @return the number of accounts copied, or -1 if an error occurred 15040993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank */ 15059dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki private static int copyAccountTables(SQLiteDatabase fromDatabase, SQLiteDatabase toDatabase) { 15060993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank if (fromDatabase == null || toDatabase == null) return -1; 1507f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 1508f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Lock both databases; for the "from" database, we don't want anyone changing it from 1509f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // under us; for the "to" database, we want to make the operation atomic 15100993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank int copyCount = 0; 1511f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank fromDatabase.beginTransaction(); 15120993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank try { 15130993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank toDatabase.beginTransaction(); 15140993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank try { 1515f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Delete anything hanging around here 1516f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank toDatabase.delete(Account.TABLE_NAME, null, null); 1517f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank toDatabase.delete(HostAuth.TABLE_NAME, null, null); 1518f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 1519f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Get our account cursor 1520f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Cursor c = fromDatabase.query(Account.TABLE_NAME, Account.CONTENT_PROJECTION, 1521f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank null, null, null, null, null); 1522f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (c == null) return 0; 1523560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.d(TAG, "fromDatabase accounts: " + c.getCount()); 1524f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank try { 1525f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Loop through accounts, copying them and associated host auth's 1526f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank while (c.moveToNext()) { 1527f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Account account = new Account(); 1528f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank account.restore(c); 1529f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 1530f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Clear security sync key and sync key, as these were specific to the 1531f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // state of the account, and we've reset that... 1532f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Clear policy key so that we can re-establish policies from the server 1533f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // TODO This is pretty EAS specific, but there's a lot of that around 1534f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank account.mSecuritySyncKey = null; 1535f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank account.mSyncKey = null; 1536f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank account.mPolicyKey = 0; 1537f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 1538f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Copy host auth's and update foreign keys 1539f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank HostAuth hostAuth = restoreHostAuth(fromDatabase, 1540f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank account.mHostAuthKeyRecv); 1541f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 1542f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // The account might have gone away, though very unlikely 15430993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank if (hostAuth == null) continue; 1544f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank account.mHostAuthKeyRecv = toDatabase.insert(HostAuth.TABLE_NAME, null, 15450993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank hostAuth.toContentValues()); 1546f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 1547f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // EAS accounts have no send HostAuth 1548f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (account.mHostAuthKeySend > 0) { 1549f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank hostAuth = restoreHostAuth(fromDatabase, account.mHostAuthKeySend); 1550f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Belt and suspenders; I can't imagine that this is possible, 1551f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // since we checked the validity of the account above, and the 1552f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // database is now locked 1553f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (hostAuth == null) continue; 1554f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank account.mHostAuthKeySend = toDatabase.insert( 1555f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank HostAuth.TABLE_NAME, null, hostAuth.toContentValues()); 1556f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 1557f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 1558f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Now, create the account in the "to" database 1559f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank toDatabase.insert(Account.TABLE_NAME, null, account.toContentValues()); 1560f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank copyCount++; 15610993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 1562f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } finally { 1563f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c.close(); 15640993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 1565f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 1566f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Say it's ok to commit 1567f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank toDatabase.setTransactionSuccessful(); 15680993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } finally { 15690993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank toDatabase.endTransaction(); 15700993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 1571f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } catch (SQLiteException ex) { 1572560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.w(TAG, "Exception while copying account tables", ex); 15730993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank copyCount = -1; 1574f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } finally { 1575f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank fromDatabase.endTransaction(); 15760993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 15770993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank return copyCount; 15780993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 15790993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank 15800993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank /** 15810993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank * Backup account data, returning the number of accounts backed up 15820993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank */ 158382a207132b34377d532f19882f5bfc70bc657da0Tony Mantler private static int backupAccounts(final Context context, final SQLiteDatabase db) { 158482a207132b34377d532f19882f5bfc70bc657da0Tony Mantler final AccountManager am = AccountManager.get(context); 158582a207132b34377d532f19882f5bfc70bc657da0Tony Mantler final Cursor accountCursor = db.query(Account.TABLE_NAME, Account.CONTENT_PROJECTION, 158682a207132b34377d532f19882f5bfc70bc657da0Tony Mantler null, null, null, null, null); 158782a207132b34377d532f19882f5bfc70bc657da0Tony Mantler int updatedCount = 0; 15880993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank try { 158982a207132b34377d532f19882f5bfc70bc657da0Tony Mantler while (accountCursor.moveToNext()) { 159082a207132b34377d532f19882f5bfc70bc657da0Tony Mantler final Account account = new Account(); 159182a207132b34377d532f19882f5bfc70bc657da0Tony Mantler account.restore(accountCursor); 159282a207132b34377d532f19882f5bfc70bc657da0Tony Mantler EmailServiceInfo serviceInfo = 159382a207132b34377d532f19882f5bfc70bc657da0Tony Mantler EmailServiceUtils.getServiceInfo(context, account.getProtocol(context)); 159482a207132b34377d532f19882f5bfc70bc657da0Tony Mantler if (serviceInfo == null) { 159582a207132b34377d532f19882f5bfc70bc657da0Tony Mantler LogUtils.d(LogUtils.TAG, "Could not find service info for account"); 159682a207132b34377d532f19882f5bfc70bc657da0Tony Mantler continue; 159782a207132b34377d532f19882f5bfc70bc657da0Tony Mantler } 159882a207132b34377d532f19882f5bfc70bc657da0Tony Mantler final String jsonString = account.toJsonString(context); 159982a207132b34377d532f19882f5bfc70bc657da0Tony Mantler final android.accounts.Account amAccount = 160082a207132b34377d532f19882f5bfc70bc657da0Tony Mantler account.getAccountManagerAccount(serviceInfo.accountType); 160182a207132b34377d532f19882f5bfc70bc657da0Tony Mantler am.setUserData(amAccount, ACCOUNT_MANAGER_JSON_TAG, jsonString); 160282a207132b34377d532f19882f5bfc70bc657da0Tony Mantler updatedCount++; 16039dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki } 16040993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } finally { 160582a207132b34377d532f19882f5bfc70bc657da0Tony Mantler accountCursor.close(); 16060993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 160782a207132b34377d532f19882f5bfc70bc657da0Tony Mantler return updatedCount; 16080993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 16090993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank 16100993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank /** 16110993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank * Restore account data, returning the number of accounts restored 16120993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank */ 161382a207132b34377d532f19882f5bfc70bc657da0Tony Mantler private static int restoreAccounts(final Context context) { 161482a207132b34377d532f19882f5bfc70bc657da0Tony Mantler final Collection<EmailServiceInfo> infos = EmailServiceUtils.getServiceInfoList(context); 161582a207132b34377d532f19882f5bfc70bc657da0Tony Mantler // Find all possible account types 161682a207132b34377d532f19882f5bfc70bc657da0Tony Mantler final Set<String> accountTypes = new HashSet<String>(3); 161782a207132b34377d532f19882f5bfc70bc657da0Tony Mantler for (final EmailServiceInfo info : infos) { 16181381d4083bbfdf046eceac081420ab3fa7a1ae81Tony Mantler if (!TextUtils.isEmpty(info.accountType)) { 16191381d4083bbfdf046eceac081420ab3fa7a1ae81Tony Mantler // accountType will be empty for the gmail stub entry 16201381d4083bbfdf046eceac081420ab3fa7a1ae81Tony Mantler accountTypes.add(info.accountType); 16211381d4083bbfdf046eceac081420ab3fa7a1ae81Tony Mantler } 16229dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki } 162382a207132b34377d532f19882f5bfc70bc657da0Tony Mantler // Find all accounts we own 162482a207132b34377d532f19882f5bfc70bc657da0Tony Mantler final List<android.accounts.Account> amAccounts = new ArrayList<android.accounts.Account>(); 162582a207132b34377d532f19882f5bfc70bc657da0Tony Mantler final AccountManager am = AccountManager.get(context); 162682a207132b34377d532f19882f5bfc70bc657da0Tony Mantler for (final String accountType : accountTypes) { 162782a207132b34377d532f19882f5bfc70bc657da0Tony Mantler amAccounts.addAll(Arrays.asList(am.getAccountsByType(accountType))); 162882a207132b34377d532f19882f5bfc70bc657da0Tony Mantler } 162982a207132b34377d532f19882f5bfc70bc657da0Tony Mantler // Try to restore them from saved JSON 163082a207132b34377d532f19882f5bfc70bc657da0Tony Mantler int restoredCount = 0; 163182a207132b34377d532f19882f5bfc70bc657da0Tony Mantler for (final android.accounts.Account amAccount : amAccounts) { 16320a17fcfae53d75f1a9e9b897b041a4696e7f7683Andrew Sapperstein String jsonString = null; 16330a17fcfae53d75f1a9e9b897b041a4696e7f7683Andrew Sapperstein jsonString = am.getUserData(amAccount, ACCOUNT_MANAGER_JSON_TAG); 163482a207132b34377d532f19882f5bfc70bc657da0Tony Mantler if (TextUtils.isEmpty(jsonString)) { 163582a207132b34377d532f19882f5bfc70bc657da0Tony Mantler continue; 16369dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki } 163782a207132b34377d532f19882f5bfc70bc657da0Tony Mantler final Account account = Account.fromJsonString(jsonString); 163882a207132b34377d532f19882f5bfc70bc657da0Tony Mantler if (account != null) { 163982a207132b34377d532f19882f5bfc70bc657da0Tony Mantler AccountSettingsUtils.commitSettings(context, account); 164082a207132b34377d532f19882f5bfc70bc657da0Tony Mantler restoredCount++; 16410993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 16420993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 164382a207132b34377d532f19882f5bfc70bc657da0Tony Mantler return restoredCount; 16440993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 16450993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank 1646ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu private static final String MESSAGE_CHANGE_LOG_TABLE_INSERT_PREFIX = "insert into %s (" 1647ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu + MessageChangeLogTable.MESSAGE_KEY + "," + MessageChangeLogTable.SERVER_ID + "," 1648ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu + MessageChangeLogTable.ACCOUNT_KEY + "," + MessageChangeLogTable.STATUS + ","; 1649ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 1650ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu private static final String MESSAGE_CHANGE_LOG_TABLE_VALUES_PREFIX = ") values (%s, " 16513dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + "(select " + MessageColumns.SERVER_ID + " from " + 16523dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler Message.TABLE_NAME + " where _id=%s)," 16533dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + "(select " + MessageColumns.ACCOUNT_KEY + " from " + 16543dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler Message.TABLE_NAME + " where _id=%s)," 1655ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu + MessageMove.STATUS_NONE_STRING + ","; 1656ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 1657ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** 1658ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * Formatting string to generate the SQL statement for inserting into MessageMove. 1659ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * The formatting parameters are: 1660ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * table name, message id x 4, destination folder id, message id, destination folder id. 1661ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * Duplications are needed for sub-selects. 1662ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu */ 1663ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu private static final String MESSAGE_MOVE_INSERT = MESSAGE_CHANGE_LOG_TABLE_INSERT_PREFIX 1664ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu + MessageMove.SRC_FOLDER_KEY + "," + MessageMove.DST_FOLDER_KEY + "," 1665ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu + MessageMove.SRC_FOLDER_SERVER_ID + "," + MessageMove.DST_FOLDER_SERVER_ID 1666ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu + MESSAGE_CHANGE_LOG_TABLE_VALUES_PREFIX 16673dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + "(select " + MessageColumns.MAILBOX_KEY + 16683dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler " from " + Message.TABLE_NAME + " where _id=%s)," + "%d," 1669ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu + "(select " + Mailbox.SERVER_ID + " from " + Mailbox.TABLE_NAME + " where _id=(select " 16703dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + MessageColumns.MAILBOX_KEY + " from " + Message.TABLE_NAME + " where _id=%s))," 1671ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu + "(select " + Mailbox.SERVER_ID + " from " + Mailbox.TABLE_NAME + " where _id=%d))"; 1672ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 1673ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** 1674ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * Insert a row into the MessageMove table when that message is moved. 1675ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param db The {@link SQLiteDatabase}. 1676ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param messageId The id of the message being moved. 1677ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param dstFolderKey The folder to which the message is being moved. 1678ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu */ 1679ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu private void addToMessageMove(final SQLiteDatabase db, final String messageId, 1680ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu final long dstFolderKey) { 1681ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu db.execSQL(String.format(Locale.US, MESSAGE_MOVE_INSERT, MessageMove.TABLE_NAME, 1682ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu messageId, messageId, messageId, messageId, dstFolderKey, messageId, dstFolderKey)); 1683ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 1684ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 1685ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** 1686ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * Formatting string to generate the SQL statement for inserting into MessageStateChange. 1687ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * The formatting parameters are: 1688ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * table name, message id x 4, new flag read, message id, new flag favorite. 1689ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * Duplications are needed for sub-selects. 1690ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu */ 1691ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu private static final String MESSAGE_STATE_CHANGE_INSERT = MESSAGE_CHANGE_LOG_TABLE_INSERT_PREFIX 1692ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu + MessageStateChange.OLD_FLAG_READ + "," + MessageStateChange.NEW_FLAG_READ + "," 1693ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu + MessageStateChange.OLD_FLAG_FAVORITE + "," + MessageStateChange.NEW_FLAG_FAVORITE 1694ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu + MESSAGE_CHANGE_LOG_TABLE_VALUES_PREFIX 16953dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + "(select " + MessageColumns.FLAG_READ + 16963dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler " from " + Message.TABLE_NAME + " where _id=%s)," + "%d," 16973dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + "(select " + MessageColumns.FLAG_FAVORITE + 16983dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler " from " + Message.TABLE_NAME + " where _id=%s)," + "%d)"; 1699ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 1700ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu private void addToMessageStateChange(final SQLiteDatabase db, final String messageId, 1701ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu final int newFlagRead, final int newFlagFavorite) { 1702ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu db.execSQL(String.format(Locale.US, MESSAGE_STATE_CHANGE_INSERT, 1703ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu MessageStateChange.TABLE_NAME, messageId, messageId, messageId, messageId, 1704ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu newFlagRead, messageId, newFlagFavorite)); 1705ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 1706ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 1707f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // select count(*) from (select count(*) as dupes from Mailbox where accountKey=? 1708f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // group by serverId) where dupes > 1; 1709f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String ACCOUNT_INTEGRITY_SQL = 1710f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "select count(*) from (select count(*) as dupes from " + Mailbox.TABLE_NAME + 1711f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " where accountKey=? group by " + MailboxColumns.SERVER_ID + ") where dupes > 1"; 1712f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 1713e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu 1714e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu // Query to get the protocol for a message. Temporary to switch between new and old upsync 1715e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu // behavior; should go away when IMAP gets converted. 1716feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert private static final String GET_MESSAGE_DETAILS = "SELECT" 1717feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert + " h." + HostAuthColumns.PROTOCOL + "," 17183dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + " m." + MessageColumns.MAILBOX_KEY + "," 17193dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + " a." + AccountColumns._ID 1720feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert + " FROM " + Message.TABLE_NAME + " AS m" 1721feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert + " INNER JOIN " + Account.TABLE_NAME + " AS a" 17223dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + " ON m." + MessageColumns.ACCOUNT_KEY + "=a." + AccountColumns._ID 1723feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert + " INNER JOIN " + HostAuth.TABLE_NAME + " AS h" 17243dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + " ON a." + AccountColumns.HOST_AUTH_KEY_RECV + "=h." + HostAuthColumns._ID 17253dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + " WHERE m." + MessageColumns._ID + "=?"; 17265e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private static final int INDEX_PROTOCOL = 0; 17275e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private static final int INDEX_MAILBOX_KEY = 1; 17285e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private static final int INDEX_ACCOUNT_KEY = 2; 17295e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu 17305e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu /** 17315e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * Query to get the protocol and email address for an account. Note that this uses 17325e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * {@link #INDEX_PROTOCOL} and {@link #INDEX_EMAIL_ADDRESS} for its columns. 17335e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu */ 17345e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private static final String GET_ACCOUNT_DETAILS = "SELECT" 17355e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu + " h." + HostAuthColumns.PROTOCOL + "," 17363f24a9e2c76af8b772953c8a026d9886321f0044Yu Ping Hu + " a." + AccountColumns.EMAIL_ADDRESS + "," 17373f24a9e2c76af8b772953c8a026d9886321f0044Yu Ping Hu + " a." + AccountColumns.SYNC_KEY 17385e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu + " FROM " + Account.TABLE_NAME + " AS a" 17395e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu + " INNER JOIN " + HostAuth.TABLE_NAME + " AS h" 17403dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + " ON a." + AccountColumns.HOST_AUTH_KEY_RECV + "=h." + HostAuthColumns._ID 17413dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + " WHERE a." + AccountColumns._ID + "=?"; 17425e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private static final int INDEX_EMAIL_ADDRESS = 1; 17433f24a9e2c76af8b772953c8a026d9886321f0044Yu Ping Hu private static final int INDEX_SYNC_KEY = 2; 17445e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu 17455e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu /** 17465e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * Restart push if we need it (currently only for Exchange accounts). 17475e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param context A {@link Context}. 17485e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param db The {@link SQLiteDatabase}. 17495e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param id The id of the thing we're looking for. 17505e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @return Whether or not we sent a request to restart the push. 17515e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu */ 17525e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private static boolean restartPush(final Context context, final SQLiteDatabase db, 17535e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu final String id) { 17545e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu final Cursor c = db.rawQuery(GET_ACCOUNT_DETAILS, new String[] {id}); 17555e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu if (c != null) { 17565e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu try { 17575e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu if (c.moveToFirst()) { 17585e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu final String protocol = c.getString(INDEX_PROTOCOL); 17593f24a9e2c76af8b772953c8a026d9886321f0044Yu Ping Hu // Only restart push for EAS accounts that have completed initial sync. 17603f24a9e2c76af8b772953c8a026d9886321f0044Yu Ping Hu if (context.getString(R.string.protocol_eas).equals(protocol) && 17613f24a9e2c76af8b772953c8a026d9886321f0044Yu Ping Hu !EmailContent.isInitialSyncKey(c.getString(INDEX_SYNC_KEY))) { 17623f24a9e2c76af8b772953c8a026d9886321f0044Yu Ping Hu final String emailAddress = c.getString(INDEX_EMAIL_ADDRESS); 17635e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu final android.accounts.Account account = 17645e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu getAccountManagerAccount(context, emailAddress, protocol); 176591e8e6f70921e65eabf128f14b5d43385b22f0a1Tony Mantler if (account != null) { 176691e8e6f70921e65eabf128f14b5d43385b22f0a1Tony Mantler restartPush(account); 176791e8e6f70921e65eabf128f14b5d43385b22f0a1Tony Mantler return true; 176891e8e6f70921e65eabf128f14b5d43385b22f0a1Tony Mantler } 17695e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 17705e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 17715e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } finally { 17725e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu c.close(); 17735e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 17745e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 17755e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu return false; 17765e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 17775e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu 17785e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu /** 17795e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * Restart push if a mailbox's settings change in a way that requires it. 17805e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param context A {@link Context}. 17815e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param db The {@link SQLiteDatabase}. 17825e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param values The {@link ContentValues} that were updated for the mailbox. 17835e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param accountId The id of the account for this mailbox. 17845e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @return Whether or not the push was restarted. 17855e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu */ 17865e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private static boolean restartPushForMailbox(final Context context, final SQLiteDatabase db, 17875e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu final ContentValues values, final String accountId) { 17885e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu if (values.containsKey(MailboxColumns.SYNC_LOOKBACK) || 17895e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu values.containsKey(MailboxColumns.SYNC_INTERVAL)) { 17905e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu return restartPush(context, db, accountId); 17915e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 17925e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu return false; 17935e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 17945e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu 17955e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu /** 17965e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * Restart push if an account's settings change in a way that requires it. 17975e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param context A {@link Context}. 17985e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param db The {@link SQLiteDatabase}. 17995e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param values The {@link ContentValues} that were updated for the account. 18005e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param accountId The id of the account. 18015e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @return Whether or not the push was restarted. 18025e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu */ 18035e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private static boolean restartPushForAccount(final Context context, final SQLiteDatabase db, 18045e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu final ContentValues values, final String accountId) { 18055e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu if (values.containsKey(AccountColumns.SYNC_LOOKBACK) || 18065e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu values.containsKey(AccountColumns.SYNC_INTERVAL)) { 18075e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu return restartPush(context, db, accountId); 18085e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 18095e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu return false; 18105e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 1811e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu 1812f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler @Override 1813f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 18149a342b31472536b89f55b1e6ae2e6f868ba1064dAlon Albert LogUtils.d(TAG, "Update: " + uri); 1815f678a8e67ace74ea285dcec9727d0117e23a5c73Makoto Onuki // Handle this special case the fastest possible way 1816e8a3c14f28bac4912842761b04c96272caf52810Tony Mantler if (INTEGRITY_CHECK_URI.equals(uri)) { 1817f678a8e67ace74ea285dcec9727d0117e23a5c73Makoto Onuki checkDatabases(); 1818f678a8e67ace74ea285dcec9727d0117e23a5c73Makoto Onuki return 0; 1819e8a3c14f28bac4912842761b04c96272caf52810Tony Mantler } else if (ACCOUNT_BACKUP_URI.equals(uri)) { 18209dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki return backupAccounts(getContext(), getDatabase(getContext())); 1821f678a8e67ace74ea285dcec9727d0117e23a5c73Makoto Onuki } 1822f678a8e67ace74ea285dcec9727d0117e23a5c73Makoto Onuki 1823261d6c3f0c97a12256519a2c3b131a56e57ab45fMakoto Onuki // Notify all existing cursors, except for ACCOUNT_RESET_NEW_COUNT(_ID) 1824261d6c3f0c97a12256519a2c3b131a56e57ab45fMakoto Onuki Uri notificationUri = EmailContent.CONTENT_URI; 1825261d6c3f0c97a12256519a2c3b131a56e57ab45fMakoto Onuki 18262d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final int match = findMatch(uri, "update"); 18272d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final Context context = getContext(); 1828cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank // See the comment at delete(), above 18292d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final SQLiteDatabase db = getDatabase(context); 18302d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final int table = match >> BASE_SHIFT; 1831626f3e48a4f14c38a973dd2bea2e2debea7637a5Andrew Stadler int result; 1832a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank 18335b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki // We do NOT allow setting of unreadCount/messageCount via the provider 18345b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki // These columns are maintained via triggers 18355b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki if (match == MAILBOX_ID || match == MAILBOX) { 18365b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki values.remove(MailboxColumns.UNREAD_COUNT); 18375b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki values.remove(MailboxColumns.MESSAGE_COUNT); 18385b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki } 18390e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank 18402d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final String tableName = TABLE_NAMES.valueAt(table); 1841bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy String id = "0"; 1842fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank 18430e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank try { 18440e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank switch (match) { 1845c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank case ACCOUNT_PICK_TRASH_FOLDER: 1846c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank return pickTrashFolder(uri); 1847a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank case ACCOUNT_PICK_SENT_FOLDER: 1848a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank return pickSentFolder(uri); 1849b7e0834121d564982c0389c87df775ba311429d4Tony Mantler case UI_ACCTSETTINGS: 1850b7e0834121d564982c0389c87df775ba311429d4Tony Mantler return uiUpdateSettings(context, values); 1851f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_FOLDER: 1852b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy return uiUpdateFolder(context, uri, values); 1853f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_RECENT_FOLDERS: 1854f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return uiUpdateRecentFolders(uri, values); 1855f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_DEFAULT_RECENT_FOLDERS: 1856f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return uiPopulateRecentFolders(uri); 1857f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ATTACHMENT: 1858f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return uiUpdateAttachment(uri, values); 1859f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_MESSAGE: 1860f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return uiUpdateMessage(uri, values); 1861f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case ACCOUNT_CHECK: 1862f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank id = uri.getLastPathSegment(); 1863f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // With any error, return 1 (a failure) 1864f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank int res = 1; 1865f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Cursor ic = null; 1866f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank try { 1867f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ic = db.rawQuery(ACCOUNT_INTEGRITY_SQL, new String[] {id}); 1868f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (ic.moveToFirst()) { 1869f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank res = ic.getInt(0); 1870f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 1871f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } finally { 1872f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (ic != null) { 1873f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ic.close(); 1874f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 1875f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 1876f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Count of duplicated mailboxes 1877f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return res; 187800287c4d8f54ae07c89bb3893f440acdca09d728Marc Blank case MESSAGE_SELECTION: 1879c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank Cursor findCursor = db.query(tableName, Message.ID_COLUMN_PROJECTION, selection, 1880c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank selectionArgs, null, null, null); 1881c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank try { 1882c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank if (findCursor.moveToFirst()) { 1883c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank return update(ContentUris.withAppendedId( 188400287c4d8f54ae07c89bb3893f440acdca09d728Marc Blank Message.CONTENT_URI, 1885c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank findCursor.getLong(Message.ID_COLUMNS_ID_COLUMN)), 1886c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank values, null, null); 1887c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } else { 1888c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank return 0; 1889c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } 1890c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } finally { 1891c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank findCursor.close(); 1892c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } 18930e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case SYNCED_MESSAGE_ID: 18940e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case UPDATED_MESSAGE_ID: 18951b9337ea4f41c12cb108cbe67e0077169b1f0b8cMarc Blank case MESSAGE_ID: 18960e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ATTACHMENT_ID: 18970e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case MAILBOX_ID: 18980e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ACCOUNT_ID: 18990e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case HOSTAUTH_ID: 1900e8eb6e659b5914eb7deab451c583e906010d0457Martin Hibdon case CREDENTIAL_ID: 19015a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo case QUICK_RESPONSE_ID: 19026e418aa41a17136be0dddb816d843428a0a1e722Marc Blank case POLICY_ID: 19030e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank id = uri.getPathSegments().get(1); 1904c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu if (match == SYNCED_MESSAGE_ID) { 1905e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu // TODO: Migrate IMAP to use MessageMove/MessageStateChange as well. 1906e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu boolean isEas = false; 1907feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert long mailboxId = -1; 1908feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert long accountId = -1; 1909feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert final Cursor c = db.rawQuery(GET_MESSAGE_DETAILS, new String[] {id}); 1910e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu if (c != null) { 1911e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu try { 1912e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu if (c.moveToFirst()) { 1913feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert final String protocol = c.getString(INDEX_PROTOCOL); 1914e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu isEas = context.getString(R.string.protocol_eas) 1915e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu .equals(protocol); 1916feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert mailboxId = c.getLong(INDEX_MAILBOX_KEY); 1917feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert accountId = c.getLong(INDEX_ACCOUNT_KEY); 1918e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu } 1919e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu } finally { 1920e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu c.close(); 1921e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu } 1922ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 1923e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu 1924e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu if (isEas) { 1925e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu // EAS uses the new upsync classes. 1926e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu Long dstFolderId = values.getAsLong(MessageColumns.MAILBOX_KEY); 1927e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu if (dstFolderId != null) { 1928e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu addToMessageMove(db, id, dstFolderId); 1929e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu } 1930e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu Integer flagRead = values.getAsInteger(MessageColumns.FLAG_READ); 1931e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu Integer flagFavorite = values.getAsInteger(MessageColumns.FLAG_FAVORITE); 1932e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu int flagReadValue = (flagRead != null) ? 1933e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu flagRead : MessageStateChange.VALUE_UNCHANGED; 1934e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu int flagFavoriteValue = (flagFavorite != null) ? 1935e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu flagFavorite : MessageStateChange.VALUE_UNCHANGED; 1936e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu if (flagRead != null || flagFavorite != null) { 1937e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu addToMessageStateChange(db, id, flagReadValue, flagFavoriteValue); 1938e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu } 1939feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert 1940feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // Request a sync for the messages mailbox so the update will upsync. 1941feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // This is normally done with ContentResolver.notifyUpdate() but doesn't 1942feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // work for Exchange because the Sync Adapter is declared as 1943feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // android:supportsUploading="false". Changing it to true is not trivial 1944feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // because that would require us to protect all calls to notifyUpdate() 1945feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // with syncToServer=false except in cases where we actually want to 1946feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // upsync. 1947feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // TODO: Look into making Exchange Sync Adapter supportsUploading=true 1948feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // Since we can't use the Sync Manager "delayed-sync" feature which 1949feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // applies only to UPLOAD syncs, we need to do this ourselves. The 1950feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // purpose of this is not to spam syncs when making frequent 1951feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // modifications. 1952feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert final Handler handler = getDelayedSyncHandler(); 1953b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler final android.accounts.Account amAccount = 1954b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler getAccountManagerAccount(accountId); 1955b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler if (amAccount != null) { 1956b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler final SyncRequestMessage request = new SyncRequestMessage( 1957b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler uri.getAuthority(), amAccount, mailboxId); 1958b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler synchronized (mDelayedSyncRequests) { 1959b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler if (!mDelayedSyncRequests.contains(request)) { 1960b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler mDelayedSyncRequests.add(request); 1961b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler final android.os.Message message = 1962b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler handler.obtainMessage(0, request); 1963b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler handler.sendMessageDelayed(message, SYNC_DELAY_MILLIS); 1964b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler } 1965feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 1966b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler } else { 1967b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler LogUtils.d(TAG, 1968b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler "Attempted to start delayed sync for invalid account %d", 1969b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler accountId); 1970feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 1971e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu } else { 1972e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu // Old way of doing upsync. 1973e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu // For synced messages, first copy the old message to the updated table 1974e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu // Note the insert or ignore semantics, guaranteeing that only the first 1975e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu // update will be reflected in the updated message table; therefore this 1976e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu // row will always have the "original" data 1977e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu db.execSQL(UPDATED_MESSAGE_INSERT + id); 1978ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 1979c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } else if (match == MESSAGE_ID) { 1980c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu db.execSQL(UPDATED_MESSAGE_DELETE + id); 19810e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank } 1982c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu result = db.update(tableName, values, whereWithId(id, selection), 1983c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu selectionArgs); 1984c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank if (match == MESSAGE_ID || match == SYNCED_MESSAGE_ID) { 1985c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu handleMessageUpdateNotifications(uri, id, values); 1986c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } else if (match == ATTACHMENT_ID) { 1987f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank long attId = Integer.parseInt(id); 19883dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler if (values.containsKey(AttachmentColumns.FLAGS)) { 19893dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler int flags = values.getAsInteger(AttachmentColumns.FLAGS); 1990f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mAttachmentService.attachmentChanged(context, attId, flags); 1991f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 1992f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Notify UI if necessary; there are only two columns we can change that 1993f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // would be worth a notification 1994f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (values.containsKey(AttachmentColumns.UI_STATE) || 1995f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.containsKey(AttachmentColumns.UI_DOWNLOADED_SIZE)) { 1996f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Notify on individual attachment 1997f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUI(UIPROVIDER_ATTACHMENT_NOTIFIER, id); 1998f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Attachment att = Attachment.restoreAttachmentWithId(context, attId); 1999f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (att != null) { 2000f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // And on owning Message 2001f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUI(UIPROVIDER_ATTACHMENTS_NOTIFIER, att.mMessageKey); 2002f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 200325fe72687df8fd3aa4d7dc81054cbf9f2be7f1f3Marc Blank } 2004c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } else if (match == MAILBOX_ID) { 20055e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu final long accountId = Mailbox.getAccountIdForMailbox(context, id); 20065e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu notifyUIFolder(id, accountId); 20075e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu restartPushForMailbox(context, db, values, Long.toString(accountId)); 2008f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else if (match == ACCOUNT_ID) { 2009e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu updateAccountSyncInterval(Long.parseLong(id), values); 201097a198292e665fff5d27d727d415f35b0a0633e4Marc Blank // Notify individual account and "all accounts" 2011f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUI(UIPROVIDER_ACCOUNT_NOTIFIER, id); 201205649dca2f59f28cd4295e041045a605badddb15Tony Mantler notifyUI(UIPROVIDER_ALL_ACCOUNTS_NOTIFIER, null); 20135e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu restartPushForAccount(context, db, values, id); 201409fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank } 20150e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank break; 20167525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler case BODY_ID: { 20177525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final ContentValues updateValues = new ContentValues(values); 20187525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler updateValues.remove(BodyColumns.HTML_CONTENT); 20197525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler updateValues.remove(BodyColumns.TEXT_CONTENT); 20207525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler 20217525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler result = db.update(tableName, updateValues, whereWithId(id, selection), 20227525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler selectionArgs); 20237525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler 20247525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (values.containsKey(BodyColumns.HTML_CONTENT) || 20257525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler values.containsKey(BodyColumns.TEXT_CONTENT)) { 20267525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final long messageId; 20277525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (values.containsKey(BodyColumns.MESSAGE_KEY)) { 20287525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler messageId = values.getAsLong(BodyColumns.MESSAGE_KEY); 20297525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } else { 20307525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final long bodyId = Long.parseLong(id); 20317525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final SQLiteStatement sql = db.compileStatement( 20327525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler "select " + BodyColumns.MESSAGE_KEY + 20337525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler " from " + Body.TABLE_NAME + 20347525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler " where " + BodyColumns._ID + "=" + Long 20357525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler .toString(bodyId) 20367525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler ); 20377525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler messageId = sql.simpleQueryForLong(); 20387525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 20397525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler writeBodyFiles(context, messageId, values); 20407525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 20417525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler break; 20427525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 20437525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler case BODY: { 20447525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final ContentValues updateValues = new ContentValues(values); 20457525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler updateValues.remove(BodyColumns.HTML_CONTENT); 20467525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler updateValues.remove(BodyColumns.TEXT_CONTENT); 20477525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler 20487525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler result = db.update(tableName, updateValues, selection, selectionArgs); 20497525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler 2050d0b81a0d062f9bad15c9d9ba104b6cdf8590e5feYu Ping Hu if (result == 0 && selection.equals(Body.SELECTION_BY_MESSAGE_KEY)) { 2051d0b81a0d062f9bad15c9d9ba104b6cdf8590e5feYu Ping Hu // TODO: This is a hack. Notably, the selection equality test above 2052d0b81a0d062f9bad15c9d9ba104b6cdf8590e5feYu Ping Hu // is hokey at best. 2053d0b81a0d062f9bad15c9d9ba104b6cdf8590e5feYu Ping Hu LogUtils.i(TAG, "Body Update to non-existent row, morphing to insert"); 2054d0b81a0d062f9bad15c9d9ba104b6cdf8590e5feYu Ping Hu final ContentValues insertValues = new ContentValues(values); 20553dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler insertValues.put(BodyColumns.MESSAGE_KEY, selectionArgs[0]); 20563dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler insert(Body.CONTENT_URI, insertValues); 20577525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } else { 20587525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler // possibly need to write new body values 20597525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (values.containsKey(BodyColumns.HTML_CONTENT) || 20607525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler values.containsKey(BodyColumns.TEXT_CONTENT)) { 20617525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final long messageIds[]; 20627525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (values.containsKey(BodyColumns.MESSAGE_KEY)) { 20637525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler messageIds = new long[] {values.getAsLong(BodyColumns.MESSAGE_KEY)}; 20647525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } else if (values.containsKey(BodyColumns._ID)) { 20657525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final long bodyId = values.getAsLong(BodyColumns._ID); 20667525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final SQLiteStatement sql = db.compileStatement( 20677525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler "select " + BodyColumns.MESSAGE_KEY + 20687525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler " from " + Body.TABLE_NAME + 20697525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler " where " + BodyColumns._ID + "=" + Long 20707525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler .toString(bodyId) 20717525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler ); 20727525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler messageIds = new long[] {sql.simpleQueryForLong()}; 20737525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } else { 20747525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final String proj[] = {BodyColumns.MESSAGE_KEY}; 20757525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final Cursor c = db.query(Body.TABLE_NAME, proj, 20767525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler selection, selectionArgs, 20777525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler null, null, null); 20787525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler try { 20797525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final int count = c.getCount(); 20807525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (count == 0) { 20817525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler throw new IllegalStateException("Can't find body record"); 20827525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 20837525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler messageIds = new long[count]; 20847525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler int i = 0; 20857525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler while (c.moveToNext()) { 20867525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler messageIds[i++] = c.getLong(0); 20877525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 20887525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } finally { 20897525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler c.close(); 20907525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 20917525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 20927525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler // This is probably overkill 20937525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler for (int i = 0; i < messageIds.length; i++) { 20947525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final long messageId = messageIds[i]; 20957525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler writeBodyFiles(context, messageId, values); 20967525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 20977525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 2098d0b81a0d062f9bad15c9d9ba104b6cdf8590e5feYu Ping Hu } 2099d0b81a0d062f9bad15c9d9ba104b6cdf8590e5feYu Ping Hu break; 21007525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 21010e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case MESSAGE: 21025057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux decodeEmailAddresses(values); 21030e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case UPDATED_MESSAGE: 21040e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ATTACHMENT: 21050e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case MAILBOX: 21060e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ACCOUNT: 21070e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case HOSTAUTH: 21080b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon case CREDENTIAL: 21096e418aa41a17136be0dddb816d843428a0a1e722Marc Blank case POLICY: 21105ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon if (match == ATTACHMENT) { 21115ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon if (values.containsKey(AttachmentColumns.LOCATION) && 21125ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon TextUtils.isEmpty(values.getAsString(AttachmentColumns.LOCATION))) { 21135ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon LogUtils.w(TAG, new Throwable(), "attachment with blank location"); 21145ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon } 21155ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon } 2116503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu result = db.update(tableName, values, selection, selectionArgs); 2117503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu break; 2118ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu case MESSAGE_MOVE: 2119ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu result = db.update(MessageMove.TABLE_NAME, values, selection, selectionArgs); 2120ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu break; 2121ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu case MESSAGE_STATE_CHANGE: 2122ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu result = db.update(MessageStateChange.TABLE_NAME, values, selection, 2123ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu selectionArgs); 2124ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu break; 21250e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank default: 21260e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank throw new IllegalArgumentException("Unknown URI " + uri); 21270e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank } 21280e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank } catch (SQLiteException e) { 21290e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank checkDatabases(); 21300e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank throw e; 2131fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank } 2132a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank 2133b3db04b80bd4344a5c69f9c36f9c99fcd03d5becJames Lemieux // Notify all notifier cursors if some records where changed in the database 2134b3db04b80bd4344a5c69f9c36f9c99fcd03d5becJames Lemieux if (result > 0) { 2135b3db04b80bd4344a5c69f9c36f9c99fcd03d5becJames Lemieux sendNotifierChange(getBaseNotificationUri(match), NOTIFICATION_OP_UPDATE, id); 2136b3db04b80bd4344a5c69f9c36f9c99fcd03d5becJames Lemieux notifyUI(notificationUri, null); 2137b3db04b80bd4344a5c69f9c36f9c99fcd03d5becJames Lemieux } 2138626f3e48a4f14c38a973dd2bea2e2debea7637a5Andrew Stadler return result; 2139fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank } 2140f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 21412075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu private void updateSyncStatus(final Bundle extras) { 21422075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu final long id = extras.getLong(EmailServiceStatus.SYNC_STATUS_ID); 21438c989772dfba08438650575f1ac2bb952bd56158Alon Albert final int statusCode = extras.getInt(EmailServiceStatus.SYNC_STATUS_CODE); 21442075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu final Uri uri = ContentUris.withAppendedId(FOLDER_STATUS_URI, id); 214505649dca2f59f28cd4295e041045a605badddb15Tony Mantler notifyUI(uri, null); 21468c989772dfba08438650575f1ac2bb952bd56158Alon Albert final boolean inProgress = statusCode == EmailServiceStatus.IN_PROGRESS; 21478c989772dfba08438650575f1ac2bb952bd56158Alon Albert if (inProgress) { 21488c989772dfba08438650575f1ac2bb952bd56158Alon Albert RefreshStatusMonitor.getInstance(getContext()).setSyncStarted(id); 21498c989772dfba08438650575f1ac2bb952bd56158Alon Albert } else { 21508c989772dfba08438650575f1ac2bb952bd56158Alon Albert final int result = extras.getInt(EmailServiceStatus.SYNC_RESULT); 21518c989772dfba08438650575f1ac2bb952bd56158Alon Albert final ContentValues values = new ContentValues(); 21528c989772dfba08438650575f1ac2bb952bd56158Alon Albert values.put(Mailbox.UI_LAST_SYNC_RESULT, result); 21538c989772dfba08438650575f1ac2bb952bd56158Alon Albert mDatabase.update( 21548c989772dfba08438650575f1ac2bb952bd56158Alon Albert Mailbox.TABLE_NAME, 21558c989772dfba08438650575f1ac2bb952bd56158Alon Albert values, 21568c989772dfba08438650575f1ac2bb952bd56158Alon Albert WHERE_ID, 21578c989772dfba08438650575f1ac2bb952bd56158Alon Albert new String[] { String.valueOf(id) }); 21588c989772dfba08438650575f1ac2bb952bd56158Alon Albert } 21592075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu } 21602075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu 2161779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook @Override 2162779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook public Bundle call(String method, String arg, Bundle extras) { 2163779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook LogUtils.d(TAG, "EmailProvider#call(%s, %s)", method, arg); 216471737836e6be308f752cb95c955a03146b039a9cYu Ping Hu 21655181cd6d4a60ed0b7dbed022484d299a3e91f0daYu Ping Hu // Handle queries for the device friendly name. 21665181cd6d4a60ed0b7dbed022484d299a3e91f0daYu Ping Hu // TODO: This should eventually be a device property, not defined by the app. 21675181cd6d4a60ed0b7dbed022484d299a3e91f0daYu Ping Hu if (TextUtils.equals(method, EmailContent.DEVICE_FRIENDLY_NAME)) { 21685181cd6d4a60ed0b7dbed022484d299a3e91f0daYu Ping Hu final Bundle bundle = new Bundle(1); 21695181cd6d4a60ed0b7dbed022484d299a3e91f0daYu Ping Hu // TODO: For now, just use the model name since we don't yet have a user-supplied name. 21705181cd6d4a60ed0b7dbed022484d299a3e91f0daYu Ping Hu bundle.putString(EmailContent.DEVICE_FRIENDLY_NAME, Build.MODEL); 21715181cd6d4a60ed0b7dbed022484d299a3e91f0daYu Ping Hu return bundle; 21725181cd6d4a60ed0b7dbed022484d299a3e91f0daYu Ping Hu } 21735181cd6d4a60ed0b7dbed022484d299a3e91f0daYu Ping Hu 21742075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu // Handle sync status callbacks. 217571737836e6be308f752cb95c955a03146b039a9cYu Ping Hu if (TextUtils.equals(method, SYNC_STATUS_CALLBACK_METHOD)) { 21762075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu updateSyncStatus(extras); 217771737836e6be308f752cb95c955a03146b039a9cYu Ping Hu return null; 217871737836e6be308f752cb95c955a03146b039a9cYu Ping Hu } 2179f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon if (TextUtils.equals(method, MailboxUtilities.FIX_PARENT_KEYS_METHOD)) { 2180f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon fixParentKeys(getDatabase(getContext())); 2181f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon return null; 2182f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon } 218371737836e6be308f752cb95c955a03146b039a9cYu Ping Hu 218471737836e6be308f752cb95c955a03146b039a9cYu Ping Hu // Handle send & save. 2185779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook final Uri accountUri = Uri.parse(arg); 21860eb47994a328fe450c54e483b894138fd449d9c9Yu Ping Hu final long accountId = Long.parseLong(accountUri.getPathSegments().get(1)); 2187779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook 2188779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook Uri messageUri = null; 2189f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon 2190779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook if (TextUtils.equals(method, UIProvider.AccountCallMethods.SEND_MESSAGE)) { 219171737836e6be308f752cb95c955a03146b039a9cYu Ping Hu messageUri = uiSendDraftMessage(accountId, extras); 2192229c070b0b177793032ce9249cb77f6ca98e5aa4Scott Kennedy Preferences.getPreferences(getContext()).setLastUsedAccountId(accountId); 2193779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook } else if (TextUtils.equals(method, UIProvider.AccountCallMethods.SAVE_MESSAGE)) { 219471737836e6be308f752cb95c955a03146b039a9cYu Ping Hu messageUri = uiSaveDraftMessage(accountId, extras); 2195229c070b0b177793032ce9249cb77f6ca98e5aa4Scott Kennedy } else if (TextUtils.equals(method, UIProvider.AccountCallMethods.SET_CURRENT_ACCOUNT)) { 2196229c070b0b177793032ce9249cb77f6ca98e5aa4Scott Kennedy LogUtils.d(TAG, "Unhandled (but expected) Content provider method: %s", method); 2197229c070b0b177793032ce9249cb77f6ca98e5aa4Scott Kennedy } else { 2198229c070b0b177793032ce9249cb77f6ca98e5aa4Scott Kennedy LogUtils.wtf(TAG, "Unexpected Content provider method: %s", method); 2199779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook } 2200779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook 2201779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook final Bundle result; 2202779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook if (messageUri != null) { 2203779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook result = new Bundle(1); 2204779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook result.putParcelable(UIProvider.MessageColumns.URI, messageUri); 2205779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook } else { 2206779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook result = null; 2207779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook } 2208779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook 2209779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook return result; 2210779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook } 2211779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook 22127525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler /** 22137525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * Writes message bodies to disk, read from a set of ContentValues 22147525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * 22157525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @param c Context for finding files 22167525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @param messageId id of message to write body for 22177525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @param cv {@link ContentValues} containing {@link BodyColumns#HTML_CONTENT} and/or 22187525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * {@link BodyColumns#TEXT_CONTENT}. Inserting a null or empty value will delete the 22197525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * associated text or html body file 22207525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @throws IllegalStateException 22217525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler */ 22227525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler private static void writeBodyFiles(final Context c, final long messageId, 22237525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final ContentValues cv) throws IllegalStateException { 22247525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (cv.containsKey(BodyColumns.HTML_CONTENT)) { 22257525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final String htmlContent = cv.getAsString(BodyColumns.HTML_CONTENT); 22267525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler try { 22277525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler writeBodyFile(c, messageId, "html", htmlContent); 22287525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } catch (final IOException e) { 22297525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler throw new IllegalStateException("IOException while writing html body " + 22307525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler "for message id " + Long.toString(messageId), e); 22317525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 22327525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 22337525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (cv.containsKey(BodyColumns.TEXT_CONTENT)) { 22347525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final String textContent = cv.getAsString(BodyColumns.TEXT_CONTENT); 22357525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler try { 22367525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler writeBodyFile(c, messageId, "txt", textContent); 22377525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } catch (final IOException e) { 22387525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler throw new IllegalStateException("IOException while writing text body " + 22397525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler "for message id " + Long.toString(messageId), e); 22407525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 22417525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 22427525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 22432f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler 22447525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler /** 22457525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * Writes a message body file to disk 22467525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * 22477525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @param c Context for finding files dir 22487525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @param messageId id of message to write body for 22497525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @param ext "html" or "txt" 22507525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @param content Body content to write to file, or null/empty to delete file 22517525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @throws IOException 22527525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler */ 22537525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler private static void writeBodyFile(final Context c, final long messageId, final String ext, 22547525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final String content) throws IOException { 22557525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final File textFile = getBodyFile(c, messageId, ext); 22567525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (TextUtils.isEmpty(content)) { 22577525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (!textFile.delete()) { 22587525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler LogUtils.v(LogUtils.TAG, "did not delete text body for %d", messageId); 22597525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 22607525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } else { 22617525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final FileWriter w = new FileWriter(textFile); 22627525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler try { 22637525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler w.write(content); 22647525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } finally { 22657525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler w.close(); 22667525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 22672f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler } 22687525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 22692f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler 22702f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler /** 22717525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * Returns a {@link java.io.File} object pointing to the body content file for the message 22722f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler * 22737525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @param c Context for finding files dir 22747525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @param messageId id of message to locate 22757525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @param ext "html" or "txt" 22767525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @return File ready for operating upon 22772f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler */ 22787525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler protected static File getBodyFile(final Context c, final long messageId, final String ext) 22797525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler throws FileNotFoundException { 22807525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (!TextUtils.equals(ext, "html") && !TextUtils.equals(ext, "txt")) { 22817525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler throw new IllegalArgumentException("ext must be one of 'html' or 'txt'"); 22827525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 22837525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler long l1 = messageId / 100 % 100; 22847525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler long l2 = messageId % 100; 22857525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final File dir = new File(c.getFilesDir(), 22867525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler "body/" + Long.toString(l1) + "/" + Long.toString(l2) + "/"); 22877525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (!dir.isDirectory() && !dir.mkdirs()) { 22887525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler throw new FileNotFoundException("Could not create directory for body file"); 22897525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 22907525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler return new File(dir, Long.toString(messageId) + "." + ext); 22917525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 22922f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler 22935a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook @Override 22942f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler public ParcelFileDescriptor openFile(final Uri uri, final String mode) 22952f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler throws FileNotFoundException { 22965a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook if (LogUtils.isLoggable(TAG, LogUtils.DEBUG)) { 22975a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook LogUtils.d(TAG, "EmailProvider.openFile: %s", LogUtils.contentUriToString(TAG, uri)); 22985a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook } 22995a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook 23005a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook final int match = findMatch(uri, "openFile"); 23015a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook switch (match) { 23025a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook case ATTACHMENTS_CACHED_FILE_ACCESS: 23035a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook // Parse the cache file path out from the uri 23045a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook final String cachedFilePath = 23053dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler uri.getQueryParameter(Attachment.CACHED_FILE_QUERY_PARAM); 23065a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook 23075a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook if (cachedFilePath != null) { 23085a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook // clearCallingIdentity means that the download manager will 23095a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook // check our permissions rather than the permissions of whatever 23105a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook // code is calling us. 23115a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook long binderToken = Binder.clearCallingIdentity(); 23125a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook try { 23135a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook LogUtils.d(TAG, "Opening attachment %s", cachedFilePath); 23145a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook return ParcelFileDescriptor.open( 23155a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook new File(cachedFilePath), ParcelFileDescriptor.MODE_READ_ONLY); 23165a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook } finally { 23175a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook Binder.restoreCallingIdentity(binderToken); 23185a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook } 23195a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook } 23205a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook break; 23217525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler case BODY_HTML: { 23222f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler final long messageKey = Long.valueOf(uri.getLastPathSegment()); 23237525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler return ParcelFileDescriptor.open(getBodyFile(getContext(), messageKey, "html"), 23247525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler Utilities.parseMode(mode)); 23257525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 23267525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler case BODY_TEXT:{ 23277525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final long messageKey = Long.valueOf(uri.getLastPathSegment()); 23287525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler return ParcelFileDescriptor.open(getBodyFile(getContext(), messageKey, "txt"), 23297525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler Utilities.parseMode(mode)); 23307525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 23315a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook } 23325a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook 23335a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook throw new FileNotFoundException("unable to open file"); 23345a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook } 23355a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook 23365a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook 2337bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy /** 2338e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy * Returns the base notification URI for the given content type. 2339e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy * 2340e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy * @param match The type of content that was modified. 2341e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy */ 2342b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static Uri getBaseNotificationUri(int match) { 2343e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy Uri baseUri = null; 2344e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy switch (match) { 2345e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy case MESSAGE: 2346e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy case MESSAGE_ID: 2347e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy case SYNCED_MESSAGE_ID: 2348e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy baseUri = Message.NOTIFIER_URI; 2349e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy break; 2350e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy case ACCOUNT: 2351e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy case ACCOUNT_ID: 2352e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy baseUri = Account.NOTIFIER_URI; 2353e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy break; 2354e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy } 2355e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy return baseUri; 2356e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy } 2357e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy 2358e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy /** 2359bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * Sends a change notification to any cursors observers of the given base URI. The final 2360bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * notification URI is dynamically built to contain the specified information. It will be 2361bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * of the format <<baseURI>>/<<op>>/<<id>>; where <<op>> and <<id>> are optional depending 2362bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * upon the given values. 2363bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * NOTE: If <<op>> is specified, notifications for <<baseURI>>/<<id>> will NOT be invoked. 2364bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * If this is necessary, it can be added. However, due to the implementation of 2365bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * {@link ContentObserver}, observers of <<baseURI>> will receive multiple notifications. 2366bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * 2367bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * @param baseUri The base URI to send notifications to. Must be able to take appended IDs. 2368bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * @param op Optional operation to be appended to the URI. 2369bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * @param id If a positive value, the ID to append to the base URI. Otherwise, no ID will be 2370bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * appended to the base URI. 2371fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank */ 2372bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy private void sendNotifierChange(Uri baseUri, String op, String id) { 2373e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy if (baseUri == null) return; 2374e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy 2375bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy // Append the operation, if specified 2376bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy if (op != null) { 2377bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy baseUri = baseUri.buildUpon().appendEncodedPath(op).build(); 2378bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy } 2379bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy 2380bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy long longId = 0L; 2381bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy try { 2382bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy longId = Long.valueOf(id); 2383bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy } catch (NumberFormatException ignore) {} 2384bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy if (longId > 0) { 238505649dca2f59f28cd4295e041045a605badddb15Tony Mantler notifyUI(baseUri, id); 2386bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy } else { 238705649dca2f59f28cd4295e041045a605badddb15Tony Mantler notifyUI(baseUri, null); 2388bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy } 238907676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook 239007676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook // We want to send the message list changed notification if baseUri is Message.NOTIFIER_URI. 239107676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook if (baseUri.equals(Message.NOTIFIER_URI)) { 239207676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook sendMessageListDataChangedNotification(); 239307676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook } 239407676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook } 239507676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook 239607676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook private void sendMessageListDataChangedNotification() { 239707676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook final Context context = getContext(); 239807676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook final Intent intent = new Intent(ACTION_NOTIFY_MESSAGE_LIST_DATASET_CHANGED); 239907676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook // Ideally this intent would contain information about which account changed, to limit the 240007676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook // updates to that particular account. Unfortunately, that information is not available in 240107676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook // sendNotifierChange(). 240207676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook context.sendBroadcast(intent); 2403bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy } 2404bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy 240500219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler // We might have more than one thread trying to make its way through applyBatch() so the 240600219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler // notification coalescing needs to be thread-local to work correctly. 240700219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler private final ThreadLocal<Set<Uri>> mTLBatchNotifications = 240800219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler new ThreadLocal<Set<Uri>>(); 240900219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler 241000219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler private Set<Uri> getBatchNotificationsSet() { 241100219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler return mTLBatchNotifications.get(); 241200219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler } 241300219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler 241400219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler private void setBatchNotificationsSet(Set<Uri> batchNotifications) { 241500219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler mTLBatchNotifications.set(batchNotifications); 241600219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler } 241705649dca2f59f28cd4295e041045a605badddb15Tony Mantler 2418758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank @Override 241984969fb580f569c0e3625a3c59a71d2909ae198dFred Quintana public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 2420b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank throws OperationApplicationException { 242105649dca2f59f28cd4295e041045a605badddb15Tony Mantler /** 242205649dca2f59f28cd4295e041045a605badddb15Tony Mantler * Collect notification URIs to notify at the end of batch processing. 242305649dca2f59f28cd4295e041045a605badddb15Tony Mantler * These are populated by calls to notifyUI() by way of update(), insert() and delete() 242405649dca2f59f28cd4295e041045a605badddb15Tony Mantler * calls made in super.applyBatch() 242505649dca2f59f28cd4295e041045a605badddb15Tony Mantler */ 242600219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler setBatchNotificationsSet(Sets.<Uri>newHashSet()); 2427cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank Context context = getContext(); 2428cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank SQLiteDatabase db = getDatabase(context); 2429fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank db.beginTransaction(); 2430fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank try { 2431fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank ContentProviderResult[] results = super.applyBatch(operations); 2432fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank db.setTransactionSuccessful(); 2433fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank return results; 2434fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank } finally { 2435fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank db.endTransaction(); 243600219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler final Set<Uri> notifications = getBatchNotificationsSet(); 243700219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler setBatchNotificationsSet(null); 243805649dca2f59f28cd4295e041045a605badddb15Tony Mantler for (final Uri uri : notifications) { 243905649dca2f59f28cd4295e041045a605badddb15Tony Mantler context.getContentResolver().notifyChange(uri, null); 244005649dca2f59f28cd4295e041045a605badddb15Tony Mantler } 2441f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 2442f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 2443574854b528163f3bf1a7cb974aa80082d1768edfMakoto Onuki 24443d16e5d4b994d92db51962c8c461c53bee04309fAnthony Lee public static interface EmailAttachmentService { 244503cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank /** 244603cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank * Notify the service that an attachment has changed. 244703cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank */ 24483d16e5d4b994d92db51962c8c461c53bee04309fAnthony Lee void attachmentChanged(final Context context, final long id, final int flags); 244955d0e821eaecb5e454812a30c1137dbc95db98e2Marc Blank } 245055d0e821eaecb5e454812a30c1137dbc95db98e2Marc Blank 24513d16e5d4b994d92db51962c8c461c53bee04309fAnthony Lee private final EmailAttachmentService DEFAULT_ATTACHMENT_SERVICE = new EmailAttachmentService() { 245259e10b6b3dbc14884b032b1843413b08adaaf288Marc Blank @Override 24533d16e5d4b994d92db51962c8c461c53bee04309fAnthony Lee public void attachmentChanged(final Context context, final long id, final int flags) { 245403cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank // The default implementation delegates to the real service. 24553d16e5d4b994d92db51962c8c461c53bee04309fAnthony Lee AttachmentService.attachmentChanged(context, id, flags); 245659e10b6b3dbc14884b032b1843413b08adaaf288Marc Blank } 245759e10b6b3dbc14884b032b1843413b08adaaf288Marc Blank }; 24583d16e5d4b994d92db51962c8c461c53bee04309fAnthony Lee private EmailAttachmentService mAttachmentService = DEFAULT_ATTACHMENT_SERVICE; 245917d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie 246017d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie // exposed for testing 24613d16e5d4b994d92db51962c8c461c53bee04309fAnthony Lee public void injectAttachmentService(final EmailAttachmentService attachmentService) { 246217d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie mAttachmentService = 246317d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie attachmentService == null ? DEFAULT_ATTACHMENT_SERVICE : attachmentService; 246417d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie } 2465ebb79619e8ed3c9f0c051e7f323e3971bce7508dMarc Blank 2466b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private Cursor notificationQuery(final Uri uri) { 2467b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final SQLiteDatabase db = getDatabase(getContext()); 2468b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final String accountId = uri.getLastPathSegment(); 2469b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy 24700053401d07cd11f19c63dfbc3942d027b4067de8Tony Mantler final String sql = "SELECT " + MessageColumns.MAILBOX_KEY + ", " + 24710053401d07cd11f19c63dfbc3942d027b4067de8Tony Mantler "SUM(CASE " + MessageColumns.FLAG_READ + " WHEN 0 THEN 1 ELSE 0 END), " + 24720053401d07cd11f19c63dfbc3942d027b4067de8Tony Mantler "SUM(CASE " + MessageColumns.FLAG_SEEN + " WHEN 0 THEN 1 ELSE 0 END)\n" + 24730053401d07cd11f19c63dfbc3942d027b4067de8Tony Mantler "FROM " + Message.TABLE_NAME + "\n" + 24740053401d07cd11f19c63dfbc3942d027b4067de8Tony Mantler "WHERE " + MessageColumns.ACCOUNT_KEY + " = ?\n" + 24750053401d07cd11f19c63dfbc3942d027b4067de8Tony Mantler "GROUP BY " + MessageColumns.MAILBOX_KEY; 2476b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy 2477b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final String[] selectionArgs = {accountId}; 2478b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy 2479b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy return db.rawQuery(sql, selectionArgs); 2480ebb79619e8ed3c9f0c051e7f323e3971bce7508dMarc Blank } 2481f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2482f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank public Cursor mostRecentMessageQuery(Uri uri) { 2483f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank SQLiteDatabase db = getDatabase(getContext()); 2484f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank String mailboxId = uri.getLastPathSegment(); 2485f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return db.rawQuery("select max(_id) from Message where mailboxKey=?", 2486f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank new String[] {mailboxId}); 248717d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu } 248817d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu 248917d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu private Cursor getMailboxMessageCount(Uri uri) { 249017d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu SQLiteDatabase db = getDatabase(getContext()); 249117d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu String mailboxId = uri.getLastPathSegment(); 249217d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu return db.rawQuery("select count(*) from Message where mailboxKey=?", 249317d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu new String[] {mailboxId}); 249417d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu } 2495f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2496f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2497f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Support for UnifiedEmail below 2498f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2499f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2500f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String NOT_A_DRAFT_STRING = 2501f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Integer.toString(UIProvider.DraftType.NOT_A_DRAFT); 2502f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2503f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String CONVERSATION_FLAGS = 2504f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "CASE WHEN (" + MessageColumns.FLAGS + "&" + Message.FLAG_INCOMING_MEETING_INVITE + 2505f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ") !=0 THEN " + UIProvider.ConversationFlags.CALENDAR_INVITE + 2506f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " ELSE 0 END + " + 2507f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "CASE WHEN (" + MessageColumns.FLAGS + "&" + Message.FLAG_FORWARDED + 2508f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ") !=0 THEN " + UIProvider.ConversationFlags.FORWARDED + 2509f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " ELSE 0 END + " + 2510f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "CASE WHEN (" + MessageColumns.FLAGS + "&" + Message.FLAG_REPLIED_TO + 2511f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ") !=0 THEN " + UIProvider.ConversationFlags.REPLIED + 2512f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " ELSE 0 END"; 2513f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2514f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2515f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Array of pre-defined account colors (legacy colors from old email app) 2516f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2517f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final int[] ACCOUNT_COLORS = new int[] { 2518f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 0xff71aea7, 0xff621919, 0xff18462f, 0xffbf8e52, 0xff001f79, 2519f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 0xffa8afc2, 0xff6b64c4, 0xff738359, 0xff9d50a4 2520f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank }; 2521f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2522f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String CONVERSATION_COLOR = 2523f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "@CASE (" + MessageColumns.ACCOUNT_KEY + " - 1) % " + ACCOUNT_COLORS.length + 2524f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 0 THEN " + ACCOUNT_COLORS[0] + 2525f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 1 THEN " + ACCOUNT_COLORS[1] + 2526f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 2 THEN " + ACCOUNT_COLORS[2] + 2527f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 3 THEN " + ACCOUNT_COLORS[3] + 2528f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 4 THEN " + ACCOUNT_COLORS[4] + 2529f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 5 THEN " + ACCOUNT_COLORS[5] + 2530f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 6 THEN " + ACCOUNT_COLORS[6] + 2531f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 7 THEN " + ACCOUNT_COLORS[7] + 2532f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 8 THEN " + ACCOUNT_COLORS[8] + 2533f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " END"; 2534f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2535f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String ACCOUNT_COLOR = 25363dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler "@CASE (" + AccountColumns._ID + " - 1) % " + ACCOUNT_COLORS.length + 2537f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 0 THEN " + ACCOUNT_COLORS[0] + 2538f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 1 THEN " + ACCOUNT_COLORS[1] + 2539f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 2 THEN " + ACCOUNT_COLORS[2] + 2540f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 3 THEN " + ACCOUNT_COLORS[3] + 2541f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 4 THEN " + ACCOUNT_COLORS[4] + 2542f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 5 THEN " + ACCOUNT_COLORS[5] + 2543f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 6 THEN " + ACCOUNT_COLORS[6] + 2544f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 7 THEN " + ACCOUNT_COLORS[7] + 2545f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 8 THEN " + ACCOUNT_COLORS[8] + 2546f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " END"; 25470053401d07cd11f19c63dfbc3942d027b4067de8Tony Mantler 2548f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2549f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Mapping of UIProvider columns to EmailProvider columns for the message list (called the 2550f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * conversation list in UnifiedEmail) 2551f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2552b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static ProjectionMap getMessageListMap() { 2553e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank if (sMessageListMap == null) { 2554e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank sMessageListMap = ProjectionMap.builder() 25553dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(BaseColumns._ID, MessageColumns._ID) 2556e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.URI, uriWithId("uimessage")) 2557e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.MESSAGE_LIST_URI, uriWithId("uimessage")) 2558e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.SUBJECT, MessageColumns.SUBJECT) 2559e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.SNIPPET, MessageColumns.SNIPPET) 2560e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.CONVERSATION_INFO, null) 2561e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.DATE_RECEIVED_MS, MessageColumns.TIMESTAMP) 2562e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.HAS_ATTACHMENTS, MessageColumns.FLAG_ATTACHMENT) 2563e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.NUM_MESSAGES, "1") 2564e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.NUM_DRAFTS, "0") 2565e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.SENDING_STATE, 2566e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank Integer.toString(ConversationSendingState.OTHER)) 2567e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.PRIORITY, 2568e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank Integer.toString(ConversationPriority.LOW)) 2569e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.READ, MessageColumns.FLAG_READ) 2570b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy .add(UIProvider.ConversationColumns.SEEN, MessageColumns.FLAG_SEEN) 2571e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.STARRED, MessageColumns.FLAG_FAVORITE) 2572e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.FLAGS, CONVERSATION_FLAGS) 2573e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.ACCOUNT_URI, 2574e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank uriWithColumn("uiaccount", MessageColumns.ACCOUNT_KEY)) 2575968a2fe7805756ef6aa1f10f71306e865b9f7f09Paul Westbrook .add(UIProvider.ConversationColumns.SENDER_INFO, MessageColumns.FROM_LIST) 25769773c96d83f126b8418b192bcf46f939f44fdb44Alan Lau .add(UIProvider.ConversationColumns.ORDER_KEY, MessageColumns.TIMESTAMP) 2577e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .build(); 2578e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank } 2579e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank return sMessageListMap; 2580e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank } 2581e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank private static ProjectionMap sMessageListMap; 2582f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2583f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2584f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate UIProvider draft type; note the test for "reply all" must come before "reply" 2585f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2586f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String MESSAGE_DRAFT_TYPE = 2587f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "CASE WHEN (" + MessageColumns.FLAGS + "&" + Message.FLAG_TYPE_ORIGINAL + 2588f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ") !=0 THEN " + UIProvider.DraftType.COMPOSE + 258985d2190552d05dbc06518bdc21674c6aabeb583bMartin Hibdon " WHEN (" + MessageColumns.FLAGS + "&" + Message.FLAG_TYPE_REPLY_ALL + 2590f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ") !=0 THEN " + UIProvider.DraftType.REPLY_ALL + 2591f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN (" + MessageColumns.FLAGS + "&" + Message.FLAG_TYPE_REPLY + 2592f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ") !=0 THEN " + UIProvider.DraftType.REPLY + 2593f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN (" + MessageColumns.FLAGS + "&" + Message.FLAG_TYPE_FORWARD + 2594f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ") !=0 THEN " + UIProvider.DraftType.FORWARD + 2595f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " ELSE " + UIProvider.DraftType.NOT_A_DRAFT + " END"; 2596f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2597f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String MESSAGE_FLAGS = 2598f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "CASE WHEN (" + MessageColumns.FLAGS + "&" + Message.FLAG_INCOMING_MEETING_INVITE + 2599f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ") !=0 THEN " + UIProvider.MessageFlags.CALENDAR_INVITE + 2600f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " ELSE 0 END"; 2601f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2602f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2603f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Mapping of UIProvider columns to EmailProvider columns for a detailed message view in 2604f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * UnifiedEmail 2605f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2606b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static ProjectionMap getMessageViewMap() { 2607e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank if (sMessageViewMap == null) { 2608e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank sMessageViewMap = ProjectionMap.builder() 26093dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(BaseColumns._ID, Message.TABLE_NAME + "." + MessageColumns._ID) 2610e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.SERVER_ID, SyncColumns.SERVER_ID) 2611e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.URI, uriWithFQId("uimessage", Message.TABLE_NAME)) 2612e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.CONVERSATION_ID, 2613e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank uriWithFQId("uimessage", Message.TABLE_NAME)) 26143dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.SUBJECT, MessageColumns.SUBJECT) 26153dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.SNIPPET, MessageColumns.SNIPPET) 26163dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.FROM, MessageColumns.FROM_LIST) 26173dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.TO, MessageColumns.TO_LIST) 26183dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.CC, MessageColumns.CC_LIST) 26193dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.BCC, MessageColumns.BCC_LIST) 26203dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.REPLY_TO, MessageColumns.REPLY_TO_LIST) 26213dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.DATE_RECEIVED_MS, MessageColumns.TIMESTAMP) 26229caaebb14282034576345b35402f5b6654c3f08dTony Mantler .add(UIProvider.MessageColumns.BODY_HTML, null) // Loaded in EmailMessageCursor 26239caaebb14282034576345b35402f5b6654c3f08dTony Mantler .add(UIProvider.MessageColumns.BODY_TEXT, null) // Loaded in EmailMessageCursor 2624e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.REF_MESSAGE_ID, "0") 2625e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.DRAFT_TYPE, NOT_A_DRAFT_STRING) 2626e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.APPEND_REF_MESSAGE_CONTENT, "0") 26273dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.HAS_ATTACHMENTS, MessageColumns.FLAG_ATTACHMENT) 2628e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.ATTACHMENT_LIST_URI, 2629e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank uriWithFQId("uiattachments", Message.TABLE_NAME)) 26308cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux .add(UIProvider.MessageColumns.ATTACHMENT_BY_CID_URI, 26318cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux uriWithFQId("uiattachmentbycid", Message.TABLE_NAME)) 2632e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.MESSAGE_FLAGS, MESSAGE_FLAGS) 2633e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.DRAFT_TYPE, MESSAGE_DRAFT_TYPE) 2634e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.MESSAGE_ACCOUNT_URI, 2635b2c7bcff7813f2cecba5c9c52b69cf5ef2cc9cadPaul Westbrook uriWithColumn("uiaccount", MessageColumns.ACCOUNT_KEY)) 26363dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.STARRED, MessageColumns.FLAG_FAVORITE) 26373dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.READ, MessageColumns.FLAG_READ) 26383dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.SEEN, MessageColumns.FLAG_SEEN) 2639e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.SPAM_WARNING_STRING, null) 2640e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.SPAM_WARNING_LEVEL, 2641e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank Integer.toString(UIProvider.SpamWarningLevel.NO_WARNING)) 2642e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.SPAM_WARNING_LINK_TYPE, 2643e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank Integer.toString(UIProvider.SpamWarningLinkType.NO_LINK)) 2644e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.VIA_DOMAIN, null) 264507d674f9fef8d78b3a97f2d8c28ca444de607742Andrew Sapperstein .add(UIProvider.MessageColumns.CLIPPED, "0") 26461bb18931e29dfe55a9b3368bd2393ac57c5fdebbAndrew Sapperstein .add(UIProvider.MessageColumns.PERMALINK, null) 2647e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .build(); 2648e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank } 2649e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank return sMessageViewMap; 2650e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank } 2651e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank private static ProjectionMap sMessageViewMap; 2652f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2653f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2654f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate UIProvider folder capabilities from mailbox flags 2655f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2656f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String FOLDER_CAPABILITIES = 2657f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "CASE WHEN (" + MailboxColumns.FLAGS + "&" + Mailbox.FLAG_ACCEPTS_MOVED_MAIL + 2658f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ") !=0 THEN " + UIProvider.FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES + 2659f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " ELSE 0 END"; 2660f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2661f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2662f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Convert EmailProvider type to UIProvider type 2663f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2664f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String FOLDER_TYPE = "CASE " + MailboxColumns.TYPE 2665f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_INBOX + " THEN " + UIProvider.FolderType.INBOX 2666f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_DRAFTS + " THEN " + UIProvider.FolderType.DRAFT 2667f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_OUTBOX + " THEN " + UIProvider.FolderType.OUTBOX 2668f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_SENT + " THEN " + UIProvider.FolderType.SENT 2669f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_TRASH + " THEN " + UIProvider.FolderType.TRASH 2670f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_JUNK + " THEN " + UIProvider.FolderType.SPAM 2671f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_STARRED + " THEN " + UIProvider.FolderType.STARRED 2672cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein + " WHEN " + Mailbox.TYPE_UNREAD + " THEN " + UIProvider.FolderType.UNREAD 2673e743a06ddf7677706da7450100e19d0f4509a43cScott Kennedy + " WHEN " + Mailbox.TYPE_SEARCH + " THEN " 2674e743a06ddf7677706da7450100e19d0f4509a43cScott Kennedy + getFolderTypeFromMailboxType(Mailbox.TYPE_SEARCH) 2675f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " ELSE " + UIProvider.FolderType.DEFAULT + " END"; 2676f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2677f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String FOLDER_ICON = "CASE " + MailboxColumns.TYPE 26784fb5412e1b3a4fad45eed90c7040b6ff0fe323b8Tony Mantler + " WHEN " + Mailbox.TYPE_INBOX + " THEN " + R.drawable.ic_drawer_inbox 26794fb5412e1b3a4fad45eed90c7040b6ff0fe323b8Tony Mantler + " WHEN " + Mailbox.TYPE_DRAFTS + " THEN " + R.drawable.ic_drawer_drafts 26804fb5412e1b3a4fad45eed90c7040b6ff0fe323b8Tony Mantler + " WHEN " + Mailbox.TYPE_OUTBOX + " THEN " + R.drawable.ic_drawer_outbox 26814fb5412e1b3a4fad45eed90c7040b6ff0fe323b8Tony Mantler + " WHEN " + Mailbox.TYPE_SENT + " THEN " + R.drawable.ic_drawer_sent 26824fb5412e1b3a4fad45eed90c7040b6ff0fe323b8Tony Mantler + " WHEN " + Mailbox.TYPE_TRASH + " THEN " + R.drawable.ic_drawer_trash 26834fb5412e1b3a4fad45eed90c7040b6ff0fe323b8Tony Mantler + " WHEN " + Mailbox.TYPE_STARRED + " THEN " + R.drawable.ic_drawer_starred 26844fb5412e1b3a4fad45eed90c7040b6ff0fe323b8Tony Mantler + " ELSE " + R.drawable.ic_drawer_folder + " END"; 2685f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 26865ff368b84573833497764c9d1661cc97717b7094Yu Ping Hu /** 2687bcd81d96a40f3d987f4d780f64d339dd7f5ab2edYu Ping Hu * Local-only folders set totalCount < 0; such folders should substitute message count for 2688bcd81d96a40f3d987f4d780f64d339dd7f5ab2edYu Ping Hu * total count. 2689bcd81d96a40f3d987f4d780f64d339dd7f5ab2edYu Ping Hu * TODO: IMAP and POP don't adhere to this convention yet so for now we force a few types. 26905ff368b84573833497764c9d1661cc97717b7094Yu Ping Hu */ 26915ff368b84573833497764c9d1661cc97717b7094Yu Ping Hu private static final String TOTAL_COUNT = "CASE WHEN " 2692bcd81d96a40f3d987f4d780f64d339dd7f5ab2edYu Ping Hu + MailboxColumns.TOTAL_COUNT + "<0 OR " 26935ff368b84573833497764c9d1661cc97717b7094Yu Ping Hu + MailboxColumns.TYPE + "=" + Mailbox.TYPE_DRAFTS + " OR " 26945ff368b84573833497764c9d1661cc97717b7094Yu Ping Hu + MailboxColumns.TYPE + "=" + Mailbox.TYPE_OUTBOX + " OR " 26955ff368b84573833497764c9d1661cc97717b7094Yu Ping Hu + MailboxColumns.TYPE + "=" + Mailbox.TYPE_TRASH 26965ff368b84573833497764c9d1661cc97717b7094Yu Ping Hu + " THEN " + MailboxColumns.MESSAGE_COUNT 26975ff368b84573833497764c9d1661cc97717b7094Yu Ping Hu + " ELSE " + MailboxColumns.TOTAL_COUNT + " END"; 26985ff368b84573833497764c9d1661cc97717b7094Yu Ping Hu 2699b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static ProjectionMap getFolderListMap() { 2700e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank if (sFolderListMap == null) { 2701e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank sFolderListMap = ProjectionMap.builder() 27023dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(BaseColumns._ID, MailboxColumns._ID) 2703b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy .add(UIProvider.FolderColumns.PERSISTENT_ID, MailboxColumns.SERVER_ID) 2704e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.URI, uriWithId("uifolder")) 2705e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.NAME, "displayName") 2706e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.HAS_CHILDREN, 2707e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank MailboxColumns.FLAGS + "&" + Mailbox.FLAG_HAS_CHILDREN) 2708e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.CAPABILITIES, FOLDER_CAPABILITIES) 2709e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.SYNC_WINDOW, "3") 2710e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.CONVERSATION_LIST_URI, uriWithId("uimessages")) 2711e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.CHILD_FOLDERS_LIST_URI, uriWithId("uisubfolders")) 2712e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.UNREAD_COUNT, MailboxColumns.UNREAD_COUNT) 27135ff368b84573833497764c9d1661cc97717b7094Yu Ping Hu .add(UIProvider.FolderColumns.TOTAL_COUNT, TOTAL_COUNT) 271464cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu .add(UIProvider.FolderColumns.REFRESH_URI, uriWithId(QUERY_UIREFRESH)) 2715e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.SYNC_STATUS, MailboxColumns.UI_SYNC_STATUS) 2716e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.LAST_SYNC_RESULT, MailboxColumns.UI_LAST_SYNC_RESULT) 2717e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.TYPE, FOLDER_TYPE) 2718e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.ICON_RES_ID, FOLDER_ICON) 27191004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu .add(UIProvider.FolderColumns.LOAD_MORE_URI, uriWithId("uiloadmore")) 2720e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.HIERARCHICAL_DESC, MailboxColumns.HIERARCHICAL_NAME) 272150f645e019c3165b14457c0b661c59cd4e6ce375Vikram Aggarwal .add(UIProvider.FolderColumns.PARENT_URI, "case when " + MailboxColumns.PARENT_KEY 272250f645e019c3165b14457c0b661c59cd4e6ce375Vikram Aggarwal + "=" + Mailbox.NO_MAILBOX + " then NULL else " + 272350f645e019c3165b14457c0b661c59cd4e6ce375Vikram Aggarwal uriWithColumn("uifolder", MailboxColumns.PARENT_KEY) + " end") 27244cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler /** 27254cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler * SELECT group_concat(fromList) FROM 27264cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler * (SELECT fromList FROM message WHERE mailboxKey=? AND flagRead=0 27274cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler * GROUP BY fromList ORDER BY timestamp DESC) 27284cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler */ 27294cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler .add(UIProvider.FolderColumns.UNREAD_SENDERS, 27304cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler "(SELECT group_concat(" + MessageColumns.FROM_LIST + ") FROM " + 27314cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler "(SELECT " + MessageColumns.FROM_LIST + " FROM " + Message.TABLE_NAME + 27324cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler " WHERE " + MessageColumns.MAILBOX_KEY + "=" + Mailbox.TABLE_NAME + "." + 27333dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler MailboxColumns._ID + " AND " + MessageColumns.FLAG_READ + "=0" + 27344cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler " GROUP BY " + MessageColumns.FROM_LIST + " ORDER BY " + 27354cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler MessageColumns.TIMESTAMP + " DESC))") 2736e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .build(); 2737e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank } 2738e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank return sFolderListMap; 2739e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank } 2740e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank private static ProjectionMap sFolderListMap; 2741e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank 27424b09765a2e8a0fd22a9db0e876aaaada4246aff8Vikram Aggarwal /** 27434b09765a2e8a0fd22a9db0e876aaaada4246aff8Vikram Aggarwal * Constructs the map of default entries for accounts. These values can be overridden in 27444b09765a2e8a0fd22a9db0e876aaaada4246aff8Vikram Aggarwal * {@link #genQueryAccount(String[], String)}. 27454b09765a2e8a0fd22a9db0e876aaaada4246aff8Vikram Aggarwal */ 27465a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook private static ProjectionMap getAccountListMap(Context context) { 2747e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank if (sAccountListMap == null) { 27485a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook final ProjectionMap.Builder builder = ProjectionMap.builder() 27493dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(BaseColumns._ID, AccountColumns._ID) 27505a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.FOLDER_LIST_URI, uriWithId("uifolders")) 275196192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler .add(UIProvider.AccountColumns.FULL_FOLDER_LIST_URI, uriWithId("uifullfolders")) 275296192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler .add(UIProvider.AccountColumns.ALL_FOLDER_LIST_URI, uriWithId("uiallfolders")) 27535a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.NAME, AccountColumns.DISPLAY_NAME) 27547349fbff64328100cb5bd878f4d400ccc611ec80Tony Mantler .add(UIProvider.AccountColumns.ACCOUNT_MANAGER_NAME, 27557349fbff64328100cb5bd878f4d400ccc611ec80Tony Mantler AccountColumns.EMAIL_ADDRESS) 2756045aa05777a097717c1a915e66eb9ab671e02d56Ray Chen .add(UIProvider.AccountColumns.ACCOUNT_ID, 2757045aa05777a097717c1a915e66eb9ab671e02d56Ray Chen AccountColumns.EMAIL_ADDRESS) 2758632ee24d48f308c855ddec8f013b674e5ade67e2Tony Mantler .add(UIProvider.AccountColumns.SENDER_NAME, 2759632ee24d48f308c855ddec8f013b674e5ade67e2Tony Mantler AccountColumns.SENDER_NAME) 27605a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.UNDO_URI, 2761d0e7d88f43bcd7d612a880f3525ef40dbe8f461aYu Ping Hu ("'content://" + EmailContent.AUTHORITY + "/uiundo'")) 27625a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.URI, uriWithId("uiaccount")) 27635a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.SEARCH_URI, uriWithId("uisearch")) 27645a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook // TODO: Is provider version used? 27655a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.PROVIDER_VERSION, "1") 27665a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.SYNC_STATUS, "0") 27675a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.RECENT_FOLDER_LIST_URI, 27685a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook uriWithId("uirecentfolders")) 27695a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.DEFAULT_RECENT_FOLDER_LIST_URI, 27705a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook uriWithId("uidefaultrecentfolders")) 27715a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.SettingsColumns.SIGNATURE, 27725a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook AccountColumns.SIGNATURE) 27735a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.SettingsColumns.SNAP_HEADERS, 27745a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook Integer.toString(UIProvider.SnapHeaderValue.ALWAYS)) 27755a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.SettingsColumns.CONFIRM_ARCHIVE, "0") 27765a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.SettingsColumns.CONVERSATION_VIEW_MODE, 27775a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook Integer.toString(UIProvider.ConversationViewMode.UNDEFINED)) 27785a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.SettingsColumns.VEILED_ADDRESS_PATTERN, null); 27795a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook 27805a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook final String feedbackUri = context.getString(R.string.email_feedback_uri); 27815a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook if (!TextUtils.isEmpty(feedbackUri)) { 2782dbb8b75a4bd201f8472a511ef77ca2ed05bd808bPaul Westbrook // This string needs to be in single quotes, as it will be used as a constant 2783dbb8b75a4bd201f8472a511ef77ca2ed05bd808bPaul Westbrook // in a sql expression 2784dbb8b75a4bd201f8472a511ef77ca2ed05bd808bPaul Westbrook builder.add(UIProvider.AccountColumns.SEND_FEEDBACK_INTENT_URI, 2785dbb8b75a4bd201f8472a511ef77ca2ed05bd808bPaul Westbrook "'" + feedbackUri + "'"); 27865a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook } 27875a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook 278831ce5555b8b277a05e4af01c57cb078be3049409James Lemieux final String helpUri = context.getString(R.string.help_uri); 278931ce5555b8b277a05e4af01c57cb078be3049409James Lemieux if (!TextUtils.isEmpty(helpUri)) { 279031ce5555b8b277a05e4af01c57cb078be3049409James Lemieux // This string needs to be in single quotes, as it will be used as a constant 279131ce5555b8b277a05e4af01c57cb078be3049409James Lemieux // in a sql expression 279231ce5555b8b277a05e4af01c57cb078be3049409James Lemieux builder.add(UIProvider.AccountColumns.HELP_INTENT_URI, 279331ce5555b8b277a05e4af01c57cb078be3049409James Lemieux "'" + helpUri + "'"); 279431ce5555b8b277a05e4af01c57cb078be3049409James Lemieux } 279531ce5555b8b277a05e4af01c57cb078be3049409James Lemieux 27965a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook sAccountListMap = builder.build(); 2797e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank } 2798e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank return sAccountListMap; 2799e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank } 2800e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank private static ProjectionMap sAccountListMap; 2801f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2802c6953b77552d4cb71776cf0537dc226029381628Tony Mantler private static ProjectionMap getQuickResponseMap() { 2803c6953b77552d4cb71776cf0537dc226029381628Tony Mantler if (sQuickResponseMap == null) { 2804c6953b77552d4cb71776cf0537dc226029381628Tony Mantler sQuickResponseMap = ProjectionMap.builder() 28053dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.QuickResponseColumns.TEXT, QuickResponseColumns.TEXT) 2806c6953b77552d4cb71776cf0537dc226029381628Tony Mantler .add(UIProvider.QuickResponseColumns.URI, 2807c6953b77552d4cb71776cf0537dc226029381628Tony Mantler "'" + combinedUriString("quickresponse", "") + "'||" 28083dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + QuickResponseColumns._ID) 2809c6953b77552d4cb71776cf0537dc226029381628Tony Mantler .build(); 2810c6953b77552d4cb71776cf0537dc226029381628Tony Mantler } 2811c6953b77552d4cb71776cf0537dc226029381628Tony Mantler return sQuickResponseMap; 2812c6953b77552d4cb71776cf0537dc226029381628Tony Mantler } 2813c6953b77552d4cb71776cf0537dc226029381628Tony Mantler private static ProjectionMap sQuickResponseMap; 2814c6953b77552d4cb71776cf0537dc226029381628Tony Mantler 2815f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2816f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * The "ORDER BY" clause for top level folders 2817f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2818f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String MAILBOX_ORDER_BY = "CASE " + MailboxColumns.TYPE 2819f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_INBOX + " THEN 0" 2820f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_DRAFTS + " THEN 1" 2821f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_OUTBOX + " THEN 2" 2822f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_SENT + " THEN 3" 2823f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_TRASH + " THEN 4" 2824f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_JUNK + " THEN 5" 2825f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Other mailboxes (i.e. of Mailbox.TYPE_MAIL) are shown in alphabetical order. 2826f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " ELSE 10 END" 2827f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " ," + MailboxColumns.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; 2828f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2829f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2830f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Mapping of UIProvider columns to EmailProvider columns for a message's attachments 2831f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2832b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static ProjectionMap getAttachmentMap() { 2833e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank if (sAttachmentMap == null) { 2834e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank sAttachmentMap = ProjectionMap.builder() 2835e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.AttachmentColumns.NAME, AttachmentColumns.FILENAME) 2836e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.AttachmentColumns.SIZE, AttachmentColumns.SIZE) 2837e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.AttachmentColumns.URI, uriWithId("uiattachment")) 2838e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.AttachmentColumns.CONTENT_TYPE, AttachmentColumns.MIME_TYPE) 2839e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.AttachmentColumns.STATE, AttachmentColumns.UI_STATE) 2840e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.AttachmentColumns.DESTINATION, AttachmentColumns.UI_DESTINATION) 2841e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.AttachmentColumns.DOWNLOADED_SIZE, 2842e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank AttachmentColumns.UI_DOWNLOADED_SIZE) 2843e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.AttachmentColumns.CONTENT_URI, AttachmentColumns.CONTENT_URI) 2844aad690f699f61793facecc950d3d060baa62fd45Martin Hibdon .add(UIProvider.AttachmentColumns.FLAGS, AttachmentColumns.FLAGS) 2845e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .build(); 2846e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank } 2847e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank return sAttachmentMap; 2848e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank } 2849e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank private static ProjectionMap sAttachmentMap; 2850f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2851f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2852f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate the SELECT clause using a specified mapping and the original UI projection 2853f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param map the ProjectionMap to use for this projection 2854f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param projection the projection as sent by UnifiedEmail 2855f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return a StringBuilder containing the SELECT expression for a SQLite query 2856f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2857b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static StringBuilder genSelect(ProjectionMap map, String[] projection) { 2858f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return genSelect(map, projection, EMPTY_CONTENT_VALUES); 2859f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 2860f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2861b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static StringBuilder genSelect(ProjectionMap map, String[] projection, 2862b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy ContentValues values) { 2863582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler final StringBuilder sb = new StringBuilder("SELECT "); 2864f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank boolean first = true; 2865582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler for (final String column: projection) { 2866f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (first) { 2867f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank first = false; 2868f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 2869f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank sb.append(','); 2870f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 2871582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler final String val; 2872f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // First look at values; this is an override of default behavior 2873f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (values.containsKey(column)) { 2874582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler final String value = values.getAsString(column); 2875296d18c02b4397c320a273cc94c234620e13b3fdMarc Blank if (value == null) { 2876df9c1f3aa54792cc65f95ddff8e36a34a9dcdda1Marc Blank val = "NULL AS " + column; 2877296d18c02b4397c320a273cc94c234620e13b3fdMarc Blank } else if (value.startsWith("@")) { 2878f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank val = value.substring(1) + " AS " + column; 2879f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 28804db2d1cf74640d6560e739627f245198819568a0Tony Mantler val = DatabaseUtils.sqlEscapeString(value) + " AS " + column; 2881f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 2882f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 2883f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Now, get the standard value for the column from our projection map 2884582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler final String mapVal = map.get(column); 2885f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // If we don't have the column, return "NULL AS <column>", and warn 2886582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler if (mapVal == null) { 2887f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank val = "NULL AS " + column; 28882fb5d2f9dd6a243065602a2970e9f698b0d09190Tony Mantler // Apparently there's a lot of these, so don't spam the log with warnings 28892fb5d2f9dd6a243065602a2970e9f698b0d09190Tony Mantler // LogUtils.w(TAG, "column " + column + " missing from projection map"); 2890582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler } else { 2891582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler val = mapVal; 2892f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 2893f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 2894f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank sb.append(val); 2895f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 2896f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return sb; 2897f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 2898f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2899f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2900f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Convenience method to create a Uri string given the "type" of query; we append the type 2901f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * of the query and the id column name (_id) 2902f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 2903f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param type the "type" of the query, as defined by our UriMatcher definitions 2904f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return a Uri string 2905f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2906f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static String uriWithId(String type) { 29073dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler return uriWithColumn(type, BaseColumns._ID); 2908f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 2909f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2910f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2911f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Convenience method to create a Uri string given the "type" of query; we append the type 2912f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * of the query and the passed in column name 2913f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 2914f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param type the "type" of the query, as defined by our UriMatcher definitions 2915f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param columnName the column in the table being queried 2916f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return a Uri string 2917f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2918f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static String uriWithColumn(String type, String columnName) { 2919f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return "'content://" + EmailContent.AUTHORITY + "/" + type + "/' || " + columnName; 2920f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 2921f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2922f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2923f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Convenience method to create a Uri string given the "type" of query and the table name to 2924f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * which it applies; we append the type of the query and the fully qualified (FQ) id column 2925f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * (i.e. including the table name); we need this for join queries where _id would otherwise 2926f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * be ambiguous 2927f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 2928f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param type the "type" of the query, as defined by our UriMatcher definitions 2929f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param tableName the name of the table whose _id is referred to 2930f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return a Uri string 2931f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2932f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static String uriWithFQId(String type, String tableName) { 2933f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return "'content://" + EmailContent.AUTHORITY + "/" + type + "/' || " + tableName + "._id"; 2934f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 2935f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2936f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Regex that matches start of img tag. '<(?i)img\s+'. 2937f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final Pattern IMG_TAG_START_REGEX = Pattern.compile("<(?i)img\\s+"); 2938f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2939f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 29407c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank * Class that holds the sqlite query and the attachment (JSON) value (which might be null) 29417c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank */ 29427c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank private static class MessageQuery { 29437c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank final String query; 29447c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank final String attachmentJson; 29457c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank 29467c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank MessageQuery(String _query, String _attachmentJson) { 29477c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank query = _query; 29487c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank attachmentJson = _attachmentJson; 29497c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank } 29507c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank } 29517c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank 29527c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank /** 2953f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate the "view message" SQLite query, given a projection from UnifiedEmail 2954f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 2955f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 2956f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 2957f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 29587c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank private MessageQuery genQueryViewMessage(String[] uiProjection, String id) { 2959f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Context context = getContext(); 2960f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank long messageId = Long.parseLong(id); 2961f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Message msg = Message.restoreMessageWithId(context, messageId); 2962f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ContentValues values = new ContentValues(); 29637c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank String attachmentJson = null; 2964f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (msg != null) { 2965f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Body body = Body.restoreBodyWithMessageId(context, messageId); 2966f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (body != null) { 2967f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (body.mHtmlContent != null) { 2968f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (IMG_TAG_START_REGEX.matcher(body.mHtmlContent).find()) { 2969f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(UIProvider.MessageColumns.EMBEDS_EXTERNAL_RESOURCES, 1); 2970f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 2971f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 2972f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 29731fa303478c61e0d703011996e358037eef523176James Lemieux Address[] fromList = Address.fromHeader(msg.mFrom); 2974f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank int autoShowImages = 0; 297538f22dbf08664b885b4cf063ea665c02edfb1c32Paul Westbrook final MailPrefs mailPrefs = MailPrefs.get(context); 2976f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank for (Address sender : fromList) { 297738f22dbf08664b885b4cf063ea665c02edfb1c32Paul Westbrook final String email = sender.getAddress(); 297838f22dbf08664b885b4cf063ea665c02edfb1c32Paul Westbrook if (mailPrefs.getDisplayImagesFromSender(email)) { 2979f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank autoShowImages = 1; 2980f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 2981f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 2982f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 2983f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(UIProvider.MessageColumns.ALWAYS_SHOW_IMAGES, autoShowImages); 2984f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Add attachments... 2985f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Attachment[] atts = Attachment.restoreAttachmentsWithMessageId(context, messageId); 2986f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (atts.length > 0) { 2987f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ArrayList<com.android.mail.providers.Attachment> uiAtts = 2988f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank new ArrayList<com.android.mail.providers.Attachment>(); 2989f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank for (Attachment att : atts) { 2990fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // TODO: This code is intended to strip out any inlined attachments (which 2991fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // would have a non-null contentId) so that they will not display at the bottom 2992fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // along with the non-inlined attachments. 2993fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // The problem is that the UI_ATTACHMENTS query does not behave the same way, 2994fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // which causes crazy formatting. 2995fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // There is an open question here, should attachments that are inlined 2996fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // ALSO appear in the list of attachments at the bottom with the non-inlined 2997fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // attachments? 2998fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // Either way, the two queries need to behave the same way. 2999fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // As of now, they will. If we decide to stop this, then we need to enable 3000fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // the code below, and then also make the UI_ATTACHMENTS query behave 3001fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // the same way. 3002fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon// 3003fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon// if (att.mContentId != null && att.getContentUri() != null) { 3004fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon// continue; 3005fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon// } 3006f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank com.android.mail.providers.Attachment uiAtt = 3007f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank new com.android.mail.providers.Attachment(); 3008ea2edb637036a7368b6ef82a0aafdb1a790e26e9Mark Wei uiAtt.setName(att.mFileName); 3009ea2edb637036a7368b6ef82a0aafdb1a790e26e9Mark Wei uiAtt.setContentType(att.mMimeType); 3010f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank uiAtt.size = (int) att.mSize; 3011f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank uiAtt.uri = uiUri("uiattachment", att.mId); 3012aad690f699f61793facecc950d3d060baa62fd45Martin Hibdon uiAtt.flags = att.mFlags; 3013f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank uiAtts.add(uiAtt); 3014f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 30157c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank values.put(UIProvider.MessageColumns.ATTACHMENTS, "@?"); // @ for literal 30167c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank attachmentJson = com.android.mail.providers.Attachment.toJSONArray(uiAtts); 3017f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3018f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (msg.mDraftInfo != 0) { 3019f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(UIProvider.MessageColumns.APPEND_REF_MESSAGE_CONTENT, 3020f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank (msg.mDraftInfo & Message.DRAFT_INFO_APPEND_REF_MESSAGE) != 0 ? 1 : 0); 3021f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(UIProvider.MessageColumns.QUOTE_START_POS, 3022f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.mDraftInfo & Message.DRAFT_INFO_QUOTE_POS_MASK); 3023f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3024949fc3d88338861dec8eac29fffaef5b17ae07e8Marc Blank if ((msg.mFlags & Message.FLAG_INCOMING_MEETING_INVITE) != 0) { 3025949fc3d88338861dec8eac29fffaef5b17ae07e8Marc Blank values.put(UIProvider.MessageColumns.EVENT_INTENT_URI, 3026949fc3d88338861dec8eac29fffaef5b17ae07e8Marc Blank "content://ui.email2.android.com/event/" + msg.mId); 3027949fc3d88338861dec8eac29fffaef5b17ae07e8Marc Blank } 302862604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler /** 302962604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler * HACK: override the attachment uri to contain a query parameter 303062604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler * This forces the message footer to reload the attachment display when the message is 303162604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler * fully loaded. 303262604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler */ 303362604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler final Uri attachmentListUri = uiUri("uiattachments", messageId).buildUpon() 303462604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler .appendQueryParameter("MessageLoaded", 303562604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler msg.mFlagLoaded == Message.FLAG_LOADED_COMPLETE ? "true" : "false") 303662604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler .build(); 303762604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler values.put(UIProvider.MessageColumns.ATTACHMENT_LIST_URI, attachmentListUri.toString()); 3038f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3039e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank StringBuilder sb = genSelect(getMessageViewMap(), uiProjection, values); 30403dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler sb.append(" FROM " + Message.TABLE_NAME + " LEFT JOIN " + Body.TABLE_NAME + 30413dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler " ON " + BodyColumns.MESSAGE_KEY + "=" + Message.TABLE_NAME + "." + 30423dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler MessageColumns._ID + 30433dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler " WHERE " + Message.TABLE_NAME + "." + MessageColumns._ID + "=?"); 30447c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank String sql = sb.toString(); 30457c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank return new MessageQuery(sql, attachmentJson); 3046f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3047f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 30480203a06c87e389f0d3af19bc26f61d0cf846226aScott Kennedy private static void appendConversationInfoColumns(final StringBuilder stringBuilder) { 30490203a06c87e389f0d3af19bc26f61d0cf846226aScott Kennedy // TODO(skennedy) These columns are needed for the respond call for ConversationInfo :( 30500203a06c87e389f0d3af19bc26f61d0cf846226aScott Kennedy // There may be a better way to do this, but since the projection is specified by the 30510203a06c87e389f0d3af19bc26f61d0cf846226aScott Kennedy // unified UI code, it can't ask for these columns. 30520203a06c87e389f0d3af19bc26f61d0cf846226aScott Kennedy stringBuilder.append(',').append(MessageColumns.DISPLAY_NAME) 30536f4a9eb8767884a64c3e8498f6f8ce515357a993James Lemieux .append(',').append(MessageColumns.FROM_LIST) 30546f4a9eb8767884a64c3e8498f6f8ce515357a993James Lemieux .append(',').append(MessageColumns.TO_LIST); 30550203a06c87e389f0d3af19bc26f61d0cf846226aScott Kennedy } 30560203a06c87e389f0d3af19bc26f61d0cf846226aScott Kennedy 3057f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3058f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate the "message list" SQLite query, given a projection from UnifiedEmail 3059f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3060f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 3061b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy * @param unseenOnly <code>true</code> to only return unseen messages 3062f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 3063f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3064b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static String genQueryMailboxMessages(String[] uiProjection, final boolean unseenOnly) { 3065e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank StringBuilder sb = genSelect(getMessageListMap(), uiProjection); 30660203a06c87e389f0d3af19bc26f61d0cf846226aScott Kennedy appendConversationInfoColumns(sb); 3067de4c230f008ca0615b8035a560cd512624ac2cdbYu Ping Hu sb.append(" FROM " + Message.TABLE_NAME + " WHERE " + 30686dd7bd29e97e7190b01bf6325d131f24c097b560Paul Westbrook Message.FLAG_LOADED_SELECTION + " AND " + 30693dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler MessageColumns.MAILBOX_KEY + "=? "); 3070b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy if (unseenOnly) { 3071b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy sb.append("AND ").append(MessageColumns.FLAG_SEEN).append(" = 0 "); 3072d4a06f409d08a61bd387ab2e2f37eca519f10010Tony Mantler sb.append("AND ").append(MessageColumns.FLAG_READ).append(" = 0 "); 3073b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy } 3074c1d56928b2185e6a2643eea271a1fbd50e425ca2Paul Westbrook sb.append("ORDER BY " + MessageColumns.TIMESTAMP + " DESC "); 3075e31fe0d47bf9e2a4e1de7b2aa518c0b08828d7d8Tony Mantler sb.append("LIMIT " + UIProvider.CONVERSATION_PROJECTION_QUERY_CURSOR_WINDOW_LIMIT); 3076f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return sb.toString(); 3077f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3078f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3079f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3080f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate various virtual mailbox SQLite queries, given a projection from UnifiedEmail 3081f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3082f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 3083b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy * @param mailboxId the id of the virtual mailbox 3084b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy * @param unseenOnly <code>true</code> to only return unseen messages 3085f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 3086f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3087b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static Cursor getVirtualMailboxMessagesCursor(SQLiteDatabase db, String[] uiProjection, 3088b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy long mailboxId, final boolean unseenOnly) { 3089f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ContentValues values = new ContentValues(); 3090f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(UIProvider.ConversationColumns.COLOR, CONVERSATION_COLOR); 3091c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu final int virtualMailboxId = getVirtualMailboxType(mailboxId); 3092c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu final String[] selectionArgs; 3093e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank StringBuilder sb = genSelect(getMessageListMap(), uiProjection, values); 30940203a06c87e389f0d3af19bc26f61d0cf846226aScott Kennedy appendConversationInfoColumns(sb); 3095de4c230f008ca0615b8035a560cd512624ac2cdbYu Ping Hu sb.append(" FROM " + Message.TABLE_NAME + " WHERE " + 30966dd7bd29e97e7190b01bf6325d131f24c097b560Paul Westbrook Message.FLAG_LOADED_SELECTION + " AND "); 3097f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (isCombinedMailbox(mailboxId)) { 3098c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu if (unseenOnly) { 3099c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu sb.append(MessageColumns.FLAG_SEEN).append("=0 AND "); 3100d4a06f409d08a61bd387ab2e2f37eca519f10010Tony Mantler sb.append(MessageColumns.FLAG_READ).append("=0 AND "); 3101f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3102c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu selectionArgs = null; 3103f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 3104c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu if (virtualMailboxId == Mailbox.TYPE_INBOX) { 3105c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu throw new IllegalArgumentException("No virtual mailbox for: " + mailboxId); 3106f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3107c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu sb.append(MessageColumns.ACCOUNT_KEY).append("=? AND "); 3108c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu selectionArgs = new String[]{getVirtualMailboxAccountIdString(mailboxId)}; 3109c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu } 3110c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu switch (getVirtualMailboxType(mailboxId)) { 3111c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu case Mailbox.TYPE_INBOX: 31123dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler sb.append(MessageColumns.MAILBOX_KEY + " IN (SELECT " + MailboxColumns._ID + 3113c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu " FROM " + Mailbox.TABLE_NAME + " WHERE " + MailboxColumns.TYPE + 3114c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu "=" + Mailbox.TYPE_INBOX + ")"); 3115c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu break; 3116c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu case Mailbox.TYPE_STARRED: 3117c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu sb.append(MessageColumns.FLAG_FAVORITE + "=1"); 3118c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu break; 3119cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case Mailbox.TYPE_UNREAD: 3120c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu sb.append(MessageColumns.FLAG_READ + "=0 AND " + MessageColumns.MAILBOX_KEY + 31213dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler " NOT IN (SELECT " + MailboxColumns._ID + " FROM " + Mailbox.TABLE_NAME + 3122c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu " WHERE " + MailboxColumns.TYPE + "=" + Mailbox.TYPE_TRASH + ")"); 3123c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu break; 3124c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu default: 3125c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu throw new IllegalArgumentException("No virtual mailbox for: " + mailboxId); 3126f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3127c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu sb.append(" ORDER BY " + MessageColumns.TIMESTAMP + " DESC"); 3128c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu return db.rawQuery(sb.toString(), selectionArgs); 3129f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3130f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3131f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3132f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate the "message list" SQLite query, given a projection from UnifiedEmail 3133f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3134f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 3135f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 3136f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3137b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static String genQueryConversation(String[] uiProjection) { 3138e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank StringBuilder sb = genSelect(getMessageListMap(), uiProjection); 31393dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler sb.append(" FROM " + Message.TABLE_NAME + " WHERE " + MessageColumns._ID + "=?"); 3140f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return sb.toString(); 3141f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3142f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3143f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3144f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate the "top level folder list" SQLite query, given a projection from UnifiedEmail 3145f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3146f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 3147f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 3148f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3149b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static String genQueryAccountMailboxes(String[] uiProjection) { 3150e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank StringBuilder sb = genSelect(getFolderListMap(), uiProjection); 3151f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank sb.append(" FROM " + Mailbox.TABLE_NAME + " WHERE " + MailboxColumns.ACCOUNT_KEY + 3152f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "=? AND " + MailboxColumns.TYPE + " < " + Mailbox.TYPE_NOT_EMAIL + 3153555bd3c0b7132509421ae181fbdb35995819787cPaul Westbrook " AND " + MailboxColumns.TYPE + " != " + Mailbox.TYPE_SEARCH + 3154f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " AND " + MailboxColumns.PARENT_KEY + " < 0 ORDER BY "); 3155f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank sb.append(MAILBOX_ORDER_BY); 3156f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return sb.toString(); 3157f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3158f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3159f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3160f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate the "all folders" SQLite query, given a projection from UnifiedEmail. The list is 3161f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * sorted by the name as it appears in a hierarchical listing 3162f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3163f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 3164f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 3165f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3166b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static String genQueryAccountAllMailboxes(String[] uiProjection) { 3167e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank StringBuilder sb = genSelect(getFolderListMap(), uiProjection); 3168f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Use a derived column to choose either hierarchicalName or displayName 3169f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank sb.append(", case when " + MailboxColumns.HIERARCHICAL_NAME + " is null then " + 3170f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank MailboxColumns.DISPLAY_NAME + " else " + MailboxColumns.HIERARCHICAL_NAME + 3171f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " end as h_name"); 3172f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Order by the derived column 3173f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank sb.append(" FROM " + Mailbox.TABLE_NAME + " WHERE " + MailboxColumns.ACCOUNT_KEY + 3174f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "=? AND " + MailboxColumns.TYPE + " < " + Mailbox.TYPE_NOT_EMAIL + 3175555bd3c0b7132509421ae181fbdb35995819787cPaul Westbrook " AND " + MailboxColumns.TYPE + " != " + Mailbox.TYPE_SEARCH + 3176f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " ORDER BY h_name"); 3177f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return sb.toString(); 3178f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3179f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3180f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3181f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate the "recent folder list" SQLite query, given a projection from UnifiedEmail 3182f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3183f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 3184f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 3185f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3186b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static String genQueryRecentMailboxes(String[] uiProjection) { 3187e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank StringBuilder sb = genSelect(getFolderListMap(), uiProjection); 3188f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank sb.append(" FROM " + Mailbox.TABLE_NAME + " WHERE " + MailboxColumns.ACCOUNT_KEY + 3189f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "=? AND " + MailboxColumns.TYPE + " < " + Mailbox.TYPE_NOT_EMAIL + 3190555bd3c0b7132509421ae181fbdb35995819787cPaul Westbrook " AND " + MailboxColumns.TYPE + " != " + Mailbox.TYPE_SEARCH + 3191f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " AND " + MailboxColumns.PARENT_KEY + " < 0 AND " + 3192f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank MailboxColumns.LAST_TOUCHED_TIME + " > 0 ORDER BY " + 3193f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank MailboxColumns.LAST_TOUCHED_TIME + " DESC"); 3194f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return sb.toString(); 3195f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3196f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3197469c4263760373c1bc330251910ec28005051aa8James Lemieux private int getFolderCapabilities(EmailServiceInfo info, int mailboxType, long mailboxId) { 31981004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Special case for Search folders: only permit delete, do not try to give any other caps. 3199469c4263760373c1bc330251910ec28005051aa8James Lemieux if (mailboxType == Mailbox.TYPE_SEARCH) { 32001004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu return UIProvider.FolderCapabilities.DELETE; 32011004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } 32021004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu 32036edccbf1f1371157cfa6e503d8353a474aafd2a1Yu Ping Hu // All folders support delete, except drafts. 32046edccbf1f1371157cfa6e503d8353a474aafd2a1Yu Ping Hu int caps = 0; 3205469c4263760373c1bc330251910ec28005051aa8James Lemieux if (mailboxType != Mailbox.TYPE_DRAFTS) { 32066edccbf1f1371157cfa6e503d8353a474aafd2a1Yu Ping Hu caps = UIProvider.FolderCapabilities.DELETE; 32076edccbf1f1371157cfa6e503d8353a474aafd2a1Yu Ping Hu } 32085ac8d38796952a817f4693b38d62fc124651c121Marc Blank if (info != null && info.offerLookback) { 32095ac8d38796952a817f4693b38d62fc124651c121Marc Blank // Protocols supporting lookback support settings 32105ac8d38796952a817f4693b38d62fc124651c121Marc Blank caps |= UIProvider.FolderCapabilities.SUPPORTS_SETTINGS; 32115ac8d38796952a817f4693b38d62fc124651c121Marc Blank } 32121004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu 3213469c4263760373c1bc330251910ec28005051aa8James Lemieux if (mailboxType == Mailbox.TYPE_MAIL || mailboxType == Mailbox.TYPE_TRASH || 3214469c4263760373c1bc330251910ec28005051aa8James Lemieux mailboxType == Mailbox.TYPE_JUNK || mailboxType == Mailbox.TYPE_INBOX) { 32155ed8b266a480ea413264abdb5042c58b29175df8Paul Westbrook // If the mailbox can accept moved mail, report that as well 32165ed8b266a480ea413264abdb5042c58b29175df8Paul Westbrook caps |= UIProvider.FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES; 32175ed8b266a480ea413264abdb5042c58b29175df8Paul Westbrook caps |= UIProvider.FolderCapabilities.ALLOWS_REMOVE_CONVERSATION; 32185ed8b266a480ea413264abdb5042c58b29175df8Paul Westbrook } 32195ed8b266a480ea413264abdb5042c58b29175df8Paul Westbrook 32205ac8d38796952a817f4693b38d62fc124651c121Marc Blank // For trash, we don't allow undo 3221469c4263760373c1bc330251910ec28005051aa8James Lemieux if (mailboxType == Mailbox.TYPE_TRASH) { 32225ac8d38796952a817f4693b38d62fc124651c121Marc Blank caps = UIProvider.FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES | 322353836e572eb4b402140a02da949f3e3d0ca146edAndrew Sapperstein UIProvider.FolderCapabilities.ALLOWS_REMOVE_CONVERSATION | 32245ac8d38796952a817f4693b38d62fc124651c121Marc Blank UIProvider.FolderCapabilities.DELETE | 32255ac8d38796952a817f4693b38d62fc124651c121Marc Blank UIProvider.FolderCapabilities.DELETE_ACTION_FINAL; 32265ac8d38796952a817f4693b38d62fc124651c121Marc Blank } 32275ac8d38796952a817f4693b38d62fc124651c121Marc Blank if (isVirtualMailbox(mailboxId)) { 32285ac8d38796952a817f4693b38d62fc124651c121Marc Blank caps |= UIProvider.FolderCapabilities.IS_VIRTUAL; 32295ac8d38796952a817f4693b38d62fc124651c121Marc Blank } 3230ae46818a1925cc22fe20ee26ffee8779561a903bAlon Albert 32316953d5951fed975d2569ec46bd544ce21e6860dcTony Mantler // If we don't know the protocol or the protocol doesn't support it, don't allow moving 32326953d5951fed975d2569ec46bd544ce21e6860dcTony Mantler // messages 32336953d5951fed975d2569ec46bd544ce21e6860dcTony Mantler if (info == null || !info.offerMoveTo) { 3234ae46818a1925cc22fe20ee26ffee8779561a903bAlon Albert caps &= ~UIProvider.FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES & 3235ae46818a1925cc22fe20ee26ffee8779561a903bAlon Albert ~UIProvider.FolderCapabilities.ALLOWS_REMOVE_CONVERSATION & 3236ae46818a1925cc22fe20ee26ffee8779561a903bAlon Albert ~UIProvider.FolderCapabilities.ALLOWS_MOVE_TO_INBOX; 3237ae46818a1925cc22fe20ee26ffee8779561a903bAlon Albert } 3238469c4263760373c1bc330251910ec28005051aa8James Lemieux 3239469c4263760373c1bc330251910ec28005051aa8James Lemieux // If the mailbox stores outgoing mail, show recipients instead of senders 3240469c4263760373c1bc330251910ec28005051aa8James Lemieux // (however the Drafts folder shows neither senders nor recipients... just the word "Draft") 3241469c4263760373c1bc330251910ec28005051aa8James Lemieux if (mailboxType == Mailbox.TYPE_OUTBOX || mailboxType == Mailbox.TYPE_SENT) { 3242469c4263760373c1bc330251910ec28005051aa8James Lemieux caps |= UIProvider.FolderCapabilities.SHOW_RECIPIENTS; 3243469c4263760373c1bc330251910ec28005051aa8James Lemieux } 3244469c4263760373c1bc330251910ec28005051aa8James Lemieux 32455ac8d38796952a817f4693b38d62fc124651c121Marc Blank return caps; 32465ac8d38796952a817f4693b38d62fc124651c121Marc Blank } 32475ac8d38796952a817f4693b38d62fc124651c121Marc Blank 3248f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3249f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate a "single mailbox" SQLite query, given a projection from UnifiedEmail 3250f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3251f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 3252f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 3253f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3254f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private String genQueryMailbox(String[] uiProjection, String id) { 3255f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank long mailboxId = Long.parseLong(id); 32565d47ee0f87208ab22c317abc87f615b6254cc852Tony Mantler ContentValues values = new ContentValues(3); 3257f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mSearchParams != null && mailboxId == mSearchParams.mSearchMailboxId) { 3258f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // "load more" is valid for search results 3259f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(UIProvider.FolderColumns.LOAD_MORE_URI, 3260f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank uiUriString("uiloadmore", mailboxId)); 32613767da5d26c7138a6c3a293fd4b2b685f71f016fPaul Westbrook values.put(UIProvider.FolderColumns.CAPABILITIES, UIProvider.FolderCapabilities.DELETE); 3262f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 3263f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Context context = getContext(); 3264f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Mailbox mailbox = Mailbox.restoreMailboxWithId(context, mailboxId); 3265f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Make sure we can't get NPE if mailbox has disappeared (the result will end up moot) 3266f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mailbox != null) { 3267f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank String protocol = Account.getProtocol(context, mailbox.mAccountKey); 3268f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank EmailServiceInfo info = EmailServiceUtils.getServiceInfo(context, protocol); 3269285cef8ad0af4727b53a7b79e709c0ecb5f40d4fMarc Blank // All folders support delete 3270b82ae909d7514bf06090ee3a120aef2154ab0296Marc Blank if (info != null && info.offerLoadMore) { 3271285cef8ad0af4727b53a7b79e709c0ecb5f40d4fMarc Blank // "load more" is valid for protocols not supporting "lookback" 3272f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(UIProvider.FolderColumns.LOAD_MORE_URI, 3273f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank uiUriString("uiloadmore", mailboxId)); 3274cc986cf3d75dd80f59e41b829bb41c369f973d7dMarc Blank } 32755ac8d38796952a817f4693b38d62fc124651c121Marc Blank values.put(UIProvider.FolderColumns.CAPABILITIES, 32761004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu getFolderCapabilities(info, mailbox.mType, mailboxId)); 32779b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu // The persistent id is used to form a filename, so we must ensure that it doesn't 32789b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu // include illegal characters (such as '/'). Only perform the encoding if this 32799b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu // query wants the persistent id. 32809b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu boolean shouldEncodePersistentId = false; 32819b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu if (uiProjection == null) { 32829b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu shouldEncodePersistentId = true; 32839b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu } else { 32849b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu for (final String column : uiProjection) { 32859b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu if (TextUtils.equals(column, UIProvider.FolderColumns.PERSISTENT_ID)) { 32869b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu shouldEncodePersistentId = true; 32879b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu break; 32889b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu } 32899b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu } 32909b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu } 32919b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu if (shouldEncodePersistentId) { 32929b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu values.put(UIProvider.FolderColumns.PERSISTENT_ID, 32939b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu Base64.encodeToString(mailbox.mServerId.getBytes(), 32949b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING)); 32959b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu } 32965ac8d38796952a817f4693b38d62fc124651c121Marc Blank } 3297f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3298e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank StringBuilder sb = genSelect(getFolderListMap(), uiProjection, values); 32993dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler sb.append(" FROM " + Mailbox.TABLE_NAME + " WHERE " + MailboxColumns._ID + "=?"); 3300f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return sb.toString(); 3301f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3302f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3303391a7fc0e99457308b6f6bd9444c8aba94b0b7b1Paul Westbrook public static final String LEGACY_AUTHORITY = "ui.email.android.com"; 3304391a7fc0e99457308b6f6bd9444c8aba94b0b7b1Paul Westbrook private static final Uri BASE_EXTERNAL_URI = Uri.parse("content://" + LEGACY_AUTHORITY); 3305f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3306f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final Uri BASE_EXTERAL_URI2 = Uri.parse("content://ui.email2.android.com"); 3307f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3308f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static String getExternalUriString(String segment, String account) { 3309f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return BASE_EXTERNAL_URI.buildUpon().appendPath(segment) 3310f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank .appendQueryParameter("account", account).build().toString(); 3311f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3312f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3313f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static String getExternalUriStringEmail2(String segment, String account) { 3314f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return BASE_EXTERAL_URI2.buildUpon().appendPath(segment) 3315f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank .appendQueryParameter("account", account).build().toString(); 3316f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3317f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3318b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static String getBits(int bitField) { 3319983c78e92899b94b237c292968c1be2bf53c5d57Marc Blank StringBuilder sb = new StringBuilder(" "); 3320983c78e92899b94b237c292968c1be2bf53c5d57Marc Blank for (int i = 0; i < 32; i++, bitField >>= 1) { 3321983c78e92899b94b237c292968c1be2bf53c5d57Marc Blank if ((bitField & 1) != 0) { 3322582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler sb.append(i) 3323582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(" "); 3324983c78e92899b94b237c292968c1be2bf53c5d57Marc Blank } 3325983c78e92899b94b237c292968c1be2bf53c5d57Marc Blank } 3326983c78e92899b94b237c292968c1be2bf53c5d57Marc Blank return sb.toString(); 3327983c78e92899b94b237c292968c1be2bf53c5d57Marc Blank } 3328983c78e92899b94b237c292968c1be2bf53c5d57Marc Blank 33299e521deb6bb525b33365cc2926cb2d0faa7095e2Scott Kennedy private static int getCapabilities(Context context, long accountId) { 3330a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu final Account account = Account.restoreAccountWithId(context, accountId); 3331a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu if (account == null) { 3332a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu LogUtils.d(TAG, "Account %d not found during getCapabilities", accountId); 3333a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu return 0; 3334a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu } 3335a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu // Account capabilities are based on protocol -- different protocols (and, for EAS, 3336a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu // different protocol versions) support different feature sets. 3337a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu final String protocol = account.getProtocol(context); 3338a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu int capabilities; 3339a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu if (TextUtils.equals(context.getString(R.string.protocol_imap), protocol) || 3340a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu TextUtils.equals(context.getString(R.string.protocol_legacy_imap), protocol)) { 3341a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu capabilities = AccountCapabilities.SYNCABLE_FOLDERS | 334219882289991e10ba6f2f8a08d03a4b7193b6437dJames Lemieux AccountCapabilities.SERVER_SEARCH | 3343a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.FOLDER_SERVER_SEARCH | 3344a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.UNDO | 3345a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.DISCARD_CONVERSATION_DRAFTS; 3346a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu } else if (TextUtils.equals(context.getString(R.string.protocol_pop3), protocol)) { 3347a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu capabilities = AccountCapabilities.UNDO | 3348a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.DISCARD_CONVERSATION_DRAFTS; 3349a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu } else if (TextUtils.equals(context.getString(R.string.protocol_eas), protocol)) { 3350a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu final String easVersion = account.mProtocolVersion; 3351a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu double easVersionDouble = 2.5D; 3352a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu if (easVersion != null) { 3353a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu try { 3354a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu easVersionDouble = Double.parseDouble(easVersion); 3355a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu } catch (final NumberFormatException e) { 3356a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu // Use the default (lowest) set of capabilities. 3357a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu } 3358983c78e92899b94b237c292968c1be2bf53c5d57Marc Blank } 3359a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu if (easVersionDouble >= 12.0D) { 3360a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu capabilities = AccountCapabilities.SYNCABLE_FOLDERS | 3361a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.SERVER_SEARCH | 3362a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.FOLDER_SERVER_SEARCH | 3363a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.SMART_REPLY | 3364a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.UNDO | 3365a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.DISCARD_CONVERSATION_DRAFTS; 3366a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu } else { 3367a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu capabilities = AccountCapabilities.SYNCABLE_FOLDERS | 3368a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.SMART_REPLY | 3369a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.UNDO | 3370a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.DISCARD_CONVERSATION_DRAFTS; 3371a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu } 3372a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu } else { 3373a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu LogUtils.w(TAG, "Unknown protocol for account %d", accountId); 3374a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu return 0; 33750b5f15d61ebf7c0e8428100637bc479ed93a4cb2Marc Blank } 3376a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu LogUtils.d(TAG, "getCapabilities() for %d (protocol %s): 0x%x %s", accountId, protocol, 3377a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu capabilities, getBits(capabilities)); 33785a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook 33795a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook // If the configuration states that feedback is supported, add that capability 33805a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook final Resources res = context.getResources(); 33815a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook if (res.getBoolean(R.bool.feedback_supported)) { 3382e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler capabilities |= AccountCapabilities.SEND_FEEDBACK; 33835a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook } 338431ce5555b8b277a05e4af01c57cb078be3049409James Lemieux 338531ce5555b8b277a05e4af01c57cb078be3049409James Lemieux // If we can find a help URL then add the Help capability 338631ce5555b8b277a05e4af01c57cb078be3049409James Lemieux if (!TextUtils.isEmpty(context.getResources().getString(R.string.help_uri))) { 3387e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler capabilities |= AccountCapabilities.HELP_CONTENT; 338831ce5555b8b277a05e4af01c57cb078be3049409James Lemieux } 338931ce5555b8b277a05e4af01c57cb078be3049409James Lemieux 3390e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler capabilities |= AccountCapabilities.EMPTY_TRASH; 3391e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler 3392a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu // TODO: Should this be stored per-account, or some other mechanism? 3393e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler capabilities |= AccountCapabilities.NESTED_FOLDERS; 3394fc5aae98e7a440ef9ab015efd4934123c2c15e76Scott Kennedy 3395837aba39d513ffcf42c73b35c6e0edf78d1a0c97James Lemieux // sanitization happens lazily in the EmailMessageCursor as HTML email bodies are requested 3396837aba39d513ffcf42c73b35c6e0edf78d1a0c97James Lemieux capabilities |= UIProvider.AccountCapabilities.SANITIZED_HTML; 3397837aba39d513ffcf42c73b35c6e0edf78d1a0c97James Lemieux 33980b5f15d61ebf7c0e8428100637bc479ed93a4cb2Marc Blank return capabilities; 33990b5f15d61ebf7c0e8428100637bc479ed93a4cb2Marc Blank } 34000b5f15d61ebf7c0e8428100637bc479ed93a4cb2Marc Blank 3401f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3402f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate a "single account" SQLite query, given a projection from UnifiedEmail 3403f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3404f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 3405c6953b77552d4cb71776cf0537dc226029381628Tony Mantler * @param id account row ID 3406f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 3407f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3408f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private String genQueryAccount(String[] uiProjection, String id) { 340951693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook final ContentValues values = new ContentValues(); 341051693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook final long accountId = Long.parseLong(id); 34110b5f15d61ebf7c0e8428100637bc479ed93a4cb2Marc Blank final Context context = getContext(); 3412f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 34139e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu EmailServiceInfo info = null; 34149e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu 3415e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy // TODO: If uiProjection is null, this will NPE. We should do everything here if it's null. 341651693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook final Set<String> projectionColumns = ImmutableSet.copyOf(uiProjection); 341751693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook 341851693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains(UIProvider.AccountColumns.CAPABILITIES)) { 341951693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook // Get account capabilities from the service 34200b5f15d61ebf7c0e8428100637bc479ed93a4cb2Marc Blank values.put(UIProvider.AccountColumns.CAPABILITIES, getCapabilities(context, accountId)); 342151693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 342251693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains(UIProvider.AccountColumns.SETTINGS_INTENT_URI)) { 342351693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook values.put(UIProvider.AccountColumns.SETTINGS_INTENT_URI, 342451693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook getExternalUriString("settings", id)); 342551693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 342651693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains(UIProvider.AccountColumns.COMPOSE_URI)) { 342751693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook values.put(UIProvider.AccountColumns.COMPOSE_URI, 342851693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook getExternalUriStringEmail2("compose", id)); 342951693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 34300dffe3afd7a2fdfb394573aa0d8d06dd90e9fe12James Lemieux if (projectionColumns.contains(UIProvider.AccountColumns.REAUTHENTICATION_INTENT_URI)) { 34310dffe3afd7a2fdfb394573aa0d8d06dd90e9fe12James Lemieux values.put(UIProvider.AccountColumns.REAUTHENTICATION_INTENT_URI, 34328c03e2af9f439c6e0c6abb38b0c371da7ccdb72aTony Mantler HeadlessAccountSettingsLoader.getIncomingSettingsUri(accountId) 34338c03e2af9f439c6e0c6abb38b0c371da7ccdb72aTony Mantler .toString()); 34340dffe3afd7a2fdfb394573aa0d8d06dd90e9fe12James Lemieux } 343551693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains(UIProvider.AccountColumns.MIME_TYPE)) { 343651693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook values.put(UIProvider.AccountColumns.MIME_TYPE, EMAIL_APP_MIME_TYPE); 343751693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 343851693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains(UIProvider.AccountColumns.COLOR)) { 343951693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook values.put(UIProvider.AccountColumns.COLOR, ACCOUNT_COLOR); 344051693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 344151693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook 3442988ad6e002810d5da713f0cda20aecf00cccb9caTony Mantler // TODO: if we're getting the values out of MailPrefs then we don't need to be passing the 3443988ad6e002810d5da713f0cda20aecf00cccb9caTony Mantler // values this way 34442f9c66d08b13c1ed4eb7d2f70baa98116ac5fcfbScott Kennedy final MailPrefs mailPrefs = MailPrefs.get(getContext()); 344551693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains(UIProvider.AccountColumns.SettingsColumns.CONFIRM_DELETE)) { 344651693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook values.put(UIProvider.AccountColumns.SettingsColumns.CONFIRM_DELETE, 3447988ad6e002810d5da713f0cda20aecf00cccb9caTony Mantler mailPrefs.getConfirmDelete() ? "1" : "0"); 344851693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 344951693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains(UIProvider.AccountColumns.SettingsColumns.CONFIRM_SEND)) { 345051693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook values.put(UIProvider.AccountColumns.SettingsColumns.CONFIRM_SEND, 3451988ad6e002810d5da713f0cda20aecf00cccb9caTony Mantler mailPrefs.getConfirmSend() ? "1" : "0"); 345251693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 3453b225298b13eb47c6251d73c28506b0a7ad56bf5cMarc Blank if (projectionColumns.contains(UIProvider.AccountColumns.SettingsColumns.SWIPE)) { 3454b225298b13eb47c6251d73c28506b0a7ad56bf5cMarc Blank values.put(UIProvider.AccountColumns.SettingsColumns.SWIPE, 3455643846abbd1ae60454fc8191992afffd08114e98Scott Kennedy mailPrefs.getConversationListSwipeActionInteger(false)); 3456b225298b13eb47c6251d73c28506b0a7ad56bf5cMarc Blank } 345751693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains( 34589f1cff0659e4b9a179690d9c31f7a9bf56aad228Alice Yang UIProvider.AccountColumns.SettingsColumns.CONV_LIST_ICON)) { 34599f1cff0659e4b9a179690d9c31f7a9bf56aad228Alice Yang values.put(UIProvider.AccountColumns.SettingsColumns.CONV_LIST_ICON, 3460ccf730fbe53c3bffb0154d0666e9fcbb5e82f551Paul Westbrook getConversationListIcon(mailPrefs)); 346151693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 346251693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains(UIProvider.AccountColumns.SettingsColumns.AUTO_ADVANCE)) { 346351693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook values.put(UIProvider.AccountColumns.SettingsColumns.AUTO_ADVANCE, 3464988ad6e002810d5da713f0cda20aecf00cccb9caTony Mantler Integer.toString(mailPrefs.getAutoAdvanceMode())); 346551693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 3466b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy // Set default inbox, if we've got an inbox; otherwise, say initial sync needed 34671079b6e9628910e726881233f62808976d5d3be1Scott Kennedy final long inboxMailboxId = 34681079b6e9628910e726881233f62808976d5d3be1Scott Kennedy Mailbox.findMailboxOfType(context, accountId, Mailbox.TYPE_INBOX); 346951693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains(UIProvider.AccountColumns.SettingsColumns.DEFAULT_INBOX) && 34701079b6e9628910e726881233f62808976d5d3be1Scott Kennedy inboxMailboxId != Mailbox.NO_MAILBOX) { 3471f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(UIProvider.AccountColumns.SettingsColumns.DEFAULT_INBOX, 34721079b6e9628910e726881233f62808976d5d3be1Scott Kennedy uiUriString("uifolder", inboxMailboxId)); 34730d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler } else { 34740d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler values.put(UIProvider.AccountColumns.SettingsColumns.DEFAULT_INBOX, 34750d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler uiUriString("uiinbox", accountId)); 347651693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 347751693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains( 347851693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook UIProvider.AccountColumns.SettingsColumns.DEFAULT_INBOX_NAME) && 34791079b6e9628910e726881233f62808976d5d3be1Scott Kennedy inboxMailboxId != Mailbox.NO_MAILBOX) { 3480a0fef46aea16c1783f681bb0053eeb3f53d975abVikram Aggarwal values.put(UIProvider.AccountColumns.SettingsColumns.DEFAULT_INBOX_NAME, 34811079b6e9628910e726881233f62808976d5d3be1Scott Kennedy Mailbox.getDisplayName(context, inboxMailboxId)); 348251693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 348351693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains(UIProvider.AccountColumns.SYNC_STATUS)) { 34841079b6e9628910e726881233f62808976d5d3be1Scott Kennedy if (inboxMailboxId != Mailbox.NO_MAILBOX) { 348551693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook values.put(UIProvider.AccountColumns.SYNC_STATUS, UIProvider.SyncStatus.NO_SYNC); 348651693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } else { 348751693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook values.put(UIProvider.AccountColumns.SYNC_STATUS, 348851693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook UIProvider.SyncStatus.INITIAL_SYNC_NEEDED); 348951693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 3490f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3491b7e0834121d564982c0389c87df775ba311429d4Tony Mantler if (projectionColumns.contains(UIProvider.AccountColumns.UPDATE_SETTINGS_URI)) { 3492b7e0834121d564982c0389c87df775ba311429d4Tony Mantler values.put(UIProvider.AccountColumns.UPDATE_SETTINGS_URI, 3493b7e0834121d564982c0389c87df775ba311429d4Tony Mantler uiUriString("uiacctsettings", -1)); 3494b7e0834121d564982c0389c87df775ba311429d4Tony Mantler } 3495837aba39d513ffcf42c73b35c6e0edf78d1a0c97James Lemieux if (projectionColumns.contains(UIProvider.AccountColumns.ENABLE_MESSAGE_TRANSFORMS)) { 3496837aba39d513ffcf42c73b35c6e0edf78d1a0c97James Lemieux // Email is now sanitized, which grants the ability to inject beautifying javascript. 3497837aba39d513ffcf42c73b35c6e0edf78d1a0c97James Lemieux values.put(UIProvider.AccountColumns.ENABLE_MESSAGE_TRANSFORMS, 1); 3498837aba39d513ffcf42c73b35c6e0edf78d1a0c97James Lemieux } 3499e0015b2800eeefbf8aaf322645038907f37e62f1Vikram Aggarwal if (projectionColumns.contains( 3500803631497c493dffbb65897d974c170008f1d096Andrew Sapperstein UIProvider.AccountColumns.SettingsColumns.IMPORTANCE_MARKERS_ENABLED)) { 3501803631497c493dffbb65897d974c170008f1d096Andrew Sapperstein // Email doesn't support priority inbox, so always state importance markers disabled. 3502803631497c493dffbb65897d974c170008f1d096Andrew Sapperstein values.put(UIProvider.AccountColumns.SettingsColumns.IMPORTANCE_MARKERS_ENABLED, "0"); 3503803631497c493dffbb65897d974c170008f1d096Andrew Sapperstein } 3504803631497c493dffbb65897d974c170008f1d096Andrew Sapperstein if (projectionColumns.contains( 3505803631497c493dffbb65897d974c170008f1d096Andrew Sapperstein UIProvider.AccountColumns.SettingsColumns.SHOW_CHEVRONS_ENABLED)) { 3506803631497c493dffbb65897d974c170008f1d096Andrew Sapperstein // Email doesn't support priority inbox, so always state show chevrons disabled. 3507803631497c493dffbb65897d974c170008f1d096Andrew Sapperstein values.put(UIProvider.AccountColumns.SettingsColumns.SHOW_CHEVRONS_ENABLED, "0"); 3508e0015b2800eeefbf8aaf322645038907f37e62f1Vikram Aggarwal } 350926164054710375519ba7468987971a7a3340ba7eMarc Blank if (projectionColumns.contains( 351026164054710375519ba7468987971a7a3340ba7eMarc Blank UIProvider.AccountColumns.SettingsColumns.SETUP_INTENT_URI)) { 351181b0f74efa39d80b0aa18686c96499faf0e2691fMarc Blank // Set the setup intent if needed 351281b0f74efa39d80b0aa18686c96499faf0e2691fMarc Blank // TODO We should clarify/document the trash/setup relationship 351326164054710375519ba7468987971a7a3340ba7eMarc Blank long trashId = Mailbox.findMailboxOfType(context, accountId, Mailbox.TYPE_TRASH); 351426164054710375519ba7468987971a7a3340ba7eMarc Blank if (trashId == Mailbox.NO_MAILBOX) { 35159e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu info = EmailServiceUtils.getServiceInfoForAccount(context, accountId); 351681b0f74efa39d80b0aa18686c96499faf0e2691fMarc Blank if (info != null && info.requiresSetup) { 3517fdb1635868e9591c3bcaf107360a7eae2e09fe18Marc Blank values.put(UIProvider.AccountColumns.SettingsColumns.SETUP_INTENT_URI, 3518fdb1635868e9591c3bcaf107360a7eae2e09fe18Marc Blank getExternalUriString("setup", id)); 3519fdb1635868e9591c3bcaf107360a7eae2e09fe18Marc Blank } 352026164054710375519ba7468987971a7a3340ba7eMarc Blank } 352126164054710375519ba7468987971a7a3340ba7eMarc Blank } 3522e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy if (projectionColumns.contains(UIProvider.AccountColumns.TYPE)) { 3523e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy final String type; 35249e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu if (info == null) { 35259e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu info = EmailServiceUtils.getServiceInfoForAccount(context, accountId); 35269e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu } 35279e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu if (info != null) { 35289e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu type = info.accountType; 3529e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy } else { 3530e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy type = "unknown"; 3531e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy } 3532e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy 3533e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy values.put(UIProvider.AccountColumns.TYPE, type); 3534e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy } 35351079b6e9628910e726881233f62808976d5d3be1Scott Kennedy if (projectionColumns.contains(UIProvider.AccountColumns.SettingsColumns.MOVE_TO_INBOX) && 35361079b6e9628910e726881233f62808976d5d3be1Scott Kennedy inboxMailboxId != Mailbox.NO_MAILBOX) { 35371079b6e9628910e726881233f62808976d5d3be1Scott Kennedy values.put(UIProvider.AccountColumns.SettingsColumns.MOVE_TO_INBOX, 35381079b6e9628910e726881233f62808976d5d3be1Scott Kennedy uiUriString("uifolder", inboxMailboxId)); 35391079b6e9628910e726881233f62808976d5d3be1Scott Kennedy } 3540f1284d4d550230a4e13247a9513f03a7f3fd2347Alice Yang if (projectionColumns.contains(UIProvider.AccountColumns.SYNC_AUTHORITY)) { 3541f1284d4d550230a4e13247a9513f03a7f3fd2347Alice Yang values.put(UIProvider.AccountColumns.SYNC_AUTHORITY, EmailContent.AUTHORITY); 3542f1284d4d550230a4e13247a9513f03a7f3fd2347Alice Yang } 3543c6953b77552d4cb71776cf0537dc226029381628Tony Mantler if (projectionColumns.contains(UIProvider.AccountColumns.QUICK_RESPONSE_URI)) { 3544c6953b77552d4cb71776cf0537dc226029381628Tony Mantler values.put(UIProvider.AccountColumns.QUICK_RESPONSE_URI, 3545c6953b77552d4cb71776cf0537dc226029381628Tony Mantler combinedUriString("quickresponse/account", id)); 3546c6953b77552d4cb71776cf0537dc226029381628Tony Mantler } 3547876c8e1408c119f6dd771fdf13a9b95ea62f704aTony Mantler if (projectionColumns.contains(UIProvider.AccountColumns.SETTINGS_FRAGMENT_CLASS)) { 3548876c8e1408c119f6dd771fdf13a9b95ea62f704aTony Mantler values.put(UIProvider.AccountColumns.SETTINGS_FRAGMENT_CLASS, 3549876c8e1408c119f6dd771fdf13a9b95ea62f704aTony Mantler AccountSettingsFragment.class.getName()); 3550876c8e1408c119f6dd771fdf13a9b95ea62f704aTony Mantler } 3551b424ffa65b809094e6b9109e2131b718ec9eae76Tony Mantler if (projectionColumns.contains(UIProvider.AccountColumns.SettingsColumns.REPLY_BEHAVIOR)) { 3552b424ffa65b809094e6b9109e2131b718ec9eae76Tony Mantler values.put(UIProvider.AccountColumns.SettingsColumns.REPLY_BEHAVIOR, 3553b424ffa65b809094e6b9109e2131b718ec9eae76Tony Mantler mailPrefs.getDefaultReplyAll() 3554b424ffa65b809094e6b9109e2131b718ec9eae76Tony Mantler ? UIProvider.DefaultReplyBehavior.REPLY_ALL 3555b424ffa65b809094e6b9109e2131b718ec9eae76Tony Mantler : UIProvider.DefaultReplyBehavior.REPLY); 3556b424ffa65b809094e6b9109e2131b718ec9eae76Tony Mantler } 355765b3850706c0fb5c7d575584186a1f3051ba82f1Tony Mantler if (projectionColumns.contains(UIProvider.AccountColumns.SettingsColumns.SHOW_IMAGES)) { 355865b3850706c0fb5c7d575584186a1f3051ba82f1Tony Mantler values.put(UIProvider.AccountColumns.SettingsColumns.SHOW_IMAGES, 355965b3850706c0fb5c7d575584186a1f3051ba82f1Tony Mantler Settings.ShowImages.ASK_FIRST); 356065b3850706c0fb5c7d575584186a1f3051ba82f1Tony Mantler } 3561e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy 35625a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook final StringBuilder sb = genSelect(getAccountListMap(getContext()), uiProjection, values); 35633dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler sb.append(" FROM " + Account.TABLE_NAME + " WHERE " + AccountColumns._ID + "=?"); 3564f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return sb.toString(); 3565f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3566f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3567f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3568f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate a Uri string for a combined mailbox uri 3569f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param type the uri command type (e.g. "uimessages") 3570f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param id the id of the item (e.g. an account, mailbox, or message id) 3571f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return a Uri string 3572f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3573f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static String combinedUriString(String type, String id) { 3574f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return "content://" + EmailContent.AUTHORITY + "/" + type + "/" + id; 3575f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3576f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 35773a82ad59928864931b826c46413831d7431057f9Mark Wei public static final long COMBINED_ACCOUNT_ID = 0x10000000; 3578f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3579f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3580f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate an id for a combined mailbox of a given type 3581f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param type the mailbox type for the combined mailbox 3582f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the id, as a String 3583f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3584f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static String combinedMailboxId(int type) { 3585f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return Long.toString(Account.ACCOUNT_ID_COMBINED_VIEW + type); 3586f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3587f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 35883a82ad59928864931b826c46413831d7431057f9Mark Wei public static long getVirtualMailboxId(long accountId, int type) { 3589f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return (accountId << 32) + type; 3590f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3591f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3592f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static boolean isVirtualMailbox(long mailboxId) { 3593f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return mailboxId >= 0x100000000L; 3594f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3595f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3596f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static boolean isCombinedMailbox(long mailboxId) { 3597f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return (mailboxId >> 32) == COMBINED_ACCOUNT_ID; 3598f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3599f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3600f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static long getVirtualMailboxAccountId(long mailboxId) { 3601f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return mailboxId >> 32; 3602f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3603f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3604f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static String getVirtualMailboxAccountIdString(long mailboxId) { 3605f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return Long.toString(mailboxId >> 32); 3606f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3607f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3608f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static int getVirtualMailboxType(long mailboxId) { 3609f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return (int)(mailboxId & 0xF); 3610f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3611f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3612f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private void addCombinedAccountRow(MatrixCursor mc) { 3613229c070b0b177793032ce9249cb77f6ca98e5aa4Scott Kennedy final long lastUsedAccountId = 3614229c070b0b177793032ce9249cb77f6ca98e5aa4Scott Kennedy Preferences.getPreferences(getContext()).getLastUsedAccountId(); 3615229c070b0b177793032ce9249cb77f6ca98e5aa4Scott Kennedy final long id = Account.getDefaultAccountId(getContext(), lastUsedAccountId); 3616f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (id == Account.NO_ACCOUNT) return; 3617b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook 3618b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook // Build a map of the requested columns to the appropriate positions 3619b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook final ImmutableMap.Builder<String, Integer> builder = 3620b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook new ImmutableMap.Builder<String, Integer>(); 3621b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook final String[] columnNames = mc.getColumnNames(); 3622b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook for (int i = 0; i < columnNames.length; i++) { 3623b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook builder.put(columnNames[i], i); 3624b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3625b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook final Map<String, Integer> colPosMap = builder.build(); 3626b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook 3627bed61a78a08f0a82c2aae12787ad64b4cd566c08Scott Kennedy final MailPrefs mailPrefs = MailPrefs.get(getContext()); 3628bed61a78a08f0a82c2aae12787ad64b4cd566c08Scott Kennedy 3629b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook final Object[] values = new Object[columnNames.length]; 3630b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(BaseColumns._ID)) { 3631b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(BaseColumns._ID)] = 0; 3632b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3633b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.CAPABILITIES)) { 3634b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.CAPABILITIES)] = 3635c2b1056a612bdd56080e0ef7f8927b69a6826113Tony Mantler AccountCapabilities.UNDO | AccountCapabilities.VIRTUAL_ACCOUNT; 3636b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3637b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.FOLDER_LIST_URI)) { 3638b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.FOLDER_LIST_URI)] = 3639b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook combinedUriString("uifolders", COMBINED_ACCOUNT_ID_STRING); 3640b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3641b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.NAME)) { 3642b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.NAME)] = getContext().getString( 36437349fbff64328100cb5bd878f4d400ccc611ec80Tony Mantler R.string.mailbox_list_account_selector_combined_view); 36447349fbff64328100cb5bd878f4d400ccc611ec80Tony Mantler } 36457349fbff64328100cb5bd878f4d400ccc611ec80Tony Mantler if (colPosMap.containsKey(UIProvider.AccountColumns.ACCOUNT_MANAGER_NAME)) { 36467349fbff64328100cb5bd878f4d400ccc611ec80Tony Mantler values[colPosMap.get(UIProvider.AccountColumns.ACCOUNT_MANAGER_NAME)] = 36477349fbff64328100cb5bd878f4d400ccc611ec80Tony Mantler getContext().getString(R.string.mailbox_list_account_selector_combined_view); 3648b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3649045aa05777a097717c1a915e66eb9ab671e02d56Ray Chen if (colPosMap.containsKey(UIProvider.AccountColumns.ACCOUNT_ID)) { 3650045aa05777a097717c1a915e66eb9ab671e02d56Ray Chen values[colPosMap.get(UIProvider.AccountColumns.ACCOUNT_ID)] = "Account Id"; 3651045aa05777a097717c1a915e66eb9ab671e02d56Ray Chen } 3652e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy if (colPosMap.containsKey(UIProvider.AccountColumns.TYPE)) { 3653e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy values[colPosMap.get(UIProvider.AccountColumns.TYPE)] = "unknown"; 3654e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy } 3655b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.UNDO_URI)) { 3656b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.UNDO_URI)] = 3657d0e7d88f43bcd7d612a880f3525ef40dbe8f461aYu Ping Hu "'content://" + EmailContent.AUTHORITY + "/uiundo'"; 3658b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3659b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.URI)) { 3660b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.URI)] = 3661b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook combinedUriString("uiaccount", COMBINED_ACCOUNT_ID_STRING); 3662b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3663b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.MIME_TYPE)) { 3664b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.MIME_TYPE)] = 3665b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook EMAIL_APP_MIME_TYPE; 3666b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3667b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.SETTINGS_INTENT_URI)) { 3668b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.SETTINGS_INTENT_URI)] = 3669b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook getExternalUriString("settings", COMBINED_ACCOUNT_ID_STRING); 3670b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3671b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.COMPOSE_URI)) { 3672b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.COMPOSE_URI)] = 3673b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook getExternalUriStringEmail2("compose", Long.toString(id)); 3674b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3675b7e0834121d564982c0389c87df775ba311429d4Tony Mantler if (colPosMap.containsKey(UIProvider.AccountColumns.UPDATE_SETTINGS_URI)) { 3676b7e0834121d564982c0389c87df775ba311429d4Tony Mantler values[colPosMap.get(UIProvider.AccountColumns.UPDATE_SETTINGS_URI)] = 3677b7e0834121d564982c0389c87df775ba311429d4Tony Mantler uiUriString("uiacctsettings", -1); 3678b7e0834121d564982c0389c87df775ba311429d4Tony Mantler } 3679f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3680b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.SettingsColumns.AUTO_ADVANCE)) { 3681b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.SettingsColumns.AUTO_ADVANCE)] = 3682988ad6e002810d5da713f0cda20aecf00cccb9caTony Mantler Integer.toString(mailPrefs.getAutoAdvanceMode()); 3683b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3684b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.SettingsColumns.SNAP_HEADERS)) { 3685b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.SettingsColumns.SNAP_HEADERS)] = 3686b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook Integer.toString(UIProvider.SnapHeaderValue.ALWAYS); 3687b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3688f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank //.add(UIProvider.SettingsColumns.SIGNATURE, AccountColumns.SIGNATURE) 3689b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.SettingsColumns.REPLY_BEHAVIOR)) { 3690b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.SettingsColumns.REPLY_BEHAVIOR)] = 3691bed61a78a08f0a82c2aae12787ad64b4cd566c08Scott Kennedy Integer.toString(mailPrefs.getDefaultReplyAll() 3692bed61a78a08f0a82c2aae12787ad64b4cd566c08Scott Kennedy ? UIProvider.DefaultReplyBehavior.REPLY_ALL 3693bed61a78a08f0a82c2aae12787ad64b4cd566c08Scott Kennedy : UIProvider.DefaultReplyBehavior.REPLY); 3694b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 36959f1cff0659e4b9a179690d9c31f7a9bf56aad228Alice Yang if (colPosMap.containsKey(UIProvider.AccountColumns.SettingsColumns.CONV_LIST_ICON)) { 36969f1cff0659e4b9a179690d9c31f7a9bf56aad228Alice Yang values[colPosMap.get(UIProvider.AccountColumns.SettingsColumns.CONV_LIST_ICON)] = 3697ccf730fbe53c3bffb0154d0666e9fcbb5e82f551Paul Westbrook getConversationListIcon(mailPrefs); 3698b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3699b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.SettingsColumns.CONFIRM_DELETE)) { 3700b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.SettingsColumns.CONFIRM_DELETE)] = 3701988ad6e002810d5da713f0cda20aecf00cccb9caTony Mantler mailPrefs.getConfirmDelete() ? 1 : 0; 3702b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3703b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.SettingsColumns.CONFIRM_ARCHIVE)) { 3704b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get( 3705b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook UIProvider.AccountColumns.SettingsColumns.CONFIRM_ARCHIVE)] = 0; 3706b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3707b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.SettingsColumns.CONFIRM_SEND)) { 3708b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.SettingsColumns.CONFIRM_SEND)] = 3709988ad6e002810d5da713f0cda20aecf00cccb9caTony Mantler mailPrefs.getConfirmSend() ? 1 : 0; 3710b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3711b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.SettingsColumns.DEFAULT_INBOX)) { 3712b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.SettingsColumns.DEFAULT_INBOX)] = 3713b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook combinedUriString("uifolder", combinedMailboxId(Mailbox.TYPE_INBOX)); 3714b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 37151079b6e9628910e726881233f62808976d5d3be1Scott Kennedy if (colPosMap.containsKey(UIProvider.AccountColumns.SettingsColumns.MOVE_TO_INBOX)) { 37161079b6e9628910e726881233f62808976d5d3be1Scott Kennedy values[colPosMap.get(UIProvider.AccountColumns.SettingsColumns.MOVE_TO_INBOX)] = 37171079b6e9628910e726881233f62808976d5d3be1Scott Kennedy combinedUriString("uifolder", combinedMailboxId(Mailbox.TYPE_INBOX)); 37181079b6e9628910e726881233f62808976d5d3be1Scott Kennedy } 371924a489c3de70a02bccbf2cfc54b36a385d72c337Alice Yang if (colPosMap.containsKey(UIProvider.AccountColumns.SettingsColumns.SHOW_IMAGES)) { 372024a489c3de70a02bccbf2cfc54b36a385d72c337Alice Yang values[colPosMap.get(UIProvider.AccountColumns.SettingsColumns.SHOW_IMAGES)] = 372124a489c3de70a02bccbf2cfc54b36a385d72c337Alice Yang Settings.ShowImages.ASK_FIRST; 372224a489c3de70a02bccbf2cfc54b36a385d72c337Alice Yang } 3723f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3724f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mc.addRow(values); 3725f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3726f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 37279e521deb6bb525b33365cc2926cb2d0faa7095e2Scott Kennedy private static int getConversationListIcon(MailPrefs mailPrefs) { 3728ccf730fbe53c3bffb0154d0666e9fcbb5e82f551Paul Westbrook return mailPrefs.getShowSenderImages() ? 3729ccf730fbe53c3bffb0154d0666e9fcbb5e82f551Paul Westbrook UIProvider.ConversationListIcon.SENDER_IMAGE : 3730ccf730fbe53c3bffb0154d0666e9fcbb5e82f551Paul Westbrook UIProvider.ConversationListIcon.NONE; 3731ccf730fbe53c3bffb0154d0666e9fcbb5e82f551Paul Westbrook } 3732ccf730fbe53c3bffb0154d0666e9fcbb5e82f551Paul Westbrook 3733e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler private Cursor getVirtualMailboxCursor(long mailboxId, String[] projection) { 3734e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler MatrixCursor mc = new MatrixCursorWithCachedColumns(projection, 1); 3735f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mc.addRow(getVirtualMailboxRow(getVirtualMailboxAccountId(mailboxId), 3736e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler getVirtualMailboxType(mailboxId), projection)); 3737f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return mc; 3738f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3739f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3740e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler private Object[] getVirtualMailboxRow(long accountId, int mailboxType, String[] projection) { 3741ddca2a0dcbcd27d2d17b5d5273eee2004fbcdf7cScott Kennedy final long id = getVirtualMailboxId(accountId, mailboxType); 3742ddca2a0dcbcd27d2d17b5d5273eee2004fbcdf7cScott Kennedy final String idString = Long.toString(id); 3743e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler Object[] values = new Object[projection.length]; 3744e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler // Not all column values are filled in here, as some are not applicable to virtual mailboxes 3745e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler // The remainder are left null 3746e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler for (int i = 0; i < projection.length; i++) { 3747e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler final String column = projection[i]; 3748e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler if (column.equals(UIProvider.FolderColumns._ID)) { 3749e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler values[i] = id; 3750e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else if (column.equals(UIProvider.FolderColumns.URI)) { 3751e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler values[i] = combinedUriString("uifolder", idString); 3752e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else if (column.equals(UIProvider.FolderColumns.NAME)) { 3753cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein // default empty string since all of these should use resource strings 3754e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler values[i] = getFolderDisplayName(getFolderTypeFromMailboxType(mailboxType), ""); 3755e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else if (column.equals(UIProvider.FolderColumns.HAS_CHILDREN)) { 3756e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler values[i] = 0; 3757e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else if (column.equals(UIProvider.FolderColumns.CAPABILITIES)) { 3758e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler values[i] = UIProvider.FolderCapabilities.DELETE 3759e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler | UIProvider.FolderCapabilities.IS_VIRTUAL; 3760e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else if (column.equals(UIProvider.FolderColumns.CONVERSATION_LIST_URI)) { 3761e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler values[i] = combinedUriString("uimessages", idString); 3762e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else if (column.equals(UIProvider.FolderColumns.UNREAD_COUNT)) { 3763e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler if (mailboxType == Mailbox.TYPE_INBOX && accountId == COMBINED_ACCOUNT_ID) { 3764ddca2a0dcbcd27d2d17b5d5273eee2004fbcdf7cScott Kennedy final int unreadCount = EmailContent.count(getContext(), Message.CONTENT_URI, 37653dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler MessageColumns.MAILBOX_KEY + " IN (SELECT " + MailboxColumns._ID 3766ddca2a0dcbcd27d2d17b5d5273eee2004fbcdf7cScott Kennedy + " FROM " + Mailbox.TABLE_NAME + " WHERE " + MailboxColumns.TYPE 3767ddca2a0dcbcd27d2d17b5d5273eee2004fbcdf7cScott Kennedy + "=" + Mailbox.TYPE_INBOX + ") AND " + MessageColumns.FLAG_READ + "=0", 3768ddca2a0dcbcd27d2d17b5d5273eee2004fbcdf7cScott Kennedy null); 3769e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler values[i] = unreadCount; 3770e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else if (mailboxType == Mailbox.TYPE_UNREAD) { 3771e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler final String accountKeyClause; 3772e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler final String[] whereArgs; 3773e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler if (accountId == COMBINED_ACCOUNT_ID) { 3774e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler accountKeyClause = ""; 3775e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler whereArgs = null; 3776e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else { 3777e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler accountKeyClause = MessageColumns.ACCOUNT_KEY + "= ? AND "; 3778e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler whereArgs = new String[] { Long.toString(accountId) }; 3779e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } 3780e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler final int unreadCount = EmailContent.count(getContext(), Message.CONTENT_URI, 3781e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler accountKeyClause + MessageColumns.FLAG_READ + "=0 AND " 37823dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + MessageColumns.MAILBOX_KEY + " NOT IN (SELECT " + MailboxColumns._ID 3783e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler + " FROM " + Mailbox.TABLE_NAME + " WHERE " + MailboxColumns.TYPE + "=" 3784e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler + Mailbox.TYPE_TRASH + ")", whereArgs); 3785e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler values[i] = unreadCount; 3786e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else if (mailboxType == Mailbox.TYPE_STARRED) { 3787e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler final String accountKeyClause; 3788e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler final String[] whereArgs; 3789e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler if (accountId == COMBINED_ACCOUNT_ID) { 3790e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler accountKeyClause = ""; 3791e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler whereArgs = null; 3792e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else { 3793e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler accountKeyClause = MessageColumns.ACCOUNT_KEY + "= ? AND "; 3794e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler whereArgs = new String[] { Long.toString(accountId) }; 3795e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } 3796e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler final int starredCount = EmailContent.count(getContext(), Message.CONTENT_URI, 3797e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler accountKeyClause + MessageColumns.FLAG_FAVORITE + "=1", whereArgs); 3798e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler values[i] = starredCount; 3799ddca2a0dcbcd27d2d17b5d5273eee2004fbcdf7cScott Kennedy } 3800e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else if (column.equals(UIProvider.FolderColumns.ICON_RES_ID)) { 3801e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler if (mailboxType == Mailbox.TYPE_INBOX) { 38024fb5412e1b3a4fad45eed90c7040b6ff0fe323b8Tony Mantler values[i] = R.drawable.ic_drawer_inbox; 3803e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else if (mailboxType == Mailbox.TYPE_UNREAD) { 38044fb5412e1b3a4fad45eed90c7040b6ff0fe323b8Tony Mantler values[i] = R.drawable.ic_drawer_unread; 3805e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else if (mailboxType == Mailbox.TYPE_STARRED) { 38064fb5412e1b3a4fad45eed90c7040b6ff0fe323b8Tony Mantler values[i] = R.drawable.ic_drawer_starred; 3807ddca2a0dcbcd27d2d17b5d5273eee2004fbcdf7cScott Kennedy } 3808ddca2a0dcbcd27d2d17b5d5273eee2004fbcdf7cScott Kennedy } 3809ddca2a0dcbcd27d2d17b5d5273eee2004fbcdf7cScott Kennedy } 3810f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return values; 3811f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3812f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 38134038f464dee0a33f1e7a58102857c24edf7e0eb2Paul Westbrook private Cursor uiAccounts(String[] uiProjection, boolean suppressCombined) { 38143e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook final Context context = getContext(); 38153e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook final SQLiteDatabase db = getDatabase(context); 38163e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook final Cursor accountIdCursor = 3817f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank db.rawQuery("select _id from " + Account.TABLE_NAME, new String[0]); 38183e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook final MatrixCursor mc; 3819f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank try { 38203e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook boolean combinedAccount = false; 38214038f464dee0a33f1e7a58102857c24edf7e0eb2Paul Westbrook if (!suppressCombined && accountIdCursor.getCount() > 1) { 38223e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook combinedAccount = true; 38233e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook } 38243e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook final Bundle extras = new Bundle(); 38253e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook // Email always returns the accurate number of accounts 38263e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook extras.putInt(AccountCursorExtraKeys.ACCOUNTS_LOADED, 1); 38273e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook mc = new MatrixCursorWithExtra(uiProjection, accountIdCursor.getCount(), extras); 38283e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook final Object[] values = new Object[uiProjection.length]; 3829f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank while (accountIdCursor.moveToNext()) { 38303e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook final String id = accountIdCursor.getString(0); 38313e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook final Cursor accountCursor = 3832f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank db.rawQuery(genQueryAccount(uiProjection, id), new String[] {id}); 38333e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook try { 38343e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook if (accountCursor.moveToNext()) { 38353e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook for (int i = 0; i < uiProjection.length; i++) { 38363e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook values[i] = accountCursor.getString(i); 38373e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook } 38383e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook mc.addRow(values); 3839f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 38403e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook } finally { 38413e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook accountCursor.close(); 3842f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3843f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 38442651bcc7be2c5fbce23faa0b0d12db63caee5a45Marc Blank if (combinedAccount) { 38452651bcc7be2c5fbce23faa0b0d12db63caee5a45Marc Blank addCombinedAccountRow(mc); 38462651bcc7be2c5fbce23faa0b0d12db63caee5a45Marc Blank } 3847f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } finally { 3848f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank accountIdCursor.close(); 3849f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 385097a198292e665fff5d27d727d415f35b0a0633e4Marc Blank mc.setNotificationUri(context.getContentResolver(), UIPROVIDER_ALL_ACCOUNTS_NOTIFIER); 38513e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook 3852f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return mc; 3853f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3854f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3855c6953b77552d4cb71776cf0537dc226029381628Tony Mantler private Cursor uiQuickResponseAccount(String[] uiProjection, String account) { 3856c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final Context context = getContext(); 3857c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final SQLiteDatabase db = getDatabase(context); 3858c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final StringBuilder sb = genSelect(getQuickResponseMap(), uiProjection); 3859c6953b77552d4cb71776cf0537dc226029381628Tony Mantler sb.append(" FROM " + QuickResponse.TABLE_NAME); 3860c6953b77552d4cb71776cf0537dc226029381628Tony Mantler sb.append(" WHERE " + QuickResponse.ACCOUNT_KEY + "=?"); 3861c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final String query = sb.toString(); 3862c6953b77552d4cb71776cf0537dc226029381628Tony Mantler return db.rawQuery(query, new String[] {account}); 3863c6953b77552d4cb71776cf0537dc226029381628Tony Mantler } 3864c6953b77552d4cb71776cf0537dc226029381628Tony Mantler 3865c6953b77552d4cb71776cf0537dc226029381628Tony Mantler private Cursor uiQuickResponseId(String[] uiProjection, String id) { 3866c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final Context context = getContext(); 3867c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final SQLiteDatabase db = getDatabase(context); 3868c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final StringBuilder sb = genSelect(getQuickResponseMap(), uiProjection); 3869c6953b77552d4cb71776cf0537dc226029381628Tony Mantler sb.append(" FROM " + QuickResponse.TABLE_NAME); 38703dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler sb.append(" WHERE " + QuickResponse._ID + "=?"); 3871c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final String query = sb.toString(); 3872c6953b77552d4cb71776cf0537dc226029381628Tony Mantler return db.rawQuery(query, new String[] {id}); 3873c6953b77552d4cb71776cf0537dc226029381628Tony Mantler } 3874c6953b77552d4cb71776cf0537dc226029381628Tony Mantler 3875c6953b77552d4cb71776cf0537dc226029381628Tony Mantler private Cursor uiQuickResponse(String[] uiProjection) { 3876c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final Context context = getContext(); 3877c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final SQLiteDatabase db = getDatabase(context); 3878c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final StringBuilder sb = genSelect(getQuickResponseMap(), uiProjection); 3879c6953b77552d4cb71776cf0537dc226029381628Tony Mantler sb.append(" FROM " + QuickResponse.TABLE_NAME); 3880c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final String query = sb.toString(); 3881c6953b77552d4cb71776cf0537dc226029381628Tony Mantler return db.rawQuery(query, new String[0]); 3882c6953b77552d4cb71776cf0537dc226029381628Tony Mantler } 3883c6953b77552d4cb71776cf0537dc226029381628Tony Mantler 3884f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3885f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate the "attachment list" SQLite query, given a projection from UnifiedEmail 3886f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3887f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 38886eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein * @param contentTypeQueryParameters list of mimeTypes, used as a filter for the attachments 38896eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein * or null if there are no query parameters 3890f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 3891f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3892b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static String genQueryAttachments(String[] uiProjection, 38936eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein List<String> contentTypeQueryParameters) { 3894478417a79440904b8a9c45fd3e4ec84db339a755Andrew Sapperstein // MAKE SURE THESE VALUES STAY IN SYNC WITH GEN QUERY ATTACHMENT 3895478417a79440904b8a9c45fd3e4ec84db339a755Andrew Sapperstein ContentValues values = new ContentValues(1); 3896478417a79440904b8a9c45fd3e4ec84db339a755Andrew Sapperstein values.put(UIProvider.AttachmentColumns.SUPPORTS_DOWNLOAD_AGAIN, 1); 3897478417a79440904b8a9c45fd3e4ec84db339a755Andrew Sapperstein StringBuilder sb = genSelect(getAttachmentMap(), uiProjection, values); 3898582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler sb.append(" FROM ") 3899582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(Attachment.TABLE_NAME) 3900582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(" WHERE ") 3901582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(AttachmentColumns.MESSAGE_KEY) 3902582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(" =? "); 39036eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein 39046eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein // Filter for certain content types. 39056eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein // The filter works by adding LIKE operators for each 39066eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein // content type you wish to request. Content types 39076eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein // are filtered by performing a case-insensitive "starts with" 39086eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein // filter. IE, "image/" would return "image/png" as well as "image/jpeg". 39096eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein if (contentTypeQueryParameters != null && !contentTypeQueryParameters.isEmpty()) { 39106eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein final int size = contentTypeQueryParameters.size(); 39116eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein sb.append("AND ("); 39126eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein for (int i = 0; i < size; i++) { 39136eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein final String contentType = contentTypeQueryParameters.get(i); 3914582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler sb.append(AttachmentColumns.MIME_TYPE) 3915582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(" LIKE '") 3916582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(contentType) 3917582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append("%'"); 39186eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein 39196eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein if (i != size - 1) { 39206eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein sb.append(" OR "); 39216eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein } 39226eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein } 39236eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein sb.append(")"); 39246eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein } 3925f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return sb.toString(); 3926f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3927f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3928f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3929f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate the "single attachment" SQLite query, given a projection from UnifiedEmail 3930f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3931f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 3932f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 3933f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 39348cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private String genQueryAttachment(String[] uiProjection) { 3935478417a79440904b8a9c45fd3e4ec84db339a755Andrew Sapperstein // MAKE SURE THESE VALUES STAY IN SYNC WITH GEN QUERY ATTACHMENTS 39368cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux final ContentValues values = new ContentValues(2); 39378cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux values.put(AttachmentColumns.CONTENT_URI, createAttachmentUriColumnSQL()); 3938478417a79440904b8a9c45fd3e4ec84db339a755Andrew Sapperstein values.put(UIProvider.AttachmentColumns.SUPPORTS_DOWNLOAD_AGAIN, 1); 39398cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux 39408cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux return genSelect(getAttachmentMap(), uiProjection, values) 39418cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux .append(" FROM ").append(Attachment.TABLE_NAME) 3942582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(" WHERE ") 39438cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux .append(AttachmentColumns._ID).append(" =? ") 39448cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux .toString(); 39458cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux } 39468cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux 39478cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux /** 39488cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux * Generate the "single attachment by Content ID" SQLite query, given a projection from 39498cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux * UnifiedEmail 39508cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux * 39518cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux * @param uiProjection as passed from UnifiedEmail 39528cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux * @return the SQLite query to be executed on the EmailProvider database 39538cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux */ 39548cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private String genQueryAttachmentByMessageIDAndCid(String[] uiProjection) { 39558cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux final ContentValues values = new ContentValues(2); 39568cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux values.put(AttachmentColumns.CONTENT_URI, createAttachmentUriColumnSQL()); 39578cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux values.put(UIProvider.AttachmentColumns.SUPPORTS_DOWNLOAD_AGAIN, 1); 39588cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux 39598cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux return genSelect(getAttachmentMap(), uiProjection, values) 39608cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux .append(" FROM ").append(Attachment.TABLE_NAME) 39618cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux .append(" WHERE ") 39628cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux .append(AttachmentColumns.MESSAGE_KEY).append(" =? ") 39638cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux .append(" AND ") 39648cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux .append(AttachmentColumns.CONTENT_ID).append(" =? ") 39658cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux .toString(); 39668cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux } 39678cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux 39688cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux /** 39698cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux * @return a fragment of SQL that is the expression which, when evaluated for a particular 39708cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux * Attachment row, produces the Content URI for the attachment 39718cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux */ 39728cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private static String createAttachmentUriColumnSQL() { 39738cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux final String uriPrefix = Attachment.ATTACHMENT_PROVIDER_URI_PREFIX; 39748cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux final String accountKey = AttachmentColumns.ACCOUNT_KEY; 39758cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux final String id = AttachmentColumns._ID; 39768cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux final String raw = AttachmentUtilities.FORMAT_RAW; 39778cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux final String contentUri = String.format("%s/' || %s || '/' || %s || '/%s", uriPrefix, 39788cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux accountKey, id, raw); 39798cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux 39808cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux return "@CASE " + 39818cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux "WHEN contentUri IS NULL THEN '" + contentUri + "' " + 39828cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux "WHEN contentUri IS NOT NULL THEN contentUri " + 39838cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux "END"; 3984f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3985f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3986f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3987f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate the "subfolder list" SQLite query, given a projection from UnifiedEmail 3988f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3989f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 3990f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 3991f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3992b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static String genQuerySubfolders(String[] uiProjection) { 3993e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank StringBuilder sb = genSelect(getFolderListMap(), uiProjection); 3994f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank sb.append(" FROM " + Mailbox.TABLE_NAME + " WHERE " + MailboxColumns.PARENT_KEY + 3995f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " =? ORDER BY "); 3996f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank sb.append(MAILBOX_ORDER_BY); 3997f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return sb.toString(); 3998f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3999f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4000f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String COMBINED_ACCOUNT_ID_STRING = Long.toString(COMBINED_ACCOUNT_ID); 4001f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4002f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 4003f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Returns a cursor over all the folders for a specific URI which corresponds to a single 4004f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * account. 4005582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler * @param uri uri to query 4006582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler * @param uiProjection projection 4007582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler * @return query result cursor 4008f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 400996192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler private Cursor uiFolders(final Uri uri, final String[] uiProjection) { 401096192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler final Context context = getContext(); 401196192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler final SQLiteDatabase db = getDatabase(context); 401296192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler final String id = uri.getPathSegments().get(1); 401396192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler 401496192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler final Uri notifyUri = 401596192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler UIPROVIDER_FOLDERLIST_NOTIFIER.buildUpon().appendEncodedPath(id).build(); 401696192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler 401796192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler final Cursor vc = uiVirtualMailboxes(id, uiProjection); 401896192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler vc.setNotificationUri(context.getContentResolver(), notifyUri); 4019f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (id.equals(COMBINED_ACCOUNT_ID_STRING)) { 402096192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler return vc; 4021f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 40221004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu Cursor c = db.rawQuery(genQueryAccountMailboxes(UIProvider.FOLDERS_PROJECTION), 40231004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu new String[] {id}); 40241004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu c = getFolderListCursor(c, Long.valueOf(id), uiProjection); 4025c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu c.setNotificationUri(context.getContentResolver(), notifyUri); 40260d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler if (c.getCount() > 0) { 40270d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler Cursor[] cursors = new Cursor[]{vc, c}; 40280d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler return new MergeCursor(cursors); 40290d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler } else { 40300d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler return c; 40310d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler } 4032f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4033f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4034f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 403596192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler private Cursor uiVirtualMailboxes(final String id, final String[] uiProjection) { 403696192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler final MatrixCursor mc = new MatrixCursorWithCachedColumns(uiProjection); 403796192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler 403896192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler if (id.equals(COMBINED_ACCOUNT_ID_STRING)) { 4039e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler mc.addRow(getVirtualMailboxRow(COMBINED_ACCOUNT_ID, Mailbox.TYPE_INBOX, uiProjection)); 4040e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler mc.addRow( 4041e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler getVirtualMailboxRow(COMBINED_ACCOUNT_ID, Mailbox.TYPE_STARRED, uiProjection)); 4042e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler mc.addRow(getVirtualMailboxRow(COMBINED_ACCOUNT_ID, Mailbox.TYPE_UNREAD, uiProjection)); 404396192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler } else { 404496192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler final long acctId = Long.parseLong(id); 4045e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler mc.addRow(getVirtualMailboxRow(acctId, Mailbox.TYPE_STARRED, uiProjection)); 4046e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler mc.addRow(getVirtualMailboxRow(acctId, Mailbox.TYPE_UNREAD, uiProjection)); 404796192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler } 404896192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler 404996192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler return mc; 405096192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler } 405196192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler 4052f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 4053f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Returns an array of the default recent folders for a given URI which is unique for an 4054f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * account. Some accounts might not have default recent folders, in which case an empty array 4055f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * is returned. 4056582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler * @param id account id 4057582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler * @return array of URIs 4058f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 4059f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private Uri[] defaultRecentFolders(final String id) { 40604524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee Uri[] recentFolders = new Uri[0]; 4061f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final SQLiteDatabase db = getDatabase(getContext()); 4062f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (id.equals(COMBINED_ACCOUNT_ID_STRING)) { 4063f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // We don't have default recents for the combined view. 40644524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee return recentFolders; 4065f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4066f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // We search for the types we want, and find corresponding IDs. 4067f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final String[] idAndType = { BaseColumns._ID, UIProvider.FolderColumns.TYPE }; 4068f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4069f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Sent, Drafts, and Starred are the default recents. 4070e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank final StringBuilder sb = genSelect(getFolderListMap(), idAndType); 4071582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler sb.append(" FROM ") 4072582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(Mailbox.TABLE_NAME) 4073582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(" WHERE ") 4074582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(MailboxColumns.ACCOUNT_KEY) 4075582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(" = ") 4076582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(id) 4077582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(" AND ") 4078582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(MailboxColumns.TYPE) 4079582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(" IN (") 4080582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(Mailbox.TYPE_SENT) 4081582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(", ") 4082582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(Mailbox.TYPE_DRAFTS) 4083582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(", ") 4084582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(Mailbox.TYPE_STARRED) 4085582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(")"); 4086f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank LogUtils.d(TAG, "defaultRecentFolders: Query is %s", sb); 4087f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final Cursor c = db.rawQuery(sb.toString(), null); 40884524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee try { 40894524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee if (c == null || c.getCount() <= 0 || !c.moveToFirst()) { 40904524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee return recentFolders; 40914524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee } 40924524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee // Read all the IDs of the mailboxes, and turn them into URIs. 40934524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee recentFolders = new Uri[c.getCount()]; 40944524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee int i = 0; 40954524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee do { 40964524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee final long folderId = c.getLong(0); 40974524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee recentFolders[i] = uiUri("uifolder", folderId); 40984524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee LogUtils.d(TAG, "Default recent folder: %d, with uri %s", folderId, 40994524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee recentFolders[i]); 41004524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee ++i; 41014524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee } while (c.moveToNext()); 41024524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee } finally { 41034524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee if (c != null) { 41044524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee c.close(); 41054524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee } 41064524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee } 4107f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return recentFolders; 4108f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4109f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4110f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 4111f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein * Convenience method to create a {@link Folder} 4112582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler * @param context to get a {@link ContentResolver} 4113f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein * @param mailboxId id of the {@link Mailbox} that we want 4114f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein * @return the {@link Folder} or null 4115f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein */ 4116f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein public static Folder getFolder(Context context, long mailboxId) { 4117f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein final ContentResolver resolver = context.getContentResolver(); 4118f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein final Cursor fc = resolver.query(EmailProvider.uiUri("uifolder", mailboxId), 4119f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein UIProvider.FOLDERS_PROJECTION, null, null, null); 4120f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein 4121f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein if (fc == null) { 4122f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein LogUtils.e(TAG, "Null folder cursor for mailboxId %d", mailboxId); 4123f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein return null; 4124f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein } 4125f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein 4126f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein Folder uiFolder = null; 4127f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein try { 4128f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein if (fc.moveToFirst()) { 4129f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein uiFolder = new Folder(fc); 4130f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein } 4131f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein } finally { 4132f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein fc.close(); 4133f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein } 4134f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein return uiFolder; 4135f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein } 4136f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein 4137114e314968f507b4237e693d279befe261b00f02Marc Blank static class AttachmentsCursor extends CursorWrapper { 4138114e314968f507b4237e693d279befe261b00f02Marc Blank private final int mContentUriIndex; 4139114e314968f507b4237e693d279befe261b00f02Marc Blank private final int mUriIndex; 4140114e314968f507b4237e693d279befe261b00f02Marc Blank private final Context mContext; 4141e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler private final String[] mContentUriStrings; 4142114e314968f507b4237e693d279befe261b00f02Marc Blank 4143114e314968f507b4237e693d279befe261b00f02Marc Blank public AttachmentsCursor(Context context, Cursor cursor) { 4144114e314968f507b4237e693d279befe261b00f02Marc Blank super(cursor); 4145114e314968f507b4237e693d279befe261b00f02Marc Blank mContentUriIndex = cursor.getColumnIndex(UIProvider.AttachmentColumns.CONTENT_URI); 4146114e314968f507b4237e693d279befe261b00f02Marc Blank mUriIndex = cursor.getColumnIndex(UIProvider.AttachmentColumns.URI); 4147114e314968f507b4237e693d279befe261b00f02Marc Blank mContext = context; 4148e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler mContentUriStrings = new String[cursor.getCount()]; 4149e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler if (mContentUriIndex == -1) { 4150e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler // Nothing to do here, move along 4151e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler return; 4152e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler } 4153e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler while (cursor.moveToNext()) { 4154e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler final int index = cursor.getPosition(); 415511472650d1fce7548939d311c4434128930c18baPaul Westbrook final Uri uri = Uri.parse(getString(mUriIndex)); 415611472650d1fce7548939d311c4434128930c18baPaul Westbrook final long id = Long.parseLong(uri.getLastPathSegment()); 415711472650d1fce7548939d311c4434128930c18baPaul Westbrook final Attachment att = Attachment.restoreAttachmentWithId(mContext, id); 4158e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler 4159e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler if (att == null) { 4160e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler mContentUriStrings[index] = ""; 4161e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler continue; 4162e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler } 4163e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler 4164f484751e060620ddf4e2dfe38f2b9f46f472ac9dMartin Hibdon if (!TextUtils.isEmpty(att.getCachedFileUri())) { 4165e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler mContentUriStrings[index] = att.getCachedFileUri(); 4166e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler continue; 4167f484751e060620ddf4e2dfe38f2b9f46f472ac9dMartin Hibdon } 416811472650d1fce7548939d311c4434128930c18baPaul Westbrook 416911472650d1fce7548939d311c4434128930c18baPaul Westbrook final String contentUri; 417011472650d1fce7548939d311c4434128930c18baPaul Westbrook // Until the package installer can handle opening apks from a content:// uri, for 417111472650d1fce7548939d311c4434128930c18baPaul Westbrook // any apk that was successfully saved in external storage, return the 417211472650d1fce7548939d311c4434128930c18baPaul Westbrook // content uri from the attachment 417311472650d1fce7548939d311c4434128930c18baPaul Westbrook if (att.mUiDestination == UIProvider.AttachmentDestination.EXTERNAL && 417411472650d1fce7548939d311c4434128930c18baPaul Westbrook att.mUiState == UIProvider.AttachmentState.SAVED && 417511472650d1fce7548939d311c4434128930c18baPaul Westbrook TextUtils.equals(att.mMimeType, MimeType.ANDROID_ARCHIVE)) { 417611472650d1fce7548939d311c4434128930c18baPaul Westbrook contentUri = att.getContentUri(); 417711472650d1fce7548939d311c4434128930c18baPaul Westbrook } else { 41782aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler final String attUriString = att.getContentUri(); 41792aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler final String authority; 41802aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler if (!TextUtils.isEmpty(attUriString)) { 41812aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler authority = Uri.parse(attUriString).getAuthority(); 41822aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler } else { 41832aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler authority = null; 41842aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler } 41852aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler if (TextUtils.equals(authority, Attachment.ATTACHMENT_PROVIDER_AUTHORITY)) { 41862aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler contentUri = attUriString; 41872aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler } else { 41882aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler contentUri = AttachmentUtilities.getAttachmentUri(att.mAccountKey, id) 41892aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler .toString(); 41902aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler } 419111472650d1fce7548939d311c4434128930c18baPaul Westbrook } 4192e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler mContentUriStrings[index] = contentUri; 4193f484751e060620ddf4e2dfe38f2b9f46f472ac9dMartin Hibdon 4194e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler } 4195e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler cursor.moveToPosition(-1); 4196e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler } 4197e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler 4198e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler @Override 4199e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler public String getString(int column) { 4200e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler if (column == mContentUriIndex) { 4201e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler return mContentUriStrings[getPosition()]; 4202114e314968f507b4237e693d279befe261b00f02Marc Blank } else { 4203114e314968f507b4237e693d279befe261b00f02Marc Blank return super.getString(column); 4204114e314968f507b4237e693d279befe261b00f02Marc Blank } 4205114e314968f507b4237e693d279befe261b00f02Marc Blank } 4206114e314968f507b4237e693d279befe261b00f02Marc Blank } 4207114e314968f507b4237e693d279befe261b00f02Marc Blank 4208f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 4209a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank * For debugging purposes; shouldn't be used in production code 4210a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank */ 4211582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler @SuppressWarnings("unused") 4212a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank static class CloseDetectingCursor extends CursorWrapper { 4213a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank 4214a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank public CloseDetectingCursor(Cursor cursor) { 4215a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank super(cursor); 4216a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank } 4217a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank 4218eaf7e3bce7a7f8f31c5677db188dec74072a43caMarc Blank @Override 4219a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank public void close() { 4220a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank super.close(); 4221560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.d(TAG, "Closing cursor", new Error()); 4222a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank } 4223a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank } 4224a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank 4225a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank /** 4226cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * Converts a mailbox in a row of the mailboxCursor into a row 4227cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * in the supplied {@link MatrixCursor} in the format required for {@link Folder}. 4228cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * As a convenience, the modified {@link MatrixCursor} is also returned. 4229cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * @param mc the {@link MatrixCursor} into which the mailbox data will be converted 4230cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * @param projectionLength the length of the projection for this Cursor 4231cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * @param mailboxCursor the cursor supplying the mailbox data 4232cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * @param nameColumn column in the cursor containing the folder name value 4233cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * @param typeColumn column in the cursor containing the folder type value 4234cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * @return the {@link MatrixCursor} containing the transformed data. 4235cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein */ 4236cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein private Cursor getUiFolderCursorRowFromMailboxCursorRow( 4237cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein MatrixCursor mc, int projectionLength, Cursor mailboxCursor, 4238cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein int nameColumn, int typeColumn) { 4239cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein final MatrixCursor.RowBuilder builder = mc.newRow(); 4240cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein for (int i = 0; i < projectionLength; i++) { 4241cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein // If we are at the name column, get the type 4242cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein // and use it to use a properly translated string 4243cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein // from resources instead of the display name. 4244cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein // This ignores display names for system mailboxes. 4245cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein if (nameColumn == i) { 4246cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein // We implicitly assume that if name is requested, 4247cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein // type has also been requested. If not, this will 4248cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein // error in unknown ways. 4249cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein final int type = mailboxCursor.getInt(typeColumn); 4250cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein builder.add(getFolderDisplayName(type, mailboxCursor.getString(i))); 4251cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein } else { 4252cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein builder.add(mailboxCursor.getString(i)); 4253cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein } 4254cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein } 4255cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return mc; 4256cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein } 4257cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein 4258cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein /** 42591004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * Takes a uifolder cursor (that was generated with a full projection) and remaps values for 42601004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * columns that are difficult to generate in the SQL query. This currently includes: 42611004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * - Folder name (due to system folder localization). 42621004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * - Capabilities (due to this varying by account protocol). 42631004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * - Persistent id (due to needing to base64 encode it). 42641004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * - Load more uri (due to this varying by account protocol). 42651004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * TODO: This would be better as a CursorWrapper, rather than doing a copy. 42661004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * @param inputCursor A cursor containing all columns of {@link UIProvider.FolderColumns}. 42671004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * Strictly speaking doesn't need all, but simpler if we assume that. 42681004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * @param outputCursor A MatrixCursor which this function will populate. 42691004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * @param accountId The account id for the mailboxes in this query. 42701004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * @param uiProjection The projection specified by the query. 42711004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu */ 42721004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu private void remapFolderCursor(final Cursor inputCursor, final MatrixCursor outputCursor, 42731004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final long accountId, final String[] uiProjection) { 42741004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Return early if our input cursor is empty. 42751004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu if (inputCursor == null || inputCursor.getCount() == 0) { 42761004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu return; 42771004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } 42781004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Get the column indices for the columns we need during remapping. 4279469c4263760373c1bc330251910ec28005051aa8James Lemieux // While we currently could assume the column indices for UIProvider.FOLDERS_PROJECTION 42801004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // and therefore avoid the calls to getColumnIndex, this at least tries to future-proof a 42811004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // bit. 42821004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Note that id and type MUST be present for this function to work correctly. 42831004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final int idColumn = inputCursor.getColumnIndex(BaseColumns._ID); 42841004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final int typeColumn = inputCursor.getColumnIndex(UIProvider.FolderColumns.TYPE); 42851004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final int nameColumn = inputCursor.getColumnIndex(UIProvider.FolderColumns.NAME); 42861004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final int capabilitiesColumn = 42871004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu inputCursor.getColumnIndex(UIProvider.FolderColumns.CAPABILITIES); 42881004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final int persistentIdColumn = 42891004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu inputCursor.getColumnIndex(UIProvider.FolderColumns.PERSISTENT_ID); 42901004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final int loadMoreUriColumn = 42911004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu inputCursor.getColumnIndex(UIProvider.FolderColumns.LOAD_MORE_URI); 42921004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu 42931004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Get the EmailServiceInfo for the current account. 42941004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final Context context = getContext(); 42951004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final String protocol = Account.getProtocol(context, accountId); 42961004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final EmailServiceInfo info = EmailServiceUtils.getServiceInfo(context, protocol); 42971004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu 42981004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Build the return cursor. We iterate over all rows of the input cursor and construct 42991004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // a row in the output using the columns in uiProjection. 43001004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu while (inputCursor.moveToNext()) { 43011004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final MatrixCursor.RowBuilder builder = outputCursor.newRow(); 4302469c4263760373c1bc330251910ec28005051aa8James Lemieux final int folderType = inputCursor.getInt(typeColumn); 43031004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu for (int i = 0; i < uiProjection.length; i++) { 43041004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Find the index in the input cursor corresponding the column requested in the 43051004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // output projection. 43061004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final int index = inputCursor.getColumnIndex(uiProjection[i]); 43071004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu if (index == -1) { 43081004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // We don't have this value, so put a blank in the output and move on. 43091004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu builder.add(null); 43101004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu continue; 43111004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } 43121004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final String value = inputCursor.getString(index); 43131004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // remapped indicates whether we've written a value to the output for this column. 43141004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final boolean remapped; 43151004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu if (nameColumn == index) { 43161004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Remap folder name for system folders. 4317469c4263760373c1bc330251910ec28005051aa8James Lemieux builder.add(getFolderDisplayName(folderType, value)); 43181004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu remapped = true; 43191004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } else if (capabilitiesColumn == index) { 43201004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Get the correct capabilities for this folder. 4321469c4263760373c1bc330251910ec28005051aa8James Lemieux final long mailboxID = inputCursor.getLong(idColumn); 4322469c4263760373c1bc330251910ec28005051aa8James Lemieux final int mailboxType = getMailboxTypeFromFolderType(folderType); 4323469c4263760373c1bc330251910ec28005051aa8James Lemieux builder.add(getFolderCapabilities(info, mailboxType, mailboxID)); 43241004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu remapped = true; 43251004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } else if (persistentIdColumn == index) { 43261004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Hash the persistent id. 43271004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu builder.add(Base64.encodeToString(value.getBytes(), 43281004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING)); 43291004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu remapped = true; 4330469c4263760373c1bc330251910ec28005051aa8James Lemieux } else if (loadMoreUriColumn == index && folderType != Mailbox.TYPE_SEARCH && 43311004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu (info == null || !info.offerLoadMore)) { 43321004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Blank the load more uri for account types that don't offer it. 43331004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Note that all account types permit load more for search results. 43341004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu builder.add(null); 43351004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu remapped = true; 43361004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } else { 43371004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu remapped = false; 43381004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } 43391004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // If the above logic didn't write some other value to the output, use the value 43401004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // from the input cursor. 43411004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu if (!remapped) { 43421004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu builder.add(value); 43431004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } 43441004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } 43451004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } 43461004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } 43471004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu 43481004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu private Cursor getFolderListCursor(final Cursor inputCursor, final long accountId, 43491004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final String[] uiProjection) { 43501004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final MatrixCursor mc = new MatrixCursorWithCachedColumns(uiProjection); 43511004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu if (inputCursor != null) { 43521004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu try { 43531004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu remapFolderCursor(inputCursor, mc, accountId, uiProjection); 43541004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } finally { 43551004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu inputCursor.close(); 43561004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } 43571004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } 43581004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu return mc; 43591004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } 43601004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu 43611004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu /** 4362cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * Returns a {@link String} from Resources corresponding 4363cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * to the {@link UIProvider.FolderType} requested. 4364cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * @param folderType {@link UIProvider.FolderType} value for the folder 4365cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * @param defaultName a {@link String} to use in case the {@link UIProvider.FolderType} 4366cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * provided is not a system folder. 4367cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * @return a {@link String} to use as the display name for the folder 4368cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein */ 4369cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein private String getFolderDisplayName(int folderType, String defaultName) { 4370582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler final int resId; 4371cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein switch (folderType) { 4372cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case UIProvider.FolderType.INBOX: 4373cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein resId = R.string.mailbox_name_display_inbox; 4374cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein break; 4375cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case UIProvider.FolderType.OUTBOX: 4376cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein resId = R.string.mailbox_name_display_outbox; 4377cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein break; 4378cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case UIProvider.FolderType.DRAFT: 4379cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein resId = R.string.mailbox_name_display_drafts; 4380cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein break; 4381cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case UIProvider.FolderType.TRASH: 4382cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein resId = R.string.mailbox_name_display_trash; 4383cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein break; 4384cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case UIProvider.FolderType.SENT: 4385cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein resId = R.string.mailbox_name_display_sent; 4386cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein break; 4387cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case UIProvider.FolderType.SPAM: 4388cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein resId = R.string.mailbox_name_display_junk; 4389cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein break; 4390cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case UIProvider.FolderType.STARRED: 4391cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein resId = R.string.mailbox_name_display_starred; 4392cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein break; 4393cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case UIProvider.FolderType.UNREAD: 4394cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein resId = R.string.mailbox_name_display_unread; 4395cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein break; 4396cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein default: 4397cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return defaultName; 4398cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein } 4399cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return getContext().getString(resId); 4400cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein } 4401cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein 4402cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein /** 4403cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * Converts a {@link Mailbox} type value to its {@link UIProvider.FolderType} 4404cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * equivalent. 4405cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * @param mailboxType a {@link Mailbox} type 4406cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * @return a {@link UIProvider.FolderType} value 4407cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein */ 4408cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein private static int getFolderTypeFromMailboxType(int mailboxType) { 4409cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein switch (mailboxType) { 4410cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case Mailbox.TYPE_INBOX: 4411cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return UIProvider.FolderType.INBOX; 4412cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case Mailbox.TYPE_OUTBOX: 4413cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return UIProvider.FolderType.OUTBOX; 4414cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case Mailbox.TYPE_DRAFTS: 4415cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return UIProvider.FolderType.DRAFT; 4416cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case Mailbox.TYPE_TRASH: 4417cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return UIProvider.FolderType.TRASH; 4418cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case Mailbox.TYPE_SENT: 4419cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return UIProvider.FolderType.SENT; 4420cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case Mailbox.TYPE_JUNK: 4421cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return UIProvider.FolderType.SPAM; 4422cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case Mailbox.TYPE_STARRED: 4423cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return UIProvider.FolderType.STARRED; 4424cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case Mailbox.TYPE_UNREAD: 4425cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return UIProvider.FolderType.UNREAD; 4426e743a06ddf7677706da7450100e19d0f4509a43cScott Kennedy case Mailbox.TYPE_SEARCH: 4427e743a06ddf7677706da7450100e19d0f4509a43cScott Kennedy // TODO Can the DEFAULT type be removed from SEARCH folders? 4428e743a06ddf7677706da7450100e19d0f4509a43cScott Kennedy return UIProvider.FolderType.DEFAULT | UIProvider.FolderType.SEARCH; 4429cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein default: 4430cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return UIProvider.FolderType.DEFAULT; 4431cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein } 4432cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein } 4433cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein 4434cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein /** 4435469c4263760373c1bc330251910ec28005051aa8James Lemieux * Converts a {@link UIProvider.FolderType} type value to its {@link Mailbox} equivalent. 4436469c4263760373c1bc330251910ec28005051aa8James Lemieux * @param folderType a {@link UIProvider.FolderType} type 4437469c4263760373c1bc330251910ec28005051aa8James Lemieux * @return a {@link Mailbox} value 4438469c4263760373c1bc330251910ec28005051aa8James Lemieux */ 4439469c4263760373c1bc330251910ec28005051aa8James Lemieux private static int getMailboxTypeFromFolderType(int folderType) { 4440469c4263760373c1bc330251910ec28005051aa8James Lemieux switch (folderType) { 4441469c4263760373c1bc330251910ec28005051aa8James Lemieux case UIProvider.FolderType.DEFAULT: 4442469c4263760373c1bc330251910ec28005051aa8James Lemieux return Mailbox.TYPE_MAIL; 4443469c4263760373c1bc330251910ec28005051aa8James Lemieux case UIProvider.FolderType.INBOX: 4444469c4263760373c1bc330251910ec28005051aa8James Lemieux return Mailbox.TYPE_INBOX; 4445469c4263760373c1bc330251910ec28005051aa8James Lemieux case UIProvider.FolderType.OUTBOX: 4446469c4263760373c1bc330251910ec28005051aa8James Lemieux return Mailbox.TYPE_OUTBOX; 4447469c4263760373c1bc330251910ec28005051aa8James Lemieux case UIProvider.FolderType.DRAFT: 4448469c4263760373c1bc330251910ec28005051aa8James Lemieux return Mailbox.TYPE_DRAFTS; 4449469c4263760373c1bc330251910ec28005051aa8James Lemieux case UIProvider.FolderType.TRASH: 4450469c4263760373c1bc330251910ec28005051aa8James Lemieux return Mailbox.TYPE_TRASH; 4451469c4263760373c1bc330251910ec28005051aa8James Lemieux case UIProvider.FolderType.SENT: 4452469c4263760373c1bc330251910ec28005051aa8James Lemieux return Mailbox.TYPE_SENT; 4453469c4263760373c1bc330251910ec28005051aa8James Lemieux case UIProvider.FolderType.SPAM: 4454469c4263760373c1bc330251910ec28005051aa8James Lemieux return Mailbox.TYPE_JUNK; 4455469c4263760373c1bc330251910ec28005051aa8James Lemieux case UIProvider.FolderType.STARRED: 4456469c4263760373c1bc330251910ec28005051aa8James Lemieux return Mailbox.TYPE_STARRED; 4457469c4263760373c1bc330251910ec28005051aa8James Lemieux case UIProvider.FolderType.UNREAD: 4458469c4263760373c1bc330251910ec28005051aa8James Lemieux return Mailbox.TYPE_UNREAD; 4459469c4263760373c1bc330251910ec28005051aa8James Lemieux case UIProvider.FolderType.DEFAULT | UIProvider.FolderType.SEARCH: 4460469c4263760373c1bc330251910ec28005051aa8James Lemieux // TODO Can the DEFAULT type be removed from SEARCH folders? 4461469c4263760373c1bc330251910ec28005051aa8James Lemieux return Mailbox.TYPE_SEARCH; 4462469c4263760373c1bc330251910ec28005051aa8James Lemieux default: 4463469c4263760373c1bc330251910ec28005051aa8James Lemieux throw new IllegalArgumentException("Unable to map folder type: " + folderType); 4464469c4263760373c1bc330251910ec28005051aa8James Lemieux } 4465469c4263760373c1bc330251910ec28005051aa8James Lemieux } 4466469c4263760373c1bc330251910ec28005051aa8James Lemieux 4467469c4263760373c1bc330251910ec28005051aa8James Lemieux /** 44684cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler * We need a reasonably full projection for getFolderListCursor to work, but don't always want 44694cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler * to do the subquery needed for FolderColumns.UNREAD_SENDERS 44704cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler * @param uiProjection The projection we actually want 44714cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler * @return Full projection, possibly with or without FolderColumns.UNREAD_SENDERS 44724cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler */ 44734cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler private String[] folderProjectionFromUiProjection(final String[] uiProjection) { 44744cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler final Set<String> columns = ImmutableSet.copyOf(uiProjection); 44754cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler if (columns.contains(UIProvider.FolderColumns.UNREAD_SENDERS)) { 44764cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler return UIProvider.FOLDERS_PROJECTION_WITH_UNREAD_SENDERS; 44774cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler } else { 44784cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler return UIProvider.FOLDERS_PROJECTION; 44794cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler } 44804cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler } 44814cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler 44824cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler /** 4483f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Handle UnifiedEmail queries here (dispatched from query()) 4484f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 4485f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param match the UriMatcher match for the original uri passed in from UnifiedEmail 4486f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uri the original uri passed in from UnifiedEmail 4487f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection the projection passed in from UnifiedEmail 4488b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy * @param unseenOnly <code>true</code> to only return unseen messages (where supported) 4489f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the result Cursor 4490f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 4491b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private Cursor uiQuery(int match, Uri uri, String[] uiProjection, final boolean unseenOnly) { 4492f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Context context = getContext(); 4493f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ContentResolver resolver = context.getContentResolver(); 4494f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank SQLiteDatabase db = getDatabase(context); 4495f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Should we ever return null, or throw an exception?? 4496f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Cursor c = null; 4497f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank String id = uri.getPathSegments().get(1); 4498f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Uri notifyUri = null; 4499f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank switch(match) { 4500f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ALL_FOLDERS: 450196192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler notifyUri = 450296192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler UIPROVIDER_FOLDERLIST_NOTIFIER.buildUpon().appendEncodedPath(id).build(); 450396192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler final Cursor vc = uiVirtualMailboxes(id, uiProjection); 450496192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler if (id.equals(COMBINED_ACCOUNT_ID_STRING)) { 450596192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler // There's no real mailboxes, so just return the virtual ones 450696192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler c = vc; 450796192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler } else { 450896192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler // Return real and virtual mailboxes alike 450996192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler final Cursor rawc = db.rawQuery(genQueryAccountAllMailboxes(uiProjection), 451096192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler new String[] {id}); 451196192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler rawc.setNotificationUri(context.getContentResolver(), notifyUri); 451296192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler vc.setNotificationUri(context.getContentResolver(), notifyUri); 45130d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler if (rawc.getCount() > 0) { 45140d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler c = new MergeCursor(new Cursor[]{rawc, vc}); 45150d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler } else { 45160d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler c = rawc; 45170d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler } 451896192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler } 451996192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler break; 45204cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler case UI_FULL_FOLDERS: { 45214cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler // We need a full projection for getFolderListCursor 45224cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler final String[] folderProjection = folderProjectionFromUiProjection(uiProjection); 45234cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler c = db.rawQuery(genQueryAccountAllMailboxes(folderProjection), new String[] {id}); 45241004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu c = getFolderListCursor(c, Long.valueOf(id), uiProjection); 4525c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu notifyUri = 4526c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu UIPROVIDER_FOLDERLIST_NOTIFIER.buildUpon().appendEncodedPath(id).build(); 4527f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 45284cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler } 4529f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_RECENT_FOLDERS: 4530f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c = db.rawQuery(genQueryRecentMailboxes(uiProjection), new String[] {id}); 4531f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUri = UIPROVIDER_RECENT_FOLDERS_NOTIFIER.buildUpon().appendPath(id).build(); 4532f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 45334cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler case UI_SUBFOLDERS: { 45344cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler // We need a full projection for getFolderListCursor 45354cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler final String[] folderProjection = folderProjectionFromUiProjection(uiProjection); 45364cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler c = db.rawQuery(genQuerySubfolders(folderProjection), new String[] {id}); 45371004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu c = getFolderListCursor(c, Mailbox.getAccountIdForMailbox(context, id), 45381004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu uiProjection); 4539c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu // Get notifications for any folder changes on this account. This is broader than 4540c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu // we need but otherwise we'd need for every folder change to notify on all relevant 4541c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu // subtrees. For now we opt for simplicity. 4542c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu final long accountId = Mailbox.getAccountIdForMailbox(context, id); 4543c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu notifyUri = ContentUris.withAppendedId(UIPROVIDER_FOLDERLIST_NOTIFIER, accountId); 4544f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 45454cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler } 4546f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_MESSAGES: 4547f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank long mailboxId = Long.parseLong(id); 454870500d2253732f4e26988659c27d1b4186926c54Yu Ping Hu final Folder folder = getFolder(context, mailboxId); 454970500d2253732f4e26988659c27d1b4186926c54Yu Ping Hu if (folder == null) { 45502c3328bfd745142f3365c676527daa853fe445d6Tony Mantler // This mailboxId is bogus. Return an empty cursor 45512c3328bfd745142f3365c676527daa853fe445d6Tony Mantler // TODO: Make callers of this query handle null cursors instead b/10819309 45522c3328bfd745142f3365c676527daa853fe445d6Tony Mantler return new MatrixCursor(uiProjection); 455370500d2253732f4e26988659c27d1b4186926c54Yu Ping Hu } 4554f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (isVirtualMailbox(mailboxId)) { 4555b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy c = getVirtualMailboxMessagesCursor(db, uiProjection, mailboxId, unseenOnly); 4556f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 4557b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy c = db.rawQuery( 4558b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy genQueryMailboxMessages(uiProjection, unseenOnly), new String[] {id}); 4559f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4560f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUri = UIPROVIDER_CONVERSATION_NOTIFIER.buildUpon().appendPath(id).build(); 456170500d2253732f4e26988659c27d1b4186926c54Yu Ping Hu c = new EmailConversationCursor(context, c, folder, mailboxId); 4562f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4563f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_MESSAGE: 45647c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank MessageQuery qq = genQueryViewMessage(uiProjection, id); 45657c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank String sql = qq.query; 45667c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank String attJson = qq.attachmentJson; 45677c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank // With attachments, we have another argument to bind 45687c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank if (attJson != null) { 45697c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank c = db.rawQuery(sql, new String[] {attJson, id}); 45707c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank } else { 45717c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank c = db.rawQuery(sql, new String[] {id}); 45727c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank } 4573f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler if (c != null) { 45747525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler c = new EmailMessageCursor(getContext(), c, UIProvider.MessageColumns.BODY_HTML, 45752f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler UIProvider.MessageColumns.BODY_TEXT); 4576f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler } 4577c637bff1989e768f1ffe0f898bd803a9c78d0514Tony Mantler notifyUri = UIPROVIDER_MESSAGE_NOTIFIER.buildUpon().appendPath(id).build(); 4578f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4579f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ATTACHMENTS: 45806eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein final List<String> contentTypeQueryParameters = 45816eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein uri.getQueryParameters(PhotoContract.ContentTypeParameters.CONTENT_TYPE); 45826eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein c = db.rawQuery(genQueryAttachments(uiProjection, contentTypeQueryParameters), 45836eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein new String[] {id}); 4584114e314968f507b4237e693d279befe261b00f02Marc Blank c = new AttachmentsCursor(context, c); 4585f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUri = UIPROVIDER_ATTACHMENTS_NOTIFIER.buildUpon().appendPath(id).build(); 4586f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4587f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ATTACHMENT: 45888cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux c = db.rawQuery(genQueryAttachment(uiProjection), new String[] {id}); 4589f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUri = UIPROVIDER_ATTACHMENT_NOTIFIER.buildUpon().appendPath(id).build(); 4590f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 45918cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux case UI_ATTACHMENT_BY_CID: 45928cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux final String cid = uri.getPathSegments().get(2); 45938cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux final String[] selectionArgs = {id, cid}; 45948cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux c = db.rawQuery(genQueryAttachmentByMessageIDAndCid(uiProjection), selectionArgs); 45958cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux 45968cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux // we don't have easy access to the attachment ID (which is buried in the cursor 45978cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux // being returned), so we notify on the parent message object 45988cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux notifyUri = UIPROVIDER_ATTACHMENTS_NOTIFIER.buildUpon().appendPath(id).build(); 45998cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux break; 4600f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_FOLDER: 46010d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler case UI_INBOX: 46020d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler if (match == UI_INBOX) { 46030d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler mailboxId = Mailbox.findMailboxOfType(context, Long.parseLong(id), 46040d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler Mailbox.TYPE_INBOX); 46050d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler if (mailboxId == Mailbox.NO_MAILBOX) { 46060d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler LogUtils.d(LogUtils.TAG, "No inbox found for account %s", id); 46070d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler return null; 46080d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler } 46090d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler LogUtils.d(LogUtils.TAG, "Found inbox id %d", mailboxId); 46100d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler } else { 46110d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler mailboxId = Long.parseLong(id); 46120d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler } 46130d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler final String mailboxIdString = Long.toString(mailboxId); 4614f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (isVirtualMailbox(mailboxId)) { 4615e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler c = getVirtualMailboxCursor(mailboxId, uiProjection); 46160d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler notifyUri = UIPROVIDER_FOLDER_NOTIFIER.buildUpon().appendPath(mailboxIdString) 46170d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler .build(); 4618f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 46190d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler c = db.rawQuery(genQueryMailbox(uiProjection, mailboxIdString), 46200d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler new String[]{mailboxIdString}); 4621cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein final List<String> projectionList = Arrays.asList(uiProjection); 4622cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein final int nameColumn = projectionList.indexOf(UIProvider.FolderColumns.NAME); 4623cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein final int typeColumn = projectionList.indexOf(UIProvider.FolderColumns.TYPE); 4624cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein if (c.moveToFirst()) { 46252eecdd1a50676eaae98b75d1d74de697cff39dd7Tony Mantler final Cursor closeThis = c; 46262eecdd1a50676eaae98b75d1d74de697cff39dd7Tony Mantler try { 46272eecdd1a50676eaae98b75d1d74de697cff39dd7Tony Mantler c = getUiFolderCursorRowFromMailboxCursorRow( 46282eecdd1a50676eaae98b75d1d74de697cff39dd7Tony Mantler new MatrixCursorWithCachedColumns(uiProjection), 46292eecdd1a50676eaae98b75d1d74de697cff39dd7Tony Mantler uiProjection.length, c, nameColumn, typeColumn); 46302eecdd1a50676eaae98b75d1d74de697cff39dd7Tony Mantler } finally { 46312eecdd1a50676eaae98b75d1d74de697cff39dd7Tony Mantler closeThis.close(); 46322eecdd1a50676eaae98b75d1d74de697cff39dd7Tony Mantler } 4633cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein } 46340d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler notifyUri = UIPROVIDER_FOLDER_NOTIFIER.buildUpon().appendPath(mailboxIdString) 46350d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler .build(); 4636f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4637f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4638f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ACCOUNT: 4639f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (id.equals(COMBINED_ACCOUNT_ID_STRING)) { 46407fdde9bb4a24e931618a7a64227e2194c89034daScott Kennedy MatrixCursor mc = new MatrixCursorWithCachedColumns(uiProjection, 1); 4641f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank addCombinedAccountRow(mc); 4642f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c = mc; 4643f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 4644f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c = db.rawQuery(genQueryAccount(uiProjection, id), new String[] {id}); 4645f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4646f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUri = UIPROVIDER_ACCOUNT_NOTIFIER.buildUpon().appendPath(id).build(); 4647f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4648f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_CONVERSATION: 4649f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c = db.rawQuery(genQueryConversation(uiProjection), new String[] {id}); 4650f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4651f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4652f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (notifyUri != null) { 4653f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c.setNotificationUri(resolver, notifyUri); 4654f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4655f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return c; 4656f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4657f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4658f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 4659f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Convert a UIProvider attachment to an EmailProvider attachment (for sending); we only need 4660f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * a few of the fields 4661f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiAtt the UIProvider attachment to convert 46629a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook * @param cachedFile the path to the cached file to 4663f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the EmailProvider attachment 4664f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 46659a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook // TODO(pwestbro): once the Attachment contains the cached uri, the second parameter can be 46669a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook // removed 4667fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // TODO(mhibdon): if the UI Attachment contained the account key, the third parameter could 4668f484751e060620ddf4e2dfe38f2b9f46f472ac9dMartin Hibdon // be removed. 4669b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static Attachment convertUiAttachmentToAttachment( 4670f484751e060620ddf4e2dfe38f2b9f46f472ac9dMartin Hibdon com.android.mail.providers.Attachment uiAtt, String cachedFile, long accountKey) { 46719a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final Attachment att = new Attachment(); 4672f484751e060620ddf4e2dfe38f2b9f46f472ac9dMartin Hibdon 46736e5bccf2c984039da5ae1dc08cffa665b73b6474Marc Blank att.setContentUri(uiAtt.contentUri.toString()); 46745a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook 46755a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook if (!TextUtils.isEmpty(cachedFile)) { 46765a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook // Generate the content provider uri for this cached file 46775a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook final Uri.Builder cachedFileBuilder = Uri.parse( 46785a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook "content://" + EmailContent.AUTHORITY + "/attachment/cachedFile").buildUpon(); 46795a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook cachedFileBuilder.appendQueryParameter(Attachment.CACHED_FILE_QUERY_PARAM, cachedFile); 46805a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook att.setCachedFileUri(cachedFileBuilder.build().toString()); 46815a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook } 4682f484751e060620ddf4e2dfe38f2b9f46f472ac9dMartin Hibdon att.mAccountKey = accountKey; 4683ea2edb637036a7368b6ef82a0aafdb1a790e26e9Mark Wei att.mFileName = uiAtt.getName(); 4684ea2edb637036a7368b6ef82a0aafdb1a790e26e9Mark Wei att.mMimeType = uiAtt.getContentType(); 4685f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank att.mSize = uiAtt.size; 4686f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return att; 4687f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4688f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4689f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 4690f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Create a mailbox given the account and mailboxType. 4691f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 4692f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private Mailbox createMailbox(long accountId, int mailboxType) { 4693f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Context context = getContext(); 46949ae81e2af07219bfad26c882516343e83c16d926Yu Ping Hu Mailbox box = Mailbox.newSystemMailbox(context, accountId, mailboxType); 4695f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Make sure drafts and save will show up in recents... 4696f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // If these already exist (from old Email app), they will have touch times 4697f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank switch (mailboxType) { 4698f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case Mailbox.TYPE_DRAFTS: 4699f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank box.mLastTouchedTime = Mailbox.DRAFTS_DEFAULT_TOUCH_TIME; 4700f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4701f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case Mailbox.TYPE_SENT: 4702f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank box.mLastTouchedTime = Mailbox.SENT_DEFAULT_TOUCH_TIME; 4703f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4704f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4705f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank box.save(context); 4706f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return box; 4707f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4708f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4709f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 4710f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Given an account name and a mailbox type, return that mailbox, creating it if necessary 4711b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy * @param accountId the account id to use 4712f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param mailboxType the type of mailbox we're trying to find 4713f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the mailbox of the given type for the account in the uri, or null if not found 4714f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 47150eb47994a328fe450c54e483b894138fd449d9c9Yu Ping Hu private Mailbox getMailboxByAccountIdAndType(final long accountId, final int mailboxType) { 47160eb47994a328fe450c54e483b894138fd449d9c9Yu Ping Hu Mailbox mailbox = Mailbox.restoreMailboxOfType(getContext(), accountId, mailboxType); 4717f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mailbox == null) { 47180eb47994a328fe450c54e483b894138fd449d9c9Yu Ping Hu mailbox = createMailbox(accountId, mailboxType); 4719f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4720f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return mailbox; 4721f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4722f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4723f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 4724f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Given a mailbox and the content values for a message, create/save the message in the mailbox 4725f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param mailbox the mailbox to use 47268e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu * @param extras the bundle containing the message fields 4727f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the uri of the newly created message 47288e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu * TODO(yph): The following fields are available in extras but unused, verify whether they 47298e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu * should be respected: 47308e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu * - UIProvider.MessageColumns.SNIPPET 47318e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu * - UIProvider.MessageColumns.REPLY_TO 47328e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu * - UIProvider.MessageColumns.FROM 4733f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 47348e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu private Uri uiSaveMessage(Message msg, Mailbox mailbox, Bundle extras) { 47359a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final Context context = getContext(); 4736f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Fill in the message 47379a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final Account account = Account.restoreAccountWithId(context, mailbox.mAccountKey); 4738f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (account == null) return null; 4739632ee24d48f308c855ddec8f013b674e5ade67e2Tony Mantler final String customFromAddress = 4740632ee24d48f308c855ddec8f013b674e5ade67e2Tony Mantler extras.getString(UIProvider.MessageColumns.CUSTOM_FROM_ADDRESS); 4741632ee24d48f308c855ddec8f013b674e5ade67e2Tony Mantler if (!TextUtils.isEmpty(customFromAddress)) { 4742632ee24d48f308c855ddec8f013b674e5ade67e2Tony Mantler msg.mFrom = customFromAddress; 4743632ee24d48f308c855ddec8f013b674e5ade67e2Tony Mantler } else { 4744632ee24d48f308c855ddec8f013b674e5ade67e2Tony Mantler msg.mFrom = account.getEmailAddress(); 4745632ee24d48f308c855ddec8f013b674e5ade67e2Tony Mantler } 4746f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.mTimeStamp = System.currentTimeMillis(); 47478e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu msg.mTo = extras.getString(UIProvider.MessageColumns.TO); 47488e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu msg.mCc = extras.getString(UIProvider.MessageColumns.CC); 47498e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu msg.mBcc = extras.getString(UIProvider.MessageColumns.BCC); 47508e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu msg.mSubject = extras.getString(UIProvider.MessageColumns.SUBJECT); 47518e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu msg.mText = extras.getString(UIProvider.MessageColumns.BODY_TEXT); 47528e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu msg.mHtml = extras.getString(UIProvider.MessageColumns.BODY_HTML); 4753f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.mMailboxKey = mailbox.mId; 4754f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.mAccountKey = mailbox.mAccountKey; 4755f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.mDisplayName = msg.mTo; 4756f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.mFlagLoaded = Message.FLAG_LOADED_COMPLETE; 4757f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.mFlagRead = true; 4758b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy msg.mFlagSeen = true; 47592d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler msg.mQuotedTextStartPos = extras.getInt(UIProvider.MessageColumns.QUOTE_START_POS, 0); 4760f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank int flags = 0; 47618e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu final int draftType = extras.getInt(UIProvider.MessageColumns.DRAFT_TYPE); 4762f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank switch(draftType) { 4763f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case DraftType.FORWARD: 4764f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank flags |= Message.FLAG_TYPE_FORWARD; 4765f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4766f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case DraftType.REPLY_ALL: 4767f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank flags |= Message.FLAG_TYPE_REPLY_ALL; 4768b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy //$FALL-THROUGH$ 4769f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case DraftType.REPLY: 4770f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank flags |= Message.FLAG_TYPE_REPLY; 4771f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4772f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case DraftType.COMPOSE: 4773f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank flags |= Message.FLAG_TYPE_ORIGINAL; 4774f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4775f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4776f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank int draftInfo = 0; 47778e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu if (extras.containsKey(UIProvider.MessageColumns.QUOTE_START_POS)) { 47788e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu draftInfo = extras.getInt(UIProvider.MessageColumns.QUOTE_START_POS); 47798e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu if (extras.getInt(UIProvider.MessageColumns.APPEND_REF_MESSAGE_CONTENT) != 0) { 4780f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank draftInfo |= Message.DRAFT_INFO_APPEND_REF_MESSAGE; 4781f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4782f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 47838e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu if (!extras.containsKey(UIProvider.MessageColumns.APPEND_REF_MESSAGE_CONTENT)) { 4784eaf7e3bce7a7f8f31c5677db188dec74072a43caMarc Blank flags |= Message.FLAG_NOT_INCLUDE_QUOTED_TEXT; 4785eaf7e3bce7a7f8f31c5677db188dec74072a43caMarc Blank } 4786f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.mDraftInfo = draftInfo; 4787eaf7e3bce7a7f8f31c5677db188dec74072a43caMarc Blank msg.mFlags = flags; 4788eaf7e3bce7a7f8f31c5677db188dec74072a43caMarc Blank 47898e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu final String ref = extras.getString(UIProvider.MessageColumns.REF_MESSAGE_ID); 479049cbb81332769c97a19cd388dcfd88957c072328Mindy Pereira if (ref != null && msg.mQuotedTextStartPos >= 0) { 4791f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank String refId = Uri.parse(ref).getLastPathSegment(); 4792f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank try { 4793582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler msg.mSourceKey = Long.parseLong(refId); 4794f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } catch (NumberFormatException e) { 4795f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // This will be zero; the default 4796f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4797f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4798f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4799f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Get attachments from the ContentValues 48009a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final List<com.android.mail.providers.Attachment> uiAtts = 4801f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank com.android.mail.providers.Attachment.fromJSONArray( 48028e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu extras.getString(UIProvider.MessageColumns.ATTACHMENTS)); 48039a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final ArrayList<Attachment> atts = new ArrayList<Attachment>(); 4804f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank boolean hasUnloadedAttachments = false; 48058e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu Bundle attachmentFds = 48068e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu extras.getParcelable(UIProvider.SendOrSaveMethodParamKeys.OPENED_FD_MAP); 4807f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank for (com.android.mail.providers.Attachment uiAtt: uiAtts) { 48089a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final Uri attUri = uiAtt.uri; 4809f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (attUri != null && attUri.getAuthority().equals(EmailContent.AUTHORITY)) { 4810f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // If it's one of ours, retrieve the attachment and add it to the list 48119a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final long attId = Long.parseLong(attUri.getLastPathSegment()); 48129a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final Attachment att = Attachment.restoreAttachmentWithId(context, attId); 4813f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (att != null) { 4814f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // We must clone the attachment into a new one for this message; easiest to 4815f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // use a parcel here 48169a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final Parcel p = Parcel.obtain(); 4817f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank att.writeToParcel(p, 0); 4818f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank p.setDataPosition(0); 48199a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final Attachment attClone = new Attachment(p); 4820f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank p.recycle(); 4821f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Clear the messageKey (this is going to be a new attachment) 4822f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank attClone.mMessageKey = 0; 4823f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // If we're sending this, it's not loaded, and we're not smart forwarding 4824f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // add the download flag, so that ADS will start up 48256e5bccf2c984039da5ae1dc08cffa665b73b6474Marc Blank if (mailbox.mType == Mailbox.TYPE_OUTBOX && att.getContentUri() == null && 4826f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ((account.mFlags & Account.FLAGS_SUPPORTS_SMART_FORWARD) == 0)) { 4827f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank attClone.mFlags |= Attachment.FLAG_DOWNLOAD_FORWARD; 4828f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank hasUnloadedAttachments = true; 4829f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4830f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank atts.add(attClone); 4831f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4832f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 48339a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook // Cache the attachment. This will allow us to send it, if the permissions are 4834f484751e060620ddf4e2dfe38f2b9f46f472ac9dMartin Hibdon // revoked. 48359a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final String cachedFileUri = 48369a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook AttachmentUtils.cacheAttachmentUri(context, uiAtt, attachmentFds); 48379a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook 4838f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Convert external attachment to one of ours and add to the list 4839f484751e060620ddf4e2dfe38f2b9f46f472ac9dMartin Hibdon atts.add(convertUiAttachmentToAttachment(uiAtt, cachedFileUri, msg.mAccountKey)); 4840f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4841f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4842f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (!atts.isEmpty()) { 4843f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.mAttachments = atts; 4844f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.mFlagAttachment = true; 4845f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (hasUnloadedAttachments) { 4846f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Utility.showToast(context, R.string.message_view_attachment_background_load); 4847f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4848f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4849f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Save it or update it... 4850f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (!msg.isSaved()) { 4851f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.save(context); 4852f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 4853f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // This is tricky due to how messages/attachments are saved; rather than putz with 4854f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // what's changed, we'll delete/re-add them 48559a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final ArrayList<ContentProviderOperation> ops = 48569a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook new ArrayList<ContentProviderOperation>(); 4857f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Delete all existing attachments 4858f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ops.add(ContentProviderOperation.newDelete( 4859f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, msg.mId)) 4860f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank .build()); 4861f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Delete the body 4862f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ops.add(ContentProviderOperation.newDelete(Body.CONTENT_URI) 48633dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .withSelection(BodyColumns.MESSAGE_KEY + "=?", 48643dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler new String[] {Long.toString(msg.mId)}) 4865f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank .build()); 4866f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Add the ops for the message, atts, and body 4867f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.addSaveOps(ops); 4868f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Do it! 4869f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank try { 4870f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank applyBatch(ops); 4871f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } catch (OperationApplicationException e) { 4872582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler LogUtils.d(TAG, "applyBatch exception"); 4873f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4874f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4875c637bff1989e768f1ffe0f898bd803a9c78d0514Tony Mantler notifyUIMessage(msg.mId); 4876c637bff1989e768f1ffe0f898bd803a9c78d0514Tony Mantler 4877f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mailbox.mType == Mailbox.TYPE_OUTBOX) { 48789e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu startSync(mailbox, 0); 48799a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final long originalMsgId = msg.mSourceKey; 4880f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (originalMsgId != 0) { 48819a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final Message originalMsg = Message.restoreMessageWithId(context, originalMsgId); 4882f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // If the original message exists, set its forwarded/replied to flags 4883f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (originalMsg != null) { 48849a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final ContentValues cv = new ContentValues(); 4885f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank flags = originalMsg.mFlags; 4886f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank switch(draftType) { 4887f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case DraftType.FORWARD: 4888f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank flags |= Message.FLAG_FORWARDED; 4889f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4890f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case DraftType.REPLY_ALL: 4891f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case DraftType.REPLY: 4892f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank flags |= Message.FLAG_REPLIED_TO; 4893f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4894f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 48953dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler cv.put(MessageColumns.FLAGS, flags); 4896f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank context.getContentResolver().update(ContentUris.withAppendedId( 4897f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Message.CONTENT_URI, originalMsgId), cv, null, null); 4898f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4899f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4900f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4901f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return uiUri("uimessage", msg.mId); 4902f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4903f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 49040eb47994a328fe450c54e483b894138fd449d9c9Yu Ping Hu private Uri uiSaveDraftMessage(final long accountId, final Bundle extras) { 49059a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final Mailbox mailbox = 49060eb47994a328fe450c54e483b894138fd449d9c9Yu Ping Hu getMailboxByAccountIdAndType(accountId, Mailbox.TYPE_DRAFTS); 4907779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook if (mailbox == null) return null; 4908bcc204dd6fa9888630348d85ebda033401a4cb0cJay Shrauner Message msg = null; 49098e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu if (extras.containsKey(BaseColumns._ID)) { 49108e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu final long messageId = extras.getLong(BaseColumns._ID); 49118e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu msg = Message.restoreMessageWithId(getContext(), messageId); 4912bcc204dd6fa9888630348d85ebda033401a4cb0cJay Shrauner } 4913bcc204dd6fa9888630348d85ebda033401a4cb0cJay Shrauner if (msg == null) { 49148e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu msg = new Message(); 49158e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu } 49168e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu return uiSaveMessage(msg, mailbox, extras); 4917779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook } 4918779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook 49190eb47994a328fe450c54e483b894138fd449d9c9Yu Ping Hu private Uri uiSendDraftMessage(final long accountId, final Bundle extras) { 4920779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook final Message msg; 4921779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook if (extras.containsKey(BaseColumns._ID)) { 4922779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook final long messageId = extras.getLong(BaseColumns._ID); 4923779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook msg = Message.restoreMessageWithId(getContext(), messageId); 4924779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook } else { 4925779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook msg = new Message(); 4926779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook } 4927779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook 4928779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook if (msg == null) return null; 49290eb47994a328fe450c54e483b894138fd449d9c9Yu Ping Hu final Mailbox mailbox = getMailboxByAccountIdAndType(accountId, Mailbox.TYPE_OUTBOX); 4930779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook if (mailbox == null) return null; 4931f7055e261821af30874f6597757468eba6830539Yu Ping Hu // Make sure the sent mailbox exists, since it will be necessary soon. 4932f7055e261821af30874f6597757468eba6830539Yu Ping Hu // TODO(yph): move system mailbox creation to somewhere sane. 49330eb47994a328fe450c54e483b894138fd449d9c9Yu Ping Hu final Mailbox sentMailbox = getMailboxByAccountIdAndType(accountId, Mailbox.TYPE_SENT); 4934f7055e261821af30874f6597757468eba6830539Yu Ping Hu if (sentMailbox == null) return null; 49358e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu final Uri messageUri = uiSaveMessage(msg, mailbox, extras); 4936779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook // Kick observers 493705649dca2f59f28cd4295e041045a605badddb15Tony Mantler notifyUI(Mailbox.CONTENT_URI, null); 4938779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook return messageUri; 4939779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook } 4940779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook 4941b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static void putIntegerLongOrBoolean(ContentValues values, String columnName, 4942b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy Object value) { 4943f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (value instanceof Integer) { 4944f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Integer intValue = (Integer)value; 4945f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(columnName, intValue); 4946f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else if (value instanceof Boolean) { 4947f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Boolean boolValue = (Boolean)value; 4948f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(columnName, boolValue ? 1 : 0); 4949f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else if (value instanceof Long) { 4950f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Long longValue = (Long)value; 4951f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(columnName, longValue); 4952f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4953f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4954f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4955f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 4956f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Update the timestamps for the folders specified and notifies on the recent folder URI. 4957582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler * @param folders array of folder Uris to update 4958f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return number of folders updated 4959f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 496005649dca2f59f28cd4295e041045a605badddb15Tony Mantler private int updateTimestamp(final Context context, String id, Uri[] folders){ 4961f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank int updated = 0; 4962f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final long now = System.currentTimeMillis(); 4963f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final ContentResolver resolver = context.getContentResolver(); 496405649dca2f59f28cd4295e041045a605badddb15Tony Mantler final ContentValues touchValues = new ContentValues(1); 49659e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler for (final Uri folder : folders) { 4966f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank touchValues.put(MailboxColumns.LAST_TOUCHED_TIME, now); 49679e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler LogUtils.d(TAG, "updateStamp: %s updated", folder); 49689e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler updated += resolver.update(folder, touchValues, null, null); 4969f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4970f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final Uri toNotify = 4971f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank UIPROVIDER_RECENT_FOLDERS_NOTIFIER.buildUpon().appendPath(id).build(); 4972f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank LogUtils.d(TAG, "updateTimestamp: Notifying on %s", toNotify); 497305649dca2f59f28cd4295e041045a605badddb15Tony Mantler notifyUI(toNotify, null); 4974f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return updated; 4975f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4976f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4977f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 4978f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Updates the recent folders. The values to be updated are specified as ContentValues pairs 4979f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * of (Folder URI, access timestamp). Returns nonzero if successful, always. 49809e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler * @param uri provider query uri 4981582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler * @param values uri, timestamp pairs 4982f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return nonzero value always. 4983f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 4984f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private int uiUpdateRecentFolders(Uri uri, ContentValues values) { 4985f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final int numFolders = values.size(); 4986f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final String id = uri.getPathSegments().get(1); 4987f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final Uri[] folders = new Uri[numFolders]; 4988f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final Context context = getContext(); 4989f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank int i = 0; 4990d8302b01faa8fc7f175c93e90458aa84e8a663c7Scott Kennedy for (final String uriString : values.keySet()) { 4991f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank folders[i] = Uri.parse(uriString); 4992f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4993f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return updateTimestamp(context, id, folders); 4994f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4995f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4996f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 4997f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Populates the recent folders according to the design. 49989e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler * @param uri provider query uri 4999f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the number of recent folders were populated. 5000f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 5001f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private int uiPopulateRecentFolders(Uri uri) { 5002f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final Context context = getContext(); 5003f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final String id = uri.getLastPathSegment(); 5004f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final Uri[] recentFolders = defaultRecentFolders(id); 5005f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final int numFolders = recentFolders.length; 5006f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (numFolders <= 0) { 5007f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return 0; 5008f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5009f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final int rowsUpdated = updateTimestamp(context, id, recentFolders); 5010f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank LogUtils.d(TAG, "uiPopulateRecentFolders: %d folders changed", rowsUpdated); 5011f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return rowsUpdated; 5012f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5013f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5014f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private int uiUpdateAttachment(Uri uri, ContentValues uiValues) { 50158f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei int result = 0; 5016f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Integer stateValue = uiValues.getAsInteger(UIProvider.AttachmentColumns.STATE); 5017f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (stateValue != null) { 5018f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // This is a command from UIProvider 5019f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank long attachmentId = Long.parseLong(uri.getLastPathSegment()); 5020f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Context context = getContext(); 5021f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Attachment attachment = 5022f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Attachment.restoreAttachmentWithId(context, attachmentId); 5023f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (attachment == null) { 5024f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Went away; ah, well... 50258f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei return result; 5026f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5027582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler int state = stateValue; 5028f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ContentValues values = new ContentValues(); 50298f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei if (state == UIProvider.AttachmentState.NOT_SAVED 50308f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei || state == UIProvider.AttachmentState.REDOWNLOADING) { 50318f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei // Set state, try to cancel request 50328f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei values.put(AttachmentColumns.UI_STATE, UIProvider.AttachmentState.NOT_SAVED); 50338f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei values.put(AttachmentColumns.FLAGS, 50348f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei attachment.mFlags &= ~Attachment.FLAG_DOWNLOAD_USER_REQUEST); 50358f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei attachment.update(context, values); 50368f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei result = 1; 50378f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei } 50388f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei if (state == UIProvider.AttachmentState.DOWNLOADING 50398f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei || state == UIProvider.AttachmentState.REDOWNLOADING) { 50408f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei // Set state and destination; request download 50418f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei values.put(AttachmentColumns.UI_STATE, UIProvider.AttachmentState.DOWNLOADING); 50428f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei Integer destinationValue = 5043f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank uiValues.getAsInteger(UIProvider.AttachmentColumns.DESTINATION); 50448f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei values.put(AttachmentColumns.UI_DESTINATION, 50458f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei destinationValue == null ? 0 : destinationValue); 50468f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei values.put(AttachmentColumns.FLAGS, 50478f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei attachment.mFlags | Attachment.FLAG_DOWNLOAD_USER_REQUEST); 50485ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon 50495ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon if (values.containsKey(AttachmentColumns.LOCATION) && 50505ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon TextUtils.isEmpty(values.getAsString(AttachmentColumns.LOCATION))) { 50515ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon LogUtils.w(TAG, new Throwable(), "attachment with blank location"); 50525ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon } 50535ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon 50548f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei attachment.update(context, values); 50558f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei result = 1; 50568f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei } 50578f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei if (state == UIProvider.AttachmentState.SAVED) { 50588f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei // If this is an inline attachment, notify message has changed 50598f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei if (!TextUtils.isEmpty(attachment.mContentId)) { 50608f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei notifyUI(UIPROVIDER_MESSAGE_NOTIFIER, attachment.mMessageKey); 50618f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei } 50628f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei result = 1; 5063f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5064f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 50658f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei return result; 5066f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5067f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5068b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private int uiUpdateFolder(final Context context, Uri uri, ContentValues uiValues) { 5069b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy // We need to mark seen separately 5070b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy if (uiValues.containsKey(UIProvider.ConversationColumns.SEEN)) { 5071b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final int seenValue = uiValues.getAsInteger(UIProvider.ConversationColumns.SEEN); 5072b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy 5073b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy if (seenValue == 1) { 5074b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final String mailboxId = uri.getLastPathSegment(); 5075b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final int rows = markAllSeen(context, mailboxId); 5076b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy 5077b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy if (uiValues.size() == 1) { 5078b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy // Nothing else to do, so return this value 5079b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy return rows; 5080b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy } 5081b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy } 5082b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy } 5083b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy 5084b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final Uri ourUri = convertToEmailProviderUri(uri, Mailbox.CONTENT_URI, true); 5085f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (ourUri == null) return 0; 5086f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ContentValues ourValues = new ContentValues(); 5087f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // This should only be called via update to "recent folders" 5088f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank for (String columnName: uiValues.keySet()) { 5089f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (columnName.equals(MailboxColumns.LAST_TOUCHED_TIME)) { 5090f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ourValues.put(MailboxColumns.LAST_TOUCHED_TIME, uiValues.getAsLong(columnName)); 5091f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5092f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5093f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return update(ourUri, ourValues, null, null); 5094f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5095f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5096b7e0834121d564982c0389c87df775ba311429d4Tony Mantler private int uiUpdateSettings(final Context c, final ContentValues uiValues) { 5097b7e0834121d564982c0389c87df775ba311429d4Tony Mantler final MailPrefs mailPrefs = MailPrefs.get(c); 5098b7e0834121d564982c0389c87df775ba311429d4Tony Mantler 5099b7e0834121d564982c0389c87df775ba311429d4Tony Mantler if (uiValues.containsKey(SettingsColumns.AUTO_ADVANCE)) { 5100b7e0834121d564982c0389c87df775ba311429d4Tony Mantler mailPrefs.setAutoAdvanceMode(uiValues.getAsInteger(SettingsColumns.AUTO_ADVANCE)); 5101b7e0834121d564982c0389c87df775ba311429d4Tony Mantler } 5102b7e0834121d564982c0389c87df775ba311429d4Tony Mantler if (uiValues.containsKey(SettingsColumns.CONVERSATION_VIEW_MODE)) { 5103b7e0834121d564982c0389c87df775ba311429d4Tony Mantler final int value = uiValues.getAsInteger(SettingsColumns.CONVERSATION_VIEW_MODE); 5104b7e0834121d564982c0389c87df775ba311429d4Tony Mantler final boolean overviewMode = value == UIProvider.ConversationViewMode.OVERVIEW; 5105b7e0834121d564982c0389c87df775ba311429d4Tony Mantler mailPrefs.setConversationOverviewMode(overviewMode); 5106b7e0834121d564982c0389c87df775ba311429d4Tony Mantler } 5107b7e0834121d564982c0389c87df775ba311429d4Tony Mantler 5108b7e0834121d564982c0389c87df775ba311429d4Tony Mantler c.getContentResolver().notifyChange(UIPROVIDER_ALL_ACCOUNTS_NOTIFIER, null, false); 5109b7e0834121d564982c0389c87df775ba311429d4Tony Mantler 5110b7e0834121d564982c0389c87df775ba311429d4Tony Mantler return 1; 5111b7e0834121d564982c0389c87df775ba311429d4Tony Mantler } 5112b7e0834121d564982c0389c87df775ba311429d4Tony Mantler 5113b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private int markAllSeen(final Context context, final String mailboxId) { 5114b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final SQLiteDatabase db = getDatabase(context); 5115b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final String table = Message.TABLE_NAME; 5116b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final ContentValues values = new ContentValues(1); 5117b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy values.put(MessageColumns.FLAG_SEEN, 1); 5118b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final String whereClause = MessageColumns.MAILBOX_KEY + " = ?"; 5119b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final String[] whereArgs = new String[] {mailboxId}; 5120b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy 5121b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy return db.update(table, values, whereClause, whereArgs); 5122b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy } 5123b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy 5124f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private ContentValues convertUiMessageValues(Message message, ContentValues values) { 51255ed8b266a480ea413264abdb5042c58b29175df8Paul Westbrook final ContentValues ourValues = new ContentValues(); 512634d8a139ce9c7eb72ec92ba6861353f221301330Mindy Pereira for (String columnName : values.keySet()) { 51275ed8b266a480ea413264abdb5042c58b29175df8Paul Westbrook final Object val = values.get(columnName); 5128f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (columnName.equals(UIProvider.ConversationColumns.STARRED)) { 5129f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank putIntegerLongOrBoolean(ourValues, MessageColumns.FLAG_FAVORITE, val); 5130f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else if (columnName.equals(UIProvider.ConversationColumns.READ)) { 5131f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank putIntegerLongOrBoolean(ourValues, MessageColumns.FLAG_READ, val); 5132b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy } else if (columnName.equals(UIProvider.ConversationColumns.SEEN)) { 5133b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy putIntegerLongOrBoolean(ourValues, MessageColumns.FLAG_SEEN, val); 5134f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else if (columnName.equals(MessageColumns.MAILBOX_KEY)) { 5135f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank putIntegerLongOrBoolean(ourValues, MessageColumns.MAILBOX_KEY, val); 51365ed8b266a480ea413264abdb5042c58b29175df8Paul Westbrook } else if (columnName.equals(UIProvider.ConversationOperations.FOLDERS_UPDATED)) { 51375ed8b266a480ea413264abdb5042c58b29175df8Paul Westbrook // Skip this column, as the folders will also be specified the RAW_FOLDERS column 5138f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else if (columnName.equals(UIProvider.ConversationColumns.RAW_FOLDERS)) { 5139709b4633eda47f81a689c3be623660d74cdad904Mindy Pereira // Convert from folder list uri to mailbox key 514068a3607895963854637215a405145f190d6458f0Andy Huang final FolderList flist = FolderList.fromBlob(values.getAsByteArray(columnName)); 514168a3607895963854637215a405145f190d6458f0Andy Huang if (flist.folders.size() != 1) { 514268a3607895963854637215a405145f190d6458f0Andy Huang LogUtils.e(TAG, 514334d8a139ce9c7eb72ec92ba6861353f221301330Mindy Pereira "Incorrect number of folders for this message: Message is %s", 514434d8a139ce9c7eb72ec92ba6861353f221301330Mindy Pereira message.mId); 514534d8a139ce9c7eb72ec92ba6861353f221301330Mindy Pereira } else { 514668a3607895963854637215a405145f190d6458f0Andy Huang final Folder f = flist.folders.get(0); 5147281c6365fb95037ca284dd8c910538639e8b3dcbScott Kennedy final Uri uri = f.folderUri.fullUri; 514868a3607895963854637215a405145f190d6458f0Andy Huang final Long mailboxId = Long.parseLong(uri.getLastPathSegment()); 5149709b4633eda47f81a689c3be623660d74cdad904Mindy Pereira putIntegerLongOrBoolean(ourValues, MessageColumns.MAILBOX_KEY, mailboxId); 5150709b4633eda47f81a689c3be623660d74cdad904Mindy Pereira } 5151f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else if (columnName.equals(UIProvider.MessageColumns.ALWAYS_SHOW_IMAGES)) { 51521fa303478c61e0d703011996e358037eef523176James Lemieux Address[] fromList = Address.fromHeader(message.mFrom); 515338f22dbf08664b885b4cf063ea665c02edfb1c32Paul Westbrook final MailPrefs mailPrefs = MailPrefs.get(getContext()); 5154f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank for (Address sender : fromList) { 515538f22dbf08664b885b4cf063ea665c02edfb1c32Paul Westbrook final String email = sender.getAddress(); 515638f22dbf08664b885b4cf063ea665c02edfb1c32Paul Westbrook mailPrefs.setDisplayImagesFromSender(email, null); 5157f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5158947911082955d00014d1eccf04cd4b157d8cd8c6Paul Westbrook } else if (columnName.equals(UIProvider.ConversationColumns.VIEWED) || 5159947911082955d00014d1eccf04cd4b157d8cd8c6Paul Westbrook columnName.equals(UIProvider.ConversationOperations.Parameters.SUPPRESS_UNDO)) { 51607f7f7e6402eec1baab6bedcb58da61369cae4097Marc Blank // Ignore for now 5161fc5aae98e7a440ef9ab015efd4934123c2c15e76Scott Kennedy } else if (UIProvider.ConversationColumns.CONVERSATION_INFO.equals(columnName)) { 5162fc5aae98e7a440ef9ab015efd4934123c2c15e76Scott Kennedy // Email's conversation info is generated, not stored, so just ignore this update 5163f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 5164f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank throw new IllegalArgumentException("Can't update " + columnName + " in message"); 5165f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5166f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5167f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return ourValues; 5168f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5169f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5170b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static Uri convertToEmailProviderUri(Uri uri, Uri newBaseUri, boolean asProvider) { 51715ed8b266a480ea413264abdb5042c58b29175df8Paul Westbrook final String idString = uri.getLastPathSegment(); 5172f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank try { 51735ed8b266a480ea413264abdb5042c58b29175df8Paul Westbrook final long id = Long.parseLong(idString); 5174f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Uri ourUri = ContentUris.withAppendedId(newBaseUri, id); 5175f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (asProvider) { 5176f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ourUri = ourUri.buildUpon().appendQueryParameter(IS_UIPROVIDER, "true").build(); 5177f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5178f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return ourUri; 5179f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } catch (NumberFormatException e) { 5180f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return null; 5181f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5182f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5183f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5184f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private Message getMessageFromLastSegment(Uri uri) { 5185f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank long messageId = Long.parseLong(uri.getLastPathSegment()); 5186f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return Message.restoreMessageWithId(getContext(), messageId); 5187f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5188f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5189f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 5190f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Add an undo operation for the current sequence; if the sequence is newer than what we've had, 5191f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * clear out the undo list and start over 5192f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uri the uri we're working on 5193f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param op the ContentProviderOperation to perform upon undo 5194f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 5195f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private void addToSequence(Uri uri, ContentProviderOperation op) { 5196f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank String sequenceString = uri.getQueryParameter(UIProvider.SEQUENCE_QUERY_PARAMETER); 5197f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (sequenceString != null) { 5198f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank int sequence = Integer.parseInt(sequenceString); 5199f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (sequence > mLastSequence) { 5200f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Reset sequence 5201f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mLastSequenceOps.clear(); 5202f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mLastSequence = sequence; 5203f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5204f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // TODO: Need something to indicate a change isn't ready (undoable) 5205f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mLastSequenceOps.add(op); 5206f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5207f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5208f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5209f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // TODO: This should depend on flags on the mailbox... 5210b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static boolean uploadsToServer(Context context, Mailbox m) { 5211f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (m.mType == Mailbox.TYPE_DRAFTS || m.mType == Mailbox.TYPE_OUTBOX || 5212f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank m.mType == Mailbox.TYPE_SEARCH) { 5213f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return false; 5214f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5215f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank String protocol = Account.getProtocol(context, m.mAccountKey); 5216f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank EmailServiceInfo info = EmailServiceUtils.getServiceInfo(context, protocol); 5217f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return (info != null && info.syncChanges); 5218f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5219f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5220f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private int uiUpdateMessage(Uri uri, ContentValues values) { 52217f7f7e6402eec1baab6bedcb58da61369cae4097Marc Blank return uiUpdateMessage(uri, values, false); 52227f7f7e6402eec1baab6bedcb58da61369cae4097Marc Blank } 52237f7f7e6402eec1baab6bedcb58da61369cae4097Marc Blank 52247f7f7e6402eec1baab6bedcb58da61369cae4097Marc Blank private int uiUpdateMessage(Uri uri, ContentValues values, boolean forceSync) { 5225f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Context context = getContext(); 5226f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Message msg = getMessageFromLastSegment(uri); 5227f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (msg == null) return 0; 5228f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Mailbox mailbox = Mailbox.restoreMailboxWithId(context, msg.mMailboxKey); 5229f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mailbox == null) return 0; 52307f7f7e6402eec1baab6bedcb58da61369cae4097Marc Blank Uri ourBaseUri = 52317f7f7e6402eec1baab6bedcb58da61369cae4097Marc Blank (forceSync || uploadsToServer(context, mailbox)) ? Message.SYNCED_CONTENT_URI : 52327f7f7e6402eec1baab6bedcb58da61369cae4097Marc Blank Message.CONTENT_URI; 5233f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Uri ourUri = convertToEmailProviderUri(uri, ourBaseUri, true); 5234f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (ourUri == null) return 0; 5235f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5236f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Special case - meeting response 5237f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (values.containsKey(UIProvider.MessageOperations.RESPOND_COLUMN)) { 52382075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu final EmailServiceProxy service = 52392075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu EmailServiceUtils.getServiceForAccount(context, mailbox.mAccountKey); 5240f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank try { 5241f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank service.sendMeetingResponse(msg.mId, 5242f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.getAsInteger(UIProvider.MessageOperations.RESPOND_COLUMN)); 5243f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Delete the message immediately 5244f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank uiDeleteMessage(uri); 5245f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Utility.showToast(context, R.string.confirm_response); 5246f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Notify box has changed so the deletion is reflected in the UI 5247f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUIConversationMailbox(mailbox.mId); 5248f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } catch (RemoteException e) { 52499e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler LogUtils.d(TAG, "Remote exception while sending meeting response"); 5250f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5251f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return 1; 5252f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5253f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 52546edccbf1f1371157cfa6e503d8353a474aafd2a1Yu Ping Hu // Another special case - deleting a draft. 52556edccbf1f1371157cfa6e503d8353a474aafd2a1Yu Ping Hu final String operation = values.getAsString( 52566edccbf1f1371157cfa6e503d8353a474aafd2a1Yu Ping Hu UIProvider.ConversationOperations.OPERATION_KEY); 525799e882e22d92f4d359c71b5affdff33119f13163Jin Cao // TODO: for now let's just default to delete for MOVE_FAILED_TO_DRAFT operation 525899e882e22d92f4d359c71b5affdff33119f13163Jin Cao if (UIProvider.ConversationOperations.DISCARD_DRAFTS.equals(operation) || 525999e882e22d92f4d359c71b5affdff33119f13163Jin Cao UIProvider.ConversationOperations.MOVE_FAILED_TO_DRAFTS.equals(operation)) { 52606edccbf1f1371157cfa6e503d8353a474aafd2a1Yu Ping Hu uiDeleteMessage(uri); 52616edccbf1f1371157cfa6e503d8353a474aafd2a1Yu Ping Hu return 1; 52626edccbf1f1371157cfa6e503d8353a474aafd2a1Yu Ping Hu } 52636edccbf1f1371157cfa6e503d8353a474aafd2a1Yu Ping Hu 5264f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ContentValues undoValues = new ContentValues(); 5265f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ContentValues ourValues = convertUiMessageValues(msg, values); 5266f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank for (String columnName: ourValues.keySet()) { 5267f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (columnName.equals(MessageColumns.MAILBOX_KEY)) { 5268f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank undoValues.put(MessageColumns.MAILBOX_KEY, msg.mMailboxKey); 5269f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else if (columnName.equals(MessageColumns.FLAG_READ)) { 5270f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank undoValues.put(MessageColumns.FLAG_READ, msg.mFlagRead); 5271b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy } else if (columnName.equals(MessageColumns.FLAG_SEEN)) { 5272b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy undoValues.put(MessageColumns.FLAG_SEEN, msg.mFlagSeen); 5273f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else if (columnName.equals(MessageColumns.FLAG_FAVORITE)) { 5274f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank undoValues.put(MessageColumns.FLAG_FAVORITE, msg.mFlagFavorite); 5275f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5276f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 52771b8e0fa23f6e9957f0b8753dd3f5b95d3f5d98eaScott Kennedy if (undoValues.size() == 0) { 5278f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return -1; 5279f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5280c7636b8a47b39a482414cf7a9695846956add963Paul Westbrook final Boolean suppressUndo = 5281c7636b8a47b39a482414cf7a9695846956add963Paul Westbrook values.getAsBoolean(UIProvider.ConversationOperations.Parameters.SUPPRESS_UNDO); 5282582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler if (suppressUndo == null || !suppressUndo) { 5283c7636b8a47b39a482414cf7a9695846956add963Paul Westbrook final ContentProviderOperation op = 5284c7636b8a47b39a482414cf7a9695846956add963Paul Westbrook ContentProviderOperation.newUpdate(convertToEmailProviderUri( 5285c7636b8a47b39a482414cf7a9695846956add963Paul Westbrook uri, ourBaseUri, false)) 5286c7636b8a47b39a482414cf7a9695846956add963Paul Westbrook .withValues(undoValues) 5287c7636b8a47b39a482414cf7a9695846956add963Paul Westbrook .build(); 5288c7636b8a47b39a482414cf7a9695846956add963Paul Westbrook addToSequence(uri, op); 5289c7636b8a47b39a482414cf7a9695846956add963Paul Westbrook } 5290c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu 5291f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return update(ourUri, ourValues, null, null); 5292f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5293f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5294c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu /** 5295c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu * Projection for use with getting mailbox & account keys for a message. 5296c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu */ 5297c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu private static final String[] MESSAGE_KEYS_PROJECTION = 5298c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu { MessageColumns.MAILBOX_KEY, MessageColumns.ACCOUNT_KEY }; 5299c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu private static final int MESSAGE_KEYS_MAILBOX_KEY_COLUMN = 0; 5300c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu private static final int MESSAGE_KEYS_ACCOUNT_KEY_COLUMN = 1; 5301c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu 5302c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu /** 5303c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu * Notify necessary UI components in response to a message update. 5304c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu * @param uri The {@link Uri} for this message update. 5305c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu * @param messageId The id of the message that's been updated. 5306c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu * @param values The {@link ContentValues} that were updated in the message. 5307c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu */ 5308c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu private void handleMessageUpdateNotifications(final Uri uri, final String messageId, 5309c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu final ContentValues values) { 5310c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu if (!uri.getBooleanQueryParameter(IS_UIPROVIDER, false)) { 5311c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu notifyUIConversation(uri); 5312c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } 531362604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler notifyUIMessage(messageId); 5314c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu // TODO: Ideally, also test that the values actually changed. 5315c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu if (values.containsKey(MessageColumns.FLAG_READ) || 5316c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu values.containsKey(MessageColumns.MAILBOX_KEY)) { 5317c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu final Cursor c = query( 5318c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu Message.CONTENT_URI.buildUpon().appendEncodedPath(messageId).build(), 5319c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu MESSAGE_KEYS_PROJECTION, null, null, null); 5320c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu if (c != null) { 5321c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu try { 5322c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu if (c.moveToFirst()) { 5323c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu notifyUIFolder(c.getLong(MESSAGE_KEYS_MAILBOX_KEY_COLUMN), 5324c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu c.getLong(MESSAGE_KEYS_ACCOUNT_KEY_COLUMN)); 5325c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } 5326c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } finally { 5327c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu c.close(); 5328c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } 5329c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } 5330c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } 5331c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } 5332c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu 53339e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler /** 53349e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler * Perform a "Delete" operation 53359e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler * @param uri message to delete 53369e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler * @return number of rows affected 53379e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler */ 5338f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private int uiDeleteMessage(Uri uri) { 5339c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank final Context context = getContext(); 5340f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Message msg = getMessageFromLastSegment(uri); 5341f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (msg == null) return 0; 5342f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Mailbox mailbox = Mailbox.restoreMailboxWithId(context, msg.mMailboxKey); 5343f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mailbox == null) return 0; 5344f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mailbox.mType == Mailbox.TYPE_TRASH || mailbox.mType == Mailbox.TYPE_DRAFTS) { 5345f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // We actually delete these, including attachments 5346f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank AttachmentUtilities.deleteAllAttachmentFiles(context, msg.mAccountKey, msg.mId); 53479e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler final int r = context.getContentResolver().delete( 5348c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg.mId), null, null); 53499e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler notifyUIFolder(mailbox.mId, mailbox.mAccountKey); 5350d17359c2b4e39baa426c7bce09f1a5d293378c77Tony Mantler notifyUIMessage(msg.mId); 53519e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler return r; 5352f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5353f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Mailbox trashMailbox = 5354f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Mailbox.restoreMailboxOfType(context, msg.mAccountKey, Mailbox.TYPE_TRASH); 5355c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank if (trashMailbox == null) { 5356c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank return 0; 5357c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } 5358f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ContentValues values = new ContentValues(); 5359f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(MessageColumns.MAILBOX_KEY, trashMailbox.mId); 53609e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler final int r = uiUpdateMessage(uri, values, true); 5361fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu notifyUIFolder(mailbox.mId, mailbox.mAccountKey); 5362d17359c2b4e39baa426c7bce09f1a5d293378c77Tony Mantler notifyUIMessage(msg.mId); 53639e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler return r; 5364f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5365f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5366e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler /** 5367e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler * Hard delete all synced messages in a particular mailbox 5368e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler * @param uri Mailbox to empty (Trash, or maybe Spam/Junk later) 5369e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler * @return number of rows affected 5370e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler */ 5371e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler private int uiPurgeFolder(Uri uri) { 5372e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler final Context context = getContext(); 5373e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler final long mailboxId = Long.parseLong(uri.getLastPathSegment()); 5374e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler final SQLiteDatabase db = getDatabase(context); 5375e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler 5376e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler // Find the account ID (needed in a few calls) 5377e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler final Cursor mailboxCursor = db.query( 5378e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler Mailbox.TABLE_NAME, new String[] { MailboxColumns.ACCOUNT_KEY }, 53793dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler Mailbox._ID + "=" + mailboxId, null, null, null, null); 5380e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler if (mailboxCursor == null || !mailboxCursor.moveToFirst()) { 5381e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler LogUtils.wtf(LogUtils.TAG, "Null or empty cursor when trying to purge mailbox %d", 5382e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler mailboxId); 5383e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler return 0; 5384e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler } 5385e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler final long accountId = mailboxCursor.getLong(mailboxCursor.getColumnIndex( 5386e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler MailboxColumns.ACCOUNT_KEY)); 5387e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler 5388e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler // Find all the messages in the mailbox 5389e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler final String[] messageProjection = 53903dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler new String[] { MessageColumns._ID }; 5391e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler final String messageWhere = MessageColumns.MAILBOX_KEY + "=" + mailboxId; 5392e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler final Cursor messageCursor = db.query(Message.TABLE_NAME, messageProjection, messageWhere, 5393e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler null, null, null, null); 5394e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler int deletedCount = 0; 5395e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler 5396e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler // Kill them with fire 5397e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler while (messageCursor != null && messageCursor.moveToNext()) { 5398e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler final long messageId = messageCursor.getLong(messageCursor.getColumnIndex( 53993dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler MessageColumns._ID)); 5400e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler AttachmentUtilities.deleteAllAttachmentFiles(context, accountId, messageId); 5401e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler deletedCount += context.getContentResolver().delete( 5402e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, messageId), null, null); 5403e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler notifyUIMessage(messageId); 5404e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler } 5405e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler 5406e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler notifyUIFolder(mailboxId, accountId); 5407e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler return deletedCount; 5408e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler } 5409e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler 54109e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler public static final String PICKER_UI_ACCOUNT = "picker_ui_account"; 54119e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler public static final String PICKER_MAILBOX_TYPE = "picker_mailbox_type"; 54129e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler // Currently unused 54139e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler //public static final String PICKER_MESSAGE_ID = "picker_message_id"; 54149e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler public static final String PICKER_HEADER_ID = "picker_header_id"; 54159e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler 5416a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank private int pickFolder(Uri uri, int type, int headerId) { 5417c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank Context context = getContext(); 5418c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank Long acctId = Long.parseLong(uri.getLastPathSegment()); 5419c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank // For push imap, for example, we want the user to select the trash mailbox 5420c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank Cursor ac = query(uiUri("uiaccount", acctId), UIProvider.ACCOUNTS_PROJECTION, 5421c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank null, null, null); 5422c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank try { 5423c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank if (ac.moveToFirst()) { 5424c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank final com.android.mail.providers.Account uiAccount = 54257e75afadb152659e3a237c62e4d95cefb60e228dRay Chen com.android.mail.providers.Account.builder().buildFrom(ac); 5426c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank Intent intent = new Intent(context, FolderPickerActivity.class); 5427c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank intent.putExtra(PICKER_UI_ACCOUNT, uiAccount); 5428a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank intent.putExtra(PICKER_MAILBOX_TYPE, type); 5429a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank intent.putExtra(PICKER_HEADER_ID, headerId); 5430c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 5431c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank context.startActivity(intent); 5432c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank return 1; 5433c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } 5434c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank return 0; 5435c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } finally { 5436c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank ac.close(); 5437c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } 5438c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } 5439c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank 5440a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank private int pickTrashFolder(Uri uri) { 5441a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank return pickFolder(uri, Mailbox.TYPE_TRASH, R.string.trash_folder_selection_title); 5442a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank } 5443a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank 5444a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank private int pickSentFolder(Uri uri) { 5445a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank return pickFolder(uri, Mailbox.TYPE_SENT, R.string.sent_folder_selection_title); 5446a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank } 5447a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank 5448f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private Cursor uiUndo(String[] projection) { 5449f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // First see if we have any operations saved 5450f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // TODO: Make sure seq matches 5451f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (!mLastSequenceOps.isEmpty()) { 5452f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank try { 5453f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // TODO Always use this projection? Or what's passed in? 5454f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Not sure if UI wants it, but I'm making a cursor of convo uri's 54557fdde9bb4a24e931618a7a64227e2194c89034daScott Kennedy MatrixCursor c = new MatrixCursorWithCachedColumns( 5456f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank new String[] {UIProvider.ConversationColumns.URI}, 5457f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mLastSequenceOps.size()); 5458f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank for (ContentProviderOperation op: mLastSequenceOps) { 5459f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c.addRow(new String[] {op.getUri().toString()}); 5460f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5461f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Just apply the batch and we're done! 5462f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank applyBatch(mLastSequenceOps); 5463f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // But clear the operations 5464f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mLastSequenceOps.clear(); 5465f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return c; 5466f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } catch (OperationApplicationException e) { 5467582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler LogUtils.d(TAG, "applyBatch exception"); 5468f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5469f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 54707fdde9bb4a24e931618a7a64227e2194c89034daScott Kennedy return new MatrixCursorWithCachedColumns(projection, 0); 5471f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5472f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5473f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private void notifyUIConversation(Uri uri) { 5474f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank String id = uri.getLastPathSegment(); 5475f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Message msg = Message.restoreMessageWithId(getContext(), Long.parseLong(id)); 5476f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (msg != null) { 5477f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUIConversationMailbox(msg.mMailboxKey); 5478f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5479f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5480f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5481f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 5482f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Notify about the Mailbox id passed in 5483f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param id the Mailbox id to be notified 5484f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 5485f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private void notifyUIConversationMailbox(long id) { 5486f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUI(UIPROVIDER_CONVERSATION_NOTIFIER, Long.toString(id)); 5487f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Mailbox mailbox = Mailbox.restoreMailboxWithId(getContext(), id); 54880b6b83c6f90652b506c7761b923663c08f3af833Marc Blank if (mailbox == null) { 5489560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.w(TAG, "No mailbox for notification: " + id); 54900b6b83c6f90652b506c7761b923663c08f3af833Marc Blank return; 54910b6b83c6f90652b506c7761b923663c08f3af833Marc Blank } 5492f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Notify combined inbox... 5493f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mailbox.mType == Mailbox.TYPE_INBOX) { 5494f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUI(UIPROVIDER_CONVERSATION_NOTIFIER, 5495f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank EmailProvider.combinedMailboxId(Mailbox.TYPE_INBOX)); 5496f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5497f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyWidgets(id); 5498f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5499f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 55003e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook /** 5501c637bff1989e768f1ffe0f898bd803a9c78d0514Tony Mantler * Notify about the message id passed in 5502c637bff1989e768f1ffe0f898bd803a9c78d0514Tony Mantler * @param id the message id to be notified 5503c637bff1989e768f1ffe0f898bd803a9c78d0514Tony Mantler */ 5504c637bff1989e768f1ffe0f898bd803a9c78d0514Tony Mantler private void notifyUIMessage(long id) { 5505c637bff1989e768f1ffe0f898bd803a9c78d0514Tony Mantler notifyUI(UIPROVIDER_MESSAGE_NOTIFIER, id); 5506c637bff1989e768f1ffe0f898bd803a9c78d0514Tony Mantler } 5507c637bff1989e768f1ffe0f898bd803a9c78d0514Tony Mantler 5508c637bff1989e768f1ffe0f898bd803a9c78d0514Tony Mantler /** 550962604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler * Notify about the message id passed in 551062604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler * @param id the message id to be notified 551162604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler */ 551262604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler private void notifyUIMessage(String id) { 551362604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler notifyUI(UIPROVIDER_MESSAGE_NOTIFIER, id); 551462604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler } 551562604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler 551662604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler /** 55173e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook * Notify about the Account id passed in 55183e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook * @param id the Account id to be notified 55193e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook */ 55203e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook private void notifyUIAccount(long id) { 55213e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook // Notify on the specific account 55223e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook notifyUI(UIPROVIDER_ACCOUNT_NOTIFIER, Long.toString(id)); 55233e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook 55243e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook // Notify on the all accounts list 55253e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook notifyUI(UIPROVIDER_ALL_ACCOUNTS_NOTIFIER, null); 55263e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook } 55273e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook 5528e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler // TODO: temporary workaround for ConversationCursor 5529e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler @Deprecated 5530e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler private static final int NOTIFY_FOLDER_LOOP_MESSAGE_ID = 0; 5531e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler @Deprecated 5532e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler private Handler mFolderNotifierHandler; 5533e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler 5534fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu /** 5535fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu * Notify about a folder update. Because folder changes can affect the conversation cursor's 5536fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu * extras, the conversation must also be notified here. 5537fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu * @param folderId the folder id to be notified 5538c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu * @param accountId the account id to be notified (for folder list notification). 5539fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu */ 5540c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu private void notifyUIFolder(final String folderId, final long accountId) { 5541fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu notifyUI(UIPROVIDER_CONVERSATION_NOTIFIER, folderId); 5542fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu notifyUI(UIPROVIDER_FOLDER_NOTIFIER, folderId); 5543c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu if (accountId != Account.NO_ACCOUNT) { 5544fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu notifyUI(UIPROVIDER_FOLDERLIST_NOTIFIER, accountId); 5545fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu } 5546fc906340f9a3ef0246f4d693f0a2afc15af8cd6cTony Mantler 5547fc906340f9a3ef0246f4d693f0a2afc15af8cd6cTony Mantler // Notify for combined account too 5548fc906340f9a3ef0246f4d693f0a2afc15af8cd6cTony Mantler // TODO: might be nice to only notify when an inbox changes 5549fc906340f9a3ef0246f4d693f0a2afc15af8cd6cTony Mantler notifyUI(UIPROVIDER_FOLDER_NOTIFIER, 5550fc906340f9a3ef0246f4d693f0a2afc15af8cd6cTony Mantler getVirtualMailboxId(COMBINED_ACCOUNT_ID, Mailbox.TYPE_INBOX)); 5551fc906340f9a3ef0246f4d693f0a2afc15af8cd6cTony Mantler notifyUI(UIPROVIDER_FOLDERLIST_NOTIFIER, COMBINED_ACCOUNT_ID); 5552e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler 5553e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler // TODO: temporary workaround for ConversationCursor 5554e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler synchronized (this) { 5555e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler if (mFolderNotifierHandler == null) { 5556e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler mFolderNotifierHandler = new Handler(Looper.getMainLooper(), 5557e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler new Callback() { 5558e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler @Override 5559e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler public boolean handleMessage(final android.os.Message message) { 5560e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler final String folderId = (String) message.obj; 5561e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler LogUtils.d(TAG, "Notifying conversation Uri %s twice", folderId); 5562e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler notifyUI(UIPROVIDER_CONVERSATION_NOTIFIER, folderId); 5563e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler return true; 5564e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler } 5565e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler }); 5566e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler } 5567e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler } 5568e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler mFolderNotifierHandler.removeMessages(NOTIFY_FOLDER_LOOP_MESSAGE_ID); 5569e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler android.os.Message message = android.os.Message.obtain(mFolderNotifierHandler, 5570e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler NOTIFY_FOLDER_LOOP_MESSAGE_ID); 5571e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler message.obj = folderId; 5572e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler mFolderNotifierHandler.sendMessageDelayed(message, 2000); 5573fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu } 5574fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu 5575c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu private void notifyUIFolder(final long folderId, final long accountId) { 5576c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu notifyUIFolder(Long.toString(folderId), accountId); 5577fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu } 5578fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu 557905649dca2f59f28cd4295e041045a605badddb15Tony Mantler private void notifyUI(final Uri uri, final String id) { 55803e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook final Uri notifyUri = (id != null) ? uri.buildUpon().appendPath(id).build() : uri; 558100219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler final Set<Uri> batchNotifications = getBatchNotificationsSet(); 558200219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler if (batchNotifications != null) { 558300219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler batchNotifications.add(notifyUri); 558405649dca2f59f28cd4295e041045a605badddb15Tony Mantler } else { 558505649dca2f59f28cd4295e041045a605badddb15Tony Mantler getContext().getContentResolver().notifyChange(notifyUri, null); 558605649dca2f59f28cd4295e041045a605badddb15Tony Mantler } 5587f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5588f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5589f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private void notifyUI(Uri uri, long id) { 5590f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUI(uri, Long.toString(id)); 5591f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5592f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 559364cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu private Mailbox getMailbox(final Uri uri) { 559464cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu final long id = Long.parseLong(uri.getLastPathSegment()); 559564cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu return Mailbox.restoreMailboxWithId(getContext(), id); 559664cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu } 559764cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu 5598e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu /** 5599e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu * Create an android.accounts.Account object for this account. 5600e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu * @param accountId id of account to load. 5601e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu * @return an android.accounts.Account for this account, or null if we can't load it. 5602e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu */ 5603e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu private android.accounts.Account getAccountManagerAccount(final long accountId) { 5604e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu final Context context = getContext(); 5605e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu final Account account = Account.restoreAccountWithId(context, accountId); 5606e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu if (account == null) return null; 56075e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu return getAccountManagerAccount(context, account.mEmailAddress, 56085e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu account.getProtocol(context)); 56095e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 56105e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu 56115e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu /** 56125e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * Create an android.accounts.Account object for an emailAddress/protocol pair. 56135e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param context A {@link Context}. 56145e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param emailAddress The email address we're interested in. 56155e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param protocol The protocol we're intereted in. 56165e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @return an {@link android.accounts.Account} for this info. 56175e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu */ 56185e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private static android.accounts.Account getAccountManagerAccount(final Context context, 56195e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu final String emailAddress, final String protocol) { 56205e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu final EmailServiceInfo info = EmailServiceUtils.getServiceInfo(context, protocol); 562191e8e6f70921e65eabf128f14b5d43385b22f0a1Tony Mantler if (info == null) { 562291e8e6f70921e65eabf128f14b5d43385b22f0a1Tony Mantler return null; 562391e8e6f70921e65eabf128f14b5d43385b22f0a1Tony Mantler } 56245e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu return new android.accounts.Account(emailAddress, info.accountType); 5625e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu } 5626e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu 5627e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu /** 5628e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu * Update an account's periodic sync if the sync interval has changed. 5629e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu * @param accountId id for the account to update. 5630e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu * @param values the ContentValues for this update to the account. 5631e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu */ 5632e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu private void updateAccountSyncInterval(final long accountId, final ContentValues values) { 5633e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu final Integer syncInterval = values.getAsInteger(AccountColumns.SYNC_INTERVAL); 5634e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu if (syncInterval == null) { 5635e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu // No change to the sync interval. 5636e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu return; 5637e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu } 5638e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu final android.accounts.Account account = getAccountManagerAccount(accountId); 5639e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu if (account == null) { 5640e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu // Unable to load the account, or unknown protocol. 5641e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu return; 5642e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu } 5643e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu 56447afbeee47e1a82680c815f2fb8cfdba32d6b0b84Martin Hibdon LogUtils.d(TAG, "Setting sync interval for account %s to %d minutes", 56457afbeee47e1a82680c815f2fb8cfdba32d6b0b84Martin Hibdon accountId, syncInterval); 5646e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu 56476f2beeb59ae75ee26c78d99ded532acd87e1ff97Yu Ping Hu // First remove all existing periodic syncs. 56486f2beeb59ae75ee26c78d99ded532acd87e1ff97Yu Ping Hu final List<PeriodicSync> syncs = 56496f2beeb59ae75ee26c78d99ded532acd87e1ff97Yu Ping Hu ContentResolver.getPeriodicSyncs(account, EmailContent.AUTHORITY); 56506f2beeb59ae75ee26c78d99ded532acd87e1ff97Yu Ping Hu for (final PeriodicSync sync : syncs) { 56516f2beeb59ae75ee26c78d99ded532acd87e1ff97Yu Ping Hu ContentResolver.removePeriodicSync(account, EmailContent.AUTHORITY, sync.extras); 56526f2beeb59ae75ee26c78d99ded532acd87e1ff97Yu Ping Hu } 5653e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu 565405cf8a1c1f9b13aff75ec9e5c300fbf5c7aee27fYu Ping Hu // Only positive values of sync interval indicate periodic syncs. The value is in minutes, 565505cf8a1c1f9b13aff75ec9e5c300fbf5c7aee27fYu Ping Hu // while addPeriodicSync expects its time in seconds. 565605cf8a1c1f9b13aff75ec9e5c300fbf5c7aee27fYu Ping Hu if (syncInterval > 0) { 565705cf8a1c1f9b13aff75ec9e5c300fbf5c7aee27fYu Ping Hu ContentResolver.addPeriodicSync(account, EmailContent.AUTHORITY, Bundle.EMPTY, 565805cf8a1c1f9b13aff75ec9e5c300fbf5c7aee27fYu Ping Hu syncInterval * DateUtils.MINUTE_IN_MILLIS / DateUtils.SECOND_IN_MILLIS); 5659e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu } 5660e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu } 5661e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu 56625e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu /** 56635e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * Request a sync. 56645e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param account The {@link android.accounts.Account} we want to sync. 56655e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param mailboxId The mailbox id we want to sync (or one of the special constants in 56665e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * {@link Mailbox}). 56675e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param deltaMessageCount If we're requesting a load more, the number of additional messages 56685e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * to sync. 56695e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu */ 56705e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private static void startSync(final android.accounts.Account account, final long mailboxId, 56715e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu final int deltaMessageCount) { 567256aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon final Bundle extras = Mailbox.createSyncBundle(mailboxId); 56739e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); 56749e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu extras.putBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, true); 56759e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu extras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true); 56769e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu if (deltaMessageCount != 0) { 56779e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu extras.putInt(Mailbox.SYNC_EXTRA_DELTA_MESSAGE_COUNT, deltaMessageCount); 56789e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu } 567971737836e6be308f752cb95c955a03146b039a9cYu Ping Hu extras.putString(EmailServiceStatus.SYNC_EXTRAS_CALLBACK_URI, 568071737836e6be308f752cb95c955a03146b039a9cYu Ping Hu EmailContent.CONTENT_URI.toString()); 568171737836e6be308f752cb95c955a03146b039a9cYu Ping Hu extras.putString(EmailServiceStatus.SYNC_EXTRAS_CALLBACK_METHOD, 568271737836e6be308f752cb95c955a03146b039a9cYu Ping Hu SYNC_STATUS_CALLBACK_METHOD); 56839e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu ContentResolver.requestSync(account, EmailContent.AUTHORITY, extras); 5684921c04d2ac5df091fb3c5cfa823e6dc2fc6cdf5aMartin Hibdon LogUtils.i(TAG, "requestSync EmailProvider startSync %s, %s", account.toString(), 5685921c04d2ac5df091fb3c5cfa823e6dc2fc6cdf5aMartin Hibdon extras.toString()); 56869e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu } 56879e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu 56885e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu /** 56895e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * Request a sync. 56905e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param mailbox The {@link Mailbox} we want to sync. 56915e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param deltaMessageCount If we're requesting a load more, the number of additional messages 56925e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * to sync. 56935e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu */ 56945e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private void startSync(final Mailbox mailbox, final int deltaMessageCount) { 56955e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu final android.accounts.Account account = getAccountManagerAccount(mailbox.mAccountKey); 569691e8e6f70921e65eabf128f14b5d43385b22f0a1Tony Mantler if (account != null) { 569791e8e6f70921e65eabf128f14b5d43385b22f0a1Tony Mantler startSync(account, mailbox.mId, deltaMessageCount); 569891e8e6f70921e65eabf128f14b5d43385b22f0a1Tony Mantler } 56995e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 57005e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu 57015e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu /** 57025e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * Restart any push operations for an account. 57035e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param account The {@link android.accounts.Account} we're interested in. 57045e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu */ 57055e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private static void restartPush(final android.accounts.Account account) { 570656aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon final Bundle extras = new Bundle(); 570756aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); 570856aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon extras.putBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, true); 570956aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon extras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true); 571056aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon extras.putBoolean(Mailbox.SYNC_EXTRA_PUSH_ONLY, true); 571156aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon extras.putString(EmailServiceStatus.SYNC_EXTRAS_CALLBACK_URI, 571256aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon EmailContent.CONTENT_URI.toString()); 571356aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon extras.putString(EmailServiceStatus.SYNC_EXTRAS_CALLBACK_METHOD, 571456aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon SYNC_STATUS_CALLBACK_METHOD); 571556aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon ContentResolver.requestSync(account, EmailContent.AUTHORITY, extras); 571656aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon LogUtils.i(TAG, "requestSync EmailProvider startSync %s, %s", account.toString(), 571756aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon extras.toString()); 57185e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 57195e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu 572064cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu private Cursor uiFolderRefresh(final Mailbox mailbox, final int deltaMessageCount) { 57219e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu if (mailbox != null) { 57228c989772dfba08438650575f1ac2bb952bd56158Alon Albert RefreshStatusMonitor.getInstance(getContext()) 57238c989772dfba08438650575f1ac2bb952bd56158Alon Albert .monitorRefreshStatus(mailbox.mId, new RefreshStatusMonitor.Callback() { 57248c989772dfba08438650575f1ac2bb952bd56158Alon Albert @Override 57258c989772dfba08438650575f1ac2bb952bd56158Alon Albert public void onRefreshCompleted(long mailboxId, int result) { 57268c989772dfba08438650575f1ac2bb952bd56158Alon Albert final ContentValues values = new ContentValues(); 57278c989772dfba08438650575f1ac2bb952bd56158Alon Albert values.put(Mailbox.UI_SYNC_STATUS, UIProvider.SyncStatus.NO_SYNC); 57288c989772dfba08438650575f1ac2bb952bd56158Alon Albert values.put(Mailbox.UI_LAST_SYNC_RESULT, result); 57298c989772dfba08438650575f1ac2bb952bd56158Alon Albert mDatabase.update( 57308c989772dfba08438650575f1ac2bb952bd56158Alon Albert Mailbox.TABLE_NAME, 57318c989772dfba08438650575f1ac2bb952bd56158Alon Albert values, 57328c989772dfba08438650575f1ac2bb952bd56158Alon Albert WHERE_ID, 57338c989772dfba08438650575f1ac2bb952bd56158Alon Albert new String[] { String.valueOf(mailboxId) }); 57348c989772dfba08438650575f1ac2bb952bd56158Alon Albert notifyUIFolder(mailbox.mId, mailbox.mAccountKey); 57358c989772dfba08438650575f1ac2bb952bd56158Alon Albert } 57368c989772dfba08438650575f1ac2bb952bd56158Alon Albert 57378c989772dfba08438650575f1ac2bb952bd56158Alon Albert @Override 57388c989772dfba08438650575f1ac2bb952bd56158Alon Albert public void onTimeout(long mailboxId) { 57398c989772dfba08438650575f1ac2bb952bd56158Alon Albert // todo 57408c989772dfba08438650575f1ac2bb952bd56158Alon Albert } 57418c989772dfba08438650575f1ac2bb952bd56158Alon Albert }); 57429e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu startSync(mailbox, deltaMessageCount); 5743f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5744f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return null; 5745f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5746f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5747f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank //Number of additional messages to load when a user selects "Load more..." in POP/IMAP boxes 5748f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank public static final int VISIBLE_LIMIT_INCREMENT = 10; 5749f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank //Number of additional messages to load when a user selects "Load more..." in a search 5750f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank public static final int SEARCH_MORE_INCREMENT = 10; 5751f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 575264cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu private Cursor uiFolderLoadMore(final Mailbox mailbox) { 5753f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mailbox == null) return null; 5754f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mailbox.mType == Mailbox.TYPE_SEARCH) { 5755f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Ask for 10 more messages 5756f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mSearchParams.mOffset += SEARCH_MORE_INCREMENT; 575764cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu runSearchQuery(getContext(), mailbox.mAccountKey, mailbox.mId); 5758f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 575964cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu uiFolderRefresh(mailbox, VISIBLE_LIMIT_INCREMENT); 5760f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5761f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return null; 5762f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5763f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5764f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String SEARCH_MAILBOX_SERVER_ID = "__search_mailbox__"; 5765f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private SearchParams mSearchParams; 5766f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5767f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 5768f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Returns the search mailbox for the specified account, creating one if necessary 5769f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the search mailbox for the passed in account 5770f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 5771f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private Mailbox getSearchMailbox(long accountId) { 5772f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Context context = getContext(); 5773f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Mailbox m = Mailbox.restoreMailboxOfType(context, accountId, Mailbox.TYPE_SEARCH); 5774f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (m == null) { 5775f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank m = new Mailbox(); 5776f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank m.mAccountKey = accountId; 5777f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank m.mServerId = SEARCH_MAILBOX_SERVER_ID; 5778f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank m.mFlagVisible = false; 5779f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank m.mDisplayName = SEARCH_MAILBOX_SERVER_ID; 5780a54ee609cdb79ad3abdda2d7180a29617fa38610Yu Ping Hu m.mSyncInterval = 0; 5781f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank m.mType = Mailbox.TYPE_SEARCH; 5782f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank m.mFlags = Mailbox.FLAG_HOLDS_MAIL; 5783f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank m.mParentKey = Mailbox.NO_MAILBOX; 5784f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank m.save(context); 5785f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5786f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return m; 5787f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5788f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5789f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private void runSearchQuery(final Context context, final long accountId, 5790f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final long searchMailboxId) { 57919d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook LogUtils.d(TAG, "runSearchQuery. account: %d mailbox id: %d", 57929d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook accountId, searchMailboxId); 57939d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook 5794f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Start the search running in the background 57959d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook new AsyncTask<Void, Void, Void>() { 5796f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank @Override 57979d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook public Void doInBackground(Void... params) { 57982075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu final EmailServiceProxy service = 57992075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu EmailServiceUtils.getServiceForAccount(context, accountId); 58009d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook if (service != null) { 58019d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook try { 58025d47ee0f87208ab22c317abc87f615b6254cc852Tony Mantler final int totalCount = 58039d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook service.searchMessages(accountId, mSearchParams, searchMailboxId); 58045d47ee0f87208ab22c317abc87f615b6254cc852Tony Mantler 58055d47ee0f87208ab22c317abc87f615b6254cc852Tony Mantler // Save away the total count 58065d47ee0f87208ab22c317abc87f615b6254cc852Tony Mantler final ContentValues cv = new ContentValues(1); 58075d47ee0f87208ab22c317abc87f615b6254cc852Tony Mantler cv.put(MailboxColumns.TOTAL_COUNT, totalCount); 58085d47ee0f87208ab22c317abc87f615b6254cc852Tony Mantler update(ContentUris.withAppendedId(Mailbox.CONTENT_URI, searchMailboxId), cv, 58095d47ee0f87208ab22c317abc87f615b6254cc852Tony Mantler null, null); 58109d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook LogUtils.d(TAG, "EmailProvider#runSearchQuery. TotalCount to UI: %d", 58115d47ee0f87208ab22c317abc87f615b6254cc852Tony Mantler totalCount); 58129d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook } catch (RemoteException e) { 5813560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.e("searchMessages", "RemoteException", e); 5814f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5815f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 58169d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook return null; 58179d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook } 58189d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 5819f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5820f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 58217dad461e9e0c17bc909da2afbd8023cf7059d931Martin Hibdon // This handles an initial search query. More results are loaded using uiFolderLoadMore. 5822f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private Cursor uiSearch(Uri uri, String[] projection) { 58239d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook LogUtils.d(TAG, "runSearchQuery in search %s", uri); 5824f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final long accountId = Long.parseLong(uri.getLastPathSegment()); 5825f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5826f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // TODO: Check the actual mailbox 5827f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Mailbox inbox = Mailbox.restoreMailboxOfType(getContext(), accountId, Mailbox.TYPE_INBOX); 5828c0e2b147e09dd0bf15f19e63807b1b3bab798f50Marc Blank if (inbox == null) { 5829560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.w(Logging.LOG_TAG, "In uiSearch, inbox doesn't exist for account " 5830560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy + accountId); 58319d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook 5832c0e2b147e09dd0bf15f19e63807b1b3bab798f50Marc Blank return null; 5833c0e2b147e09dd0bf15f19e63807b1b3bab798f50Marc Blank } 5834f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5835f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank String filter = uri.getQueryParameter(UIProvider.SearchQueryParameters.QUERY); 5836f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (filter == null) { 5837f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank throw new IllegalArgumentException("No query parameter in search query"); 5838f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5839f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5840f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Find/create our search mailbox 5841f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Mailbox searchMailbox = getSearchMailbox(accountId); 5842f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final long searchMailboxId = searchMailbox.mId; 5843f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5844f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mSearchParams = new SearchParams(inbox.mId, filter, searchMailboxId); 5845f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5846f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final Context context = getContext(); 5847f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mSearchParams.mOffset == 0) { 58487dad461e9e0c17bc909da2afbd8023cf7059d931Martin Hibdon // TODO: This conditional is unnecessary, just two lines earlier we created 58497dad461e9e0c17bc909da2afbd8023cf7059d931Martin Hibdon // mSearchParams using a constructor that never sets mOffset. 58509d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook LogUtils.d(TAG, "deleting existing search results."); 58519d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook 5852f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Delete existing contents of search mailbox 5853f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ContentResolver resolver = context.getContentResolver(); 58543dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler resolver.delete(Message.CONTENT_URI, MessageColumns.MAILBOX_KEY + "=" + searchMailboxId, 5855f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank null); 58567d761f3de3b05657363a03c8afe3d4d1114a1b2fTony Mantler final ContentValues cv = new ContentValues(1); 5857f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // For now, use the actual query as the name of the mailbox 5858f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank cv.put(Mailbox.DISPLAY_NAME, mSearchParams.mFilter); 5859f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank resolver.update(ContentUris.withAppendedId(Mailbox.CONTENT_URI, searchMailboxId), 5860f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank cv, null, null); 5861f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5862f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5863f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Start the search running in the background 5864f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank runSearchQuery(context, accountId, searchMailboxId); 5865f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5866f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // This will look just like a "normal" folder 5867f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return uiQuery(UI_FOLDER, ContentUris.withAppendedId(Mailbox.CONTENT_URI, 5868b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy searchMailbox.mId), projection, false); 5869f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5870f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5871f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String MAILBOXES_FOR_ACCOUNT_SELECTION = MailboxColumns.ACCOUNT_KEY + "=?"; 5872f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5873f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 5874f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Delete an account and clean it up 5875f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 5876f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private int uiDeleteAccount(Uri uri) { 5877f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Context context = getContext(); 5878f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank long accountId = Long.parseLong(uri.getLastPathSegment()); 5879f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank try { 5880f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Get the account URI. 5881f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final Account account = Account.restoreAccountWithId(context, accountId); 5882f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (account == null) { 5883f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return 0; // Already deleted? 5884f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5885f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5886f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank deleteAccountData(context, accountId); 5887f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5888f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Now delete the account itself 5889f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank uri = ContentUris.withAppendedId(Account.CONTENT_URI, accountId); 5890f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank context.getContentResolver().delete(uri, null, null); 5891f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5892f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Clean up 5893f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank AccountBackupRestore.backup(context); 5894f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank SecurityPolicy.getInstance(context).reducePolicies(); 5895f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank MailActivityEmail.setServicesEnabledSync(context); 5896a60550e0eb08e0239d1fcea261b37ba592a35ba4Yu Ping Hu // TODO: We ought to reconcile accounts here, but some callers do this in a loop, 5897a60550e0eb08e0239d1fcea261b37ba592a35ba4Yu Ping Hu // which would be a problem when the first account reconciliation shuts us down. 5898f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return 1; 5899f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } catch (Exception e) { 5900560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.w(Logging.LOG_TAG, "Exception while deleting account", e); 5901f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5902f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return 0; 5903f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5904f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5905f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private int uiDeleteAccountData(Uri uri) { 5906f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Context context = getContext(); 5907f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank long accountId = Long.parseLong(uri.getLastPathSegment()); 5908f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Get the account URI. 5909f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final Account account = Account.restoreAccountWithId(context, accountId); 5910f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (account == null) { 5911f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return 0; // Already deleted? 5912f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5913f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank deleteAccountData(context, accountId); 5914f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return 1; 5915f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5916f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 59175057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux /** 5918974ccb1735e5ef697a5c4adc3f627582a03c89ecJames Lemieux * The method will no longer be needed after platform L releases. As emails are received from 59195057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux * various protocols the email addresses are decoded and intended to be stored in the database 59205057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux * in decoded form. The problem is that Exchange is a separate .apk and the old Exchange .apk 59215057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux * still attempts to store <strong>encoded</strong> email addresses. So, we decode here at the 59225057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux * Provider before writing to the database to ensure the addresses are written in decoded form. 59235057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux * 59245057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux * @param values the values to be written into the Message table 59255057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux */ 59265057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux private static void decodeEmailAddresses(ContentValues values) { 59275057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux if (values.containsKey(Message.MessageColumns.TO_LIST)) { 59285057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux final String to = values.getAsString(Message.MessageColumns.TO_LIST); 59295057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux values.put(Message.MessageColumns.TO_LIST, Address.fromHeaderToString(to)); 59305057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux } 59315057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux 59325057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux if (values.containsKey(Message.MessageColumns.FROM_LIST)) { 59335057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux final String from = values.getAsString(Message.MessageColumns.FROM_LIST); 59345057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux values.put(Message.MessageColumns.FROM_LIST, Address.fromHeaderToString(from)); 59355057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux } 59365057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux 59375057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux if (values.containsKey(Message.MessageColumns.CC_LIST)) { 59385057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux final String cc = values.getAsString(Message.MessageColumns.CC_LIST); 59395057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux values.put(Message.MessageColumns.CC_LIST, Address.fromHeaderToString(cc)); 59405057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux } 59415057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux 59425057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux if (values.containsKey(Message.MessageColumns.BCC_LIST)) { 59435057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux final String bcc = values.getAsString(Message.MessageColumns.BCC_LIST); 59445057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux values.put(Message.MessageColumns.BCC_LIST, Address.fromHeaderToString(bcc)); 59455057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux } 59465057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux 59475057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux if (values.containsKey(Message.MessageColumns.REPLY_TO_LIST)) { 59485057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux final String replyTo = values.getAsString(Message.MessageColumns.REPLY_TO_LIST); 59495057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux values.put(Message.MessageColumns.REPLY_TO_LIST, 59505057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux Address.fromHeaderToString(replyTo)); 59515057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux } 59525057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux } 59535057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux 59549a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu /** Projection used for getting email address for an account. */ 59559a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu private static final String[] ACCOUNT_EMAIL_PROJECTION = { AccountColumns.EMAIL_ADDRESS }; 59569a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu 5957b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static void deleteAccountData(Context context, long accountId) { 59589a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu // We will delete PIM data, but by the time the asynchronous call to do that happens, 59599a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu // the account may have been deleted from the DB. Therefore we have to get the email 59609a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu // address now and send that, rather than the account id. 59619a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu final String emailAddress = Utility.getFirstRowString(context, Account.CONTENT_URI, 59629a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu ACCOUNT_EMAIL_PROJECTION, Account.ID_SELECTION, 59639a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu new String[] {Long.toString(accountId)}, null, 0); 59649a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu if (emailAddress == null) { 59659a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu LogUtils.e(TAG, "Could not find email address for account %d", accountId); 59669a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu } 59679a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu 5968f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Delete synced attachments 5969f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank AttachmentUtilities.deleteAllAccountAttachmentFiles(context, accountId); 5970f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5971aa0ca16a27e4a56a029e5cdebf96de5723bd84b6Yu Ping Hu // Delete all mailboxes. 5972f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ContentResolver resolver = context.getContentResolver(); 5973f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank String[] accountIdArgs = new String[] { Long.toString(accountId) }; 5974aa0ca16a27e4a56a029e5cdebf96de5723bd84b6Yu Ping Hu resolver.delete(Mailbox.CONTENT_URI, MAILBOXES_FOR_ACCOUNT_SELECTION, accountIdArgs); 5975f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5976aa0ca16a27e4a56a029e5cdebf96de5723bd84b6Yu Ping Hu // Delete account sync key. 5977aa0ca16a27e4a56a029e5cdebf96de5723bd84b6Yu Ping Hu final ContentValues cv = new ContentValues(); 59783dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler cv.putNull(AccountColumns.SYNC_KEY); 5979f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank resolver.update(Account.CONTENT_URI, cv, Account.ID_SELECTION, accountIdArgs); 5980f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5981c5f5a14ae9095f76d8e8c411cfd8f8e0e8970aa2Martin Hibdon // Delete PIM data (contacts, calendar), stop syncs, etc. if applicable 59829a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu if (emailAddress != null) { 5983c5f5a14ae9095f76d8e8c411cfd8f8e0e8970aa2Martin Hibdon final IEmailService service = 5984c5f5a14ae9095f76d8e8c411cfd8f8e0e8970aa2Martin Hibdon EmailServiceUtils.getServiceForAccount(context, accountId); 5985c5f5a14ae9095f76d8e8c411cfd8f8e0e8970aa2Martin Hibdon if (service != null) { 5986c5f5a14ae9095f76d8e8c411cfd8f8e0e8970aa2Martin Hibdon try { 59877afbeee47e1a82680c815f2fb8cfdba32d6b0b84Martin Hibdon service.deleteExternalAccountPIMData(emailAddress); 5988c5f5a14ae9095f76d8e8c411cfd8f8e0e8970aa2Martin Hibdon } catch (final RemoteException e) { 5989c5f5a14ae9095f76d8e8c411cfd8f8e0e8970aa2Martin Hibdon // Can't do anything about this 5990c5f5a14ae9095f76d8e8c411cfd8f8e0e8970aa2Martin Hibdon } 5991c5f5a14ae9095f76d8e8c411cfd8f8e0e8970aa2Martin Hibdon } 5992f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5993f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5994f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5995f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private int[] mSavedWidgetIds = new int[0]; 5996ea2edb637036a7368b6ef82a0aafdb1a790e26e9Mark Wei private final ArrayList<Long> mWidgetNotifyMailboxes = new ArrayList<Long>(); 5997f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private AppWidgetManager mAppWidgetManager; 5998f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private ComponentName mEmailComponent; 5999f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 6000f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private void notifyWidgets(long mailboxId) { 6001f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Context context = getContext(); 6002f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Lazily initialize these 6003f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mAppWidgetManager == null) { 6004f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mAppWidgetManager = AppWidgetManager.getInstance(context); 600537aa460ef7ee4d996e04b24a181846879fb6b601Tony Mantler mEmailComponent = new ComponentName(context, WidgetProvider.getProviderName(context)); 6006f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6007f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 6008f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // See if we have to populate our array of mailboxes used in widgets 6009f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank int[] widgetIds = mAppWidgetManager.getAppWidgetIds(mEmailComponent); 6010f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (!Arrays.equals(widgetIds, mSavedWidgetIds)) { 6011f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mSavedWidgetIds = widgetIds; 6012f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank String[][] widgetInfos = BaseWidgetProvider.getWidgetInfo(context, widgetIds); 6013f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // widgetInfo now has pairs of account uri/folder uri 6014f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mWidgetNotifyMailboxes.clear(); 6015f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank for (String[] widgetInfo: widgetInfos) { 6016f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank try { 601737aa460ef7ee4d996e04b24a181846879fb6b601Tony Mantler if (widgetInfo == null || TextUtils.isEmpty(widgetInfo[1])) continue; 6018f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank long id = Long.parseLong(Uri.parse(widgetInfo[1]).getLastPathSegment()); 6019f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (!isCombinedMailbox(id)) { 6020f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // For a regular mailbox, just add it to the list 6021f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (!mWidgetNotifyMailboxes.contains(id)) { 6022f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mWidgetNotifyMailboxes.add(id); 6023f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6024f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 6025f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank switch (getVirtualMailboxType(id)) { 6026f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // We only handle the combined inbox in widgets 6027f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case Mailbox.TYPE_INBOX: 6028f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Cursor c = query(Mailbox.CONTENT_URI, Mailbox.ID_PROJECTION, 6029f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank MailboxColumns.TYPE + "=?", 6030f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank new String[] {Integer.toString(Mailbox.TYPE_INBOX)}, null); 6031f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank try { 6032f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank while (c.moveToNext()) { 6033f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mWidgetNotifyMailboxes.add( 6034f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c.getLong(Mailbox.ID_PROJECTION_COLUMN)); 6035f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6036f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } finally { 6037f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c.close(); 6038f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6039f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 6040f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6041f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6042f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } catch (NumberFormatException e) { 6043f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Move along 6044f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6045f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6046f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6047f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 6048f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // If our mailbox needs to be notified, do so... 6049f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mWidgetNotifyMailboxes.contains(mailboxId)) { 6050f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Intent intent = new Intent(Utils.ACTION_NOTIFY_DATASET_CHANGED); 6051f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank intent.putExtra(Utils.EXTRA_FOLDER_URI, uiUri("uifolder", mailboxId)); 6052f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank intent.setType(EMAIL_APP_MIME_TYPE); 6053f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank context.sendBroadcast(intent); 6054f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6055f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6056af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank 60579e521deb6bb525b33365cc2926cb2d0faa7095e2Scott Kennedy @Override 6058af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 6059af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank Context context = getContext(); 6060af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank writer.println("Installed services:"); 6061af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank for (EmailServiceInfo info: EmailServiceUtils.getServiceInfoList(context)) { 6062af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank writer.println(" " + info); 6063af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank } 6064af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank writer.println(); 6065af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank writer.println("Accounts: "); 6066af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank Cursor cursor = query(Account.CONTENT_URI, Account.CONTENT_PROJECTION, null, null, null); 6067af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank if (cursor.getCount() == 0) { 6068af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank writer.println(" None"); 6069af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank } 6070af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank try { 6071af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank while (cursor.moveToNext()) { 6072af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank Account account = new Account(); 6073af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank account.restore(cursor); 6074af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank writer.println(" Account " + account.mDisplayName); 6075af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank HostAuth hostAuth = 6076af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank HostAuth.restoreHostAuthWithId(context, account.mHostAuthKeyRecv); 6077af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank if (hostAuth != null) { 6078af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank writer.println(" Protocol = " + hostAuth.mProtocol + 6079af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank (TextUtils.isEmpty(account.mProtocolVersion) ? "" : " version " + 6080af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank account.mProtocolVersion)); 6081af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank } 6082af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank } 6083af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank } finally { 6084af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank cursor.close(); 6085af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank } 6086af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank } 6087feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert 6088feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert synchronized public Handler getDelayedSyncHandler() { 6089feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert if (mDelayedSyncHandler == null) { 6090feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert mDelayedSyncHandler = new Handler(getContext().getMainLooper(), new Callback() { 6091feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert @Override 6092feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert public boolean handleMessage(android.os.Message msg) { 6093feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert synchronized (mDelayedSyncRequests) { 6094feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert final SyncRequestMessage request = (SyncRequestMessage) msg.obj; 6095b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler // TODO: It's possible that the account is deleted by the time we get here 6096b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler // It would be nice if we could validate it before trying to sync 6097b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler final android.accounts.Account account = request.mAccount; 609856aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon final Bundle extras = Mailbox.createSyncBundle(request.mMailboxId); 6099b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler ContentResolver.requestSync(account, request.mAuthority, extras); 6100921c04d2ac5df091fb3c5cfa823e6dc2fc6cdf5aMartin Hibdon LogUtils.i(TAG, "requestSync getDelayedSyncHandler %s, %s", 6101921c04d2ac5df091fb3c5cfa823e6dc2fc6cdf5aMartin Hibdon account.toString(), extras.toString()); 6102feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert mDelayedSyncRequests.remove(request); 6103feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert return true; 6104feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 6105feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 6106feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert }); 6107feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 6108feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert return mDelayedSyncHandler; 6109feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 6110feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert 6111feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert private class SyncRequestMessage { 6112feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert private final String mAuthority; 6113b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler private final android.accounts.Account mAccount; 6114feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert private final long mMailboxId; 6115feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert 6116b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler private SyncRequestMessage(final String authority, final android.accounts.Account account, 6117b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler final long mailboxId) { 6118feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert mAuthority = authority; 6119b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler mAccount = account; 6120feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert mMailboxId = mailboxId; 6121feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 6122feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert 6123feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert @Override 6124feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert public boolean equals(Object o) { 6125feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert if (this == o) { 6126feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert return true; 6127feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 6128feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert if (o == null || getClass() != o.getClass()) { 6129feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert return false; 6130feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 6131feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert 6132feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert SyncRequestMessage that = (SyncRequestMessage) o; 6133feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert 6134b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler return mAccount.equals(that.mAccount) 6135b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler && mMailboxId == that.mMailboxId 6136b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler && mAuthority.equals(that.mAuthority); 6137feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 6138feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert 6139feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert @Override 6140feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert public int hashCode() { 6141feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert int result = mAuthority.hashCode(); 6142b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler result = 31 * result + mAccount.hashCode(); 6143feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert result = 31 * result + (int) (mMailboxId ^ (mMailboxId >>> 32)); 6144feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert return result; 6145feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 6146feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 6147c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler 6148c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler @Override 6149c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { 6150c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler if (PreferenceKeys.REMOVAL_ACTION.equals(key) || 6151c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler PreferenceKeys.CONVERSATION_LIST_SWIPE.equals(key) || 6152c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler PreferenceKeys.SHOW_SENDER_IMAGES.equals(key) || 6153c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler PreferenceKeys.DEFAULT_REPLY_ALL.equals(key) || 6154c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler PreferenceKeys.CONVERSATION_OVERVIEW_MODE.equals(key) || 6155c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler PreferenceKeys.AUTO_ADVANCE_MODE.equals(key) || 6156c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler PreferenceKeys.SNAP_HEADER_MODE.equals(key) || 6157c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler PreferenceKeys.CONFIRM_DELETE.equals(key) || 6158c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler PreferenceKeys.CONFIRM_ARCHIVE.equals(key) || 6159c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler PreferenceKeys.CONFIRM_SEND.equals(key)) { 6160c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler notifyUI(UIPROVIDER_ALL_ACCOUNTS_NOTIFIER, null); 6161c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler } 6162c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler } 6163f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler} 6164