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; 36bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrookimport android.content.pm.PackageManager; 3703dc3f22d151d0cddc6487429786a708de813d67Tony Mantlerimport android.content.res.Configuration; 385a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrookimport android.content.res.Resources; 396e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport android.database.ContentObserver; 406e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport android.database.Cursor; 41f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport android.database.CursorWrapper; 42901faf1bfb3473b4e40ccd82dab3f3f99eb599bbYu Ping Huimport android.database.DatabaseUtils; 436e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport android.database.MatrixCursor; 44f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport android.database.MergeCursor; 456e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport android.database.sqlite.SQLiteDatabase; 466e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport android.database.sqlite.SQLiteException; 472f288864b621cfb5aee44eda27df463460d33dd3Tony Mantlerimport android.database.sqlite.SQLiteStatement; 486e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport android.net.Uri; 499d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrookimport android.os.AsyncTask; 505a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrookimport android.os.Binder; 515181cd6d4a60ed0b7dbed022484d299a3e91f0daYu Ping Huimport android.os.Build; 52f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport android.os.Bundle; 53feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albertimport android.os.Handler; 54feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albertimport android.os.Handler.Callback; 55e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantlerimport android.os.Looper; 56f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport android.os.Parcel; 575a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrookimport android.os.ParcelFileDescriptor; 58f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport android.os.RemoteException; 59f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport android.provider.BaseColumns; 606e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport android.text.TextUtils; 6164cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Huimport android.text.format.DateUtils; 629b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Huimport android.util.Base64; 63feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albertimport android.util.Log; 64c6953b77552d4cb71776cf0537dc226029381628Tony Mantlerimport android.util.SparseArray; 656e418aa41a17136be0dddb816d843428a0a1e722Marc Blank 66f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.common.content.ProjectionMap; 6751c653646d14d841fbe527aee9fab7a1886338f8Martin Hibdonimport com.android.email.DebugUtils; 6840236a89316ab2151a8c93de0e286c2f1a9a8d37James Lemieuximport com.android.email.NotificationController; 6940236a89316ab2151a8c93de0e286c2f1a9a8d37James Lemieuximport com.android.email.NotificationControllerCreatorHolder; 709dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onukiimport com.android.email.Preferences; 71f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.email.R; 72f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.email.SecurityPolicy; 738209d6c081243d58cf9957c1900e550b440af431Martin Hibdonimport com.android.email.activity.setup.AccountSecurity; 7482a207132b34377d532f19882f5bfc70bc657da0Tony Mantlerimport com.android.email.activity.setup.AccountSettingsUtils; 753d16e5d4b994d92db51962c8c461c53bee04309fAnthony Leeimport com.android.email.service.AttachmentService; 76f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.email.service.EmailServiceUtils; 77f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.email.service.EmailServiceUtils.EmailServiceInfo; 78bfac9f2e8a13f6c719608a6948203bbef921c99fMakoto Onukiimport com.android.emailcommon.Logging; 79f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.emailcommon.mail.Address; 80f5418f1f93b02e7fab9f15eb201800b65510998eMarc Blankimport com.android.emailcommon.provider.Account; 810b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdonimport com.android.emailcommon.provider.Credential; 82a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent; 83a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.AccountColumns; 84a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.Attachment; 85a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.AttachmentColumns; 86a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.Body; 87a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.BodyColumns; 88feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albertimport com.android.emailcommon.provider.EmailContent.HostAuthColumns; 89a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.MailboxColumns; 90a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.Message; 91a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.MessageColumns; 92aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blankimport com.android.emailcommon.provider.EmailContent.PolicyColumns; 933dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantlerimport com.android.emailcommon.provider.EmailContent.QuickResponseColumns; 94a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.SyncColumns; 9512b82d9374947c9268217f45befe8a74bd9b60d7Ben Komaloimport com.android.emailcommon.provider.HostAuth; 9653ea83ebf91f820692e8fa8e781f5cc982dd94dbBen Komaloimport com.android.emailcommon.provider.Mailbox; 97f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdonimport com.android.emailcommon.provider.MailboxUtilities; 98ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Huimport com.android.emailcommon.provider.MessageChangeLogTable; 99ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Huimport com.android.emailcommon.provider.MessageMove; 100ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Huimport com.android.emailcommon.provider.MessageStateChange; 101aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blankimport com.android.emailcommon.provider.Policy; 1026e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport com.android.emailcommon.provider.QuickResponse; 103f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.emailcommon.service.EmailServiceProxy; 10471737836e6be308f752cb95c955a03146b039a9cYu Ping Huimport com.android.emailcommon.service.EmailServiceStatus; 105f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.emailcommon.service.IEmailService; 106f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.emailcommon.service.SearchParams; 107f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.emailcommon.utility.AttachmentUtilities; 1083f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdonimport com.android.emailcommon.utility.EmailAsyncTask; 109bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrookimport com.android.emailcommon.utility.IntentUtilities; 110f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.emailcommon.utility.Utility; 1116eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sappersteinimport com.android.ex.photo.provider.PhotoContract; 1122f9c66d08b13c1ed4eb7d2f70baa98116ac5fcfbScott Kennedyimport com.android.mail.preferences.MailPrefs; 113c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantlerimport com.android.mail.preferences.MailPrefs.PreferenceKeys; 114709b4633eda47f81a689c3be623660d74cdad904Mindy Pereiraimport com.android.mail.providers.Folder; 11568a3607895963854637215a405145f190d6458f0Andy Huangimport com.android.mail.providers.FolderList; 11624a489c3de70a02bccbf2cfc54b36a385d72c337Alice Yangimport com.android.mail.providers.Settings; 117f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.mail.providers.UIProvider; 118f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.mail.providers.UIProvider.AccountCapabilities; 119b7e0834121d564982c0389c87df775ba311429d4Tony Mantlerimport com.android.mail.providers.UIProvider.AccountColumns.SettingsColumns; 120f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.mail.providers.UIProvider.AccountCursorExtraKeys; 121f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.mail.providers.UIProvider.ConversationPriority; 122f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.mail.providers.UIProvider.ConversationSendingState; 123f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.mail.providers.UIProvider.DraftType; 1249a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrookimport com.android.mail.utils.AttachmentUtils; 125560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedyimport com.android.mail.utils.LogTag; 126f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.mail.utils.LogUtils; 1277fdde9bb4a24e931618a7a64227e2194c89034daScott Kennedyimport com.android.mail.utils.MatrixCursorWithCachedColumns; 128f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.mail.utils.MatrixCursorWithExtra; 12911472650d1fce7548939d311c4434128930c18baPaul Westbrookimport com.android.mail.utils.MimeType; 130f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.mail.utils.Utils; 131f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport com.android.mail.widget.BaseWidgetProvider; 132b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrookimport com.google.common.collect.ImmutableMap; 13351693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrookimport com.google.common.collect.ImmutableSet; 13405649dca2f59f28cd4295e041045a605badddb15Tony Mantlerimport com.google.common.collect.Sets; 135f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 1360e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blankimport java.io.File; 137af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blankimport java.io.FileDescriptor; 1385a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrookimport java.io.FileNotFoundException; 1397525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantlerimport java.io.FileWriter; 1402f288864b621cfb5aee44eda27df463460d33dd3Tony Mantlerimport java.io.IOException; 141af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blankimport java.io.PrintWriter; 14284969fb580f569c0e3625a3c59a71d2909ae198dFred Quintanaimport java.util.ArrayList; 1436e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport java.util.Arrays; 14482a207132b34377d532f19882f5bfc70bc657da0Tony Mantlerimport java.util.Collection; 145feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albertimport java.util.HashSet; 1465d7ff8577d7efd938390ddc5d5476717203d0a55Marc Blankimport java.util.List; 147ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Huimport java.util.Locale; 1486e418aa41a17136be0dddb816d843428a0a1e722Marc Blankimport java.util.Map; 14951693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrookimport java.util.Set; 150f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blankimport java.util.regex.Pattern; 15184969fb580f569c0e3625a3c59a71d2909ae198dFred Quintana 152c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantlerpublic class EmailProvider extends ContentProvider 153c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler implements SharedPreferences.OnSharedPreferenceChangeListener { 154f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 155560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy private static final String TAG = LogTag.getLogTag(); 156f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 157feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // Time to delay upsync requests. 158feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert public static final long SYNC_DELAY_MILLIS = 30 * DateUtils.SECOND_IN_MILLIS; 159feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert 1607e5df63fc9771c7950d3f95da17cfb112ebbf7f3Marc Blank public static String EMAIL_APP_MIME_TYPE; 161f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 16217d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie // exposed for testing 16317d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie public static final String DATABASE_NAME = "EmailProvider.db"; 16417d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie public static final String BODY_DATABASE_NAME = "EmailProviderBody.db"; 16517d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie 16682a207132b34377d532f19882f5bfc70bc657da0Tony Mantler // We don't back up to the backup database anymore, just keep this constant here so we can 16782a207132b34377d532f19882f5bfc70bc657da0Tony Mantler // delete the old backups and trigger a new backup to the account manager 16882a207132b34377d532f19882f5bfc70bc657da0Tony Mantler @Deprecated 169b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static final String BACKUP_DATABASE_NAME = "EmailProviderBackup.db"; 17082a207132b34377d532f19882f5bfc70bc657da0Tony Mantler private static final String ACCOUNT_MANAGER_JSON_TAG = "accountJson"; 17109fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank 172bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook 173bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook private static final String PREFERENCE_FRAGMENT_CLASS_NAME = 174bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook "com.android.email.activity.setup.AccountSettingsFragment"; 17507676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook /** 17607676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook * Notifies that changes happened. Certain UI components, e.g., widgets, can register for this 17707676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook * {@link android.content.Intent} and update accordingly. However, this can be very broad and 17807676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook * is NOT the preferred way of getting notification. 17907676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook */ 180b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static final String ACTION_NOTIFY_MESSAGE_LIST_DATASET_CHANGED = 181f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "com.android.email.MESSAGE_LIST_DATASET_CHANGED"; 18207676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook 183b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static final String EMAIL_MESSAGE_MIME_TYPE = 184c81bef672089654e6da3babbeb0172bd636564b2Marc Blank "vnd.android.cursor.item/email-message"; 185b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static final String EMAIL_ATTACHMENT_MIME_TYPE = 18609fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank "vnd.android.cursor.item/email-attachment"; 18709fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank 188bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy /** Appended to the notification URI for delete operations */ 189b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static final String NOTIFICATION_OP_DELETE = "delete"; 190bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy /** Appended to the notification URI for insert operations */ 191b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static final String NOTIFICATION_OP_INSERT = "insert"; 192bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy /** Appended to the notification URI for update operations */ 193b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static final String NOTIFICATION_OP_UPDATE = "update"; 194bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy 19564cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu /** The query string to trigger a folder refresh. */ 1960053401d07cd11f19c63dfbc3942d027b4067de8Tony Mantler protected static String QUERY_UIREFRESH = "uirefresh"; 19764cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu 198ef83299b99288c00b9d661260d19715e73e6889cMarc Blank // Definitions for our queries looking for orphaned messages 199ef83299b99288c00b9d661260d19715e73e6889cMarc Blank private static final String[] ORPHANS_PROJECTION 2003dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler = new String[] {MessageColumns._ID, MessageColumns.MAILBOX_KEY}; 201ef83299b99288c00b9d661260d19715e73e6889cMarc Blank private static final int ORPHANS_ID = 0; 202ef83299b99288c00b9d661260d19715e73e6889cMarc Blank private static final int ORPHANS_MAILBOX_KEY = 1; 203ef83299b99288c00b9d661260d19715e73e6889cMarc Blank 2043dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler private static final String WHERE_ID = BaseColumns._ID + "=?"; 205f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 206f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int ACCOUNT_BASE = 0; 207f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int ACCOUNT = ACCOUNT_BASE; 2087bcf1882bcb33b690f0b104f7605c9a6da39f344Makoto Onuki private static final int ACCOUNT_ID = ACCOUNT_BASE + 1; 20982a207132b34377d532f19882f5bfc70bc657da0Tony Mantler private static final int ACCOUNT_CHECK = ACCOUNT_BASE + 2; 21082a207132b34377d532f19882f5bfc70bc657da0Tony Mantler private static final int ACCOUNT_PICK_TRASH_FOLDER = ACCOUNT_BASE + 3; 21182a207132b34377d532f19882f5bfc70bc657da0Tony Mantler private static final int ACCOUNT_PICK_SENT_FOLDER = ACCOUNT_BASE + 4; 212f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 213f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int MAILBOX_BASE = 0x1000; 214f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int MAILBOX = MAILBOX_BASE; 2157bcf1882bcb33b690f0b104f7605c9a6da39f344Makoto Onuki private static final int MAILBOX_ID = MAILBOX_BASE + 1; 216503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu private static final int MAILBOX_NOTIFICATION = MAILBOX_BASE + 2; 217503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu private static final int MAILBOX_MOST_RECENT_MESSAGE = MAILBOX_BASE + 3; 218503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu private static final int MAILBOX_MESSAGE_COUNT = MAILBOX_BASE + 4; 219f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 220f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int MESSAGE_BASE = 0x2000; 221f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int MESSAGE = MESSAGE_BASE; 2224119218e2fd64341ac946fb8f2cbdb796a444cb8Andrew Stadler private static final int MESSAGE_ID = MESSAGE_BASE + 1; 2234119218e2fd64341ac946fb8f2cbdb796a444cb8Andrew Stadler private static final int SYNCED_MESSAGE_ID = MESSAGE_BASE + 2; 22400287c4d8f54ae07c89bb3893f440acdca09d728Marc Blank private static final int MESSAGE_SELECTION = MESSAGE_BASE + 3; 225ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu private static final int MESSAGE_MOVE = MESSAGE_BASE + 4; 226ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu private static final int MESSAGE_STATE_CHANGE = MESSAGE_BASE + 5; 227f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 228f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int ATTACHMENT_BASE = 0x3000; 229f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int ATTACHMENT = ATTACHMENT_BASE; 2307bcf1882bcb33b690f0b104f7605c9a6da39f344Makoto Onuki private static final int ATTACHMENT_ID = ATTACHMENT_BASE + 1; 2317bcf1882bcb33b690f0b104f7605c9a6da39f344Makoto Onuki private static final int ATTACHMENTS_MESSAGE_ID = ATTACHMENT_BASE + 2; 2325a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook private static final int ATTACHMENTS_CACHED_FILE_ACCESS = ATTACHMENT_BASE + 3; 233f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 234f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int HOSTAUTH_BASE = 0x4000; 235f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int HOSTAUTH = HOSTAUTH_BASE; 236f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int HOSTAUTH_ID = HOSTAUTH_BASE + 1; 237f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 238e34525d0f026a7467cee1cb5fddcf25ba6f35207Marc Blank private static final int UPDATED_MESSAGE_BASE = 0x5000; 239e34525d0f026a7467cee1cb5fddcf25ba6f35207Marc Blank private static final int UPDATED_MESSAGE = UPDATED_MESSAGE_BASE; 240f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank private static final int UPDATED_MESSAGE_ID = UPDATED_MESSAGE_BASE + 1; 241f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 242f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank private static final int DELETED_MESSAGE_BASE = 0x6000; 243f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank private static final int DELETED_MESSAGE = DELETED_MESSAGE_BASE; 244f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank private static final int DELETED_MESSAGE_ID = DELETED_MESSAGE_BASE + 1; 245f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 246aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank private static final int POLICY_BASE = 0x7000; 247aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank private static final int POLICY = POLICY_BASE; 248aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank private static final int POLICY_ID = POLICY_BASE + 1; 249aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank 2505a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo private static final int QUICK_RESPONSE_BASE = 0x8000; 2515a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo private static final int QUICK_RESPONSE = QUICK_RESPONSE_BASE; 2525a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo private static final int QUICK_RESPONSE_ID = QUICK_RESPONSE_BASE + 1; 2535a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo private static final int QUICK_RESPONSE_ACCOUNT_ID = QUICK_RESPONSE_BASE + 2; 2545a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo 255f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final int UI_BASE = 0x9000; 256f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final int UI_FOLDERS = UI_BASE; 257f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final int UI_SUBFOLDERS = UI_BASE + 1; 258f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final int UI_MESSAGES = UI_BASE + 2; 259f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final int UI_MESSAGE = UI_BASE + 3; 2608e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu private static final int UI_UNDO = UI_BASE + 4; 2618e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu private static final int UI_FOLDER_REFRESH = UI_BASE + 5; 2628e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu private static final int UI_FOLDER = UI_BASE + 6; 2638e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu private static final int UI_ACCOUNT = UI_BASE + 7; 2648e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu private static final int UI_ACCTS = UI_BASE + 8; 2658e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu private static final int UI_ATTACHMENTS = UI_BASE + 9; 2668e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu private static final int UI_ATTACHMENT = UI_BASE + 10; 2678cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private static final int UI_ATTACHMENT_BY_CID = UI_BASE + 11; 2688cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private static final int UI_SEARCH = UI_BASE + 12; 2698cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private static final int UI_ACCOUNT_DATA = UI_BASE + 13; 2708cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private static final int UI_FOLDER_LOAD_MORE = UI_BASE + 14; 2718cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private static final int UI_CONVERSATION = UI_BASE + 15; 2728cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private static final int UI_RECENT_FOLDERS = UI_BASE + 16; 2738cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private static final int UI_DEFAULT_RECENT_FOLDERS = UI_BASE + 17; 2748cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private static final int UI_FULL_FOLDERS = UI_BASE + 18; 2758cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private static final int UI_ALL_FOLDERS = UI_BASE + 19; 2768cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private static final int UI_PURGE_FOLDER = UI_BASE + 20; 277f837c474a44f421b4f02bcb5cf3a67fccbced2d2Tony Mantler private static final int UI_INBOX = UI_BASE + 21; 278b7e0834121d564982c0389c87df775ba311429d4Tony Mantler private static final int UI_ACCTSETTINGS = UI_BASE + 22; 279f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 280c6953b77552d4cb71776cf0537dc226029381628Tony Mantler private static final int BODY_BASE = 0xA000; 281f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int BODY = BODY_BASE; 282f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int BODY_ID = BODY_BASE + 1; 2832f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler private static final int BODY_HTML = BODY_BASE + 2; 2842f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler private static final int BODY_TEXT = BODY_BASE + 3; 285f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 2860b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon private static final int CREDENTIAL_BASE = 0xB000; 2870b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon private static final int CREDENTIAL = CREDENTIAL_BASE; 2880b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon private static final int CREDENTIAL_ID = CREDENTIAL_BASE + 1; 2890b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon 290f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler private static final int BASE_SHIFT = 12; // 12 bits to the base type: 0, 0x1000, 0x2000, etc. 291f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 292c6953b77552d4cb71776cf0537dc226029381628Tony Mantler private static final SparseArray<String> TABLE_NAMES; 293c6953b77552d4cb71776cf0537dc226029381628Tony Mantler static { 294c6953b77552d4cb71776cf0537dc226029381628Tony Mantler SparseArray<String> array = new SparseArray<String>(11); 295c6953b77552d4cb71776cf0537dc226029381628Tony Mantler array.put(ACCOUNT_BASE >> BASE_SHIFT, Account.TABLE_NAME); 296c6953b77552d4cb71776cf0537dc226029381628Tony Mantler array.put(MAILBOX_BASE >> BASE_SHIFT, Mailbox.TABLE_NAME); 297c6953b77552d4cb71776cf0537dc226029381628Tony Mantler array.put(MESSAGE_BASE >> BASE_SHIFT, Message.TABLE_NAME); 298c6953b77552d4cb71776cf0537dc226029381628Tony Mantler array.put(ATTACHMENT_BASE >> BASE_SHIFT, Attachment.TABLE_NAME); 299c6953b77552d4cb71776cf0537dc226029381628Tony Mantler array.put(HOSTAUTH_BASE >> BASE_SHIFT, HostAuth.TABLE_NAME); 300c6953b77552d4cb71776cf0537dc226029381628Tony Mantler array.put(UPDATED_MESSAGE_BASE >> BASE_SHIFT, Message.UPDATED_TABLE_NAME); 301c6953b77552d4cb71776cf0537dc226029381628Tony Mantler array.put(DELETED_MESSAGE_BASE >> BASE_SHIFT, Message.DELETED_TABLE_NAME); 302c6953b77552d4cb71776cf0537dc226029381628Tony Mantler array.put(POLICY_BASE >> BASE_SHIFT, Policy.TABLE_NAME); 303c6953b77552d4cb71776cf0537dc226029381628Tony Mantler array.put(QUICK_RESPONSE_BASE >> BASE_SHIFT, QuickResponse.TABLE_NAME); 304c6953b77552d4cb71776cf0537dc226029381628Tony Mantler array.put(UI_BASE >> BASE_SHIFT, null); 305c6953b77552d4cb71776cf0537dc226029381628Tony Mantler array.put(BODY_BASE >> BASE_SHIFT, Body.TABLE_NAME); 3060b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon array.put(CREDENTIAL_BASE >> BASE_SHIFT, Credential.TABLE_NAME); 307c6953b77552d4cb71776cf0537dc226029381628Tony Mantler TABLE_NAMES = array; 308c6953b77552d4cb71776cf0537dc226029381628Tony Mantler } 309f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 3104525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH); 3114525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu 3124525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu /** 3134525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu * Functions which manipulate the database connection or files synchronize on this. 3144525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu * It's static because there can be multiple provider objects. 3154525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu * TODO: Do we actually need to synchronize across all DB access, not just connection creation? 3164525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu */ 3174525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu private static final Object sDatabaseLock = new Object(); 318f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 319f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank /** 320f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank * Let's only generate these SQL strings once, as they are used frequently 321f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank * Note that this isn't relevant for table creation strings, since they are used only once 322f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank */ 323f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank private static final String UPDATED_MESSAGE_INSERT = "insert or ignore into " + 324f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank Message.UPDATED_TABLE_NAME + " select * from " + Message.TABLE_NAME + " where " + 3253dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler BaseColumns._ID + '='; 326f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 327f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank private static final String UPDATED_MESSAGE_DELETE = "delete from " + 3283dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler Message.UPDATED_TABLE_NAME + " where " + BaseColumns._ID + '='; 329f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 330f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank private static final String DELETED_MESSAGE_INSERT = "insert or replace into " + 331f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank Message.DELETED_TABLE_NAME + " select * from " + Message.TABLE_NAME + " where " + 3323dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler BaseColumns._ID + '='; 333f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 3347525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler private static final String ORPHAN_BODY_MESSAGE_ID_SELECT = 3357525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler "select " + BodyColumns.MESSAGE_KEY + " from " + Body.TABLE_NAME + 3367525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler " except select " + BaseColumns._ID + " from " + Message.TABLE_NAME; 3377525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler 338f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank private static final String DELETE_ORPHAN_BODIES = "delete from " + Body.TABLE_NAME + 3397525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler " where " + BodyColumns.MESSAGE_KEY + " in " + '(' + ORPHAN_BODY_MESSAGE_ID_SELECT + ')'; 340f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 341f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank private static final String DELETE_BODY = "delete from " + Body.TABLE_NAME + 342fb7974f5bfb6275fb856b0f7ff386ef10680c83aMihai Preda " where " + BodyColumns.MESSAGE_KEY + '='; 343f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 344f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final ContentValues EMPTY_CONTENT_VALUES = new ContentValues(); 345261d6c3f0c97a12256519a2c3b131a56e57ab45fMakoto Onuki 346b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static final String MESSAGE_URI_PARAMETER_MAILBOX_ID = "mailboxId"; 347c81bef672089654e6da3babbeb0172bd636564b2Marc Blank 348f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // For undo handling 349f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private int mLastSequence = -1; 350ea2edb637036a7368b6ef82a0aafdb1a790e26e9Mark Wei private final ArrayList<ContentProviderOperation> mLastSequenceOps = 351f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank new ArrayList<ContentProviderOperation>(); 352f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 353f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Query parameter indicating the command came from UIProvider 354f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String IS_UIPROVIDER = "is_uiprovider"; 355f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 35671737836e6be308f752cb95c955a03146b039a9cYu Ping Hu private static final String SYNC_STATUS_CALLBACK_METHOD = "sync_status"; 35771737836e6be308f752cb95c955a03146b039a9cYu Ping Hu 35889272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon private static final String[] MIME_TYPE_PROJECTION = new String[]{AttachmentColumns.MIME_TYPE}; 35989272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon 36089272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon private static final String[] CACHED_FILE_QUERY_PROJECTION = new String[] 36189272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon { AttachmentColumns._ID, AttachmentColumns.FILENAME, AttachmentColumns.SIZE, 36289272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon AttachmentColumns.CONTENT_URI }; 36389272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon 364e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank /** 365e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank * Wrap the UriMatcher call so we can throw a runtime exception if an unknown Uri is passed in 366e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank * @param uri the Uri to match 367e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank * @return the match value 368e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank */ 369e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank private static int findMatch(Uri uri, String methodName) { 370e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank int match = sURIMatcher.match(uri); 371e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank if (match < 0) { 3721c1bd6a3eb2b7d99e30713648616c807ae20cbb5Marc Blank throw new IllegalArgumentException("Unknown uri: " + uri); 373bfac9f2e8a13f6c719608a6948203bbef921c99fMakoto Onuki } else if (Logging.LOGD) { 374560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.v(TAG, methodName + ": uri=" + uri + ", match is " + match); 375e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank } 376e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank return match; 377e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank } 378e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank 37917d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie // exposed for testing 38017d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie public static Uri INTEGRITY_CHECK_URI; 38117d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie 382e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank public static Uri ACCOUNT_BACKUP_URI; 383b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static Uri FOLDER_STATUS_URI; 384e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank 385f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private SQLiteDatabase mDatabase; 386f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private SQLiteDatabase mBodyDatabase; 387ebb79619e8ed3c9f0c051e7f323e3971bce7508dMarc Blank 388feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert private Handler mDelayedSyncHandler; 389feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert private final Set<SyncRequestMessage> mDelayedSyncRequests = new HashSet<SyncRequestMessage>(); 390feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert 3913f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon private static void reconcileAccountsAsync(final Context context) { 39250591a7be4fe59cc7063acddcb1f61833ba2f100James Lemieux if (context.getResources().getBoolean(R.bool.reconcile_accounts)) { 39350591a7be4fe59cc7063acddcb1f61833ba2f100James Lemieux EmailAsyncTask.runAsyncParallel(new Runnable() { 39450591a7be4fe59cc7063acddcb1f61833ba2f100James Lemieux @Override 39550591a7be4fe59cc7063acddcb1f61833ba2f100James Lemieux public void run() { 39650591a7be4fe59cc7063acddcb1f61833ba2f100James Lemieux AccountReconciler.reconcileAccounts(context); 39750591a7be4fe59cc7063acddcb1f61833ba2f100James Lemieux } 39850591a7be4fe59cc7063acddcb1f61833ba2f100James Lemieux }); 39950591a7be4fe59cc7063acddcb1f61833ba2f100James Lemieux } 4003f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon } 4013f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon 402f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank public static Uri uiUri(String type, long id) { 403f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return Uri.parse(uiUriString(type, id)); 404ebb79619e8ed3c9f0c051e7f323e3971bce7508dMarc Blank } 405ebb79619e8ed3c9f0c051e7f323e3971bce7508dMarc Blank 406f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 407f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Creates a URI string from a database ID (guaranteed to be unique). 408f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param type of the resource: uifolder, message, etc. 409f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param id the id of the resource. 410582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler * @return uri string 411f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 412f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank public static String uiUriString(String type, long id) { 413f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return "content://" + EmailContent.AUTHORITY + "/" + type + ((id == -1) ? "" : ("/" + id)); 41403cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank } 41503cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank 4162bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank /** 4172bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank * Orphan record deletion utility. Generates a sqlite statement like: 4182bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank * delete from <table> where <column> not in (select <foreignColumn> from <foreignTable>) 41917d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie * Exposed for testing. 4202bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank * @param db the EmailProvider database 4212bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank * @param table the table whose orphans are to be removed 4222bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank * @param column the column deletion will be based on 4232bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank * @param foreignColumn the column in the foreign table whose absence will trigger the deletion 4242bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank * @param foreignTable the foreign table 4252bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank */ 42617d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie public static void deleteUnlinked(SQLiteDatabase db, String table, String column, 427b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy String foreignColumn, String foreignTable) { 4282bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank int count = db.delete(table, column + " not in (select " + foreignColumn + " from " + 4292bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank foreignTable + ")", null); 4302bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank if (count > 0) { 431560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.w(TAG, "Found " + count + " orphaned row(s) in " + table); 4322bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank } 4332bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank } 4342bdf7ee0f0f4a2b11b5f7c0f8b193080600fefd8Marc Blank 435f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon 436f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon /** 437f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon * Make sure that parentKeys match with parentServerId. 438f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon * When we sync folders, we do two passes: First to create the mailbox rows, and second 439f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon * to set the parentKeys. Two passes are needed because we won't know the parent's Id 440f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon * until that row is inserted, and the order in which the rows are given is arbitrary. 441f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon * If we crash while this operation is in progress, the parent keys can be left uninitialized. 4420053401d07cd11f19c63dfbc3942d027b4067de8Tony Mantler * @param db SQLiteDatabase to modify 443f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon */ 444f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon private void fixParentKeys(SQLiteDatabase db) { 445f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon LogUtils.d(TAG, "Fixing parent keys"); 446f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon 447f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // Update the parentKey for each mailbox row to match the _id of the row whose 448f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // serverId matches our parentServerId. This will leave parentKey blank for any 449f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // row that does not have a parentServerId 450f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon 451f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // This is kind of a confusing sql statement, so here's the actual text of it, 452f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // for reference: 453f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // 454f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // update mailbox set parentKey = (select _id from mailbox as b where 455f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // mailbox.parentServerId=b.serverId and mailbox.parentServerId not null and 456f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // mailbox.accountKey=b.accountKey) 457f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon db.execSQL("update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.PARENT_KEY + "=" 4583dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + "(select " + Mailbox._ID + " from " + Mailbox.TABLE_NAME + " as b where " 459f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon + Mailbox.TABLE_NAME + "." + MailboxColumns.PARENT_SERVER_ID + "=" 460f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon + "b." + MailboxColumns.SERVER_ID + " and " 461f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon + Mailbox.TABLE_NAME + "." + MailboxColumns.PARENT_SERVER_ID + " not null and " 462f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon + Mailbox.TABLE_NAME + "." + MailboxColumns.ACCOUNT_KEY 463f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon + "=b." + Mailbox.ACCOUNT_KEY + ")"); 464f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon 465f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // Top level folders can still have uninitialized parent keys. Update these 466f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // to indicate that the parent is -1. 467f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // 468f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon // update mailbox set parentKey = -1 where parentKey=0 or parentKey is null; 469f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon db.execSQL("update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.PARENT_KEY 470f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon + "=" + Mailbox.NO_MAILBOX + " where " + MailboxColumns.PARENT_KEY 471f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon + "=" + Mailbox.PARENT_KEY_UNINITIALIZED + " or " + MailboxColumns.PARENT_KEY 472f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon + " is null"); 473f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon 474f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon } 475f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon 47617d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie // exposed for testing 47717d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie public SQLiteDatabase getDatabase(Context context) { 4784525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu synchronized (sDatabaseLock) { 4794525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // Always return the cached database, if we've got one 4804525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu if (mDatabase != null) { 4814525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu return mDatabase; 4824525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu } 4830e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank 4844525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // Whenever we create or re-cache the databases, make sure that we haven't lost one 4854525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // to corruption 4864525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu checkDatabases(); 4870e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank 4884525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu DBHelper.DatabaseHelper helper = new DBHelper.DatabaseHelper(context, DATABASE_NAME); 4894525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu mDatabase = helper.getWritableDatabase(); 4904525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu DBHelper.BodyDatabaseHelper bodyHelper = 4914525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu new DBHelper.BodyDatabaseHelper(context, BODY_DATABASE_NAME); 4924525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu mBodyDatabase = bodyHelper.getWritableDatabase(); 4934525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu if (mBodyDatabase != null) { 4944525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu String bodyFileName = mBodyDatabase.getPath(); 4954525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu mDatabase.execSQL("attach \"" + bodyFileName + "\" as BodyDatabase"); 4964525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu } 497ef83299b99288c00b9d661260d19715e73e6889cMarc Blank 4984525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // Restore accounts if the database is corrupted... 4994525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu restoreIfNeeded(context, mDatabase); 5004525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // Check for any orphaned Messages in the updated/deleted tables 5014525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu deleteMessageOrphans(mDatabase, Message.UPDATED_TABLE_NAME); 5024525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu deleteMessageOrphans(mDatabase, Message.DELETED_TABLE_NAME); 5034525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // Delete orphaned mailboxes/messages/policies (account no longer exists) 5044525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu deleteUnlinked(mDatabase, Mailbox.TABLE_NAME, MailboxColumns.ACCOUNT_KEY, 5053dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler AccountColumns._ID, Account.TABLE_NAME); 5064525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu deleteUnlinked(mDatabase, Message.TABLE_NAME, MessageColumns.ACCOUNT_KEY, 5073dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler AccountColumns._ID, Account.TABLE_NAME); 5083dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler deleteUnlinked(mDatabase, Policy.TABLE_NAME, PolicyColumns._ID, 5094525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu AccountColumns.POLICY_KEY, Account.TABLE_NAME); 510f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon fixParentKeys(mDatabase); 5114525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu initUiProvider(); 5124525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu return mDatabase; 5134525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu } 514f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 515f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 5166e418aa41a17136be0dddb816d843428a0a1e722Marc Blank /** 517f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Perform startup actions related to UI 518f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 519f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private void initUiProvider() { 520f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Clear mailbox sync status 521f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mDatabase.execSQL("update " + Mailbox.TABLE_NAME + " set " + MailboxColumns.UI_SYNC_STATUS + 522f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "=" + UIProvider.SyncStatus.NO_SYNC); 523f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 524f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 525f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 5269dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki * Restore user Account and HostAuth data from our backup database 5279dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki */ 528b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static void restoreIfNeeded(Context context, SQLiteDatabase mainDatabase) { 52951c653646d14d841fbe527aee9fab7a1886338f8Martin Hibdon if (DebugUtils.DEBUG) { 530560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.w(TAG, "restoreIfNeeded..."); 5319dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki } 5329dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki // Check for legacy backup 5339dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki String legacyBackup = Preferences.getLegacyBackupPreference(context); 5349dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki // If there's a legacy backup, create a new-style backup and delete the legacy backup 5359dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki // In the 1:1000000000 chance that the user gets an app update just as his database becomes 5369dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki // corrupt, oh well... 5379dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki if (!TextUtils.isEmpty(legacyBackup)) { 5389dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki backupAccounts(context, mainDatabase); 5399dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki Preferences.clearLegacyBackupPreference(context); 540560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.w(TAG, "Created new EmailProvider backup database"); 5419dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki return; 5429dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki } 5439dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki 54482a207132b34377d532f19882f5bfc70bc657da0Tony Mantler // If there's a backup database (old style) delete it and trigger an account manager backup. 54582a207132b34377d532f19882f5bfc70bc657da0Tony Mantler // Roughly the same comment as above applies 54682a207132b34377d532f19882f5bfc70bc657da0Tony Mantler final File backupDb = context.getDatabasePath(BACKUP_DATABASE_NAME); 54782a207132b34377d532f19882f5bfc70bc657da0Tony Mantler if (backupDb.exists()) { 54882a207132b34377d532f19882f5bfc70bc657da0Tony Mantler backupAccounts(context, mainDatabase); 54982a207132b34377d532f19882f5bfc70bc657da0Tony Mantler context.deleteDatabase(BACKUP_DATABASE_NAME); 55082a207132b34377d532f19882f5bfc70bc657da0Tony Mantler LogUtils.w(TAG, "Migrated from backup database to account manager"); 55182a207132b34377d532f19882f5bfc70bc657da0Tony Mantler return; 55282a207132b34377d532f19882f5bfc70bc657da0Tony Mantler } 55382a207132b34377d532f19882f5bfc70bc657da0Tony Mantler 5549dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki // If we have accounts, we're done 555a6745514643f66741229a0cca3927931bdfa47b3yi.jang if (DatabaseUtils.longForQuery(mainDatabase, 556e743a06ddf7677706da7450100e19d0f4509a43cScott Kennedy "SELECT EXISTS (SELECT ? FROM " + Account.TABLE_NAME + " )", 557a6745514643f66741229a0cca3927931bdfa47b3yi.jang EmailContent.ID_PROJECTION) > 0) { 55851c653646d14d841fbe527aee9fab7a1886338f8Martin Hibdon if (DebugUtils.DEBUG) { 559874d25ff7073731a08c09b4528add58b720c4f6aMartin Hibdon LogUtils.w(TAG, "restoreIfNeeded: Account exists."); 560874d25ff7073731a08c09b4528add58b720c4f6aMartin Hibdon } 561874d25ff7073731a08c09b4528add58b720c4f6aMartin Hibdon return; 5629dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki } 56368a3607895963854637215a405145f190d6458f0Andy Huang 56482a207132b34377d532f19882f5bfc70bc657da0Tony Mantler restoreAccounts(context); 5659dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki } 5669dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki 5676c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki /** {@inheritDoc} */ 5686c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki @Override 5696c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki public void shutdown() { 5706c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki if (mDatabase != null) { 5716c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki mDatabase.close(); 5726c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki mDatabase = null; 5736c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki } 5746c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki if (mBodyDatabase != null) { 5756c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki mBodyDatabase.close(); 5766c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki mBodyDatabase = null; 5776c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki } 5786c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki } 5796c36b4c613499655316d8c910e3c6bfb08a0d896Makoto Onuki 58017d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie // exposed for testing 58117d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie public static void deleteMessageOrphans(SQLiteDatabase database, String tableName) { 582ef83299b99288c00b9d661260d19715e73e6889cMarc Blank if (database != null) { 583ef83299b99288c00b9d661260d19715e73e6889cMarc Blank // We'll look at all of the items in the table; there won't be many typically 584ef83299b99288c00b9d661260d19715e73e6889cMarc Blank Cursor c = database.query(tableName, ORPHANS_PROJECTION, null, null, null, null, null); 585ef83299b99288c00b9d661260d19715e73e6889cMarc Blank // Usually, there will be nothing in these tables, so make a quick check 586ef83299b99288c00b9d661260d19715e73e6889cMarc Blank try { 587ef83299b99288c00b9d661260d19715e73e6889cMarc Blank if (c.getCount() == 0) return; 588ef83299b99288c00b9d661260d19715e73e6889cMarc Blank ArrayList<Long> foundMailboxes = new ArrayList<Long>(); 589ef83299b99288c00b9d661260d19715e73e6889cMarc Blank ArrayList<Long> notFoundMailboxes = new ArrayList<Long>(); 590ef83299b99288c00b9d661260d19715e73e6889cMarc Blank ArrayList<Long> deleteList = new ArrayList<Long>(); 591ef83299b99288c00b9d661260d19715e73e6889cMarc Blank String[] bindArray = new String[1]; 592ef83299b99288c00b9d661260d19715e73e6889cMarc Blank while (c.moveToNext()) { 593ef83299b99288c00b9d661260d19715e73e6889cMarc Blank // Get the mailbox key and see if we've already found this mailbox 594ef83299b99288c00b9d661260d19715e73e6889cMarc Blank // If so, we're fine 595ef83299b99288c00b9d661260d19715e73e6889cMarc Blank long mailboxId = c.getLong(ORPHANS_MAILBOX_KEY); 596ef83299b99288c00b9d661260d19715e73e6889cMarc Blank // If we already know this mailbox doesn't exist, mark the message for deletion 597ef83299b99288c00b9d661260d19715e73e6889cMarc Blank if (notFoundMailboxes.contains(mailboxId)) { 598ef83299b99288c00b9d661260d19715e73e6889cMarc Blank deleteList.add(c.getLong(ORPHANS_ID)); 599ef83299b99288c00b9d661260d19715e73e6889cMarc Blank // If we don't know about this mailbox, we'll try to find it 600ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } else if (!foundMailboxes.contains(mailboxId)) { 601ef83299b99288c00b9d661260d19715e73e6889cMarc Blank bindArray[0] = Long.toString(mailboxId); 602ef83299b99288c00b9d661260d19715e73e6889cMarc Blank Cursor boxCursor = database.query(Mailbox.TABLE_NAME, 603ef83299b99288c00b9d661260d19715e73e6889cMarc Blank Mailbox.ID_PROJECTION, WHERE_ID, bindArray, null, null, null); 604ef83299b99288c00b9d661260d19715e73e6889cMarc Blank try { 605ef83299b99288c00b9d661260d19715e73e6889cMarc Blank // If it exists, we'll add it to the "found" mailboxes 606ef83299b99288c00b9d661260d19715e73e6889cMarc Blank if (boxCursor.moveToFirst()) { 607ef83299b99288c00b9d661260d19715e73e6889cMarc Blank foundMailboxes.add(mailboxId); 608ef83299b99288c00b9d661260d19715e73e6889cMarc Blank // Otherwise, we'll add to "not found" and mark the message for deletion 609ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } else { 610ef83299b99288c00b9d661260d19715e73e6889cMarc Blank notFoundMailboxes.add(mailboxId); 611ef83299b99288c00b9d661260d19715e73e6889cMarc Blank deleteList.add(c.getLong(ORPHANS_ID)); 612ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } 613ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } finally { 614ef83299b99288c00b9d661260d19715e73e6889cMarc Blank boxCursor.close(); 615ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } 616ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } 617ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } 618ef83299b99288c00b9d661260d19715e73e6889cMarc Blank // Now, delete the orphan messages 619ef83299b99288c00b9d661260d19715e73e6889cMarc Blank for (long messageId: deleteList) { 620ef83299b99288c00b9d661260d19715e73e6889cMarc Blank bindArray[0] = Long.toString(messageId); 621ef83299b99288c00b9d661260d19715e73e6889cMarc Blank database.delete(tableName, WHERE_ID, bindArray); 622ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } 623ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } finally { 624ef83299b99288c00b9d661260d19715e73e6889cMarc Blank c.close(); 625ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } 626ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } 627ef83299b99288c00b9d661260d19715e73e6889cMarc Blank } 628ef83299b99288c00b9d661260d19715e73e6889cMarc Blank 629f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler @Override 630f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler public int delete(Uri uri, String selection, String[] selectionArgs) { 631feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert Log.d(TAG, "Delete: " + uri); 632e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank final int match = findMatch(uri, "delete"); 6332d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final Context context = getContext(); 634cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank // Pick the correct database for this operation 635cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank // If we're in a transaction already (which would happen during applyBatch), then the 636cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank // body database is already attached to the email database and any attempt to use the 637cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank // body database directly will result in a SQLiteException (the database is locked) 6382d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final SQLiteDatabase db = getDatabase(context); 6392d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final int table = match >> BASE_SHIFT; 6402c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank String id = "0"; 641cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank boolean messageDeletion = false; 642f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 6432d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final String tableName = TABLE_NAMES.valueAt(table); 644b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank int result = -1; 645f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 6462c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank try { 647f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (match == MESSAGE_ID || match == SYNCED_MESSAGE_ID) { 648f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (!uri.getBooleanQueryParameter(IS_UIPROVIDER, false)) { 649f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUIConversation(uri); 650f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 651f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6522c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank switch (match) { 653f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_MESSAGE: 654f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return uiDeleteMessage(uri); 655f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ACCOUNT_DATA: 656f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return uiDeleteAccountData(uri); 657f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ACCOUNT: 658f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return uiDeleteAccount(uri); 659e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler case UI_PURGE_FOLDER: 660e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler return uiPurgeFolder(uri); 66100287c4d8f54ae07c89bb3893f440acdca09d728Marc Blank case MESSAGE_SELECTION: 662c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank Cursor findCursor = db.query(tableName, Message.ID_COLUMN_PROJECTION, selection, 663c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank selectionArgs, null, null, null); 664c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank try { 665c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank if (findCursor.moveToFirst()) { 666c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank return delete(ContentUris.withAppendedId( 66700287c4d8f54ae07c89bb3893f440acdca09d728Marc Blank Message.CONTENT_URI, 668c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank findCursor.getLong(Message.ID_COLUMNS_ID_COLUMN)), 669c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank null, null); 670c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } else { 671c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank return 0; 672c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } 673c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } finally { 674c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank findCursor.close(); 675c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } 6762c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank // These are cases in which one or more Messages might get deleted, either by 6772c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank // cascade or explicitly 6782c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case MAILBOX_ID: 6792c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case MAILBOX: 6802c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case ACCOUNT_ID: 6812c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case ACCOUNT: 6822c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case MESSAGE: 683f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank case SYNCED_MESSAGE_ID: 6842c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case MESSAGE_ID: 6852c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank // Handle lost Body records here, since this cannot be done in a trigger 6862c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank // The process is: 687a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank // 1) Begin a transaction, ensuring that both databases are affected atomically 688a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank // 2) Do the requested deletion, with cascading deletions handled in triggers 689a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank // 3) End the transaction, committing all changes atomically 6906c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler // 6916c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler // Bodies are auto-deleted here; Attachments are auto-deleted via trigger 692cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank messageDeletion = true; 6938587aa61211d288d05b5fb2ddf02d69cabe6a9e2Marc Blank db.beginTransaction(); 6942c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank break; 6952c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank } 6962c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank switch (match) { 6972c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case BODY_ID: 698f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank case DELETED_MESSAGE_ID: 699f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank case SYNCED_MESSAGE_ID: 7002c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case MESSAGE_ID: 7012c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case UPDATED_MESSAGE_ID: 7022c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case ATTACHMENT_ID: 7032c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case MAILBOX_ID: 7042c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case ACCOUNT_ID: 7052c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case HOSTAUTH_ID: 706aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank case POLICY_ID: 7075a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo case QUICK_RESPONSE_ID: 7080b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon case CREDENTIAL_ID: 7092c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank id = uri.getPathSegments().get(1); 710f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank if (match == SYNCED_MESSAGE_ID) { 711f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank // For synced messages, first copy the old message to the deleted table and 712f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank // delete it from the updated table (in case it was updated first) 713f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank // Note that this is all within a transaction, for atomicity 714f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank db.execSQL(DELETED_MESSAGE_INSERT + id); 715f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank db.execSQL(UPDATED_MESSAGE_DELETE + id); 716f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank } 717503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu 718c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu final long accountId; 719c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu if (match == MAILBOX_ID) { 720c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu accountId = Mailbox.getAccountIdForMailbox(context, id); 721c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } else { 722c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu accountId = Account.NO_ACCOUNT; 723c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } 724c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu 725503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu result = db.delete(tableName, whereWithId(id, selection), selectionArgs); 726503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu 727f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (match == ACCOUNT_ID) { 728f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUI(UIPROVIDER_ACCOUNT_NOTIFIER, id); 72905649dca2f59f28cd4295e041045a605badddb15Tony Mantler notifyUI(UIPROVIDER_ALL_ACCOUNTS_NOTIFIER, null); 730f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else if (match == MAILBOX_ID) { 731c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu notifyUIFolder(id, accountId); 732f6db592c313c77190727c7cd72d3edda9d23a099Marc Blank } else if (match == ATTACHMENT_ID) { 733f6db592c313c77190727c7cd72d3edda9d23a099Marc Blank notifyUI(UIPROVIDER_ATTACHMENT_NOTIFIER, id); 734f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 7352c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank break; 7366c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler case ATTACHMENTS_MESSAGE_ID: 7376c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler // All attachments for the given message 7386c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler id = uri.getPathSegments().get(2); 739fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank result = db.delete(tableName, 7403dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler whereWith(AttachmentColumns.MESSAGE_KEY + "=" + id, selection), 7413dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler selectionArgs); 7426c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler break; 7436c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler 7442c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case BODY: 7452c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case MESSAGE: 746f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank case DELETED_MESSAGE: 7472c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case UPDATED_MESSAGE: 7482c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case ATTACHMENT: 7492c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case MAILBOX: 7502c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case ACCOUNT: 7512c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank case HOSTAUTH: 752aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank case POLICY: 753fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank result = db.delete(tableName, selection, selectionArgs); 7542c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank break; 755ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu case MESSAGE_MOVE: 756ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu db.delete(MessageMove.TABLE_NAME, selection, selectionArgs); 757ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu break; 758ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu case MESSAGE_STATE_CHANGE: 759ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu db.delete(MessageStateChange.TABLE_NAME, selection, selectionArgs); 760ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu break; 7612c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank default: 7622c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank throw new IllegalArgumentException("Unknown URI " + uri); 7632c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank } 764cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank if (messageDeletion) { 765fb7974f5bfb6275fb856b0f7ff386ef10680c83aMihai Preda if (match == MESSAGE_ID) { 7665f4dbd64389cd6540a93cde1daed304bf9392a01Andrew Stadler // Delete the Body record associated with the deleted message 7677525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final long messageId = Long.valueOf(id); 7687525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler try { 769b62067e3c3ec01559568705df4908fe7f2860af9Tony Mantler deleteBodyFiles(context, messageId); 7707525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } catch (final IllegalStateException e) { 7717525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler LogUtils.v(LogUtils.TAG, e, "Exception while deleting bodies"); 7727525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 773f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank db.execSQL(DELETE_BODY + id); 774fb7974f5bfb6275fb856b0f7ff386ef10680c83aMihai Preda } else { 775fb7974f5bfb6275fb856b0f7ff386ef10680c83aMihai Preda // Delete any orphaned Body records 7767525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final Cursor orphans = db.rawQuery(ORPHAN_BODY_MESSAGE_ID_SELECT, null); 7777525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler try { 7787525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler while (orphans.moveToNext()) { 7797525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final long messageId = orphans.getLong(0); 7807525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler try { 781b62067e3c3ec01559568705df4908fe7f2860af9Tony Mantler deleteBodyFiles(context, messageId); 7827525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } catch (final IllegalStateException e) { 7837525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler LogUtils.v(LogUtils.TAG, e, "Exception while deleting bodies"); 7847525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 7857525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 7867525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } finally { 7877525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler orphans.close(); 7887525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 789fb7974f5bfb6275fb856b0f7ff386ef10680c83aMihai Preda db.execSQL(DELETE_ORPHAN_BODIES); 790cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank } 7918587aa61211d288d05b5fb2ddf02d69cabe6a9e2Marc Blank db.setTransactionSuccessful(); 7925f4dbd64389cd6540a93cde1daed304bf9392a01Andrew Stadler } 7930e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank } catch (SQLiteException e) { 7940e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank checkDatabases(); 7950e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank throw e; 7962c67f1f8b869454ed24c0ac3c813aca26d2f3978Marc Blank } finally { 797cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank if (messageDeletion) { 7988587aa61211d288d05b5fb2ddf02d69cabe6a9e2Marc Blank db.endTransaction(); 7995f4dbd64389cd6540a93cde1daed304bf9392a01Andrew Stadler } 800f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 801261d6c3f0c97a12256519a2c3b131a56e57ab45fMakoto Onuki 802bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy // Notify all notifier cursors 803e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy sendNotifierChange(getBaseNotificationUri(match), NOTIFICATION_OP_DELETE, id); 804bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy 805bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy // Notify all email content cursors 80605649dca2f59f28cd4295e041045a605badddb15Tony Mantler notifyUI(EmailContent.CONTENT_URI, null); 807626f3e48a4f14c38a973dd2bea2e2debea7637a5Andrew Stadler return result; 808f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 809f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 810f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler @Override 811f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler // Use the email- prefix because message, mailbox, and account are so generic (e.g. SMS, IM) 812f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler public String getType(Uri uri) { 813e6a22dff397e6453e1f56518d840c0bdd11f673bMarc Blank int match = findMatch(uri, "getType"); 814f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler switch (match) { 815a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank case BODY_ID: 816a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank return "vnd.android.cursor.item/email-body"; 817a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank case BODY: 818c81bef672089654e6da3babbeb0172bd636564b2Marc Blank return "vnd.android.cursor.dir/email-body"; 819e34525d0f026a7467cee1cb5fddcf25ba6f35207Marc Blank case UPDATED_MESSAGE_ID: 820a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank case MESSAGE_ID: 821c81bef672089654e6da3babbeb0172bd636564b2Marc Blank // NOTE: According to the framework folks, we're supposed to invent mime types as 822c81bef672089654e6da3babbeb0172bd636564b2Marc Blank // a way of passing information to drag & drop recipients. 823c81bef672089654e6da3babbeb0172bd636564b2Marc Blank // If there's a mailboxId parameter in the url, we respond with a mime type that 824c81bef672089654e6da3babbeb0172bd636564b2Marc Blank // has -n appended, where n is the mailboxId of the message. The drag & drop code 825c81bef672089654e6da3babbeb0172bd636564b2Marc Blank // uses this information to know not to allow dragging the item to its own mailbox 826c81bef672089654e6da3babbeb0172bd636564b2Marc Blank String mimeType = EMAIL_MESSAGE_MIME_TYPE; 827c81bef672089654e6da3babbeb0172bd636564b2Marc Blank String mailboxId = uri.getQueryParameter(MESSAGE_URI_PARAMETER_MAILBOX_ID); 828c81bef672089654e6da3babbeb0172bd636564b2Marc Blank if (mailboxId != null) { 829c81bef672089654e6da3babbeb0172bd636564b2Marc Blank mimeType += "-" + mailboxId; 830c81bef672089654e6da3babbeb0172bd636564b2Marc Blank } 831c81bef672089654e6da3babbeb0172bd636564b2Marc Blank return mimeType; 832e34525d0f026a7467cee1cb5fddcf25ba6f35207Marc Blank case UPDATED_MESSAGE: 833fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank case MESSAGE: 834a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank return "vnd.android.cursor.dir/email-message"; 835fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank case MAILBOX: 836fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank return "vnd.android.cursor.dir/email-mailbox"; 837fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank case MAILBOX_ID: 838fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank return "vnd.android.cursor.item/email-mailbox"; 839fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank case ACCOUNT: 840fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank return "vnd.android.cursor.dir/email-account"; 841fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank case ACCOUNT_ID: 842fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank return "vnd.android.cursor.item/email-account"; 8434119218e2fd64341ac946fb8f2cbdb796a444cb8Andrew Stadler case ATTACHMENTS_MESSAGE_ID: 844fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank case ATTACHMENT: 845fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank return "vnd.android.cursor.dir/email-attachment"; 846fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank case ATTACHMENT_ID: 84709fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank return EMAIL_ATTACHMENT_MIME_TYPE; 848fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank case HOSTAUTH: 849fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank return "vnd.android.cursor.dir/email-hostauth"; 850fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank case HOSTAUTH_ID: 851fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank return "vnd.android.cursor.item/email-hostauth"; 85289272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon case ATTACHMENTS_CACHED_FILE_ACCESS: { 85389272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon SQLiteDatabase db = getDatabase(getContext()); 85489272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon Cursor c = db.query(Attachment.TABLE_NAME, MIME_TYPE_PROJECTION, 85589272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon AttachmentColumns.CACHED_FILE + "=?", new String[]{uri.toString()}, 85689272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon null, null, null, null); 85789272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon try { 85889272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon if (c != null && c.moveToFirst()) { 85989272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon return c.getString(0); 86089272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon } else { 86189272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon return null; 86289272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon } 86389272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon } finally { 86489272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon if (c != null) { 86589272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon c.close(); 86689272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon } 86789272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon } 86889272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon } 869fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank default: 870f9fd4b6bb4a275d12548c250176b9be918619c7dYu Ping Hu return null; 871f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 872f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 873f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 874c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu // These URIs are used for specific UI notifications. We don't use EmailContent.CONTENT_URI 875c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu // as the base because that gets spammed. 876de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler // These can't be statically initialized because they depend on EmailContent.AUTHORITY 877de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler private static Uri UIPROVIDER_CONVERSATION_NOTIFIER; 878de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler private static Uri UIPROVIDER_FOLDER_NOTIFIER; 879de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler private static Uri UIPROVIDER_FOLDERLIST_NOTIFIER; 880de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler private static Uri UIPROVIDER_ACCOUNT_NOTIFIER; 8819e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler // Not currently used 882de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler //public static Uri UIPROVIDER_SETTINGS_NOTIFIER; 883de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler private static Uri UIPROVIDER_ATTACHMENT_NOTIFIER; 884de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler private static Uri UIPROVIDER_ATTACHMENTS_NOTIFIER; 8853bdce9b515f6bde3506596a6b5d3bdbaff9b7423James Lemieux private static Uri UIPROVIDER_ALL_ACCOUNTS_NOTIFIER; 886de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler private static Uri UIPROVIDER_MESSAGE_NOTIFIER; 887de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler private static Uri UIPROVIDER_RECENT_FOLDERS_NOTIFIER; 888f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 889f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler @Override 890f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler public Uri insert(Uri uri, ContentValues values) { 891feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert Log.d(TAG, "Insert: " + uri); 8922d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final int match = findMatch(uri, "insert"); 8932d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final Context context = getContext(); 8941b9337ea4f41c12cb108cbe67e0077169b1f0b8cMarc Blank 895cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank // See the comment at delete(), above 8962d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final SQLiteDatabase db = getDatabase(context); 8972d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final int table = match >> BASE_SHIFT; 898bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy String id = "0"; 899bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy long longId; 900f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 9015b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki // We do NOT allow setting of unreadCount/messageCount via the provider 9025b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki // These columns are maintained via triggers 9035b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki if (match == MAILBOX_ID || match == MAILBOX) { 9045b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki values.put(MailboxColumns.UNREAD_COUNT, 0); 9055b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki values.put(MailboxColumns.MESSAGE_COUNT, 0); 9065b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki } 907f678a8e67ace74ea285dcec9727d0117e23a5c73Makoto Onuki 9089e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler final Uri resultUri; 909f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 9100e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank try { 9110e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank switch (match) { 9127525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler case BODY: 9137525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final ContentValues dbValues = new ContentValues(values); 9147525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler // Prune out the content we don't want in the DB 9157525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler dbValues.remove(BodyColumns.HTML_CONTENT); 9167525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler dbValues.remove(BodyColumns.TEXT_CONTENT); 9177525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler // TODO: move this to the message table 9187525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler longId = db.insert(Body.TABLE_NAME, "foo", dbValues); 9197525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler resultUri = ContentUris.withAppendedId(uri, longId); 9207525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler // Write content to the filesystem where appropriate 9217525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler // This will look less ugly once the body table is folded into the message table 9227525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler // and we can just use longId instead 9237525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (!values.containsKey(BodyColumns.MESSAGE_KEY)) { 9247525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler throw new IllegalArgumentException( 9257525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler "Cannot insert body without MESSAGE_KEY"); 9267525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 9277525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final long messageId = values.getAsLong(BodyColumns.MESSAGE_KEY); 928b62067e3c3ec01559568705df4908fe7f2860af9Tony Mantler // Ensure that no pre-existing body files contaminate the message 929b62067e3c3ec01559568705df4908fe7f2860af9Tony Mantler deleteBodyFiles(context, messageId); 9307525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler writeBodyFiles(getContext(), messageId, values); 9317525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler break; 9326e418aa41a17136be0dddb816d843428a0a1e722Marc Blank // NOTE: It is NOT legal for production code to insert directly into UPDATED_MESSAGE 9336e418aa41a17136be0dddb816d843428a0a1e722Marc Blank // or DELETED_MESSAGE; see the comment below for details 9340e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case UPDATED_MESSAGE: 9350e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case DELETED_MESSAGE: 9366e418aa41a17136be0dddb816d843428a0a1e722Marc Blank case MESSAGE: 9375057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux decodeEmailAddresses(values); 9380e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ATTACHMENT: 9390e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case MAILBOX: 9400e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ACCOUNT: 9410e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case HOSTAUTH: 9420b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon case CREDENTIAL: 943aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank case POLICY: 9445a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo case QUICK_RESPONSE: 945c6953b77552d4cb71776cf0537dc226029381628Tony Mantler longId = db.insert(TABLE_NAMES.valueAt(table), "foo", values); 946bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy resultUri = ContentUris.withAppendedId(uri, longId); 9476e418aa41a17136be0dddb816d843428a0a1e722Marc Blank switch(match) { 948f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case MESSAGE: 9493dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler final long mailboxId = values.getAsLong(MessageColumns.MAILBOX_KEY); 950f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (!uri.getBooleanQueryParameter(IS_UIPROVIDER, false)) { 951c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu notifyUIConversationMailbox(mailboxId); 952f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 9533dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler notifyUIFolder(mailboxId, values.getAsLong(MessageColumns.ACCOUNT_KEY)); 954f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 9556e418aa41a17136be0dddb816d843428a0a1e722Marc Blank case MAILBOX: 9566e418aa41a17136be0dddb816d843428a0a1e722Marc Blank if (values.containsKey(MailboxColumns.TYPE)) { 957c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu if (values.getAsInteger(MailboxColumns.TYPE) < 958c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu Mailbox.TYPE_NOT_EMAIL) { 959c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu // Notify the account when a new mailbox is added 960c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu final Long accountId = 961c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu values.getAsLong(MailboxColumns.ACCOUNT_KEY); 9629e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler if (accountId != null && accountId > 0) { 963c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu notifyUI(UIPROVIDER_ACCOUNT_NOTIFIER, accountId); 964c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu notifyUI(UIPROVIDER_FOLDERLIST_NOTIFIER, accountId); 965c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } 9666e418aa41a17136be0dddb816d843428a0a1e722Marc Blank } 9676e418aa41a17136be0dddb816d843428a0a1e722Marc Blank } 968503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu break; 9696e418aa41a17136be0dddb816d843428a0a1e722Marc Blank case ACCOUNT: 970e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu updateAccountSyncInterval(longId, values); 971503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu if (!uri.getBooleanQueryParameter(IS_UIPROVIDER, false)) { 972503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu notifyUIAccount(longId); 9736e418aa41a17136be0dddb816d843428a0a1e722Marc Blank } 97405649dca2f59f28cd4295e041045a605badddb15Tony Mantler notifyUI(UIPROVIDER_ALL_ACCOUNTS_NOTIFIER, null); 975503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu break; 976503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu case UPDATED_MESSAGE: 977503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu case DELETED_MESSAGE: 978503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu throw new IllegalArgumentException("Unknown URL " + uri); 979503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu case ATTACHMENT: 980503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu int flags = 0; 9813dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler if (values.containsKey(AttachmentColumns.FLAGS)) { 9823dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler flags = values.getAsInteger(AttachmentColumns.FLAGS); 983503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu } 984503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu // Report all new attachments to the download service 9853dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler if (TextUtils.isEmpty(values.getAsString(AttachmentColumns.LOCATION))) { 9865ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon LogUtils.w(TAG, new Throwable(), "attachment with blank location"); 9875ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon } 988503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu mAttachmentService.attachmentChanged(getContext(), longId, flags); 9896e418aa41a17136be0dddb816d843428a0a1e722Marc Blank break; 99009fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank } 9910e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank break; 992c6953b77552d4cb71776cf0537dc226029381628Tony Mantler case QUICK_RESPONSE_ACCOUNT_ID: 993c6953b77552d4cb71776cf0537dc226029381628Tony Mantler longId = Long.parseLong(uri.getPathSegments().get(2)); 9943dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler values.put(QuickResponseColumns.ACCOUNT_KEY, longId); 995c6953b77552d4cb71776cf0537dc226029381628Tony Mantler return insert(QuickResponse.CONTENT_URI, values); 9960e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case MAILBOX_ID: 9970e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank // This implies adding a message to a mailbox 9980e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank // Hmm, a problem here is that we can't link the account as well, so it must be 9990e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank // already in the values... 1000bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy longId = Long.parseLong(uri.getPathSegments().get(1)); 1001bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy values.put(MessageColumns.MAILBOX_KEY, longId); 1002261d6c3f0c97a12256519a2c3b131a56e57ab45fMakoto Onuki return insert(Message.CONTENT_URI, values); // Recurse 10030e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case MESSAGE_ID: 10040e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank // This implies adding an attachment to a message. 1005bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy id = uri.getPathSegments().get(1); 1006bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy longId = Long.parseLong(id); 1007bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy values.put(AttachmentColumns.MESSAGE_KEY, longId); 1008261d6c3f0c97a12256519a2c3b131a56e57ab45fMakoto Onuki return insert(Attachment.CONTENT_URI, values); // Recurse 10090e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ACCOUNT_ID: 10100e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank // This implies adding a mailbox to an account. 1011bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy longId = Long.parseLong(uri.getPathSegments().get(1)); 1012bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy values.put(MailboxColumns.ACCOUNT_KEY, longId); 1013261d6c3f0c97a12256519a2c3b131a56e57ab45fMakoto Onuki return insert(Mailbox.CONTENT_URI, values); // Recurse 10140e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ATTACHMENTS_MESSAGE_ID: 1015c6953b77552d4cb71776cf0537dc226029381628Tony Mantler longId = db.insert(TABLE_NAMES.valueAt(table), "foo", values); 1016bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy resultUri = ContentUris.withAppendedId(Attachment.CONTENT_URI, longId); 10170e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank break; 10180e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank default: 1019ef83299b99288c00b9d661260d19715e73e6889cMarc Blank throw new IllegalArgumentException("Unknown URL " + uri); 10200e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank } 10210e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank } catch (SQLiteException e) { 10220e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank checkDatabases(); 10230e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank throw e; 1024f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 1025f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 1026bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy // Notify all notifier cursors 1027e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy sendNotifierChange(getBaseNotificationUri(match), NOTIFICATION_OP_INSERT, id); 1028bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy 1029261d6c3f0c97a12256519a2c3b131a56e57ab45fMakoto Onuki // Notify all existing cursors. 103005649dca2f59f28cd4295e041045a605badddb15Tony Mantler notifyUI(EmailContent.CONTENT_URI, null); 1031626f3e48a4f14c38a973dd2bea2e2debea7637a5Andrew Stadler return resultUri; 1032f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 1033f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 1034c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler @Override 1035c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler public boolean onCreate() { 1036c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler Context context = getContext(); 1037c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler EmailContent.init(context); 10384525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu init(context); 103951c653646d14d841fbe527aee9fab7a1886338f8Martin Hibdon DebugUtils.init(context); 10404525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // Do this last, so that EmailContent/EmailProvider are initialized 1041bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook setServicesEnabledAsync(context); 10423f4a556d54cb6dd20f89c7e7fe94723e18ec6d28Martin Hibdon reconcileAccountsAsync(context); 104302b9ac1b95947a2dc66bc0f6c770a1cb3ffdbbc9Tony Mantler 104402b9ac1b95947a2dc66bc0f6c770a1cb3ffdbbc9Tony Mantler // Update widgets 104502b9ac1b95947a2dc66bc0f6c770a1cb3ffdbbc9Tony Mantler final Intent updateAllWidgetsIntent = 104602b9ac1b95947a2dc66bc0f6c770a1cb3ffdbbc9Tony Mantler new Intent(com.android.mail.utils.Utils.ACTION_NOTIFY_DATASET_CHANGED); 104702b9ac1b95947a2dc66bc0f6c770a1cb3ffdbbc9Tony Mantler updateAllWidgetsIntent.putExtra(BaseWidgetProvider.EXTRA_UPDATE_ALL_WIDGETS, true); 104802b9ac1b95947a2dc66bc0f6c770a1cb3ffdbbc9Tony Mantler updateAllWidgetsIntent.setType(context.getString(R.string.application_mime_type)); 104902b9ac1b95947a2dc66bc0f6c770a1cb3ffdbbc9Tony Mantler context.sendBroadcast(updateAllWidgetsIntent); 105002b9ac1b95947a2dc66bc0f6c770a1cb3ffdbbc9Tony Mantler 105103dc3f22d151d0cddc6487429786a708de813d67Tony Mantler // The combined account name changes on locale changes 105203dc3f22d151d0cddc6487429786a708de813d67Tony Mantler final Configuration oldConfiguration = 105303dc3f22d151d0cddc6487429786a708de813d67Tony Mantler new Configuration(context.getResources().getConfiguration()); 105403dc3f22d151d0cddc6487429786a708de813d67Tony Mantler context.registerComponentCallbacks(new ComponentCallbacks() { 105503dc3f22d151d0cddc6487429786a708de813d67Tony Mantler @Override 105603dc3f22d151d0cddc6487429786a708de813d67Tony Mantler public void onConfigurationChanged(Configuration configuration) { 105703dc3f22d151d0cddc6487429786a708de813d67Tony Mantler int delta = oldConfiguration.updateFrom(configuration); 105803dc3f22d151d0cddc6487429786a708de813d67Tony Mantler if (Configuration.needNewResources(delta, ActivityInfo.CONFIG_LOCALE)) { 105903dc3f22d151d0cddc6487429786a708de813d67Tony Mantler notifyUIAccount(COMBINED_ACCOUNT_ID); 106003dc3f22d151d0cddc6487429786a708de813d67Tony Mantler } 106103dc3f22d151d0cddc6487429786a708de813d67Tony Mantler } 106203dc3f22d151d0cddc6487429786a708de813d67Tony Mantler 106303dc3f22d151d0cddc6487429786a708de813d67Tony Mantler @Override 106403dc3f22d151d0cddc6487429786a708de813d67Tony Mantler public void onLowMemory() {} 106503dc3f22d151d0cddc6487429786a708de813d67Tony Mantler }); 106603dc3f22d151d0cddc6487429786a708de813d67Tony Mantler 1067c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler MailPrefs.get(context).registerOnSharedPreferenceChangeListener(this); 1068c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler 10694525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu return false; 10704525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu } 10714525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu 10724525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu private static void init(final Context context) { 10734525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // Synchronize on the matcher rather than the class object to minimize risk of contention 10744525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // & deadlock. 10754525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu synchronized (sURIMatcher) { 10764525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // We use the existence of this variable as indicative of whether this function has 10774525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // already run. 10784525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu if (INTEGRITY_CHECK_URI != null) { 10794525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu return; 10804525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu } 1081c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler INTEGRITY_CHECK_URI = Uri.parse("content://" + EmailContent.AUTHORITY + 1082c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler "/integrityCheck"); 1083c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler ACCOUNT_BACKUP_URI = 1084c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler Uri.parse("content://" + EmailContent.AUTHORITY + "/accountBackup"); 1085c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler FOLDER_STATUS_URI = 1086c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler Uri.parse("content://" + EmailContent.AUTHORITY + "/status"); 1087c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler EMAIL_APP_MIME_TYPE = context.getString(R.string.application_mime_type); 1088c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 1089de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler final String uiNotificationAuthority = 1090de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler EmailContent.EMAIL_PACKAGE_NAME + ".uinotifications"; 1091de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler UIPROVIDER_CONVERSATION_NOTIFIER = 1092de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler Uri.parse("content://" + uiNotificationAuthority + "/uimessages"); 1093de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler UIPROVIDER_FOLDER_NOTIFIER = 1094de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler Uri.parse("content://" + uiNotificationAuthority + "/uifolder"); 1095de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler UIPROVIDER_FOLDERLIST_NOTIFIER = 1096de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler Uri.parse("content://" + uiNotificationAuthority + "/uifolders"); 1097de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler UIPROVIDER_ACCOUNT_NOTIFIER = 1098de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler Uri.parse("content://" + uiNotificationAuthority + "/uiaccount"); 1099de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler // Not currently used 1100de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler /* UIPROVIDER_SETTINGS_NOTIFIER = 1101de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler Uri.parse("content://" + uiNotificationAuthority + "/uisettings");*/ 1102de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler UIPROVIDER_ATTACHMENT_NOTIFIER = 1103de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler Uri.parse("content://" + uiNotificationAuthority + "/uiattachment"); 1104de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler UIPROVIDER_ATTACHMENTS_NOTIFIER = 1105de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler Uri.parse("content://" + uiNotificationAuthority + "/uiattachments"); 1106de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler UIPROVIDER_ALL_ACCOUNTS_NOTIFIER = 1107de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler Uri.parse("content://" + uiNotificationAuthority + "/uiaccts"); 1108de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler UIPROVIDER_MESSAGE_NOTIFIER = 1109de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler Uri.parse("content://" + uiNotificationAuthority + "/uimessage"); 1110de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler UIPROVIDER_RECENT_FOLDERS_NOTIFIER = 1111de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler Uri.parse("content://" + uiNotificationAuthority + "/uirecentfolders"); 1112de8b97c72e8d0019d892f70d3d452ada051ed8f3Tony Mantler 1113c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // All accounts 11144525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "account", ACCOUNT); 1115c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // A specific account 1116c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // insert into this URI causes a mailbox to be added to the account 11174525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "account/#", ACCOUNT_ID); 11184525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "accountCheck/#", ACCOUNT_CHECK); 1119c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 1120c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // All mailboxes 11214525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "mailbox", MAILBOX); 1122c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // A specific mailbox 1123c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // insert into this URI causes a message to be added to the mailbox 1124c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // ** NOTE For now, the accountKey must be set manually in the values! 11254525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "mailbox/*", MAILBOX_ID); 11264525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "mailboxNotification/#", 11274525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu MAILBOX_NOTIFICATION); 11284525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "mailboxMostRecentMessage/#", 1129c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler MAILBOX_MOST_RECENT_MESSAGE); 11304525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "mailboxCount/#", MAILBOX_MESSAGE_COUNT); 1131c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 1132c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // All messages 11334525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "message", MESSAGE); 1134c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // A specific message 1135c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // insert into this URI causes an attachment to be added to the message 11364525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "message/#", MESSAGE_ID); 1137c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 1138c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // A specific attachment 11394525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "attachment", ATTACHMENT); 1140c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // A specific attachment (the header information) 11414525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "attachment/#", ATTACHMENT_ID); 1142c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // The attachments of a specific message (query only) (insert & delete TBD) 11434525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "attachment/message/#", 11444525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu ATTACHMENTS_MESSAGE_ID); 11454525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "attachment/cachedFile", 1146c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler ATTACHMENTS_CACHED_FILE_ACCESS); 1147c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 1148c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // All mail bodies 11494525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "body", BODY); 1150c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // A specific mail body 11514525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "body/#", BODY_ID); 11522f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler // A specific HTML body part, for openFile 11532f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler sURIMatcher.addURI(EmailContent.AUTHORITY, "bodyHtml/#", BODY_HTML); 11542f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler // A specific text body part, for openFile 11552f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler sURIMatcher.addURI(EmailContent.AUTHORITY, "bodyText/#", BODY_TEXT); 1156c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 1157c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // All hostauth records 11584525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "hostauth", HOSTAUTH); 1159c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // A specific hostauth 11604525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "hostauth/*", HOSTAUTH_ID); 1161c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 11620b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon // All credential records 11630b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon sURIMatcher.addURI(EmailContent.AUTHORITY, "credential", CREDENTIAL); 11640b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon // A specific credential 11650b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon sURIMatcher.addURI(EmailContent.AUTHORITY, "credential/*", CREDENTIAL_ID); 11660b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon 1167c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler /** 1168c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler * THIS URI HAS SPECIAL SEMANTICS 1169c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler * ITS USE IS INTENDED FOR THE UI TO MARK CHANGES THAT NEED TO BE SYNCED BACK 1170c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler * TO A SERVER VIA A SYNC ADAPTER 1171c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler */ 11724525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "syncedMessage/#", SYNCED_MESSAGE_ID); 11734525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "messageBySelection", MESSAGE_SELECTION); 1174c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 1175ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, MessageMove.PATH, MESSAGE_MOVE); 1176ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, MessageStateChange.PATH, 1177ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu MESSAGE_STATE_CHANGE); 1178336e65b6e1eb92fac8f03b5c39dde19361577cb4Yu Ping Hu 1179c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler /** 1180c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler * THE URIs BELOW THIS POINT ARE INTENDED TO BE USED BY SYNC ADAPTERS ONLY 1181c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler * THEY REFER TO DATA CREATED AND MAINTAINED BY CALLS TO THE SYNCED_MESSAGE_ID URI 1182c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler * BY THE UI APPLICATION 1183c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler */ 1184c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // All deleted messages 11854525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "deletedMessage", DELETED_MESSAGE); 1186c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // A specific deleted message 11874525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "deletedMessage/#", DELETED_MESSAGE_ID); 1188c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 1189c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // All updated messages 11904525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "updatedMessage", UPDATED_MESSAGE); 1191c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // A specific updated message 11924525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "updatedMessage/#", UPDATED_MESSAGE_ID); 1193c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 11944525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "policy", POLICY); 11954525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "policy/#", POLICY_ID); 1196c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 1197c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // All quick responses 11984525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "quickresponse", QUICK_RESPONSE); 1199c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // A specific quick response 12004525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "quickresponse/#", QUICK_RESPONSE_ID); 1201c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // All quick responses associated with a particular account id 12024525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "quickresponse/account/#", 1203c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler QUICK_RESPONSE_ACCOUNT_ID); 1204c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler 12054525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uifolders/#", UI_FOLDERS); 120696192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler sURIMatcher.addURI(EmailContent.AUTHORITY, "uifullfolders/#", UI_FULL_FOLDERS); 12074525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uiallfolders/#", UI_ALL_FOLDERS); 12084525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uisubfolders/#", UI_SUBFOLDERS); 12094525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uimessages/#", UI_MESSAGES); 12104525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uimessage/#", UI_MESSAGE); 12114525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uiundo", UI_UNDO); 12124525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, QUERY_UIREFRESH + "/#", UI_FOLDER_REFRESH); 1213c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // We listen to everything trailing uifolder/ since there might be an appVersion 1214c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler // as in Utils.appendVersionQueryParameter(). 12154525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uifolder/*", UI_FOLDER); 12160d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler sURIMatcher.addURI(EmailContent.AUTHORITY, "uiinbox/#", UI_INBOX); 12174525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uiaccount/#", UI_ACCOUNT); 12184525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uiaccts", UI_ACCTS); 1219b7e0834121d564982c0389c87df775ba311429d4Tony Mantler sURIMatcher.addURI(EmailContent.AUTHORITY, "uiacctsettings", UI_ACCTSETTINGS); 12204525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uiattachments/#", UI_ATTACHMENTS); 12214525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uiattachment/#", UI_ATTACHMENT); 1222b7e0834121d564982c0389c87df775ba311429d4Tony Mantler sURIMatcher.addURI(EmailContent.AUTHORITY, "uiattachmentbycid/#/*", 1223b7e0834121d564982c0389c87df775ba311429d4Tony Mantler UI_ATTACHMENT_BY_CID); 12244525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uisearch/#", UI_SEARCH); 12254525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uiaccountdata/#", UI_ACCOUNT_DATA); 12264525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uiloadmore/#", UI_FOLDER_LOAD_MORE); 12274525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uiconversation/#", UI_CONVERSATION); 12284525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uirecentfolders/#", UI_RECENT_FOLDERS); 12294525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "uidefaultrecentfolders/#", 1230c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler UI_DEFAULT_RECENT_FOLDERS); 12314525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "pickTrashFolder/#", 12324525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu ACCOUNT_PICK_TRASH_FOLDER); 12334525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu sURIMatcher.addURI(EmailContent.AUTHORITY, "pickSentFolder/#", 12344525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu ACCOUNT_PICK_SENT_FOLDER); 1235e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler sURIMatcher.addURI(EmailContent.AUTHORITY, "uipurgefolder/#", UI_PURGE_FOLDER); 1236c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler } 1237c0a1a81543d147309876701484f5c5be93bdd203Tony Mantler } 1238f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 12390e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank /** 12400e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank * The idea here is that the two databases (EmailProvider.db and EmailProviderBody.db must 12410e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank * always be in sync (i.e. there are two database or NO databases). This code will delete 12420e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank * any "orphan" database, so that both will be created together. Note that an "orphan" database 12430e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank * will exist after either of the individual databases is deleted due to data corruption. 12440e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank */ 12454525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu public void checkDatabases() { 12464525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu synchronized (sDatabaseLock) { 12474525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // Uncache the databases 12484525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu if (mDatabase != null) { 12494525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu mDatabase = null; 12504525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu } 12514525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu if (mBodyDatabase != null) { 12524525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu mBodyDatabase = null; 12534525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu } 12544525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // Look for orphans, and delete as necessary; these must always be in sync 12554525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu final File databaseFile = getContext().getDatabasePath(DATABASE_NAME); 12564525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu final File bodyFile = getContext().getDatabasePath(BODY_DATABASE_NAME); 12574525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu 12584525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu // TODO Make sure attachments are deleted 12594525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu if (databaseFile.exists() && !bodyFile.exists()) { 12604525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu LogUtils.w(TAG, "Deleting orphaned EmailProvider database..."); 12614525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu getContext().deleteDatabase(DATABASE_NAME); 12624525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu } else if (bodyFile.exists() && !databaseFile.exists()) { 12634525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu LogUtils.w(TAG, "Deleting orphaned EmailProviderBody database..."); 12644525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu getContext().deleteDatabase(BODY_DATABASE_NAME); 12654525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu } 12660e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank } 12670e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank } 12684525565948db8728f5608da21bb9fd95993c6be9Yu Ping Hu 1269f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler @Override 1270758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 1271fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank String sortOrder) { 1272f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler Cursor c = null; 1273d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank int match; 1274d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank try { 1275d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank match = findMatch(uri, "query"); 1276d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank } catch (IllegalArgumentException e) { 1277d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank String uriString = uri.toString(); 1278d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank // If we were passed an illegal uri, see if it ends in /-1 1279d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank // if so, and if substituting 0 for -1 results in a valid uri, return an empty cursor 1280d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank if (uriString != null && uriString.endsWith("/-1")) { 1281d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank uri = Uri.parse(uriString.substring(0, uriString.length() - 2) + "0"); 1282d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank match = findMatch(uri, "query"); 1283d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank switch (match) { 1284d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank case BODY_ID: 1285d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank case MESSAGE_ID: 1286d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank case DELETED_MESSAGE_ID: 1287d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank case UPDATED_MESSAGE_ID: 1288d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank case ATTACHMENT_ID: 1289d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank case MAILBOX_ID: 1290d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank case ACCOUNT_ID: 1291d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank case HOSTAUTH_ID: 1292e8eb6e659b5914eb7deab451c583e906010d0457Martin Hibdon case CREDENTIAL_ID: 1293aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank case POLICY_ID: 12947fdde9bb4a24e931618a7a64227e2194c89034daScott Kennedy return new MatrixCursorWithCachedColumns(projection, 0); 1295d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank } 1296d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank } 1297d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank throw e; 1298d306ba34387f3a7e77a4b8d98c6ac45cc14b95adMarc Blank } 1299a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank Context context = getContext(); 1300cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank // See the comment at delete(), above 1301a867ebba6233becf2061c80e1c53d7d395a6cffcMarc Blank SQLiteDatabase db = getDatabase(context); 1302f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler int table = match >> BASE_SHIFT; 130307597e547bc02cd2247caa866d25b94745dcd448Marc Blank String limit = uri.getQueryParameter(EmailContent.PARAMETER_LIMIT); 1304f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler String id; 1305f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 1306c6953b77552d4cb71776cf0537dc226029381628Tony Mantler String tableName = TABLE_NAMES.valueAt(table); 1307fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank 13080e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank try { 13090e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank switch (match) { 13108cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux // First, dispatch queries from UnifiedEmail 1311f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_SEARCH: 1312c0e2b147e09dd0bf15f19e63807b1b3bab798f50Marc Blank c = uiSearch(uri, projection); 1313c0e2b147e09dd0bf15f19e63807b1b3bab798f50Marc Blank return c; 1314f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ACCTS: 13154038f464dee0a33f1e7a58102857c24edf7e0eb2Paul Westbrook final String suppressParam = 13164038f464dee0a33f1e7a58102857c24edf7e0eb2Paul Westbrook uri.getQueryParameter(EmailContent.SUPPRESS_COMBINED_ACCOUNT_PARAM); 13174038f464dee0a33f1e7a58102857c24edf7e0eb2Paul Westbrook final boolean suppressCombined = 13184038f464dee0a33f1e7a58102857c24edf7e0eb2Paul Westbrook suppressParam != null && Boolean.parseBoolean(suppressParam); 13194038f464dee0a33f1e7a58102857c24edf7e0eb2Paul Westbrook c = uiAccounts(projection, suppressCombined); 1320f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return c; 1321f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_UNDO: 1322f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return uiUndo(projection); 1323f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_SUBFOLDERS: 1324f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_MESSAGES: 1325f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_MESSAGE: 1326f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_FOLDER: 13270d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler case UI_INBOX: 1328f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ACCOUNT: 1329f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ATTACHMENT: 1330f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ATTACHMENTS: 13318cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux case UI_ATTACHMENT_BY_CID: 1332f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_CONVERSATION: 1333f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_RECENT_FOLDERS: 133496192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler case UI_FULL_FOLDERS: 1335f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ALL_FOLDERS: 1336f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // For now, we don't allow selection criteria within these queries 1337f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (selection != null || selectionArgs != null) { 1338f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank throw new IllegalArgumentException("UI queries can't have selection/args"); 1339f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 1340b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy 1341b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final String seenParam = uri.getQueryParameter(UIProvider.SEEN_QUERY_PARAMETER); 13429e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler final boolean unseenOnly = 13439e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler seenParam != null && Boolean.FALSE.toString().equals(seenParam); 1344b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy 1345b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy c = uiQuery(match, uri, projection, unseenOnly); 1346f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return c; 1347f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_FOLDERS: 1348f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c = uiFolders(uri, projection); 1349f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return c; 1350f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_FOLDER_LOAD_MORE: 135164cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu c = uiFolderLoadMore(getMailbox(uri)); 1352f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return c; 1353f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_FOLDER_REFRESH: 135464cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu c = uiFolderRefresh(getMailbox(uri), 0); 1355f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return c; 1356f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case MAILBOX_NOTIFICATION: 1357f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c = notificationQuery(uri); 1358f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return c; 1359f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case MAILBOX_MOST_RECENT_MESSAGE: 1360f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c = mostRecentMessageQuery(uri); 1361f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return c; 136217d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu case MAILBOX_MESSAGE_COUNT: 136317d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu c = getMailboxMessageCount(uri); 136417d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu return c; 1365ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu case MESSAGE_MOVE: 1366ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu return db.query(MessageMove.TABLE_NAME, projection, selection, selectionArgs, 1367ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu null, null, sortOrder, limit); 1368ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu case MESSAGE_STATE_CHANGE: 1369ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu return db.query(MessageStateChange.TABLE_NAME, projection, selection, 1370ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu selectionArgs, null, null, sortOrder, limit); 13710e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case MESSAGE: 13720e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case UPDATED_MESSAGE: 13730e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case DELETED_MESSAGE: 13740e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ATTACHMENT: 13750e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case MAILBOX: 13760e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ACCOUNT: 13770e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case HOSTAUTH: 1378e8eb6e659b5914eb7deab451c583e906010d0457Martin Hibdon case CREDENTIAL: 1379aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank case POLICY: 1380fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank c = db.query(tableName, projection, 13810efe738e05a31e0c1ebfba645bd2364a373a3f33Marc Blank selection, selectionArgs, null, null, sortOrder, limit); 13820e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank break; 1383c6953b77552d4cb71776cf0537dc226029381628Tony Mantler case QUICK_RESPONSE: 1384c6953b77552d4cb71776cf0537dc226029381628Tony Mantler c = uiQuickResponse(projection); 1385c6953b77552d4cb71776cf0537dc226029381628Tony Mantler break; 1386f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler case BODY: 1387f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler case BODY_ID: { 1388f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler final ProjectionMap map = new ProjectionMap.Builder() 1389f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler .addAll(projection) 1390f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler .build(); 13912f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler if (map.containsKey(BodyColumns.HTML_CONTENT) || 13922f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler map.containsKey(BodyColumns.TEXT_CONTENT)) { 13932f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler throw new IllegalArgumentException( 13942f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler "Body content cannot be returned in the cursor"); 13952f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler } 13962f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler 1397f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler final ContentValues cv = new ContentValues(2); 13982f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler cv.put(BodyColumns.HTML_CONTENT_URI, "@" + uriWithColumn("bodyHtml", 13992f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler BodyColumns.MESSAGE_KEY)); 14002f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler cv.put(BodyColumns.TEXT_CONTENT_URI, "@" + uriWithColumn("bodyText", 14012f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler BodyColumns.MESSAGE_KEY)); 14022f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler 1403f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler final StringBuilder sb = genSelect(map, projection, cv); 1404f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler sb.append(" FROM ").append(Body.TABLE_NAME); 1405f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler if (match == BODY_ID) { 1406f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler id = uri.getPathSegments().get(1); 1407f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler sb.append(" WHERE ").append(whereWithId(id, selection)); 1408f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler } else if (!TextUtils.isEmpty(selection)) { 1409f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler sb.append(" WHERE ").append(selection); 1410f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler } 1411f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler if (!TextUtils.isEmpty(sortOrder)) { 1412f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler sb.append(" ORDER BY ").append(sortOrder); 1413f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler } 1414f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler if (!TextUtils.isEmpty(limit)) { 1415f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler sb.append(" LIMIT ").append(limit); 1416f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler } 1417f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler c = db.rawQuery(sb.toString(), selectionArgs); 1418f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler break; 1419f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler } 14200e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case MESSAGE_ID: 14210e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case DELETED_MESSAGE_ID: 14220e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case UPDATED_MESSAGE_ID: 14230e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ATTACHMENT_ID: 14240e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case MAILBOX_ID: 14250e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case HOSTAUTH_ID: 1426e8eb6e659b5914eb7deab451c583e906010d0457Martin Hibdon case CREDENTIAL_ID: 1427aeee10e57ef4d931e7708fde218d590453a82aeaMarc Blank case POLICY_ID: 14280e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank id = uri.getPathSegments().get(1); 1429503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu c = db.query(tableName, projection, whereWithId(id, selection), 1430503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu selectionArgs, null, null, sortOrder, limit); 14310e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank break; 143299665fe7bfabd0e84e3c1e05bbec5f11fb9a904cMartin Hibdon case ACCOUNT_ID: 143399665fe7bfabd0e84e3c1e05bbec5f11fb9a904cMartin Hibdon id = uri.getPathSegments().get(1); 143499665fe7bfabd0e84e3c1e05bbec5f11fb9a904cMartin Hibdon // There seems to be an issue with smart forwarding sometimes including the 143599665fe7bfabd0e84e3c1e05bbec5f11fb9a904cMartin Hibdon // quoted text from the wrong message. For now, we just disable it. 143699665fe7bfabd0e84e3c1e05bbec5f11fb9a904cMartin Hibdon final String[] alternateProjection = new String[projection.length]; 143799665fe7bfabd0e84e3c1e05bbec5f11fb9a904cMartin Hibdon for (int i = 0; i < projection.length; i++) { 143899665fe7bfabd0e84e3c1e05bbec5f11fb9a904cMartin Hibdon String column = projection[i]; 143999665fe7bfabd0e84e3c1e05bbec5f11fb9a904cMartin Hibdon if (TextUtils.equals(column, AccountColumns.FLAGS)) { 144099665fe7bfabd0e84e3c1e05bbec5f11fb9a904cMartin Hibdon alternateProjection[i] = AccountColumns.FLAGS + " & ~" + 144199665fe7bfabd0e84e3c1e05bbec5f11fb9a904cMartin Hibdon Account.FLAGS_SUPPORTS_SMART_FORWARD + " AS " + 144299665fe7bfabd0e84e3c1e05bbec5f11fb9a904cMartin Hibdon AccountColumns.FLAGS; 144399665fe7bfabd0e84e3c1e05bbec5f11fb9a904cMartin Hibdon } else { 144499665fe7bfabd0e84e3c1e05bbec5f11fb9a904cMartin Hibdon alternateProjection[i] = projection[i]; 144599665fe7bfabd0e84e3c1e05bbec5f11fb9a904cMartin Hibdon } 144699665fe7bfabd0e84e3c1e05bbec5f11fb9a904cMartin Hibdon } 144799665fe7bfabd0e84e3c1e05bbec5f11fb9a904cMartin Hibdon 144899665fe7bfabd0e84e3c1e05bbec5f11fb9a904cMartin Hibdon c = db.query(tableName, alternateProjection, whereWithId(id, selection), 144999665fe7bfabd0e84e3c1e05bbec5f11fb9a904cMartin Hibdon selectionArgs, null, null, sortOrder, limit); 145099665fe7bfabd0e84e3c1e05bbec5f11fb9a904cMartin Hibdon break; 1451c6953b77552d4cb71776cf0537dc226029381628Tony Mantler case QUICK_RESPONSE_ID: 1452c6953b77552d4cb71776cf0537dc226029381628Tony Mantler id = uri.getPathSegments().get(1); 1453c6953b77552d4cb71776cf0537dc226029381628Tony Mantler c = uiQuickResponseId(projection, id); 1454c6953b77552d4cb71776cf0537dc226029381628Tony Mantler break; 14550e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ATTACHMENTS_MESSAGE_ID: 14560e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank // All attachments for the given message 14570e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank id = uri.getPathSegments().get(2); 14580e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank c = db.query(Attachment.TABLE_NAME, projection, 14593dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler whereWith(AttachmentColumns.MESSAGE_KEY + "=" + id, selection), 14600efe738e05a31e0c1ebfba645bd2364a373a3f33Marc Blank selectionArgs, null, null, sortOrder, limit); 14610e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank break; 14625a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo case QUICK_RESPONSE_ACCOUNT_ID: 14635a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo // All quick responses for the given account 14645a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo id = uri.getPathSegments().get(2); 1465c6953b77552d4cb71776cf0537dc226029381628Tony Mantler c = uiQuickResponseAccount(projection, id); 14665a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo break; 146789272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon case ATTACHMENTS_CACHED_FILE_ACCESS: 146889272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon if (projection == null) { 146989272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon projection = 147089272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon new String[] { 147189272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon AttachmentUtilities.Columns._ID, 147289272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon AttachmentUtilities.Columns.DATA, 147389272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon }; 147489272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon } 147589272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon // Map the columns of our attachment table to the columns defined in 147689272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon // AttachmentUtils. These are a superset of OpenableColumns. 147789272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon // This mirrors similar code in AttachmentProvider. 147889272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon c = db.query(Attachment.TABLE_NAME, 147989272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon CACHED_FILE_QUERY_PROJECTION, AttachmentColumns.CACHED_FILE + "=?", 148089272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon new String[]{uri.toString()}, null, null, null, null); 148189272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon try { 148289272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon if (c.getCount() > 1) { 148389272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon LogUtils.e(TAG, "multiple results querying CACHED_FILE_ACCESS %s", uri); 148489272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon } 148589272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon if (c != null && c.moveToFirst()) { 148689272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon MatrixCursor ret = new MatrixCursorWithCachedColumns(projection); 148789272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon Object[] values = new Object[projection.length]; 148889272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon for (int i = 0, count = projection.length; i < count; i++) { 148989272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon String column = projection[i]; 149089272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon if (AttachmentUtilities.Columns._ID.equals(column)) { 149189272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon values[i] = c.getLong( 149289272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon c.getColumnIndexOrThrow(AttachmentColumns._ID)); 149389272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon } 149489272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon else if (AttachmentUtilities.Columns.DATA.equals(column)) { 149589272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon values[i] = c.getString( 149689272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon c.getColumnIndexOrThrow(AttachmentColumns.CONTENT_URI)); 149789272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon } 149889272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon else if (AttachmentUtilities.Columns.DISPLAY_NAME.equals(column)) { 149989272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon values[i] = c.getString( 150089272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon c.getColumnIndexOrThrow(AttachmentColumns.FILENAME)); 150189272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon } 150289272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon else if (AttachmentUtilities.Columns.SIZE.equals(column)) { 150389272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon values[i] = c.getInt( 150489272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon c.getColumnIndexOrThrow(AttachmentColumns.SIZE)); 150589272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon } else { 150689272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon LogUtils.e(TAG, 150789272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon "unexpected column %s requested for CACHED_FILE", 150889272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon column); 150989272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon } 151089272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon } 151189272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon ret.addRow(values); 151289272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon return ret; 151389272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon } 151489272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon } finally { 151589272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon if (c != null) { 151689272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon c.close(); 151789272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon } 151889272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon } 151989272781fa854e7f44e673bbc3d9c87b0a7b44b4Martin Hibdon return null; 15200e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank default: 15210e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank throw new IllegalArgumentException("Unknown URI " + uri); 15220e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank } 15230e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank } catch (SQLiteException e) { 15240e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank checkDatabases(); 15250e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank throw e; 1526fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank } catch (RuntimeException e) { 1527fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank checkDatabases(); 1528fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank e.printStackTrace(); 1529fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank throw e; 1530fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank } finally { 15317390b187767b559f693666156b8ca5c7c25bcfe4Marc Blank if (c == null) { 15327390b187767b559f693666156b8ca5c7c25bcfe4Marc Blank // This should never happen, but let's be sure to log it... 153366eef4565dd0a8b99e927bed7b64c472d24c276dYu Ping Hu // TODO: There are actually cases where c == null is expected, for example 153466eef4565dd0a8b99e927bed7b64c472d24c276dYu Ping Hu // UI_FOLDER_LOAD_MORE. 153566eef4565dd0a8b99e927bed7b64c472d24c276dYu Ping Hu // Demoting this to a warning for now until we figure out what to do with it. 1536c9ee5a389a8e5f9db56742a2d41eae2c912e6612Martin Hibdon LogUtils.w(TAG, "Query returning null for uri: %s selection: %s", uri, selection); 15377390b187767b559f693666156b8ca5c7c25bcfe4Marc Blank } 1538f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 1539f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 1540f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler if ((c != null) && !isTemporary()) { 1541261d6c3f0c97a12256519a2c3b131a56e57ab45fMakoto Onuki c.setNotificationUri(getContext().getContentResolver(), uri); 1542f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 1543f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler return c; 1544f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 1545f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler 1546b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static String whereWithId(String id, String selection) { 1547f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler StringBuilder sb = new StringBuilder(256); 1548f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler sb.append("_id="); 1549f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler sb.append(id); 1550f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler if (selection != null) { 15516c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler sb.append(" AND ("); 1552f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler sb.append(selection); 15536c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler sb.append(')'); 1554f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 1555f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler return sb.toString(); 1556f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 1557f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 15586c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler /** 15596c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler * Combine a locally-generated selection with a user-provided selection 15606c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler * 15616c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler * This introduces risk that the local selection might insert incorrect chars 15626c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler * into the SQL, so use caution. 15636c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler * 15646c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler * @param where locally-generated selection, must not be null 15656c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler * @param selection user-provided selection, may be null 15666c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler * @return a single selection string 15676c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler */ 1568b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static String whereWith(String where, String selection) { 15696c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler if (selection == null) { 15706c21942ec45f561d711b3d74ecca8e62afb735c4Andrew Stadler return where; 1571f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 15720053401d07cd11f19c63dfbc3942d027b4067de8Tony Mantler return where + " AND (" + selection + ")"; 1573f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 1574f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 15750993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank /** 15760993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank * Restore a HostAuth from a database, given its unique id 15770993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank * @param db the database 15780993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank * @param id the unique id (_id) of the row 15790993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank * @return a fully populated HostAuth or null if the row does not exist 15800993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank */ 15819dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki private static HostAuth restoreHostAuth(SQLiteDatabase db, long id) { 15820993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank Cursor c = db.query(HostAuth.TABLE_NAME, HostAuth.CONTENT_PROJECTION, 15833dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler HostAuthColumns._ID + "=?", new String[] {Long.toString(id)}, null, null, null); 15840993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank try { 15850993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank if (c.moveToFirst()) { 15860993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank HostAuth hostAuth = new HostAuth(); 15870993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank hostAuth.restore(c); 15880993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank return hostAuth; 15890993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 15900993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank return null; 15910993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } finally { 15920993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank c.close(); 15930993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 15940993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 15950993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank 15960993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank /** 15970993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank * Copy the Account and HostAuth tables from one database to another 15980993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank * @param fromDatabase the source database 15990993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank * @param toDatabase the destination database 16000993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank * @return the number of accounts copied, or -1 if an error occurred 16010993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank */ 16029dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki private static int copyAccountTables(SQLiteDatabase fromDatabase, SQLiteDatabase toDatabase) { 16030993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank if (fromDatabase == null || toDatabase == null) return -1; 1604f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 1605f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Lock both databases; for the "from" database, we don't want anyone changing it from 1606f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // under us; for the "to" database, we want to make the operation atomic 16070993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank int copyCount = 0; 1608f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank fromDatabase.beginTransaction(); 16090993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank try { 16100993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank toDatabase.beginTransaction(); 16110993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank try { 1612f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Delete anything hanging around here 1613f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank toDatabase.delete(Account.TABLE_NAME, null, null); 1614f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank toDatabase.delete(HostAuth.TABLE_NAME, null, null); 1615f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 1616f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Get our account cursor 1617f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Cursor c = fromDatabase.query(Account.TABLE_NAME, Account.CONTENT_PROJECTION, 1618f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank null, null, null, null, null); 1619f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (c == null) return 0; 1620560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.d(TAG, "fromDatabase accounts: " + c.getCount()); 1621f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank try { 1622f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Loop through accounts, copying them and associated host auth's 1623f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank while (c.moveToNext()) { 1624f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Account account = new Account(); 1625f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank account.restore(c); 1626f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 1627f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Clear security sync key and sync key, as these were specific to the 1628f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // state of the account, and we've reset that... 1629f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Clear policy key so that we can re-establish policies from the server 1630f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // TODO This is pretty EAS specific, but there's a lot of that around 1631f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank account.mSecuritySyncKey = null; 1632f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank account.mSyncKey = null; 1633f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank account.mPolicyKey = 0; 1634f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 1635f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Copy host auth's and update foreign keys 1636f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank HostAuth hostAuth = restoreHostAuth(fromDatabase, 1637f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank account.mHostAuthKeyRecv); 1638f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 1639f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // The account might have gone away, though very unlikely 16400993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank if (hostAuth == null) continue; 1641f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank account.mHostAuthKeyRecv = toDatabase.insert(HostAuth.TABLE_NAME, null, 16420993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank hostAuth.toContentValues()); 1643f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 1644f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // EAS accounts have no send HostAuth 1645f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (account.mHostAuthKeySend > 0) { 1646f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank hostAuth = restoreHostAuth(fromDatabase, account.mHostAuthKeySend); 1647f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Belt and suspenders; I can't imagine that this is possible, 1648f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // since we checked the validity of the account above, and the 1649f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // database is now locked 1650f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (hostAuth == null) continue; 1651f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank account.mHostAuthKeySend = toDatabase.insert( 1652f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank HostAuth.TABLE_NAME, null, hostAuth.toContentValues()); 1653f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 1654f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 1655f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Now, create the account in the "to" database 1656f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank toDatabase.insert(Account.TABLE_NAME, null, account.toContentValues()); 1657f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank copyCount++; 16580993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 1659f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } finally { 1660f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c.close(); 16610993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 1662f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 1663f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Say it's ok to commit 1664f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank toDatabase.setTransactionSuccessful(); 16650993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } finally { 16660993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank toDatabase.endTransaction(); 16670993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 1668f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } catch (SQLiteException ex) { 1669560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.w(TAG, "Exception while copying account tables", ex); 16700993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank copyCount = -1; 1671f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } finally { 1672f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank fromDatabase.endTransaction(); 16730993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 16740993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank return copyCount; 16750993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 16760993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank 16770993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank /** 16780993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank * Backup account data, returning the number of accounts backed up 16790993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank */ 168082a207132b34377d532f19882f5bfc70bc657da0Tony Mantler private static int backupAccounts(final Context context, final SQLiteDatabase db) { 168182a207132b34377d532f19882f5bfc70bc657da0Tony Mantler final AccountManager am = AccountManager.get(context); 168282a207132b34377d532f19882f5bfc70bc657da0Tony Mantler final Cursor accountCursor = db.query(Account.TABLE_NAME, Account.CONTENT_PROJECTION, 168382a207132b34377d532f19882f5bfc70bc657da0Tony Mantler null, null, null, null, null); 168482a207132b34377d532f19882f5bfc70bc657da0Tony Mantler int updatedCount = 0; 16850993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank try { 168682a207132b34377d532f19882f5bfc70bc657da0Tony Mantler while (accountCursor.moveToNext()) { 168782a207132b34377d532f19882f5bfc70bc657da0Tony Mantler final Account account = new Account(); 168882a207132b34377d532f19882f5bfc70bc657da0Tony Mantler account.restore(accountCursor); 168982a207132b34377d532f19882f5bfc70bc657da0Tony Mantler EmailServiceInfo serviceInfo = 169082a207132b34377d532f19882f5bfc70bc657da0Tony Mantler EmailServiceUtils.getServiceInfo(context, account.getProtocol(context)); 169182a207132b34377d532f19882f5bfc70bc657da0Tony Mantler if (serviceInfo == null) { 169282a207132b34377d532f19882f5bfc70bc657da0Tony Mantler LogUtils.d(LogUtils.TAG, "Could not find service info for account"); 169382a207132b34377d532f19882f5bfc70bc657da0Tony Mantler continue; 169482a207132b34377d532f19882f5bfc70bc657da0Tony Mantler } 169582a207132b34377d532f19882f5bfc70bc657da0Tony Mantler final String jsonString = account.toJsonString(context); 169682a207132b34377d532f19882f5bfc70bc657da0Tony Mantler final android.accounts.Account amAccount = 169782a207132b34377d532f19882f5bfc70bc657da0Tony Mantler account.getAccountManagerAccount(serviceInfo.accountType); 169882a207132b34377d532f19882f5bfc70bc657da0Tony Mantler am.setUserData(amAccount, ACCOUNT_MANAGER_JSON_TAG, jsonString); 169982a207132b34377d532f19882f5bfc70bc657da0Tony Mantler updatedCount++; 17009dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki } 17010993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } finally { 170282a207132b34377d532f19882f5bfc70bc657da0Tony Mantler accountCursor.close(); 17030993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 170482a207132b34377d532f19882f5bfc70bc657da0Tony Mantler return updatedCount; 17050993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 17060993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank 17070993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank /** 17080993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank * Restore account data, returning the number of accounts restored 17090993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank */ 171082a207132b34377d532f19882f5bfc70bc657da0Tony Mantler private static int restoreAccounts(final Context context) { 171182a207132b34377d532f19882f5bfc70bc657da0Tony Mantler final Collection<EmailServiceInfo> infos = EmailServiceUtils.getServiceInfoList(context); 171282a207132b34377d532f19882f5bfc70bc657da0Tony Mantler // Find all possible account types 171382a207132b34377d532f19882f5bfc70bc657da0Tony Mantler final Set<String> accountTypes = new HashSet<String>(3); 171482a207132b34377d532f19882f5bfc70bc657da0Tony Mantler for (final EmailServiceInfo info : infos) { 17151381d4083bbfdf046eceac081420ab3fa7a1ae81Tony Mantler if (!TextUtils.isEmpty(info.accountType)) { 17161381d4083bbfdf046eceac081420ab3fa7a1ae81Tony Mantler // accountType will be empty for the gmail stub entry 17171381d4083bbfdf046eceac081420ab3fa7a1ae81Tony Mantler accountTypes.add(info.accountType); 17181381d4083bbfdf046eceac081420ab3fa7a1ae81Tony Mantler } 17199dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki } 172082a207132b34377d532f19882f5bfc70bc657da0Tony Mantler // Find all accounts we own 172182a207132b34377d532f19882f5bfc70bc657da0Tony Mantler final List<android.accounts.Account> amAccounts = new ArrayList<android.accounts.Account>(); 172282a207132b34377d532f19882f5bfc70bc657da0Tony Mantler final AccountManager am = AccountManager.get(context); 172382a207132b34377d532f19882f5bfc70bc657da0Tony Mantler for (final String accountType : accountTypes) { 172482a207132b34377d532f19882f5bfc70bc657da0Tony Mantler amAccounts.addAll(Arrays.asList(am.getAccountsByType(accountType))); 172582a207132b34377d532f19882f5bfc70bc657da0Tony Mantler } 172682a207132b34377d532f19882f5bfc70bc657da0Tony Mantler // Try to restore them from saved JSON 172782a207132b34377d532f19882f5bfc70bc657da0Tony Mantler int restoredCount = 0; 172882a207132b34377d532f19882f5bfc70bc657da0Tony Mantler for (final android.accounts.Account amAccount : amAccounts) { 1729a3652cbf8b77524c70fb55d7c2f0655fa0241b27Tony Mantler final String jsonString = am.getUserData(amAccount, ACCOUNT_MANAGER_JSON_TAG); 173082a207132b34377d532f19882f5bfc70bc657da0Tony Mantler if (TextUtils.isEmpty(jsonString)) { 173182a207132b34377d532f19882f5bfc70bc657da0Tony Mantler continue; 17329dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki } 173382a207132b34377d532f19882f5bfc70bc657da0Tony Mantler final Account account = Account.fromJsonString(jsonString); 173482a207132b34377d532f19882f5bfc70bc657da0Tony Mantler if (account != null) { 173582a207132b34377d532f19882f5bfc70bc657da0Tony Mantler AccountSettingsUtils.commitSettings(context, account); 1736a3652cbf8b77524c70fb55d7c2f0655fa0241b27Tony Mantler final Bundle extras = new Bundle(3); 1737a3652cbf8b77524c70fb55d7c2f0655fa0241b27Tony Mantler extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); 1738a3652cbf8b77524c70fb55d7c2f0655fa0241b27Tony Mantler extras.putBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, true); 1739a3652cbf8b77524c70fb55d7c2f0655fa0241b27Tony Mantler extras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true); 1740a3652cbf8b77524c70fb55d7c2f0655fa0241b27Tony Mantler ContentResolver.requestSync(amAccount, EmailContent.AUTHORITY, extras); 174182a207132b34377d532f19882f5bfc70bc657da0Tony Mantler restoredCount++; 17420993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 17430993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 174482a207132b34377d532f19882f5bfc70bc657da0Tony Mantler return restoredCount; 17450993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank } 17460993190cafebc107bd27a26996b5d63d4a4ede10Marc Blank 1747ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu private static final String MESSAGE_CHANGE_LOG_TABLE_INSERT_PREFIX = "insert into %s (" 1748ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu + MessageChangeLogTable.MESSAGE_KEY + "," + MessageChangeLogTable.SERVER_ID + "," 1749ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu + MessageChangeLogTable.ACCOUNT_KEY + "," + MessageChangeLogTable.STATUS + ","; 1750ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 1751ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu private static final String MESSAGE_CHANGE_LOG_TABLE_VALUES_PREFIX = ") values (%s, " 17523dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + "(select " + MessageColumns.SERVER_ID + " from " + 17533dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler Message.TABLE_NAME + " where _id=%s)," 17543dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + "(select " + MessageColumns.ACCOUNT_KEY + " from " + 17553dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler Message.TABLE_NAME + " where _id=%s)," 1756ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu + MessageMove.STATUS_NONE_STRING + ","; 1757ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 1758ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** 1759ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * Formatting string to generate the SQL statement for inserting into MessageMove. 1760ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * The formatting parameters are: 1761ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * table name, message id x 4, destination folder id, message id, destination folder id. 1762ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * Duplications are needed for sub-selects. 1763ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu */ 1764ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu private static final String MESSAGE_MOVE_INSERT = MESSAGE_CHANGE_LOG_TABLE_INSERT_PREFIX 1765ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu + MessageMove.SRC_FOLDER_KEY + "," + MessageMove.DST_FOLDER_KEY + "," 1766ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu + MessageMove.SRC_FOLDER_SERVER_ID + "," + MessageMove.DST_FOLDER_SERVER_ID 1767ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu + MESSAGE_CHANGE_LOG_TABLE_VALUES_PREFIX 17683dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + "(select " + MessageColumns.MAILBOX_KEY + 17693dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler " from " + Message.TABLE_NAME + " where _id=%s)," + "%d," 1770ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu + "(select " + Mailbox.SERVER_ID + " from " + Mailbox.TABLE_NAME + " where _id=(select " 17713dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + MessageColumns.MAILBOX_KEY + " from " + Message.TABLE_NAME + " where _id=%s))," 1772ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu + "(select " + Mailbox.SERVER_ID + " from " + Mailbox.TABLE_NAME + " where _id=%d))"; 1773ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 1774ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** 1775ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * Insert a row into the MessageMove table when that message is moved. 1776ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param db The {@link SQLiteDatabase}. 1777ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param messageId The id of the message being moved. 1778ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * @param dstFolderKey The folder to which the message is being moved. 1779ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu */ 1780ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu private void addToMessageMove(final SQLiteDatabase db, final String messageId, 1781ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu final long dstFolderKey) { 1782ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu db.execSQL(String.format(Locale.US, MESSAGE_MOVE_INSERT, MessageMove.TABLE_NAME, 1783ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu messageId, messageId, messageId, messageId, dstFolderKey, messageId, dstFolderKey)); 1784ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 1785ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 1786ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu /** 1787ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * Formatting string to generate the SQL statement for inserting into MessageStateChange. 1788ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * The formatting parameters are: 1789ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * table name, message id x 4, new flag read, message id, new flag favorite. 1790ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu * Duplications are needed for sub-selects. 1791ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu */ 1792ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu private static final String MESSAGE_STATE_CHANGE_INSERT = MESSAGE_CHANGE_LOG_TABLE_INSERT_PREFIX 1793ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu + MessageStateChange.OLD_FLAG_READ + "," + MessageStateChange.NEW_FLAG_READ + "," 1794ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu + MessageStateChange.OLD_FLAG_FAVORITE + "," + MessageStateChange.NEW_FLAG_FAVORITE 1795ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu + MESSAGE_CHANGE_LOG_TABLE_VALUES_PREFIX 17963dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + "(select " + MessageColumns.FLAG_READ + 17973dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler " from " + Message.TABLE_NAME + " where _id=%s)," + "%d," 17983dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + "(select " + MessageColumns.FLAG_FAVORITE + 17993dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler " from " + Message.TABLE_NAME + " where _id=%s)," + "%d)"; 1800ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 1801ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu private void addToMessageStateChange(final SQLiteDatabase db, final String messageId, 1802ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu final int newFlagRead, final int newFlagFavorite) { 1803ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu db.execSQL(String.format(Locale.US, MESSAGE_STATE_CHANGE_INSERT, 1804ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu MessageStateChange.TABLE_NAME, messageId, messageId, messageId, messageId, 1805ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu newFlagRead, messageId, newFlagFavorite)); 1806ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 1807ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu 1808f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // select count(*) from (select count(*) as dupes from Mailbox where accountKey=? 1809f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // group by serverId) where dupes > 1; 1810f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String ACCOUNT_INTEGRITY_SQL = 1811f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "select count(*) from (select count(*) as dupes from " + Mailbox.TABLE_NAME + 1812f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " where accountKey=? group by " + MailboxColumns.SERVER_ID + ") where dupes > 1"; 1813f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 1814e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu 1815e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu // Query to get the protocol for a message. Temporary to switch between new and old upsync 1816e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu // behavior; should go away when IMAP gets converted. 1817feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert private static final String GET_MESSAGE_DETAILS = "SELECT" 1818feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert + " h." + HostAuthColumns.PROTOCOL + "," 18193dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + " m." + MessageColumns.MAILBOX_KEY + "," 18203dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + " a." + AccountColumns._ID 1821feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert + " FROM " + Message.TABLE_NAME + " AS m" 1822feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert + " INNER JOIN " + Account.TABLE_NAME + " AS a" 18233dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + " ON m." + MessageColumns.ACCOUNT_KEY + "=a." + AccountColumns._ID 1824feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert + " INNER JOIN " + HostAuth.TABLE_NAME + " AS h" 18253dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + " ON a." + AccountColumns.HOST_AUTH_KEY_RECV + "=h." + HostAuthColumns._ID 18263dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + " WHERE m." + MessageColumns._ID + "=?"; 18275e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private static final int INDEX_PROTOCOL = 0; 18285e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private static final int INDEX_MAILBOX_KEY = 1; 18295e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private static final int INDEX_ACCOUNT_KEY = 2; 18305e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu 18315e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu /** 18325e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * Query to get the protocol and email address for an account. Note that this uses 18335e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * {@link #INDEX_PROTOCOL} and {@link #INDEX_EMAIL_ADDRESS} for its columns. 18345e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu */ 18355e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private static final String GET_ACCOUNT_DETAILS = "SELECT" 18365e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu + " h." + HostAuthColumns.PROTOCOL + "," 18373f24a9e2c76af8b772953c8a026d9886321f0044Yu Ping Hu + " a." + AccountColumns.EMAIL_ADDRESS + "," 18383f24a9e2c76af8b772953c8a026d9886321f0044Yu Ping Hu + " a." + AccountColumns.SYNC_KEY 18395e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu + " FROM " + Account.TABLE_NAME + " AS a" 18405e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu + " INNER JOIN " + HostAuth.TABLE_NAME + " AS h" 18413dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + " ON a." + AccountColumns.HOST_AUTH_KEY_RECV + "=h." + HostAuthColumns._ID 18423dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + " WHERE a." + AccountColumns._ID + "=?"; 18435e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private static final int INDEX_EMAIL_ADDRESS = 1; 18443f24a9e2c76af8b772953c8a026d9886321f0044Yu Ping Hu private static final int INDEX_SYNC_KEY = 2; 18455e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu 18465e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu /** 18475e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * Restart push if we need it (currently only for Exchange accounts). 18485e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param context A {@link Context}. 18495e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param db The {@link SQLiteDatabase}. 18505e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param id The id of the thing we're looking for. 18515e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @return Whether or not we sent a request to restart the push. 18525e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu */ 18535e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private static boolean restartPush(final Context context, final SQLiteDatabase db, 18545e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu final String id) { 18555e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu final Cursor c = db.rawQuery(GET_ACCOUNT_DETAILS, new String[] {id}); 18565e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu if (c != null) { 18575e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu try { 18585e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu if (c.moveToFirst()) { 18595e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu final String protocol = c.getString(INDEX_PROTOCOL); 18603f24a9e2c76af8b772953c8a026d9886321f0044Yu Ping Hu // Only restart push for EAS accounts that have completed initial sync. 18613f24a9e2c76af8b772953c8a026d9886321f0044Yu Ping Hu if (context.getString(R.string.protocol_eas).equals(protocol) && 18623f24a9e2c76af8b772953c8a026d9886321f0044Yu Ping Hu !EmailContent.isInitialSyncKey(c.getString(INDEX_SYNC_KEY))) { 18633f24a9e2c76af8b772953c8a026d9886321f0044Yu Ping Hu final String emailAddress = c.getString(INDEX_EMAIL_ADDRESS); 18645e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu final android.accounts.Account account = 18655e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu getAccountManagerAccount(context, emailAddress, protocol); 186691e8e6f70921e65eabf128f14b5d43385b22f0a1Tony Mantler if (account != null) { 186791e8e6f70921e65eabf128f14b5d43385b22f0a1Tony Mantler restartPush(account); 186891e8e6f70921e65eabf128f14b5d43385b22f0a1Tony Mantler return true; 186991e8e6f70921e65eabf128f14b5d43385b22f0a1Tony Mantler } 18705e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 18715e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 18725e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } finally { 18735e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu c.close(); 18745e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 18755e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 18765e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu return false; 18775e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 18785e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu 18795e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu /** 18805e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * Restart push if a mailbox's settings change in a way that requires it. 18815e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param context A {@link Context}. 18825e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param db The {@link SQLiteDatabase}. 18835e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param values The {@link ContentValues} that were updated for the mailbox. 18845e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param accountId The id of the account for this mailbox. 18855e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @return Whether or not the push was restarted. 18865e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu */ 18875e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private static boolean restartPushForMailbox(final Context context, final SQLiteDatabase db, 18885e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu final ContentValues values, final String accountId) { 18895e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu if (values.containsKey(MailboxColumns.SYNC_LOOKBACK) || 18905e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu values.containsKey(MailboxColumns.SYNC_INTERVAL)) { 18915e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu return restartPush(context, db, accountId); 18925e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 18935e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu return false; 18945e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 18955e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu 18965e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu /** 18975e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * Restart push if an account's settings change in a way that requires it. 18985e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param context A {@link Context}. 18995e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param db The {@link SQLiteDatabase}. 19005e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param values The {@link ContentValues} that were updated for the account. 19015e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param accountId The id of the account. 19025e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @return Whether or not the push was restarted. 19035e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu */ 19045e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private static boolean restartPushForAccount(final Context context, final SQLiteDatabase db, 19055e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu final ContentValues values, final String accountId) { 19065e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu if (values.containsKey(AccountColumns.SYNC_LOOKBACK) || 19075e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu values.containsKey(AccountColumns.SYNC_INTERVAL)) { 19085e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu return restartPush(context, db, accountId); 19095e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 19105e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu return false; 19115e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 1912e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu 1913f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler @Override 1914f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 19159a342b31472536b89f55b1e6ae2e6f868ba1064dAlon Albert LogUtils.d(TAG, "Update: " + uri); 1916f678a8e67ace74ea285dcec9727d0117e23a5c73Makoto Onuki // Handle this special case the fastest possible way 1917e8a3c14f28bac4912842761b04c96272caf52810Tony Mantler if (INTEGRITY_CHECK_URI.equals(uri)) { 1918f678a8e67ace74ea285dcec9727d0117e23a5c73Makoto Onuki checkDatabases(); 1919f678a8e67ace74ea285dcec9727d0117e23a5c73Makoto Onuki return 0; 1920e8a3c14f28bac4912842761b04c96272caf52810Tony Mantler } else if (ACCOUNT_BACKUP_URI.equals(uri)) { 19219dad9ad973ccf8255228a41acc0ee78af989a651Makoto Onuki return backupAccounts(getContext(), getDatabase(getContext())); 1922f678a8e67ace74ea285dcec9727d0117e23a5c73Makoto Onuki } 1923f678a8e67ace74ea285dcec9727d0117e23a5c73Makoto Onuki 1924261d6c3f0c97a12256519a2c3b131a56e57ab45fMakoto Onuki // Notify all existing cursors, except for ACCOUNT_RESET_NEW_COUNT(_ID) 1925261d6c3f0c97a12256519a2c3b131a56e57ab45fMakoto Onuki Uri notificationUri = EmailContent.CONTENT_URI; 1926261d6c3f0c97a12256519a2c3b131a56e57ab45fMakoto Onuki 19272d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final int match = findMatch(uri, "update"); 19282d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final Context context = getContext(); 1929cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank // See the comment at delete(), above 19302d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final SQLiteDatabase db = getDatabase(context); 19312d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final int table = match >> BASE_SHIFT; 1932626f3e48a4f14c38a973dd2bea2e2debea7637a5Andrew Stadler int result; 1933a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank 19345b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki // We do NOT allow setting of unreadCount/messageCount via the provider 19355b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki // These columns are maintained via triggers 19365b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki if (match == MAILBOX_ID || match == MAILBOX) { 19375b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki values.remove(MailboxColumns.UNREAD_COUNT); 19385b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki values.remove(MailboxColumns.MESSAGE_COUNT); 19395b0c2c7f344e72915ac63ff45cf3d65885373a39Makoto Onuki } 19400e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank 19412d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler final String tableName = TABLE_NAMES.valueAt(table); 1942bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy String id = "0"; 1943fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank 19440e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank try { 19450e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank switch (match) { 1946c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank case ACCOUNT_PICK_TRASH_FOLDER: 1947c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank return pickTrashFolder(uri); 1948a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank case ACCOUNT_PICK_SENT_FOLDER: 1949a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank return pickSentFolder(uri); 1950b7e0834121d564982c0389c87df775ba311429d4Tony Mantler case UI_ACCTSETTINGS: 1951b7e0834121d564982c0389c87df775ba311429d4Tony Mantler return uiUpdateSettings(context, values); 1952f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_FOLDER: 1953b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy return uiUpdateFolder(context, uri, values); 1954f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_RECENT_FOLDERS: 1955f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return uiUpdateRecentFolders(uri, values); 1956f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_DEFAULT_RECENT_FOLDERS: 1957f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return uiPopulateRecentFolders(uri); 1958f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ATTACHMENT: 1959f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return uiUpdateAttachment(uri, values); 1960f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_MESSAGE: 1961f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return uiUpdateMessage(uri, values); 1962f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case ACCOUNT_CHECK: 1963f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank id = uri.getLastPathSegment(); 1964f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // With any error, return 1 (a failure) 1965f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank int res = 1; 1966f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Cursor ic = null; 1967f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank try { 1968f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ic = db.rawQuery(ACCOUNT_INTEGRITY_SQL, new String[] {id}); 1969f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (ic.moveToFirst()) { 1970f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank res = ic.getInt(0); 1971f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 1972f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } finally { 1973f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (ic != null) { 1974f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ic.close(); 1975f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 1976f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 1977f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Count of duplicated mailboxes 1978f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return res; 197900287c4d8f54ae07c89bb3893f440acdca09d728Marc Blank case MESSAGE_SELECTION: 1980c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank Cursor findCursor = db.query(tableName, Message.ID_COLUMN_PROJECTION, selection, 1981c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank selectionArgs, null, null, null); 1982c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank try { 1983c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank if (findCursor.moveToFirst()) { 1984c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank return update(ContentUris.withAppendedId( 198500287c4d8f54ae07c89bb3893f440acdca09d728Marc Blank Message.CONTENT_URI, 1986c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank findCursor.getLong(Message.ID_COLUMNS_ID_COLUMN)), 1987c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank values, null, null); 1988c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } else { 1989c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank return 0; 1990c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } 1991c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } finally { 1992c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank findCursor.close(); 1993c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } 19940e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case SYNCED_MESSAGE_ID: 19950e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case UPDATED_MESSAGE_ID: 19961b9337ea4f41c12cb108cbe67e0077169b1f0b8cMarc Blank case MESSAGE_ID: 19970e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ATTACHMENT_ID: 19980e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case MAILBOX_ID: 19990e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ACCOUNT_ID: 20000e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case HOSTAUTH_ID: 2001e8eb6e659b5914eb7deab451c583e906010d0457Martin Hibdon case CREDENTIAL_ID: 20025a3888f35b669ffb3cc785d7dfe4862879a3896cJorge Lugo case QUICK_RESPONSE_ID: 20036e418aa41a17136be0dddb816d843428a0a1e722Marc Blank case POLICY_ID: 20040e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank id = uri.getPathSegments().get(1); 2005c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu if (match == SYNCED_MESSAGE_ID) { 2006e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu // TODO: Migrate IMAP to use MessageMove/MessageStateChange as well. 2007e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu boolean isEas = false; 2008feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert long mailboxId = -1; 2009feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert long accountId = -1; 2010feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert final Cursor c = db.rawQuery(GET_MESSAGE_DETAILS, new String[] {id}); 2011e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu if (c != null) { 2012e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu try { 2013e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu if (c.moveToFirst()) { 2014feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert final String protocol = c.getString(INDEX_PROTOCOL); 2015e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu isEas = context.getString(R.string.protocol_eas) 2016e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu .equals(protocol); 2017feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert mailboxId = c.getLong(INDEX_MAILBOX_KEY); 2018feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert accountId = c.getLong(INDEX_ACCOUNT_KEY); 2019e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu } 2020e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu } finally { 2021e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu c.close(); 2022e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu } 2023ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 2024e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu 2025e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu if (isEas) { 2026e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu // EAS uses the new upsync classes. 2027e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu Long dstFolderId = values.getAsLong(MessageColumns.MAILBOX_KEY); 2028e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu if (dstFolderId != null) { 2029e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu addToMessageMove(db, id, dstFolderId); 2030e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu } 2031e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu Integer flagRead = values.getAsInteger(MessageColumns.FLAG_READ); 2032e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu Integer flagFavorite = values.getAsInteger(MessageColumns.FLAG_FAVORITE); 2033e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu int flagReadValue = (flagRead != null) ? 2034e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu flagRead : MessageStateChange.VALUE_UNCHANGED; 2035e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu int flagFavoriteValue = (flagFavorite != null) ? 2036e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu flagFavorite : MessageStateChange.VALUE_UNCHANGED; 2037e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu if (flagRead != null || flagFavorite != null) { 2038e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu addToMessageStateChange(db, id, flagReadValue, flagFavoriteValue); 2039e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu } 2040feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert 2041feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // Request a sync for the messages mailbox so the update will upsync. 2042feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // This is normally done with ContentResolver.notifyUpdate() but doesn't 2043feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // work for Exchange because the Sync Adapter is declared as 2044feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // android:supportsUploading="false". Changing it to true is not trivial 2045feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // because that would require us to protect all calls to notifyUpdate() 2046feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // with syncToServer=false except in cases where we actually want to 2047feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // upsync. 2048feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // TODO: Look into making Exchange Sync Adapter supportsUploading=true 2049feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // Since we can't use the Sync Manager "delayed-sync" feature which 2050feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // applies only to UPLOAD syncs, we need to do this ourselves. The 2051feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // purpose of this is not to spam syncs when making frequent 2052feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert // modifications. 2053feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert final Handler handler = getDelayedSyncHandler(); 2054b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler final android.accounts.Account amAccount = 2055b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler getAccountManagerAccount(accountId); 2056b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler if (amAccount != null) { 2057b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler final SyncRequestMessage request = new SyncRequestMessage( 2058b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler uri.getAuthority(), amAccount, mailboxId); 2059b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler synchronized (mDelayedSyncRequests) { 2060b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler if (!mDelayedSyncRequests.contains(request)) { 2061b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler mDelayedSyncRequests.add(request); 2062b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler final android.os.Message message = 2063b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler handler.obtainMessage(0, request); 2064b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler handler.sendMessageDelayed(message, SYNC_DELAY_MILLIS); 2065b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler } 2066feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 2067b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler } else { 2068b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler LogUtils.d(TAG, 2069b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler "Attempted to start delayed sync for invalid account %d", 2070b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler accountId); 2071feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 2072e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu } else { 2073e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu // Old way of doing upsync. 2074e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu // For synced messages, first copy the old message to the updated table 2075e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu // Note the insert or ignore semantics, guaranteeing that only the first 2076e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu // update will be reflected in the updated message table; therefore this 2077e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu // row will always have the "original" data 2078e9849404652f317c4fb3af822fd6fa9cd23ad881Yu Ping Hu db.execSQL(UPDATED_MESSAGE_INSERT + id); 2079ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu } 2080c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } else if (match == MESSAGE_ID) { 2081c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu db.execSQL(UPDATED_MESSAGE_DELETE + id); 20820e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank } 2083c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu result = db.update(tableName, values, whereWithId(id, selection), 2084c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu selectionArgs); 2085c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank if (match == MESSAGE_ID || match == SYNCED_MESSAGE_ID) { 2086c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu handleMessageUpdateNotifications(uri, id, values); 2087c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } else if (match == ATTACHMENT_ID) { 2088f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank long attId = Integer.parseInt(id); 20893dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler if (values.containsKey(AttachmentColumns.FLAGS)) { 20903dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler int flags = values.getAsInteger(AttachmentColumns.FLAGS); 2091f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mAttachmentService.attachmentChanged(context, attId, flags); 2092f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 2093f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Notify UI if necessary; there are only two columns we can change that 2094f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // would be worth a notification 2095f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (values.containsKey(AttachmentColumns.UI_STATE) || 2096f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.containsKey(AttachmentColumns.UI_DOWNLOADED_SIZE)) { 2097f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Notify on individual attachment 2098f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUI(UIPROVIDER_ATTACHMENT_NOTIFIER, id); 2099f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Attachment att = Attachment.restoreAttachmentWithId(context, attId); 2100f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (att != null) { 2101f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // And on owning Message 2102f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUI(UIPROVIDER_ATTACHMENTS_NOTIFIER, att.mMessageKey); 2103f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 210425fe72687df8fd3aa4d7dc81054cbf9f2be7f1f3Marc Blank } 2105c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } else if (match == MAILBOX_ID) { 21065e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu final long accountId = Mailbox.getAccountIdForMailbox(context, id); 21075e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu notifyUIFolder(id, accountId); 21085e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu restartPushForMailbox(context, db, values, Long.toString(accountId)); 2109f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else if (match == ACCOUNT_ID) { 2110e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu updateAccountSyncInterval(Long.parseLong(id), values); 211197a198292e665fff5d27d727d415f35b0a0633e4Marc Blank // Notify individual account and "all accounts" 2112f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUI(UIPROVIDER_ACCOUNT_NOTIFIER, id); 211305649dca2f59f28cd4295e041045a605badddb15Tony Mantler notifyUI(UIPROVIDER_ALL_ACCOUNTS_NOTIFIER, null); 21145e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu restartPushForAccount(context, db, values, id); 211509fd4d0a181db511a07950f52ad56cc6e686356bMarc Blank } 21160e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank break; 21177525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler case BODY_ID: { 21187525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final ContentValues updateValues = new ContentValues(values); 21197525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler updateValues.remove(BodyColumns.HTML_CONTENT); 21207525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler updateValues.remove(BodyColumns.TEXT_CONTENT); 21217525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler 21227525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler result = db.update(tableName, updateValues, whereWithId(id, selection), 21237525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler selectionArgs); 21247525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler 21257525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (values.containsKey(BodyColumns.HTML_CONTENT) || 21267525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler values.containsKey(BodyColumns.TEXT_CONTENT)) { 21277525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final long messageId; 21287525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (values.containsKey(BodyColumns.MESSAGE_KEY)) { 21297525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler messageId = values.getAsLong(BodyColumns.MESSAGE_KEY); 21307525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } else { 21317525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final long bodyId = Long.parseLong(id); 21327525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final SQLiteStatement sql = db.compileStatement( 21337525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler "select " + BodyColumns.MESSAGE_KEY + 21347525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler " from " + Body.TABLE_NAME + 21357525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler " where " + BodyColumns._ID + "=" + Long 21367525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler .toString(bodyId) 21377525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler ); 21387525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler messageId = sql.simpleQueryForLong(); 21397525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 21407525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler writeBodyFiles(context, messageId, values); 21417525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 21427525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler break; 21437525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 21447525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler case BODY: { 21457525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final ContentValues updateValues = new ContentValues(values); 21467525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler updateValues.remove(BodyColumns.HTML_CONTENT); 21477525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler updateValues.remove(BodyColumns.TEXT_CONTENT); 21487525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler 21497525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler result = db.update(tableName, updateValues, selection, selectionArgs); 21507525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler 2151d0b81a0d062f9bad15c9d9ba104b6cdf8590e5feYu Ping Hu if (result == 0 && selection.equals(Body.SELECTION_BY_MESSAGE_KEY)) { 2152d0b81a0d062f9bad15c9d9ba104b6cdf8590e5feYu Ping Hu // TODO: This is a hack. Notably, the selection equality test above 2153d0b81a0d062f9bad15c9d9ba104b6cdf8590e5feYu Ping Hu // is hokey at best. 2154d0b81a0d062f9bad15c9d9ba104b6cdf8590e5feYu Ping Hu LogUtils.i(TAG, "Body Update to non-existent row, morphing to insert"); 2155d0b81a0d062f9bad15c9d9ba104b6cdf8590e5feYu Ping Hu final ContentValues insertValues = new ContentValues(values); 21563dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler insertValues.put(BodyColumns.MESSAGE_KEY, selectionArgs[0]); 21573dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler insert(Body.CONTENT_URI, insertValues); 21587525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } else { 21597525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler // possibly need to write new body values 21607525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (values.containsKey(BodyColumns.HTML_CONTENT) || 21617525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler values.containsKey(BodyColumns.TEXT_CONTENT)) { 21627525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final long messageIds[]; 21637525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (values.containsKey(BodyColumns.MESSAGE_KEY)) { 21647525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler messageIds = new long[] {values.getAsLong(BodyColumns.MESSAGE_KEY)}; 21657525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } else if (values.containsKey(BodyColumns._ID)) { 21667525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final long bodyId = values.getAsLong(BodyColumns._ID); 21677525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final SQLiteStatement sql = db.compileStatement( 21687525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler "select " + BodyColumns.MESSAGE_KEY + 21697525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler " from " + Body.TABLE_NAME + 21707525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler " where " + BodyColumns._ID + "=" + Long 21717525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler .toString(bodyId) 21727525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler ); 21737525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler messageIds = new long[] {sql.simpleQueryForLong()}; 21747525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } else { 21757525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final String proj[] = {BodyColumns.MESSAGE_KEY}; 21767525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final Cursor c = db.query(Body.TABLE_NAME, proj, 21777525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler selection, selectionArgs, 21787525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler null, null, null); 21797525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler try { 21807525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final int count = c.getCount(); 21817525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (count == 0) { 21827525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler throw new IllegalStateException("Can't find body record"); 21837525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 21847525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler messageIds = new long[count]; 21857525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler int i = 0; 21867525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler while (c.moveToNext()) { 21877525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler messageIds[i++] = c.getLong(0); 21887525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 21897525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } finally { 21907525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler c.close(); 21917525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 21927525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 21937525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler // This is probably overkill 21947525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler for (int i = 0; i < messageIds.length; i++) { 21957525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final long messageId = messageIds[i]; 21967525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler writeBodyFiles(context, messageId, values); 21977525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 21987525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 2199d0b81a0d062f9bad15c9d9ba104b6cdf8590e5feYu Ping Hu } 2200d0b81a0d062f9bad15c9d9ba104b6cdf8590e5feYu Ping Hu break; 22017525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 22020e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case MESSAGE: 22035057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux decodeEmailAddresses(values); 22040e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case UPDATED_MESSAGE: 22050e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ATTACHMENT: 22060e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case MAILBOX: 22070e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case ACCOUNT: 22080e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank case HOSTAUTH: 22090b25179dab10dc7dfb91210cabfe637f3067d777Martin Hibdon case CREDENTIAL: 22106e418aa41a17136be0dddb816d843428a0a1e722Marc Blank case POLICY: 22115ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon if (match == ATTACHMENT) { 22125ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon if (values.containsKey(AttachmentColumns.LOCATION) && 22135ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon TextUtils.isEmpty(values.getAsString(AttachmentColumns.LOCATION))) { 22145ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon LogUtils.w(TAG, new Throwable(), "attachment with blank location"); 22155ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon } 22165ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon } 2217503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu result = db.update(tableName, values, selection, selectionArgs); 2218503cc0630d54de430a97f6013c6c7b7e851e343dYu Ping Hu break; 2219ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu case MESSAGE_MOVE: 2220ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu result = db.update(MessageMove.TABLE_NAME, values, selection, selectionArgs); 2221ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu break; 2222ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu case MESSAGE_STATE_CHANGE: 2223ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu result = db.update(MessageStateChange.TABLE_NAME, values, selection, 2224ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu selectionArgs); 2225ca79aba675d5282b6ba365184f3727b7b24a568fYu Ping Hu break; 22260e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank default: 22270e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank throw new IllegalArgumentException("Unknown URI " + uri); 22280e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank } 22290e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank } catch (SQLiteException e) { 22300e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank checkDatabases(); 22310e1595c177e40428b267a8696dfc05d015ce6a2fMarc Blank throw e; 2232fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank } 2233a290f503f14432163f74548a5e5d1dc5003ad049Marc Blank 2234b3db04b80bd4344a5c69f9c36f9c99fcd03d5becJames Lemieux // Notify all notifier cursors if some records where changed in the database 2235b3db04b80bd4344a5c69f9c36f9c99fcd03d5becJames Lemieux if (result > 0) { 2236b3db04b80bd4344a5c69f9c36f9c99fcd03d5becJames Lemieux sendNotifierChange(getBaseNotificationUri(match), NOTIFICATION_OP_UPDATE, id); 2237b3db04b80bd4344a5c69f9c36f9c99fcd03d5becJames Lemieux notifyUI(notificationUri, null); 2238b3db04b80bd4344a5c69f9c36f9c99fcd03d5becJames Lemieux } 2239626f3e48a4f14c38a973dd2bea2e2debea7637a5Andrew Stadler return result; 2240fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank } 2241f374304e92cc6c27ce1a59242d4b9ff02a9cbb14Marc Blank 22422075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu private void updateSyncStatus(final Bundle extras) { 22432075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu final long id = extras.getLong(EmailServiceStatus.SYNC_STATUS_ID); 22448c989772dfba08438650575f1ac2bb952bd56158Alon Albert final int statusCode = extras.getInt(EmailServiceStatus.SYNC_STATUS_CODE); 22452075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu final Uri uri = ContentUris.withAppendedId(FOLDER_STATUS_URI, id); 224605649dca2f59f28cd4295e041045a605badddb15Tony Mantler notifyUI(uri, null); 22478c989772dfba08438650575f1ac2bb952bd56158Alon Albert final boolean inProgress = statusCode == EmailServiceStatus.IN_PROGRESS; 22488c989772dfba08438650575f1ac2bb952bd56158Alon Albert if (inProgress) { 22498c989772dfba08438650575f1ac2bb952bd56158Alon Albert RefreshStatusMonitor.getInstance(getContext()).setSyncStarted(id); 22508c989772dfba08438650575f1ac2bb952bd56158Alon Albert } else { 22518c989772dfba08438650575f1ac2bb952bd56158Alon Albert final int result = extras.getInt(EmailServiceStatus.SYNC_RESULT); 22528c989772dfba08438650575f1ac2bb952bd56158Alon Albert final ContentValues values = new ContentValues(); 22538c989772dfba08438650575f1ac2bb952bd56158Alon Albert values.put(Mailbox.UI_LAST_SYNC_RESULT, result); 22548c989772dfba08438650575f1ac2bb952bd56158Alon Albert mDatabase.update( 22558c989772dfba08438650575f1ac2bb952bd56158Alon Albert Mailbox.TABLE_NAME, 22568c989772dfba08438650575f1ac2bb952bd56158Alon Albert values, 22578c989772dfba08438650575f1ac2bb952bd56158Alon Albert WHERE_ID, 22588c989772dfba08438650575f1ac2bb952bd56158Alon Albert new String[] { String.valueOf(id) }); 22598c989772dfba08438650575f1ac2bb952bd56158Alon Albert } 22602075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu } 22612075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu 2262779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook @Override 2263779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook public Bundle call(String method, String arg, Bundle extras) { 2264779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook LogUtils.d(TAG, "EmailProvider#call(%s, %s)", method, arg); 226571737836e6be308f752cb95c955a03146b039a9cYu Ping Hu 22665181cd6d4a60ed0b7dbed022484d299a3e91f0daYu Ping Hu // Handle queries for the device friendly name. 22675181cd6d4a60ed0b7dbed022484d299a3e91f0daYu Ping Hu // TODO: This should eventually be a device property, not defined by the app. 22685181cd6d4a60ed0b7dbed022484d299a3e91f0daYu Ping Hu if (TextUtils.equals(method, EmailContent.DEVICE_FRIENDLY_NAME)) { 22695181cd6d4a60ed0b7dbed022484d299a3e91f0daYu Ping Hu final Bundle bundle = new Bundle(1); 22705181cd6d4a60ed0b7dbed022484d299a3e91f0daYu Ping Hu // TODO: For now, just use the model name since we don't yet have a user-supplied name. 22715181cd6d4a60ed0b7dbed022484d299a3e91f0daYu Ping Hu bundle.putString(EmailContent.DEVICE_FRIENDLY_NAME, Build.MODEL); 22725181cd6d4a60ed0b7dbed022484d299a3e91f0daYu Ping Hu return bundle; 22735181cd6d4a60ed0b7dbed022484d299a3e91f0daYu Ping Hu } 22745181cd6d4a60ed0b7dbed022484d299a3e91f0daYu Ping Hu 22752075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu // Handle sync status callbacks. 227671737836e6be308f752cb95c955a03146b039a9cYu Ping Hu if (TextUtils.equals(method, SYNC_STATUS_CALLBACK_METHOD)) { 22772075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu updateSyncStatus(extras); 227871737836e6be308f752cb95c955a03146b039a9cYu Ping Hu return null; 227971737836e6be308f752cb95c955a03146b039a9cYu Ping Hu } 2280f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon if (TextUtils.equals(method, MailboxUtilities.FIX_PARENT_KEYS_METHOD)) { 2281f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon fixParentKeys(getDatabase(getContext())); 2282f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon return null; 2283f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon } 228471737836e6be308f752cb95c955a03146b039a9cYu Ping Hu 228571737836e6be308f752cb95c955a03146b039a9cYu Ping Hu // Handle send & save. 2286779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook final Uri accountUri = Uri.parse(arg); 22870eb47994a328fe450c54e483b894138fd449d9c9Yu Ping Hu final long accountId = Long.parseLong(accountUri.getPathSegments().get(1)); 2288779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook 2289779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook Uri messageUri = null; 2290f7078466c3a5ac9eefc388787aa5fcf187dfe4eeMartin Hibdon 2291779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook if (TextUtils.equals(method, UIProvider.AccountCallMethods.SEND_MESSAGE)) { 229271737836e6be308f752cb95c955a03146b039a9cYu Ping Hu messageUri = uiSendDraftMessage(accountId, extras); 2293229c070b0b177793032ce9249cb77f6ca98e5aa4Scott Kennedy Preferences.getPreferences(getContext()).setLastUsedAccountId(accountId); 2294779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook } else if (TextUtils.equals(method, UIProvider.AccountCallMethods.SAVE_MESSAGE)) { 229571737836e6be308f752cb95c955a03146b039a9cYu Ping Hu messageUri = uiSaveDraftMessage(accountId, extras); 2296229c070b0b177793032ce9249cb77f6ca98e5aa4Scott Kennedy } else if (TextUtils.equals(method, UIProvider.AccountCallMethods.SET_CURRENT_ACCOUNT)) { 2297229c070b0b177793032ce9249cb77f6ca98e5aa4Scott Kennedy LogUtils.d(TAG, "Unhandled (but expected) Content provider method: %s", method); 2298229c070b0b177793032ce9249cb77f6ca98e5aa4Scott Kennedy } else { 2299229c070b0b177793032ce9249cb77f6ca98e5aa4Scott Kennedy LogUtils.wtf(TAG, "Unexpected Content provider method: %s", method); 2300779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook } 2301779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook 2302779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook final Bundle result; 2303779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook if (messageUri != null) { 2304779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook result = new Bundle(1); 2305779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook result.putParcelable(UIProvider.MessageColumns.URI, messageUri); 2306779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook } else { 2307779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook result = null; 2308779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook } 2309779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook 2310779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook return result; 2311779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook } 2312779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook 2313b62067e3c3ec01559568705df4908fe7f2860af9Tony Mantler private static void deleteBodyFiles(final Context c, final long messageId) 2314b62067e3c3ec01559568705df4908fe7f2860af9Tony Mantler throws IllegalStateException { 2315b62067e3c3ec01559568705df4908fe7f2860af9Tony Mantler final ContentValues emptyValues = new ContentValues(2); 2316b62067e3c3ec01559568705df4908fe7f2860af9Tony Mantler emptyValues.putNull(BodyColumns.HTML_CONTENT); 2317b62067e3c3ec01559568705df4908fe7f2860af9Tony Mantler emptyValues.putNull(BodyColumns.TEXT_CONTENT); 2318b62067e3c3ec01559568705df4908fe7f2860af9Tony Mantler writeBodyFiles(c, messageId, emptyValues); 2319b62067e3c3ec01559568705df4908fe7f2860af9Tony Mantler } 2320b62067e3c3ec01559568705df4908fe7f2860af9Tony Mantler 23217525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler /** 23227525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * Writes message bodies to disk, read from a set of ContentValues 23237525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * 23247525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @param c Context for finding files 23257525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @param messageId id of message to write body for 23267525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @param cv {@link ContentValues} containing {@link BodyColumns#HTML_CONTENT} and/or 23277525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * {@link BodyColumns#TEXT_CONTENT}. Inserting a null or empty value will delete the 23287525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * associated text or html body file 23297525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @throws IllegalStateException 23307525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler */ 23317525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler private static void writeBodyFiles(final Context c, final long messageId, 23327525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final ContentValues cv) throws IllegalStateException { 23337525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (cv.containsKey(BodyColumns.HTML_CONTENT)) { 23347525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final String htmlContent = cv.getAsString(BodyColumns.HTML_CONTENT); 23357525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler try { 23367525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler writeBodyFile(c, messageId, "html", htmlContent); 23377525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } catch (final IOException e) { 23387525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler throw new IllegalStateException("IOException while writing html body " + 23397525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler "for message id " + Long.toString(messageId), e); 23407525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 23417525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 23427525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (cv.containsKey(BodyColumns.TEXT_CONTENT)) { 23437525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final String textContent = cv.getAsString(BodyColumns.TEXT_CONTENT); 23447525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler try { 23457525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler writeBodyFile(c, messageId, "txt", textContent); 23467525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } catch (final IOException e) { 23477525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler throw new IllegalStateException("IOException while writing text body " + 23487525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler "for message id " + Long.toString(messageId), e); 23497525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 23507525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 23517525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 23522f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler 23537525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler /** 23547525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * Writes a message body file to disk 23557525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * 23567525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @param c Context for finding files dir 23577525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @param messageId id of message to write body for 23587525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @param ext "html" or "txt" 23597525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @param content Body content to write to file, or null/empty to delete file 23607525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @throws IOException 23617525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler */ 23627525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler private static void writeBodyFile(final Context c, final long messageId, final String ext, 23637525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final String content) throws IOException { 23647525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final File textFile = getBodyFile(c, messageId, ext); 23657525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (TextUtils.isEmpty(content)) { 23667525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (!textFile.delete()) { 23677525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler LogUtils.v(LogUtils.TAG, "did not delete text body for %d", messageId); 23687525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 23697525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } else { 23707525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final FileWriter w = new FileWriter(textFile); 23717525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler try { 23727525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler w.write(content); 23737525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } finally { 23747525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler w.close(); 23757525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 23762f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler } 23777525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 23782f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler 23792f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler /** 23807525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * Returns a {@link java.io.File} object pointing to the body content file for the message 23812f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler * 23827525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @param c Context for finding files dir 23837525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @param messageId id of message to locate 23847525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @param ext "html" or "txt" 23857525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler * @return File ready for operating upon 23862f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler */ 23877525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler protected static File getBodyFile(final Context c, final long messageId, final String ext) 23887525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler throws FileNotFoundException { 23897525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (!TextUtils.equals(ext, "html") && !TextUtils.equals(ext, "txt")) { 23907525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler throw new IllegalArgumentException("ext must be one of 'html' or 'txt'"); 23917525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 23927525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler long l1 = messageId / 100 % 100; 23937525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler long l2 = messageId % 100; 23947525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final File dir = new File(c.getFilesDir(), 23957525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler "body/" + Long.toString(l1) + "/" + Long.toString(l2) + "/"); 23967525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler if (!dir.isDirectory() && !dir.mkdirs()) { 23977525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler throw new FileNotFoundException("Could not create directory for body file"); 23987525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 23997525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler return new File(dir, Long.toString(messageId) + "." + ext); 24007525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 24012f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler 24025a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook @Override 24032f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler public ParcelFileDescriptor openFile(final Uri uri, final String mode) 24042f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler throws FileNotFoundException { 24055a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook if (LogUtils.isLoggable(TAG, LogUtils.DEBUG)) { 24065a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook LogUtils.d(TAG, "EmailProvider.openFile: %s", LogUtils.contentUriToString(TAG, uri)); 24075a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook } 24085a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook 24095a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook final int match = findMatch(uri, "openFile"); 24105a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook switch (match) { 24115a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook case ATTACHMENTS_CACHED_FILE_ACCESS: 24125a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook // Parse the cache file path out from the uri 24135a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook final String cachedFilePath = 24143dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler uri.getQueryParameter(Attachment.CACHED_FILE_QUERY_PARAM); 24155a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook 24165a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook if (cachedFilePath != null) { 24175a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook // clearCallingIdentity means that the download manager will 24185a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook // check our permissions rather than the permissions of whatever 24195a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook // code is calling us. 24205a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook long binderToken = Binder.clearCallingIdentity(); 24215a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook try { 24225a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook LogUtils.d(TAG, "Opening attachment %s", cachedFilePath); 24235a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook return ParcelFileDescriptor.open( 24245a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook new File(cachedFilePath), ParcelFileDescriptor.MODE_READ_ONLY); 24255a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook } finally { 24265a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook Binder.restoreCallingIdentity(binderToken); 24275a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook } 24285a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook } 24295a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook break; 24307525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler case BODY_HTML: { 24312f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler final long messageKey = Long.valueOf(uri.getLastPathSegment()); 24327525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler return ParcelFileDescriptor.open(getBodyFile(getContext(), messageKey, "html"), 24337525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler Utilities.parseMode(mode)); 24347525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 24357525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler case BODY_TEXT:{ 24367525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler final long messageKey = Long.valueOf(uri.getLastPathSegment()); 24377525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler return ParcelFileDescriptor.open(getBodyFile(getContext(), messageKey, "txt"), 24387525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler Utilities.parseMode(mode)); 24397525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler } 24405a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook } 24415a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook 24425a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook throw new FileNotFoundException("unable to open file"); 24435a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook } 24445a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook 24455a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook 2446bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy /** 2447e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy * Returns the base notification URI for the given content type. 2448e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy * 2449e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy * @param match The type of content that was modified. 2450e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy */ 2451b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static Uri getBaseNotificationUri(int match) { 2452e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy Uri baseUri = null; 2453e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy switch (match) { 2454e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy case MESSAGE: 2455e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy case MESSAGE_ID: 2456e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy case SYNCED_MESSAGE_ID: 2457e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy baseUri = Message.NOTIFIER_URI; 2458e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy break; 2459e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy case ACCOUNT: 2460e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy case ACCOUNT_ID: 2461e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy baseUri = Account.NOTIFIER_URI; 2462e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy break; 2463e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy } 2464e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy return baseUri; 2465e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy } 2466e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy 2467e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy /** 2468bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * Sends a change notification to any cursors observers of the given base URI. The final 2469bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * notification URI is dynamically built to contain the specified information. It will be 2470bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * of the format <<baseURI>>/<<op>>/<<id>>; where <<op>> and <<id>> are optional depending 2471bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * upon the given values. 2472bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * NOTE: If <<op>> is specified, notifications for <<baseURI>>/<<id>> will NOT be invoked. 2473bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * If this is necessary, it can be added. However, due to the implementation of 2474bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * {@link ContentObserver}, observers of <<baseURI>> will receive multiple notifications. 2475bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * 2476bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * @param baseUri The base URI to send notifications to. Must be able to take appended IDs. 2477bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * @param op Optional operation to be appended to the URI. 2478bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * @param id If a positive value, the ID to append to the base URI. Otherwise, no ID will be 2479bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy * appended to the base URI. 2480fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank */ 2481bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy private void sendNotifierChange(Uri baseUri, String op, String id) { 2482e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy if (baseUri == null) return; 2483e7fb4ac9e3b098ece98d004403a89652f88bbe7aTodd Kennedy 2484bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy // Append the operation, if specified 2485bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy if (op != null) { 2486bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy baseUri = baseUri.buildUpon().appendEncodedPath(op).build(); 2487bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy } 2488bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy 2489bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy long longId = 0L; 2490bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy try { 2491bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy longId = Long.valueOf(id); 2492bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy } catch (NumberFormatException ignore) {} 2493bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy if (longId > 0) { 249405649dca2f59f28cd4295e041045a605badddb15Tony Mantler notifyUI(baseUri, id); 2495bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy } else { 249605649dca2f59f28cd4295e041045a605badddb15Tony Mantler notifyUI(baseUri, null); 2497bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy } 249807676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook 249907676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook // We want to send the message list changed notification if baseUri is Message.NOTIFIER_URI. 250007676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook if (baseUri.equals(Message.NOTIFIER_URI)) { 250107676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook sendMessageListDataChangedNotification(); 250207676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook } 250307676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook } 250407676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook 250507676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook private void sendMessageListDataChangedNotification() { 250607676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook final Context context = getContext(); 250707676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook final Intent intent = new Intent(ACTION_NOTIFY_MESSAGE_LIST_DATASET_CHANGED); 250807676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook // Ideally this intent would contain information about which account changed, to limit the 250907676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook // updates to that particular account. Unfortunately, that information is not available in 251007676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook // sendNotifierChange(). 251107676012f7e4060faa0d23dc6068e9dcdd4a4106Paul Westbrook context.sendBroadcast(intent); 2512bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy } 2513bf30f94c2e47a2f3340362060365809bf9258260Todd Kennedy 251400219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler // We might have more than one thread trying to make its way through applyBatch() so the 251500219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler // notification coalescing needs to be thread-local to work correctly. 251600219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler private final ThreadLocal<Set<Uri>> mTLBatchNotifications = 251700219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler new ThreadLocal<Set<Uri>>(); 251800219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler 251900219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler private Set<Uri> getBatchNotificationsSet() { 252000219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler return mTLBatchNotifications.get(); 252100219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler } 252200219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler 252300219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler private void setBatchNotificationsSet(Set<Uri> batchNotifications) { 252400219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler mTLBatchNotifications.set(batchNotifications); 252500219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler } 252605649dca2f59f28cd4295e041045a605badddb15Tony Mantler 2527758a532fce2f672673d38b2daa5f67eb757b118bMarc Blank @Override 252884969fb580f569c0e3625a3c59a71d2909ae198dFred Quintana public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 2529b6493a07ef625c0e290890c2e60256b47a066e5eMarc Blank throws OperationApplicationException { 253005649dca2f59f28cd4295e041045a605badddb15Tony Mantler /** 253105649dca2f59f28cd4295e041045a605badddb15Tony Mantler * Collect notification URIs to notify at the end of batch processing. 253205649dca2f59f28cd4295e041045a605badddb15Tony Mantler * These are populated by calls to notifyUI() by way of update(), insert() and delete() 253305649dca2f59f28cd4295e041045a605badddb15Tony Mantler * calls made in super.applyBatch() 253405649dca2f59f28cd4295e041045a605badddb15Tony Mantler */ 253500219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler setBatchNotificationsSet(Sets.<Uri>newHashSet()); 2536cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank Context context = getContext(); 2537cba3a48f97ae2e6d875ac4284a4066da94c922d5Marc Blank SQLiteDatabase db = getDatabase(context); 2538fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank db.beginTransaction(); 2539fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank try { 2540fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank ContentProviderResult[] results = super.applyBatch(operations); 2541fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank db.setTransactionSuccessful(); 2542fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank return results; 2543fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank } finally { 2544fae4727a911a13cd0bfaaf2f1167d780bafb592bMarc Blank db.endTransaction(); 254500219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler final Set<Uri> notifications = getBatchNotificationsSet(); 254600219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler setBatchNotificationsSet(null); 254705649dca2f59f28cd4295e041045a605badddb15Tony Mantler for (final Uri uri : notifications) { 254805649dca2f59f28cd4295e041045a605badddb15Tony Mantler context.getContentResolver().notifyChange(uri, null); 254905649dca2f59f28cd4295e041045a605badddb15Tony Mantler } 2550f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 2551f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler } 2552574854b528163f3bf1a7cb974aa80082d1768edfMakoto Onuki 25533d16e5d4b994d92db51962c8c461c53bee04309fAnthony Lee public static interface EmailAttachmentService { 255403cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank /** 255503cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank * Notify the service that an attachment has changed. 255603cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank */ 25573d16e5d4b994d92db51962c8c461c53bee04309fAnthony Lee void attachmentChanged(final Context context, final long id, final int flags); 255855d0e821eaecb5e454812a30c1137dbc95db98e2Marc Blank } 255955d0e821eaecb5e454812a30c1137dbc95db98e2Marc Blank 25603d16e5d4b994d92db51962c8c461c53bee04309fAnthony Lee private final EmailAttachmentService DEFAULT_ATTACHMENT_SERVICE = new EmailAttachmentService() { 256159e10b6b3dbc14884b032b1843413b08adaaf288Marc Blank @Override 25623d16e5d4b994d92db51962c8c461c53bee04309fAnthony Lee public void attachmentChanged(final Context context, final long id, final int flags) { 256303cd72805dab0379ed255d151f1c17cc60655fc3Marc Blank // The default implementation delegates to the real service. 25643d16e5d4b994d92db51962c8c461c53bee04309fAnthony Lee AttachmentService.attachmentChanged(context, id, flags); 256559e10b6b3dbc14884b032b1843413b08adaaf288Marc Blank } 256659e10b6b3dbc14884b032b1843413b08adaaf288Marc Blank }; 25673d16e5d4b994d92db51962c8c461c53bee04309fAnthony Lee private EmailAttachmentService mAttachmentService = DEFAULT_ATTACHMENT_SERVICE; 256817d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie 256917d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie // exposed for testing 25703d16e5d4b994d92db51962c8c461c53bee04309fAnthony Lee public void injectAttachmentService(final EmailAttachmentService attachmentService) { 257117d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie mAttachmentService = 257217d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie attachmentService == null ? DEFAULT_ATTACHMENT_SERVICE : attachmentService; 257317d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie } 2574ebb79619e8ed3c9f0c051e7f323e3971bce7508dMarc Blank 2575b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private Cursor notificationQuery(final Uri uri) { 2576b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final SQLiteDatabase db = getDatabase(getContext()); 2577b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final String accountId = uri.getLastPathSegment(); 2578b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy 25790053401d07cd11f19c63dfbc3942d027b4067de8Tony Mantler final String sql = "SELECT " + MessageColumns.MAILBOX_KEY + ", " + 25800053401d07cd11f19c63dfbc3942d027b4067de8Tony Mantler "SUM(CASE " + MessageColumns.FLAG_READ + " WHEN 0 THEN 1 ELSE 0 END), " + 25810053401d07cd11f19c63dfbc3942d027b4067de8Tony Mantler "SUM(CASE " + MessageColumns.FLAG_SEEN + " WHEN 0 THEN 1 ELSE 0 END)\n" + 25820053401d07cd11f19c63dfbc3942d027b4067de8Tony Mantler "FROM " + Message.TABLE_NAME + "\n" + 25830053401d07cd11f19c63dfbc3942d027b4067de8Tony Mantler "WHERE " + MessageColumns.ACCOUNT_KEY + " = ?\n" + 25840053401d07cd11f19c63dfbc3942d027b4067de8Tony Mantler "GROUP BY " + MessageColumns.MAILBOX_KEY; 2585b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy 2586b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final String[] selectionArgs = {accountId}; 2587b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy 2588b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy return db.rawQuery(sql, selectionArgs); 2589ebb79619e8ed3c9f0c051e7f323e3971bce7508dMarc Blank } 2590f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2591f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank public Cursor mostRecentMessageQuery(Uri uri) { 2592f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank SQLiteDatabase db = getDatabase(getContext()); 2593f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank String mailboxId = uri.getLastPathSegment(); 2594f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return db.rawQuery("select max(_id) from Message where mailboxKey=?", 2595f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank new String[] {mailboxId}); 259617d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu } 259717d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu 259817d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu private Cursor getMailboxMessageCount(Uri uri) { 259917d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu SQLiteDatabase db = getDatabase(getContext()); 260017d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu String mailboxId = uri.getLastPathSegment(); 260117d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu return db.rawQuery("select count(*) from Message where mailboxKey=?", 260217d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu new String[] {mailboxId}); 260317d5bbf768c27ac7782b155e2ab25bcd480f5dcfYu Ping Hu } 2604f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2605f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2606f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Support for UnifiedEmail below 2607f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2608f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2609f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String NOT_A_DRAFT_STRING = 2610f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Integer.toString(UIProvider.DraftType.NOT_A_DRAFT); 2611f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2612f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String CONVERSATION_FLAGS = 2613f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "CASE WHEN (" + MessageColumns.FLAGS + "&" + Message.FLAG_INCOMING_MEETING_INVITE + 2614f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ") !=0 THEN " + UIProvider.ConversationFlags.CALENDAR_INVITE + 2615f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " ELSE 0 END + " + 2616f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "CASE WHEN (" + MessageColumns.FLAGS + "&" + Message.FLAG_FORWARDED + 2617f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ") !=0 THEN " + UIProvider.ConversationFlags.FORWARDED + 2618f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " ELSE 0 END + " + 2619f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "CASE WHEN (" + MessageColumns.FLAGS + "&" + Message.FLAG_REPLIED_TO + 2620f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ") !=0 THEN " + UIProvider.ConversationFlags.REPLIED + 2621f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " ELSE 0 END"; 2622f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2623f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2624f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Array of pre-defined account colors (legacy colors from old email app) 2625f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2626f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final int[] ACCOUNT_COLORS = new int[] { 2627f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 0xff71aea7, 0xff621919, 0xff18462f, 0xffbf8e52, 0xff001f79, 2628f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 0xffa8afc2, 0xff6b64c4, 0xff738359, 0xff9d50a4 2629f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank }; 2630f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2631f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String CONVERSATION_COLOR = 2632f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "@CASE (" + MessageColumns.ACCOUNT_KEY + " - 1) % " + ACCOUNT_COLORS.length + 2633f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 0 THEN " + ACCOUNT_COLORS[0] + 2634f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 1 THEN " + ACCOUNT_COLORS[1] + 2635f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 2 THEN " + ACCOUNT_COLORS[2] + 2636f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 3 THEN " + ACCOUNT_COLORS[3] + 2637f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 4 THEN " + ACCOUNT_COLORS[4] + 2638f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 5 THEN " + ACCOUNT_COLORS[5] + 2639f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 6 THEN " + ACCOUNT_COLORS[6] + 2640f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 7 THEN " + ACCOUNT_COLORS[7] + 2641f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 8 THEN " + ACCOUNT_COLORS[8] + 2642f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " END"; 2643f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2644f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String ACCOUNT_COLOR = 26453dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler "@CASE (" + AccountColumns._ID + " - 1) % " + ACCOUNT_COLORS.length + 2646f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 0 THEN " + ACCOUNT_COLORS[0] + 2647f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 1 THEN " + ACCOUNT_COLORS[1] + 2648f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 2 THEN " + ACCOUNT_COLORS[2] + 2649f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 3 THEN " + ACCOUNT_COLORS[3] + 2650f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 4 THEN " + ACCOUNT_COLORS[4] + 2651f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 5 THEN " + ACCOUNT_COLORS[5] + 2652f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 6 THEN " + ACCOUNT_COLORS[6] + 2653f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 7 THEN " + ACCOUNT_COLORS[7] + 2654f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN 8 THEN " + ACCOUNT_COLORS[8] + 2655f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " END"; 26560053401d07cd11f19c63dfbc3942d027b4067de8Tony Mantler 2657f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2658f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Mapping of UIProvider columns to EmailProvider columns for the message list (called the 2659f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * conversation list in UnifiedEmail) 2660f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2661b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static ProjectionMap getMessageListMap() { 2662e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank if (sMessageListMap == null) { 2663e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank sMessageListMap = ProjectionMap.builder() 26643dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(BaseColumns._ID, MessageColumns._ID) 2665e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.URI, uriWithId("uimessage")) 2666e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.MESSAGE_LIST_URI, uriWithId("uimessage")) 2667e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.SUBJECT, MessageColumns.SUBJECT) 2668e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.SNIPPET, MessageColumns.SNIPPET) 2669e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.CONVERSATION_INFO, null) 2670e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.DATE_RECEIVED_MS, MessageColumns.TIMESTAMP) 2671e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.HAS_ATTACHMENTS, MessageColumns.FLAG_ATTACHMENT) 2672e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.NUM_MESSAGES, "1") 2673e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.NUM_DRAFTS, "0") 2674e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.SENDING_STATE, 2675e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank Integer.toString(ConversationSendingState.OTHER)) 2676e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.PRIORITY, 2677e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank Integer.toString(ConversationPriority.LOW)) 2678e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.READ, MessageColumns.FLAG_READ) 2679b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy .add(UIProvider.ConversationColumns.SEEN, MessageColumns.FLAG_SEEN) 2680e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.STARRED, MessageColumns.FLAG_FAVORITE) 2681e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.FLAGS, CONVERSATION_FLAGS) 2682e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.ConversationColumns.ACCOUNT_URI, 2683e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank uriWithColumn("uiaccount", MessageColumns.ACCOUNT_KEY)) 2684968a2fe7805756ef6aa1f10f71306e865b9f7f09Paul Westbrook .add(UIProvider.ConversationColumns.SENDER_INFO, MessageColumns.FROM_LIST) 26859773c96d83f126b8418b192bcf46f939f44fdb44Alan Lau .add(UIProvider.ConversationColumns.ORDER_KEY, MessageColumns.TIMESTAMP) 2686e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .build(); 2687e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank } 2688e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank return sMessageListMap; 2689e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank } 2690e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank private static ProjectionMap sMessageListMap; 2691f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2692f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2693f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate UIProvider draft type; note the test for "reply all" must come before "reply" 2694f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2695f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String MESSAGE_DRAFT_TYPE = 2696f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "CASE WHEN (" + MessageColumns.FLAGS + "&" + Message.FLAG_TYPE_ORIGINAL + 2697f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ") !=0 THEN " + UIProvider.DraftType.COMPOSE + 269885d2190552d05dbc06518bdc21674c6aabeb583bMartin Hibdon " WHEN (" + MessageColumns.FLAGS + "&" + Message.FLAG_TYPE_REPLY_ALL + 2699f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ") !=0 THEN " + UIProvider.DraftType.REPLY_ALL + 2700f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN (" + MessageColumns.FLAGS + "&" + Message.FLAG_TYPE_REPLY + 2701f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ") !=0 THEN " + UIProvider.DraftType.REPLY + 2702f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " WHEN (" + MessageColumns.FLAGS + "&" + Message.FLAG_TYPE_FORWARD + 2703f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ") !=0 THEN " + UIProvider.DraftType.FORWARD + 2704f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " ELSE " + UIProvider.DraftType.NOT_A_DRAFT + " END"; 2705f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2706f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String MESSAGE_FLAGS = 2707f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "CASE WHEN (" + MessageColumns.FLAGS + "&" + Message.FLAG_INCOMING_MEETING_INVITE + 2708f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ") !=0 THEN " + UIProvider.MessageFlags.CALENDAR_INVITE + 2709f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " ELSE 0 END"; 2710f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2711f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2712f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Mapping of UIProvider columns to EmailProvider columns for a detailed message view in 2713f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * UnifiedEmail 2714f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2715b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static ProjectionMap getMessageViewMap() { 2716e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank if (sMessageViewMap == null) { 2717e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank sMessageViewMap = ProjectionMap.builder() 27183dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(BaseColumns._ID, Message.TABLE_NAME + "." + MessageColumns._ID) 2719e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.SERVER_ID, SyncColumns.SERVER_ID) 2720e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.URI, uriWithFQId("uimessage", Message.TABLE_NAME)) 2721e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.CONVERSATION_ID, 2722e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank uriWithFQId("uimessage", Message.TABLE_NAME)) 27233dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.SUBJECT, MessageColumns.SUBJECT) 27243dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.SNIPPET, MessageColumns.SNIPPET) 27253dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.FROM, MessageColumns.FROM_LIST) 27263dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.TO, MessageColumns.TO_LIST) 27273dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.CC, MessageColumns.CC_LIST) 27283dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.BCC, MessageColumns.BCC_LIST) 27293dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.REPLY_TO, MessageColumns.REPLY_TO_LIST) 27303dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.DATE_RECEIVED_MS, MessageColumns.TIMESTAMP) 27319caaebb14282034576345b35402f5b6654c3f08dTony Mantler .add(UIProvider.MessageColumns.BODY_HTML, null) // Loaded in EmailMessageCursor 27329caaebb14282034576345b35402f5b6654c3f08dTony Mantler .add(UIProvider.MessageColumns.BODY_TEXT, null) // Loaded in EmailMessageCursor 2733e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.REF_MESSAGE_ID, "0") 2734e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.DRAFT_TYPE, NOT_A_DRAFT_STRING) 2735e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.APPEND_REF_MESSAGE_CONTENT, "0") 27363dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.HAS_ATTACHMENTS, MessageColumns.FLAG_ATTACHMENT) 2737e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.ATTACHMENT_LIST_URI, 2738e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank uriWithFQId("uiattachments", Message.TABLE_NAME)) 27398cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux .add(UIProvider.MessageColumns.ATTACHMENT_BY_CID_URI, 27408cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux uriWithFQId("uiattachmentbycid", Message.TABLE_NAME)) 2741e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.MESSAGE_FLAGS, MESSAGE_FLAGS) 2742e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.DRAFT_TYPE, MESSAGE_DRAFT_TYPE) 2743e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.MESSAGE_ACCOUNT_URI, 2744b2c7bcff7813f2cecba5c9c52b69cf5ef2cc9cadPaul Westbrook uriWithColumn("uiaccount", MessageColumns.ACCOUNT_KEY)) 27453dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.STARRED, MessageColumns.FLAG_FAVORITE) 27463dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.READ, MessageColumns.FLAG_READ) 27473dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.MessageColumns.SEEN, MessageColumns.FLAG_SEEN) 2748e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.SPAM_WARNING_STRING, null) 2749e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.SPAM_WARNING_LEVEL, 2750e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank Integer.toString(UIProvider.SpamWarningLevel.NO_WARNING)) 2751e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.SPAM_WARNING_LINK_TYPE, 2752e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank Integer.toString(UIProvider.SpamWarningLinkType.NO_LINK)) 2753e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.MessageColumns.VIA_DOMAIN, null) 275407d674f9fef8d78b3a97f2d8c28ca444de607742Andrew Sapperstein .add(UIProvider.MessageColumns.CLIPPED, "0") 27551bb18931e29dfe55a9b3368bd2393ac57c5fdebbAndrew Sapperstein .add(UIProvider.MessageColumns.PERMALINK, null) 2756e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .build(); 2757e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank } 2758e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank return sMessageViewMap; 2759e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank } 2760e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank private static ProjectionMap sMessageViewMap; 2761f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2762f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2763f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate UIProvider folder capabilities from mailbox flags 2764f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2765f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String FOLDER_CAPABILITIES = 2766f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "CASE WHEN (" + MailboxColumns.FLAGS + "&" + Mailbox.FLAG_ACCEPTS_MOVED_MAIL + 2767f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ") !=0 THEN " + UIProvider.FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES + 2768f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " ELSE 0 END"; 2769f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2770f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2771f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Convert EmailProvider type to UIProvider type 2772f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2773f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String FOLDER_TYPE = "CASE " + MailboxColumns.TYPE 2774f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_INBOX + " THEN " + UIProvider.FolderType.INBOX 2775f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_DRAFTS + " THEN " + UIProvider.FolderType.DRAFT 2776f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_OUTBOX + " THEN " + UIProvider.FolderType.OUTBOX 2777f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_SENT + " THEN " + UIProvider.FolderType.SENT 2778f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_TRASH + " THEN " + UIProvider.FolderType.TRASH 2779f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_JUNK + " THEN " + UIProvider.FolderType.SPAM 2780f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_STARRED + " THEN " + UIProvider.FolderType.STARRED 2781cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein + " WHEN " + Mailbox.TYPE_UNREAD + " THEN " + UIProvider.FolderType.UNREAD 2782e743a06ddf7677706da7450100e19d0f4509a43cScott Kennedy + " WHEN " + Mailbox.TYPE_SEARCH + " THEN " 2783e743a06ddf7677706da7450100e19d0f4509a43cScott Kennedy + getFolderTypeFromMailboxType(Mailbox.TYPE_SEARCH) 2784f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " ELSE " + UIProvider.FolderType.DEFAULT + " END"; 2785f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2786f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String FOLDER_ICON = "CASE " + MailboxColumns.TYPE 2787ebae672af4a423c57557e317f3befa9d318193e9Tony Mantler + " WHEN " + Mailbox.TYPE_INBOX + " THEN " + R.drawable.ic_drawer_inbox_24dp 2788ebae672af4a423c57557e317f3befa9d318193e9Tony Mantler + " WHEN " + Mailbox.TYPE_DRAFTS + " THEN " + R.drawable.ic_drawer_drafts_24dp 2789ebae672af4a423c57557e317f3befa9d318193e9Tony Mantler + " WHEN " + Mailbox.TYPE_OUTBOX + " THEN " + R.drawable.ic_drawer_outbox_24dp 2790ebae672af4a423c57557e317f3befa9d318193e9Tony Mantler + " WHEN " + Mailbox.TYPE_SENT + " THEN " + R.drawable.ic_drawer_sent_24dp 2791ebae672af4a423c57557e317f3befa9d318193e9Tony Mantler + " WHEN " + Mailbox.TYPE_TRASH + " THEN " + R.drawable.ic_drawer_trash_24dp 2792ebae672af4a423c57557e317f3befa9d318193e9Tony Mantler + " WHEN " + Mailbox.TYPE_STARRED + " THEN " + R.drawable.ic_drawer_starred_24dp 2793ebae672af4a423c57557e317f3befa9d318193e9Tony Mantler + " ELSE " + R.drawable.ic_drawer_folder_24dp + " END"; 2794f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 27955ff368b84573833497764c9d1661cc97717b7094Yu Ping Hu /** 2796bcd81d96a40f3d987f4d780f64d339dd7f5ab2edYu Ping Hu * Local-only folders set totalCount < 0; such folders should substitute message count for 2797bcd81d96a40f3d987f4d780f64d339dd7f5ab2edYu Ping Hu * total count. 2798bcd81d96a40f3d987f4d780f64d339dd7f5ab2edYu Ping Hu * TODO: IMAP and POP don't adhere to this convention yet so for now we force a few types. 27995ff368b84573833497764c9d1661cc97717b7094Yu Ping Hu */ 28005ff368b84573833497764c9d1661cc97717b7094Yu Ping Hu private static final String TOTAL_COUNT = "CASE WHEN " 2801bcd81d96a40f3d987f4d780f64d339dd7f5ab2edYu Ping Hu + MailboxColumns.TOTAL_COUNT + "<0 OR " 28025ff368b84573833497764c9d1661cc97717b7094Yu Ping Hu + MailboxColumns.TYPE + "=" + Mailbox.TYPE_DRAFTS + " OR " 28035ff368b84573833497764c9d1661cc97717b7094Yu Ping Hu + MailboxColumns.TYPE + "=" + Mailbox.TYPE_OUTBOX + " OR " 28045ff368b84573833497764c9d1661cc97717b7094Yu Ping Hu + MailboxColumns.TYPE + "=" + Mailbox.TYPE_TRASH 28055ff368b84573833497764c9d1661cc97717b7094Yu Ping Hu + " THEN " + MailboxColumns.MESSAGE_COUNT 28065ff368b84573833497764c9d1661cc97717b7094Yu Ping Hu + " ELSE " + MailboxColumns.TOTAL_COUNT + " END"; 28075ff368b84573833497764c9d1661cc97717b7094Yu Ping Hu 2808b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static ProjectionMap getFolderListMap() { 2809e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank if (sFolderListMap == null) { 2810e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank sFolderListMap = ProjectionMap.builder() 28113dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(BaseColumns._ID, MailboxColumns._ID) 2812b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy .add(UIProvider.FolderColumns.PERSISTENT_ID, MailboxColumns.SERVER_ID) 2813e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.URI, uriWithId("uifolder")) 2814e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.NAME, "displayName") 2815e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.HAS_CHILDREN, 2816e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank MailboxColumns.FLAGS + "&" + Mailbox.FLAG_HAS_CHILDREN) 2817e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.CAPABILITIES, FOLDER_CAPABILITIES) 2818e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.SYNC_WINDOW, "3") 2819e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.CONVERSATION_LIST_URI, uriWithId("uimessages")) 2820e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.CHILD_FOLDERS_LIST_URI, uriWithId("uisubfolders")) 2821e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.UNREAD_COUNT, MailboxColumns.UNREAD_COUNT) 28225ff368b84573833497764c9d1661cc97717b7094Yu Ping Hu .add(UIProvider.FolderColumns.TOTAL_COUNT, TOTAL_COUNT) 282364cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu .add(UIProvider.FolderColumns.REFRESH_URI, uriWithId(QUERY_UIREFRESH)) 2824e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.SYNC_STATUS, MailboxColumns.UI_SYNC_STATUS) 2825e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.LAST_SYNC_RESULT, MailboxColumns.UI_LAST_SYNC_RESULT) 2826e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.TYPE, FOLDER_TYPE) 2827e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.ICON_RES_ID, FOLDER_ICON) 28281004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu .add(UIProvider.FolderColumns.LOAD_MORE_URI, uriWithId("uiloadmore")) 2829e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.FolderColumns.HIERARCHICAL_DESC, MailboxColumns.HIERARCHICAL_NAME) 283050f645e019c3165b14457c0b661c59cd4e6ce375Vikram Aggarwal .add(UIProvider.FolderColumns.PARENT_URI, "case when " + MailboxColumns.PARENT_KEY 283150f645e019c3165b14457c0b661c59cd4e6ce375Vikram Aggarwal + "=" + Mailbox.NO_MAILBOX + " then NULL else " + 283250f645e019c3165b14457c0b661c59cd4e6ce375Vikram Aggarwal uriWithColumn("uifolder", MailboxColumns.PARENT_KEY) + " end") 28334cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler /** 28344cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler * SELECT group_concat(fromList) FROM 28354cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler * (SELECT fromList FROM message WHERE mailboxKey=? AND flagRead=0 28364cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler * GROUP BY fromList ORDER BY timestamp DESC) 28374cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler */ 28384cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler .add(UIProvider.FolderColumns.UNREAD_SENDERS, 28394cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler "(SELECT group_concat(" + MessageColumns.FROM_LIST + ") FROM " + 28404cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler "(SELECT " + MessageColumns.FROM_LIST + " FROM " + Message.TABLE_NAME + 28414cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler " WHERE " + MessageColumns.MAILBOX_KEY + "=" + Mailbox.TABLE_NAME + "." + 28423dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler MailboxColumns._ID + " AND " + MessageColumns.FLAG_READ + "=0" + 28434cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler " GROUP BY " + MessageColumns.FROM_LIST + " ORDER BY " + 28444cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler MessageColumns.TIMESTAMP + " DESC))") 2845e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .build(); 2846e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank } 2847e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank return sFolderListMap; 2848e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank } 2849e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank private static ProjectionMap sFolderListMap; 2850e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank 28514b09765a2e8a0fd22a9db0e876aaaada4246aff8Vikram Aggarwal /** 28524b09765a2e8a0fd22a9db0e876aaaada4246aff8Vikram Aggarwal * Constructs the map of default entries for accounts. These values can be overridden in 28534b09765a2e8a0fd22a9db0e876aaaada4246aff8Vikram Aggarwal * {@link #genQueryAccount(String[], String)}. 28544b09765a2e8a0fd22a9db0e876aaaada4246aff8Vikram Aggarwal */ 28555a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook private static ProjectionMap getAccountListMap(Context context) { 2856e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank if (sAccountListMap == null) { 28575a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook final ProjectionMap.Builder builder = ProjectionMap.builder() 28583dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(BaseColumns._ID, AccountColumns._ID) 28595a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.FOLDER_LIST_URI, uriWithId("uifolders")) 286096192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler .add(UIProvider.AccountColumns.FULL_FOLDER_LIST_URI, uriWithId("uifullfolders")) 286196192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler .add(UIProvider.AccountColumns.ALL_FOLDER_LIST_URI, uriWithId("uiallfolders")) 28625a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.NAME, AccountColumns.DISPLAY_NAME) 28637349fbff64328100cb5bd878f4d400ccc611ec80Tony Mantler .add(UIProvider.AccountColumns.ACCOUNT_MANAGER_NAME, 28647349fbff64328100cb5bd878f4d400ccc611ec80Tony Mantler AccountColumns.EMAIL_ADDRESS) 2865045aa05777a097717c1a915e66eb9ab671e02d56Ray Chen .add(UIProvider.AccountColumns.ACCOUNT_ID, 2866045aa05777a097717c1a915e66eb9ab671e02d56Ray Chen AccountColumns.EMAIL_ADDRESS) 2867632ee24d48f308c855ddec8f013b674e5ade67e2Tony Mantler .add(UIProvider.AccountColumns.SENDER_NAME, 2868632ee24d48f308c855ddec8f013b674e5ade67e2Tony Mantler AccountColumns.SENDER_NAME) 28695a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.UNDO_URI, 2870d0e7d88f43bcd7d612a880f3525ef40dbe8f461aYu Ping Hu ("'content://" + EmailContent.AUTHORITY + "/uiundo'")) 28715a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.URI, uriWithId("uiaccount")) 28725a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.SEARCH_URI, uriWithId("uisearch")) 28735a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook // TODO: Is provider version used? 28745a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.PROVIDER_VERSION, "1") 28755a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.SYNC_STATUS, "0") 28765a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.RECENT_FOLDER_LIST_URI, 28775a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook uriWithId("uirecentfolders")) 28785a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.DEFAULT_RECENT_FOLDER_LIST_URI, 28795a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook uriWithId("uidefaultrecentfolders")) 28805a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.SettingsColumns.SIGNATURE, 28815a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook AccountColumns.SIGNATURE) 28825a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.SettingsColumns.SNAP_HEADERS, 28835a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook Integer.toString(UIProvider.SnapHeaderValue.ALWAYS)) 28845a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.SettingsColumns.CONFIRM_ARCHIVE, "0") 28855a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.SettingsColumns.CONVERSATION_VIEW_MODE, 28865a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook Integer.toString(UIProvider.ConversationViewMode.UNDEFINED)) 28875a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook .add(UIProvider.AccountColumns.SettingsColumns.VEILED_ADDRESS_PATTERN, null); 28885a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook 28895a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook final String feedbackUri = context.getString(R.string.email_feedback_uri); 28905a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook if (!TextUtils.isEmpty(feedbackUri)) { 2891dbb8b75a4bd201f8472a511ef77ca2ed05bd808bPaul Westbrook // This string needs to be in single quotes, as it will be used as a constant 2892dbb8b75a4bd201f8472a511ef77ca2ed05bd808bPaul Westbrook // in a sql expression 2893dbb8b75a4bd201f8472a511ef77ca2ed05bd808bPaul Westbrook builder.add(UIProvider.AccountColumns.SEND_FEEDBACK_INTENT_URI, 2894dbb8b75a4bd201f8472a511ef77ca2ed05bd808bPaul Westbrook "'" + feedbackUri + "'"); 28955a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook } 28965a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook 289731ce5555b8b277a05e4af01c57cb078be3049409James Lemieux final String helpUri = context.getString(R.string.help_uri); 289831ce5555b8b277a05e4af01c57cb078be3049409James Lemieux if (!TextUtils.isEmpty(helpUri)) { 289931ce5555b8b277a05e4af01c57cb078be3049409James Lemieux // This string needs to be in single quotes, as it will be used as a constant 290031ce5555b8b277a05e4af01c57cb078be3049409James Lemieux // in a sql expression 290131ce5555b8b277a05e4af01c57cb078be3049409James Lemieux builder.add(UIProvider.AccountColumns.HELP_INTENT_URI, 290231ce5555b8b277a05e4af01c57cb078be3049409James Lemieux "'" + helpUri + "'"); 290331ce5555b8b277a05e4af01c57cb078be3049409James Lemieux } 290431ce5555b8b277a05e4af01c57cb078be3049409James Lemieux 29055a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook sAccountListMap = builder.build(); 2906e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank } 2907e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank return sAccountListMap; 2908e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank } 2909e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank private static ProjectionMap sAccountListMap; 2910f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2911c6953b77552d4cb71776cf0537dc226029381628Tony Mantler private static ProjectionMap getQuickResponseMap() { 2912c6953b77552d4cb71776cf0537dc226029381628Tony Mantler if (sQuickResponseMap == null) { 2913c6953b77552d4cb71776cf0537dc226029381628Tony Mantler sQuickResponseMap = ProjectionMap.builder() 29143dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .add(UIProvider.QuickResponseColumns.TEXT, QuickResponseColumns.TEXT) 2915c6953b77552d4cb71776cf0537dc226029381628Tony Mantler .add(UIProvider.QuickResponseColumns.URI, 2916c6953b77552d4cb71776cf0537dc226029381628Tony Mantler "'" + combinedUriString("quickresponse", "") + "'||" 29173dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + QuickResponseColumns._ID) 2918c6953b77552d4cb71776cf0537dc226029381628Tony Mantler .build(); 2919c6953b77552d4cb71776cf0537dc226029381628Tony Mantler } 2920c6953b77552d4cb71776cf0537dc226029381628Tony Mantler return sQuickResponseMap; 2921c6953b77552d4cb71776cf0537dc226029381628Tony Mantler } 2922c6953b77552d4cb71776cf0537dc226029381628Tony Mantler private static ProjectionMap sQuickResponseMap; 2923c6953b77552d4cb71776cf0537dc226029381628Tony Mantler 2924f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2925f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * The "ORDER BY" clause for top level folders 2926f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2927f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String MAILBOX_ORDER_BY = "CASE " + MailboxColumns.TYPE 2928f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_INBOX + " THEN 0" 2929f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_DRAFTS + " THEN 1" 2930f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_OUTBOX + " THEN 2" 2931f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_SENT + " THEN 3" 2932f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_TRASH + " THEN 4" 2933f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " WHEN " + Mailbox.TYPE_JUNK + " THEN 5" 2934f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Other mailboxes (i.e. of Mailbox.TYPE_MAIL) are shown in alphabetical order. 2935f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " ELSE 10 END" 2936f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank + " ," + MailboxColumns.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; 2937f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2938f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2939f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Mapping of UIProvider columns to EmailProvider columns for a message's attachments 2940f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2941b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static ProjectionMap getAttachmentMap() { 2942e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank if (sAttachmentMap == null) { 2943e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank sAttachmentMap = ProjectionMap.builder() 2944e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.AttachmentColumns.NAME, AttachmentColumns.FILENAME) 2945e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.AttachmentColumns.SIZE, AttachmentColumns.SIZE) 2946e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.AttachmentColumns.URI, uriWithId("uiattachment")) 2947e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.AttachmentColumns.CONTENT_TYPE, AttachmentColumns.MIME_TYPE) 2948e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.AttachmentColumns.STATE, AttachmentColumns.UI_STATE) 2949e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.AttachmentColumns.DESTINATION, AttachmentColumns.UI_DESTINATION) 2950e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.AttachmentColumns.DOWNLOADED_SIZE, 2951e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank AttachmentColumns.UI_DOWNLOADED_SIZE) 2952e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .add(UIProvider.AttachmentColumns.CONTENT_URI, AttachmentColumns.CONTENT_URI) 2953aad690f699f61793facecc950d3d060baa62fd45Martin Hibdon .add(UIProvider.AttachmentColumns.FLAGS, AttachmentColumns.FLAGS) 2954e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank .build(); 2955e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank } 2956e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank return sAttachmentMap; 2957e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank } 2958e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank private static ProjectionMap sAttachmentMap; 2959f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2960f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 2961f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate the SELECT clause using a specified mapping and the original UI projection 2962f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param map the ProjectionMap to use for this projection 2963f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param projection the projection as sent by UnifiedEmail 2964f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return a StringBuilder containing the SELECT expression for a SQLite query 2965f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 2966b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static StringBuilder genSelect(ProjectionMap map, String[] projection) { 2967f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return genSelect(map, projection, EMPTY_CONTENT_VALUES); 2968f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 2969f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 2970b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static StringBuilder genSelect(ProjectionMap map, String[] projection, 2971b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy ContentValues values) { 2972582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler final StringBuilder sb = new StringBuilder("SELECT "); 2973f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank boolean first = true; 2974582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler for (final String column: projection) { 2975f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (first) { 2976f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank first = false; 2977f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 2978f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank sb.append(','); 2979f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 2980582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler final String val; 2981f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // First look at values; this is an override of default behavior 2982f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (values.containsKey(column)) { 2983582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler final String value = values.getAsString(column); 2984296d18c02b4397c320a273cc94c234620e13b3fdMarc Blank if (value == null) { 2985df9c1f3aa54792cc65f95ddff8e36a34a9dcdda1Marc Blank val = "NULL AS " + column; 2986296d18c02b4397c320a273cc94c234620e13b3fdMarc Blank } else if (value.startsWith("@")) { 2987f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank val = value.substring(1) + " AS " + column; 2988f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 29894db2d1cf74640d6560e739627f245198819568a0Tony Mantler val = DatabaseUtils.sqlEscapeString(value) + " AS " + column; 2990f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 2991f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 2992f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Now, get the standard value for the column from our projection map 2993582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler final String mapVal = map.get(column); 2994f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // If we don't have the column, return "NULL AS <column>", and warn 2995582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler if (mapVal == null) { 2996f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank val = "NULL AS " + column; 29972fb5d2f9dd6a243065602a2970e9f698b0d09190Tony Mantler // Apparently there's a lot of these, so don't spam the log with warnings 29982fb5d2f9dd6a243065602a2970e9f698b0d09190Tony Mantler // LogUtils.w(TAG, "column " + column + " missing from projection map"); 2999582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler } else { 3000582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler val = mapVal; 3001f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3002f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3003f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank sb.append(val); 3004f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3005f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return sb; 3006f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3007f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3008f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3009f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Convenience method to create a Uri string given the "type" of query; we append the type 3010f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * of the query and the id column name (_id) 3011f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3012f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param type the "type" of the query, as defined by our UriMatcher definitions 3013f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return a Uri string 3014f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3015f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static String uriWithId(String type) { 30163dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler return uriWithColumn(type, BaseColumns._ID); 3017f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3018f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3019f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3020f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Convenience method to create a Uri string given the "type" of query; we append the type 3021f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * of the query and the passed in column name 3022f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3023f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param type the "type" of the query, as defined by our UriMatcher definitions 3024f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param columnName the column in the table being queried 3025f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return a Uri string 3026f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3027f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static String uriWithColumn(String type, String columnName) { 3028f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return "'content://" + EmailContent.AUTHORITY + "/" + type + "/' || " + columnName; 3029f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3030f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3031f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3032f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Convenience method to create a Uri string given the "type" of query and the table name to 3033f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * which it applies; we append the type of the query and the fully qualified (FQ) id column 3034f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * (i.e. including the table name); we need this for join queries where _id would otherwise 3035f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * be ambiguous 3036f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3037f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param type the "type" of the query, as defined by our UriMatcher definitions 3038f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param tableName the name of the table whose _id is referred to 3039f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return a Uri string 3040f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3041f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static String uriWithFQId(String type, String tableName) { 3042f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return "'content://" + EmailContent.AUTHORITY + "/" + type + "/' || " + tableName + "._id"; 3043f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3044f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3045f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Regex that matches start of img tag. '<(?i)img\s+'. 3046f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final Pattern IMG_TAG_START_REGEX = Pattern.compile("<(?i)img\\s+"); 3047f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3048f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 30497c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank * Class that holds the sqlite query and the attachment (JSON) value (which might be null) 30507c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank */ 30517c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank private static class MessageQuery { 30527c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank final String query; 30537c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank final String attachmentJson; 30547c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank 30557c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank MessageQuery(String _query, String _attachmentJson) { 30567c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank query = _query; 30577c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank attachmentJson = _attachmentJson; 30587c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank } 30597c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank } 30607c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank 30617c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank /** 3062f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate the "view message" SQLite query, given a projection from UnifiedEmail 3063f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3064f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 3065f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 3066f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 30677c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank private MessageQuery genQueryViewMessage(String[] uiProjection, String id) { 3068f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Context context = getContext(); 3069f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank long messageId = Long.parseLong(id); 3070f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Message msg = Message.restoreMessageWithId(context, messageId); 3071f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ContentValues values = new ContentValues(); 30727c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank String attachmentJson = null; 3073f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (msg != null) { 3074f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Body body = Body.restoreBodyWithMessageId(context, messageId); 3075f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (body != null) { 3076f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (body.mHtmlContent != null) { 3077f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (IMG_TAG_START_REGEX.matcher(body.mHtmlContent).find()) { 3078f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(UIProvider.MessageColumns.EMBEDS_EXTERNAL_RESOURCES, 1); 3079f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3080f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3081f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 30821fa303478c61e0d703011996e358037eef523176James Lemieux Address[] fromList = Address.fromHeader(msg.mFrom); 3083f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank int autoShowImages = 0; 308438f22dbf08664b885b4cf063ea665c02edfb1c32Paul Westbrook final MailPrefs mailPrefs = MailPrefs.get(context); 3085f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank for (Address sender : fromList) { 308638f22dbf08664b885b4cf063ea665c02edfb1c32Paul Westbrook final String email = sender.getAddress(); 308738f22dbf08664b885b4cf063ea665c02edfb1c32Paul Westbrook if (mailPrefs.getDisplayImagesFromSender(email)) { 3088f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank autoShowImages = 1; 3089f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 3090f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3091f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3092f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(UIProvider.MessageColumns.ALWAYS_SHOW_IMAGES, autoShowImages); 3093f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Add attachments... 3094f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Attachment[] atts = Attachment.restoreAttachmentsWithMessageId(context, messageId); 3095f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (atts.length > 0) { 3096f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ArrayList<com.android.mail.providers.Attachment> uiAtts = 3097f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank new ArrayList<com.android.mail.providers.Attachment>(); 3098f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank for (Attachment att : atts) { 3099fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // TODO: This code is intended to strip out any inlined attachments (which 3100fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // would have a non-null contentId) so that they will not display at the bottom 3101fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // along with the non-inlined attachments. 3102fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // The problem is that the UI_ATTACHMENTS query does not behave the same way, 3103fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // which causes crazy formatting. 3104fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // There is an open question here, should attachments that are inlined 3105fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // ALSO appear in the list of attachments at the bottom with the non-inlined 3106fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // attachments? 3107fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // Either way, the two queries need to behave the same way. 3108fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // As of now, they will. If we decide to stop this, then we need to enable 3109fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // the code below, and then also make the UI_ATTACHMENTS query behave 3110fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // the same way. 3111fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon// 3112fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon// if (att.mContentId != null && att.getContentUri() != null) { 3113fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon// continue; 3114fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon// } 3115f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank com.android.mail.providers.Attachment uiAtt = 3116f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank new com.android.mail.providers.Attachment(); 3117ea2edb637036a7368b6ef82a0aafdb1a790e26e9Mark Wei uiAtt.setName(att.mFileName); 3118ea2edb637036a7368b6ef82a0aafdb1a790e26e9Mark Wei uiAtt.setContentType(att.mMimeType); 3119f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank uiAtt.size = (int) att.mSize; 3120f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank uiAtt.uri = uiUri("uiattachment", att.mId); 3121aad690f699f61793facecc950d3d060baa62fd45Martin Hibdon uiAtt.flags = att.mFlags; 3122f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank uiAtts.add(uiAtt); 3123f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 31247c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank values.put(UIProvider.MessageColumns.ATTACHMENTS, "@?"); // @ for literal 31257c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank attachmentJson = com.android.mail.providers.Attachment.toJSONArray(uiAtts); 3126f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3127f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (msg.mDraftInfo != 0) { 3128f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(UIProvider.MessageColumns.APPEND_REF_MESSAGE_CONTENT, 3129f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank (msg.mDraftInfo & Message.DRAFT_INFO_APPEND_REF_MESSAGE) != 0 ? 1 : 0); 3130f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(UIProvider.MessageColumns.QUOTE_START_POS, 3131f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.mDraftInfo & Message.DRAFT_INFO_QUOTE_POS_MASK); 3132f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3133949fc3d88338861dec8eac29fffaef5b17ae07e8Marc Blank if ((msg.mFlags & Message.FLAG_INCOMING_MEETING_INVITE) != 0) { 3134949fc3d88338861dec8eac29fffaef5b17ae07e8Marc Blank values.put(UIProvider.MessageColumns.EVENT_INTENT_URI, 3135949fc3d88338861dec8eac29fffaef5b17ae07e8Marc Blank "content://ui.email2.android.com/event/" + msg.mId); 3136949fc3d88338861dec8eac29fffaef5b17ae07e8Marc Blank } 313762604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler /** 313862604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler * HACK: override the attachment uri to contain a query parameter 313962604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler * This forces the message footer to reload the attachment display when the message is 314062604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler * fully loaded. 314162604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler */ 314262604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler final Uri attachmentListUri = uiUri("uiattachments", messageId).buildUpon() 314362604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler .appendQueryParameter("MessageLoaded", 314462604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler msg.mFlagLoaded == Message.FLAG_LOADED_COMPLETE ? "true" : "false") 314562604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler .build(); 314662604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler values.put(UIProvider.MessageColumns.ATTACHMENT_LIST_URI, attachmentListUri.toString()); 3147f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3148e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank StringBuilder sb = genSelect(getMessageViewMap(), uiProjection, values); 31493dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler sb.append(" FROM " + Message.TABLE_NAME + " LEFT JOIN " + Body.TABLE_NAME + 31503dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler " ON " + BodyColumns.MESSAGE_KEY + "=" + Message.TABLE_NAME + "." + 31513dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler MessageColumns._ID + 31523dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler " WHERE " + Message.TABLE_NAME + "." + MessageColumns._ID + "=?"); 31537c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank String sql = sb.toString(); 31547c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank return new MessageQuery(sql, attachmentJson); 3155f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3156f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 31570203a06c87e389f0d3af19bc26f61d0cf846226aScott Kennedy private static void appendConversationInfoColumns(final StringBuilder stringBuilder) { 31580203a06c87e389f0d3af19bc26f61d0cf846226aScott Kennedy // TODO(skennedy) These columns are needed for the respond call for ConversationInfo :( 31590203a06c87e389f0d3af19bc26f61d0cf846226aScott Kennedy // There may be a better way to do this, but since the projection is specified by the 31600203a06c87e389f0d3af19bc26f61d0cf846226aScott Kennedy // unified UI code, it can't ask for these columns. 31610203a06c87e389f0d3af19bc26f61d0cf846226aScott Kennedy stringBuilder.append(',').append(MessageColumns.DISPLAY_NAME) 31626f4a9eb8767884a64c3e8498f6f8ce515357a993James Lemieux .append(',').append(MessageColumns.FROM_LIST) 31636f4a9eb8767884a64c3e8498f6f8ce515357a993James Lemieux .append(',').append(MessageColumns.TO_LIST); 31640203a06c87e389f0d3af19bc26f61d0cf846226aScott Kennedy } 31650203a06c87e389f0d3af19bc26f61d0cf846226aScott Kennedy 3166f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3167f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate the "message list" SQLite query, given a projection from UnifiedEmail 3168f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3169f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 3170b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy * @param unseenOnly <code>true</code> to only return unseen messages 3171f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 3172f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3173b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static String genQueryMailboxMessages(String[] uiProjection, final boolean unseenOnly) { 3174e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank StringBuilder sb = genSelect(getMessageListMap(), uiProjection); 31750203a06c87e389f0d3af19bc26f61d0cf846226aScott Kennedy appendConversationInfoColumns(sb); 3176de4c230f008ca0615b8035a560cd512624ac2cdbYu Ping Hu sb.append(" FROM " + Message.TABLE_NAME + " WHERE " + 31776dd7bd29e97e7190b01bf6325d131f24c097b560Paul Westbrook Message.FLAG_LOADED_SELECTION + " AND " + 31783dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler MessageColumns.MAILBOX_KEY + "=? "); 3179b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy if (unseenOnly) { 3180b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy sb.append("AND ").append(MessageColumns.FLAG_SEEN).append(" = 0 "); 3181d4a06f409d08a61bd387ab2e2f37eca519f10010Tony Mantler sb.append("AND ").append(MessageColumns.FLAG_READ).append(" = 0 "); 3182b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy } 3183c1d56928b2185e6a2643eea271a1fbd50e425ca2Paul Westbrook sb.append("ORDER BY " + MessageColumns.TIMESTAMP + " DESC "); 3184e31fe0d47bf9e2a4e1de7b2aa518c0b08828d7d8Tony Mantler sb.append("LIMIT " + UIProvider.CONVERSATION_PROJECTION_QUERY_CURSOR_WINDOW_LIMIT); 3185f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return sb.toString(); 3186f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3187f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3188f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3189f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate various virtual mailbox SQLite queries, given a projection from UnifiedEmail 3190f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3191f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 3192b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy * @param mailboxId the id of the virtual mailbox 3193b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy * @param unseenOnly <code>true</code> to only return unseen messages 3194f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 3195f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3196b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static Cursor getVirtualMailboxMessagesCursor(SQLiteDatabase db, String[] uiProjection, 3197b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy long mailboxId, final boolean unseenOnly) { 3198f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ContentValues values = new ContentValues(); 3199f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(UIProvider.ConversationColumns.COLOR, CONVERSATION_COLOR); 3200c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu final int virtualMailboxId = getVirtualMailboxType(mailboxId); 3201c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu final String[] selectionArgs; 3202e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank StringBuilder sb = genSelect(getMessageListMap(), uiProjection, values); 32030203a06c87e389f0d3af19bc26f61d0cf846226aScott Kennedy appendConversationInfoColumns(sb); 3204de4c230f008ca0615b8035a560cd512624ac2cdbYu Ping Hu sb.append(" FROM " + Message.TABLE_NAME + " WHERE " + 32056dd7bd29e97e7190b01bf6325d131f24c097b560Paul Westbrook Message.FLAG_LOADED_SELECTION + " AND "); 3206f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (isCombinedMailbox(mailboxId)) { 3207c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu if (unseenOnly) { 3208c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu sb.append(MessageColumns.FLAG_SEEN).append("=0 AND "); 3209d4a06f409d08a61bd387ab2e2f37eca519f10010Tony Mantler sb.append(MessageColumns.FLAG_READ).append("=0 AND "); 3210f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3211c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu selectionArgs = null; 3212f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 3213c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu if (virtualMailboxId == Mailbox.TYPE_INBOX) { 3214c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu throw new IllegalArgumentException("No virtual mailbox for: " + mailboxId); 3215f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3216c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu sb.append(MessageColumns.ACCOUNT_KEY).append("=? AND "); 3217c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu selectionArgs = new String[]{getVirtualMailboxAccountIdString(mailboxId)}; 3218c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu } 3219c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu switch (getVirtualMailboxType(mailboxId)) { 3220c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu case Mailbox.TYPE_INBOX: 32213dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler sb.append(MessageColumns.MAILBOX_KEY + " IN (SELECT " + MailboxColumns._ID + 3222c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu " FROM " + Mailbox.TABLE_NAME + " WHERE " + MailboxColumns.TYPE + 3223c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu "=" + Mailbox.TYPE_INBOX + ")"); 3224c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu break; 3225c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu case Mailbox.TYPE_STARRED: 3226c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu sb.append(MessageColumns.FLAG_FAVORITE + "=1"); 3227c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu break; 3228cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case Mailbox.TYPE_UNREAD: 3229c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu sb.append(MessageColumns.FLAG_READ + "=0 AND " + MessageColumns.MAILBOX_KEY + 32303dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler " NOT IN (SELECT " + MailboxColumns._ID + " FROM " + Mailbox.TABLE_NAME + 3231c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu " WHERE " + MailboxColumns.TYPE + "=" + Mailbox.TYPE_TRASH + ")"); 3232c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu break; 3233c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu default: 3234c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu throw new IllegalArgumentException("No virtual mailbox for: " + mailboxId); 3235f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3236c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu sb.append(" ORDER BY " + MessageColumns.TIMESTAMP + " DESC"); 3237c065e72819fad62c083fd97e8d300a6b8e78a7aeYu Ping Hu return db.rawQuery(sb.toString(), selectionArgs); 3238f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3239f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3240f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3241f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate the "message list" SQLite query, given a projection from UnifiedEmail 3242f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3243f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 3244f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 3245f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3246b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static String genQueryConversation(String[] uiProjection) { 3247e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank StringBuilder sb = genSelect(getMessageListMap(), uiProjection); 32483dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler sb.append(" FROM " + Message.TABLE_NAME + " WHERE " + MessageColumns._ID + "=?"); 3249f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return sb.toString(); 3250f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3251f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3252f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3253f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate the "top level folder list" SQLite query, given a projection from UnifiedEmail 3254f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3255f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 3256f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 3257f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3258b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static String genQueryAccountMailboxes(String[] uiProjection) { 3259e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank StringBuilder sb = genSelect(getFolderListMap(), uiProjection); 3260f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank sb.append(" FROM " + Mailbox.TABLE_NAME + " WHERE " + MailboxColumns.ACCOUNT_KEY + 3261f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "=? AND " + MailboxColumns.TYPE + " < " + Mailbox.TYPE_NOT_EMAIL + 3262555bd3c0b7132509421ae181fbdb35995819787cPaul Westbrook " AND " + MailboxColumns.TYPE + " != " + Mailbox.TYPE_SEARCH + 3263f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " AND " + MailboxColumns.PARENT_KEY + " < 0 ORDER BY "); 3264f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank sb.append(MAILBOX_ORDER_BY); 3265f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return sb.toString(); 3266f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3267f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3268f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3269f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate the "all folders" SQLite query, given a projection from UnifiedEmail. The list is 3270f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * sorted by the name as it appears in a hierarchical listing 3271f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3272f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 3273f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 3274f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3275b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static String genQueryAccountAllMailboxes(String[] uiProjection) { 3276e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank StringBuilder sb = genSelect(getFolderListMap(), uiProjection); 3277f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Use a derived column to choose either hierarchicalName or displayName 3278f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank sb.append(", case when " + MailboxColumns.HIERARCHICAL_NAME + " is null then " + 3279f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank MailboxColumns.DISPLAY_NAME + " else " + MailboxColumns.HIERARCHICAL_NAME + 3280f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " end as h_name"); 3281f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Order by the derived column 3282f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank sb.append(" FROM " + Mailbox.TABLE_NAME + " WHERE " + MailboxColumns.ACCOUNT_KEY + 3283f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "=? AND " + MailboxColumns.TYPE + " < " + Mailbox.TYPE_NOT_EMAIL + 3284555bd3c0b7132509421ae181fbdb35995819787cPaul Westbrook " AND " + MailboxColumns.TYPE + " != " + Mailbox.TYPE_SEARCH + 3285f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " ORDER BY h_name"); 3286f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return sb.toString(); 3287f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3288f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3289f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3290f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate the "recent folder list" SQLite query, given a projection from UnifiedEmail 3291f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3292f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 3293f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 3294f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3295b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static String genQueryRecentMailboxes(String[] uiProjection) { 3296e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank StringBuilder sb = genSelect(getFolderListMap(), uiProjection); 3297f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank sb.append(" FROM " + Mailbox.TABLE_NAME + " WHERE " + MailboxColumns.ACCOUNT_KEY + 3298f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank "=? AND " + MailboxColumns.TYPE + " < " + Mailbox.TYPE_NOT_EMAIL + 3299555bd3c0b7132509421ae181fbdb35995819787cPaul Westbrook " AND " + MailboxColumns.TYPE + " != " + Mailbox.TYPE_SEARCH + 3300f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " AND " + MailboxColumns.PARENT_KEY + " < 0 AND " + 3301f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank MailboxColumns.LAST_TOUCHED_TIME + " > 0 ORDER BY " + 3302f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank MailboxColumns.LAST_TOUCHED_TIME + " DESC"); 3303f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return sb.toString(); 3304f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3305f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3306469c4263760373c1bc330251910ec28005051aa8James Lemieux private int getFolderCapabilities(EmailServiceInfo info, int mailboxType, long mailboxId) { 33071004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Special case for Search folders: only permit delete, do not try to give any other caps. 3308469c4263760373c1bc330251910ec28005051aa8James Lemieux if (mailboxType == Mailbox.TYPE_SEARCH) { 33091004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu return UIProvider.FolderCapabilities.DELETE; 33101004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } 33111004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu 33126edccbf1f1371157cfa6e503d8353a474aafd2a1Yu Ping Hu // All folders support delete, except drafts. 33136edccbf1f1371157cfa6e503d8353a474aafd2a1Yu Ping Hu int caps = 0; 3314469c4263760373c1bc330251910ec28005051aa8James Lemieux if (mailboxType != Mailbox.TYPE_DRAFTS) { 33156edccbf1f1371157cfa6e503d8353a474aafd2a1Yu Ping Hu caps = UIProvider.FolderCapabilities.DELETE; 33166edccbf1f1371157cfa6e503d8353a474aafd2a1Yu Ping Hu } 33175ac8d38796952a817f4693b38d62fc124651c121Marc Blank if (info != null && info.offerLookback) { 33185ac8d38796952a817f4693b38d62fc124651c121Marc Blank // Protocols supporting lookback support settings 33195ac8d38796952a817f4693b38d62fc124651c121Marc Blank caps |= UIProvider.FolderCapabilities.SUPPORTS_SETTINGS; 33205ac8d38796952a817f4693b38d62fc124651c121Marc Blank } 33211004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu 3322469c4263760373c1bc330251910ec28005051aa8James Lemieux if (mailboxType == Mailbox.TYPE_MAIL || mailboxType == Mailbox.TYPE_TRASH || 3323469c4263760373c1bc330251910ec28005051aa8James Lemieux mailboxType == Mailbox.TYPE_JUNK || mailboxType == Mailbox.TYPE_INBOX) { 33245ed8b266a480ea413264abdb5042c58b29175df8Paul Westbrook // If the mailbox can accept moved mail, report that as well 33255ed8b266a480ea413264abdb5042c58b29175df8Paul Westbrook caps |= UIProvider.FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES; 33265ed8b266a480ea413264abdb5042c58b29175df8Paul Westbrook caps |= UIProvider.FolderCapabilities.ALLOWS_REMOVE_CONVERSATION; 33275ed8b266a480ea413264abdb5042c58b29175df8Paul Westbrook } 33285ed8b266a480ea413264abdb5042c58b29175df8Paul Westbrook 33295ac8d38796952a817f4693b38d62fc124651c121Marc Blank // For trash, we don't allow undo 3330469c4263760373c1bc330251910ec28005051aa8James Lemieux if (mailboxType == Mailbox.TYPE_TRASH) { 33315ac8d38796952a817f4693b38d62fc124651c121Marc Blank caps = UIProvider.FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES | 333253836e572eb4b402140a02da949f3e3d0ca146edAndrew Sapperstein UIProvider.FolderCapabilities.ALLOWS_REMOVE_CONVERSATION | 33335ac8d38796952a817f4693b38d62fc124651c121Marc Blank UIProvider.FolderCapabilities.DELETE | 33345ac8d38796952a817f4693b38d62fc124651c121Marc Blank UIProvider.FolderCapabilities.DELETE_ACTION_FINAL; 33355ac8d38796952a817f4693b38d62fc124651c121Marc Blank } 33365ac8d38796952a817f4693b38d62fc124651c121Marc Blank if (isVirtualMailbox(mailboxId)) { 33375ac8d38796952a817f4693b38d62fc124651c121Marc Blank caps |= UIProvider.FolderCapabilities.IS_VIRTUAL; 33385ac8d38796952a817f4693b38d62fc124651c121Marc Blank } 3339ae46818a1925cc22fe20ee26ffee8779561a903bAlon Albert 33406953d5951fed975d2569ec46bd544ce21e6860dcTony Mantler // If we don't know the protocol or the protocol doesn't support it, don't allow moving 33416953d5951fed975d2569ec46bd544ce21e6860dcTony Mantler // messages 33426953d5951fed975d2569ec46bd544ce21e6860dcTony Mantler if (info == null || !info.offerMoveTo) { 3343ae46818a1925cc22fe20ee26ffee8779561a903bAlon Albert caps &= ~UIProvider.FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES & 3344ae46818a1925cc22fe20ee26ffee8779561a903bAlon Albert ~UIProvider.FolderCapabilities.ALLOWS_REMOVE_CONVERSATION & 3345ae46818a1925cc22fe20ee26ffee8779561a903bAlon Albert ~UIProvider.FolderCapabilities.ALLOWS_MOVE_TO_INBOX; 3346ae46818a1925cc22fe20ee26ffee8779561a903bAlon Albert } 3347469c4263760373c1bc330251910ec28005051aa8James Lemieux 3348469c4263760373c1bc330251910ec28005051aa8James Lemieux // If the mailbox stores outgoing mail, show recipients instead of senders 3349469c4263760373c1bc330251910ec28005051aa8James Lemieux // (however the Drafts folder shows neither senders nor recipients... just the word "Draft") 3350469c4263760373c1bc330251910ec28005051aa8James Lemieux if (mailboxType == Mailbox.TYPE_OUTBOX || mailboxType == Mailbox.TYPE_SENT) { 3351469c4263760373c1bc330251910ec28005051aa8James Lemieux caps |= UIProvider.FolderCapabilities.SHOW_RECIPIENTS; 3352469c4263760373c1bc330251910ec28005051aa8James Lemieux } 3353469c4263760373c1bc330251910ec28005051aa8James Lemieux 33545ac8d38796952a817f4693b38d62fc124651c121Marc Blank return caps; 33555ac8d38796952a817f4693b38d62fc124651c121Marc Blank } 33565ac8d38796952a817f4693b38d62fc124651c121Marc Blank 3357f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3358f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate a "single mailbox" SQLite query, given a projection from UnifiedEmail 3359f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3360f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 3361f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 3362f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3363f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private String genQueryMailbox(String[] uiProjection, String id) { 3364f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank long mailboxId = Long.parseLong(id); 33655d47ee0f87208ab22c317abc87f615b6254cc852Tony Mantler ContentValues values = new ContentValues(3); 3366f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mSearchParams != null && mailboxId == mSearchParams.mSearchMailboxId) { 3367f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // "load more" is valid for search results 3368f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(UIProvider.FolderColumns.LOAD_MORE_URI, 3369f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank uiUriString("uiloadmore", mailboxId)); 33703767da5d26c7138a6c3a293fd4b2b685f71f016fPaul Westbrook values.put(UIProvider.FolderColumns.CAPABILITIES, UIProvider.FolderCapabilities.DELETE); 3371f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 3372f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Context context = getContext(); 3373f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Mailbox mailbox = Mailbox.restoreMailboxWithId(context, mailboxId); 3374f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Make sure we can't get NPE if mailbox has disappeared (the result will end up moot) 3375f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mailbox != null) { 3376f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank String protocol = Account.getProtocol(context, mailbox.mAccountKey); 3377f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank EmailServiceInfo info = EmailServiceUtils.getServiceInfo(context, protocol); 3378285cef8ad0af4727b53a7b79e709c0ecb5f40d4fMarc Blank // All folders support delete 3379b82ae909d7514bf06090ee3a120aef2154ab0296Marc Blank if (info != null && info.offerLoadMore) { 3380285cef8ad0af4727b53a7b79e709c0ecb5f40d4fMarc Blank // "load more" is valid for protocols not supporting "lookback" 3381f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(UIProvider.FolderColumns.LOAD_MORE_URI, 3382f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank uiUriString("uiloadmore", mailboxId)); 3383cc986cf3d75dd80f59e41b829bb41c369f973d7dMarc Blank } 33845ac8d38796952a817f4693b38d62fc124651c121Marc Blank values.put(UIProvider.FolderColumns.CAPABILITIES, 33851004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu getFolderCapabilities(info, mailbox.mType, mailboxId)); 33869b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu // The persistent id is used to form a filename, so we must ensure that it doesn't 33879b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu // include illegal characters (such as '/'). Only perform the encoding if this 33889b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu // query wants the persistent id. 33899b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu boolean shouldEncodePersistentId = false; 33909b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu if (uiProjection == null) { 33919b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu shouldEncodePersistentId = true; 33929b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu } else { 33939b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu for (final String column : uiProjection) { 33949b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu if (TextUtils.equals(column, UIProvider.FolderColumns.PERSISTENT_ID)) { 33959b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu shouldEncodePersistentId = true; 33969b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu break; 33979b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu } 33989b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu } 33999b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu } 34009b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu if (shouldEncodePersistentId) { 34019b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu values.put(UIProvider.FolderColumns.PERSISTENT_ID, 34029b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu Base64.encodeToString(mailbox.mServerId.getBytes(), 34039b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING)); 34049b040bde34529e4e55c70774ecea87868c79f1e5Yu Ping Hu } 34055ac8d38796952a817f4693b38d62fc124651c121Marc Blank } 3406f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3407e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank StringBuilder sb = genSelect(getFolderListMap(), uiProjection, values); 34083dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler sb.append(" FROM " + Mailbox.TABLE_NAME + " WHERE " + MailboxColumns._ID + "=?"); 3409f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return sb.toString(); 3410f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3411f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3412391a7fc0e99457308b6f6bd9444c8aba94b0b7b1Paul Westbrook public static final String LEGACY_AUTHORITY = "ui.email.android.com"; 3413391a7fc0e99457308b6f6bd9444c8aba94b0b7b1Paul Westbrook private static final Uri BASE_EXTERNAL_URI = Uri.parse("content://" + LEGACY_AUTHORITY); 3414f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3415f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final Uri BASE_EXTERAL_URI2 = Uri.parse("content://ui.email2.android.com"); 3416f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3417f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static String getExternalUriString(String segment, String account) { 3418f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return BASE_EXTERNAL_URI.buildUpon().appendPath(segment) 3419f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank .appendQueryParameter("account", account).build().toString(); 3420f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3421f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3422f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static String getExternalUriStringEmail2(String segment, String account) { 3423f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return BASE_EXTERAL_URI2.buildUpon().appendPath(segment) 3424f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank .appendQueryParameter("account", account).build().toString(); 3425f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3426f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3427b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static String getBits(int bitField) { 3428983c78e92899b94b237c292968c1be2bf53c5d57Marc Blank StringBuilder sb = new StringBuilder(" "); 3429983c78e92899b94b237c292968c1be2bf53c5d57Marc Blank for (int i = 0; i < 32; i++, bitField >>= 1) { 3430983c78e92899b94b237c292968c1be2bf53c5d57Marc Blank if ((bitField & 1) != 0) { 3431582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler sb.append(i) 3432582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(" "); 3433983c78e92899b94b237c292968c1be2bf53c5d57Marc Blank } 3434983c78e92899b94b237c292968c1be2bf53c5d57Marc Blank } 3435983c78e92899b94b237c292968c1be2bf53c5d57Marc Blank return sb.toString(); 3436983c78e92899b94b237c292968c1be2bf53c5d57Marc Blank } 3437983c78e92899b94b237c292968c1be2bf53c5d57Marc Blank 34388209d6c081243d58cf9957c1900e550b440af431Martin Hibdon private static int getCapabilities(Context context, final Account account) { 3439a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu if (account == null) { 3440a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu return 0; 3441a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu } 3442a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu // Account capabilities are based on protocol -- different protocols (and, for EAS, 3443a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu // different protocol versions) support different feature sets. 3444a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu final String protocol = account.getProtocol(context); 3445a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu int capabilities; 3446a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu if (TextUtils.equals(context.getString(R.string.protocol_imap), protocol) || 3447a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu TextUtils.equals(context.getString(R.string.protocol_legacy_imap), protocol)) { 3448a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu capabilities = AccountCapabilities.SYNCABLE_FOLDERS | 344919882289991e10ba6f2f8a08d03a4b7193b6437dJames Lemieux AccountCapabilities.SERVER_SEARCH | 3450a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.FOLDER_SERVER_SEARCH | 3451a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.UNDO | 3452a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.DISCARD_CONVERSATION_DRAFTS; 3453a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu } else if (TextUtils.equals(context.getString(R.string.protocol_pop3), protocol)) { 3454a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu capabilities = AccountCapabilities.UNDO | 3455a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.DISCARD_CONVERSATION_DRAFTS; 3456a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu } else if (TextUtils.equals(context.getString(R.string.protocol_eas), protocol)) { 3457a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu final String easVersion = account.mProtocolVersion; 3458a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu double easVersionDouble = 2.5D; 3459a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu if (easVersion != null) { 3460a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu try { 3461a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu easVersionDouble = Double.parseDouble(easVersion); 3462a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu } catch (final NumberFormatException e) { 3463a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu // Use the default (lowest) set of capabilities. 3464a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu } 3465983c78e92899b94b237c292968c1be2bf53c5d57Marc Blank } 3466a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu if (easVersionDouble >= 12.0D) { 3467a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu capabilities = AccountCapabilities.SYNCABLE_FOLDERS | 3468a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.SERVER_SEARCH | 3469a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.FOLDER_SERVER_SEARCH | 3470a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.SMART_REPLY | 3471a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.UNDO | 3472a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.DISCARD_CONVERSATION_DRAFTS; 3473a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu } else { 3474a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu capabilities = AccountCapabilities.SYNCABLE_FOLDERS | 3475a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.SMART_REPLY | 3476a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.UNDO | 3477a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu AccountCapabilities.DISCARD_CONVERSATION_DRAFTS; 3478a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu } 3479a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu } else { 34808209d6c081243d58cf9957c1900e550b440af431Martin Hibdon LogUtils.w(TAG, "Unknown protocol for account %d", account.getId()); 3481a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu return 0; 34820b5f15d61ebf7c0e8428100637bc479ed93a4cb2Marc Blank } 34838209d6c081243d58cf9957c1900e550b440af431Martin Hibdon LogUtils.d(TAG, "getCapabilities() for %d (protocol %s): 0x%x %s", account.getId(), protocol, 3484a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu capabilities, getBits(capabilities)); 34855a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook 34865a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook // If the configuration states that feedback is supported, add that capability 34875a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook final Resources res = context.getResources(); 34885a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook if (res.getBoolean(R.bool.feedback_supported)) { 3489e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler capabilities |= AccountCapabilities.SEND_FEEDBACK; 34905a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook } 349131ce5555b8b277a05e4af01c57cb078be3049409James Lemieux 349231ce5555b8b277a05e4af01c57cb078be3049409James Lemieux // If we can find a help URL then add the Help capability 349331ce5555b8b277a05e4af01c57cb078be3049409James Lemieux if (!TextUtils.isEmpty(context.getResources().getString(R.string.help_uri))) { 3494e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler capabilities |= AccountCapabilities.HELP_CONTENT; 349531ce5555b8b277a05e4af01c57cb078be3049409James Lemieux } 349631ce5555b8b277a05e4af01c57cb078be3049409James Lemieux 3497e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler capabilities |= AccountCapabilities.EMPTY_TRASH; 3498e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler 3499a5a28ffb63785eefe8602174316d9ba6233ac428Yu Ping Hu // TODO: Should this be stored per-account, or some other mechanism? 3500e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler capabilities |= AccountCapabilities.NESTED_FOLDERS; 3501fc5aae98e7a440ef9ab015efd4934123c2c15e76Scott Kennedy 35023bdce9b515f6bde3506596a6b5d3bdbaff9b7423James Lemieux // the client is permitted to sanitize HTML emails for all Email accounts 35033bdce9b515f6bde3506596a6b5d3bdbaff9b7423James Lemieux capabilities |= AccountCapabilities.CLIENT_SANITIZED_HTML; 3504837aba39d513ffcf42c73b35c6e0edf78d1a0c97James Lemieux 35050b5f15d61ebf7c0e8428100637bc479ed93a4cb2Marc Blank return capabilities; 35060b5f15d61ebf7c0e8428100637bc479ed93a4cb2Marc Blank } 35070b5f15d61ebf7c0e8428100637bc479ed93a4cb2Marc Blank 3508f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3509f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate a "single account" SQLite query, given a projection from UnifiedEmail 3510f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 3511f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 3512c6953b77552d4cb71776cf0537dc226029381628Tony Mantler * @param id account row ID 3513f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 3514f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3515f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private String genQueryAccount(String[] uiProjection, String id) { 351651693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook final ContentValues values = new ContentValues(); 351751693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook final long accountId = Long.parseLong(id); 35180b5f15d61ebf7c0e8428100637bc479ed93a4cb2Marc Blank final Context context = getContext(); 3519f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 35209e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu EmailServiceInfo info = null; 35219e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu 3522e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy // TODO: If uiProjection is null, this will NPE. We should do everything here if it's null. 352351693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook final Set<String> projectionColumns = ImmutableSet.copyOf(uiProjection); 352451693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook 35258209d6c081243d58cf9957c1900e550b440af431Martin Hibdon final Account account = Account.restoreAccountWithId(context, accountId); 35268209d6c081243d58cf9957c1900e550b440af431Martin Hibdon if (account == null) { 35278209d6c081243d58cf9957c1900e550b440af431Martin Hibdon LogUtils.d(TAG, "Account %d not found during genQueryAccount", accountId); 35288209d6c081243d58cf9957c1900e550b440af431Martin Hibdon } 352951693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains(UIProvider.AccountColumns.CAPABILITIES)) { 353051693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook // Get account capabilities from the service 35318209d6c081243d58cf9957c1900e550b440af431Martin Hibdon values.put(UIProvider.AccountColumns.CAPABILITIES, 35328209d6c081243d58cf9957c1900e550b440af431Martin Hibdon (account == null ? 0 : getCapabilities(context, account))); 353351693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 353451693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains(UIProvider.AccountColumns.SETTINGS_INTENT_URI)) { 353551693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook values.put(UIProvider.AccountColumns.SETTINGS_INTENT_URI, 353651693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook getExternalUriString("settings", id)); 353751693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 353851693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains(UIProvider.AccountColumns.COMPOSE_URI)) { 353951693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook values.put(UIProvider.AccountColumns.COMPOSE_URI, 354051693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook getExternalUriStringEmail2("compose", id)); 354151693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 35420dffe3afd7a2fdfb394573aa0d8d06dd90e9fe12James Lemieux if (projectionColumns.contains(UIProvider.AccountColumns.REAUTHENTICATION_INTENT_URI)) { 35430dffe3afd7a2fdfb394573aa0d8d06dd90e9fe12James Lemieux values.put(UIProvider.AccountColumns.REAUTHENTICATION_INTENT_URI, 3544bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook getIncomingSettingsUri(accountId).toString()); 35450dffe3afd7a2fdfb394573aa0d8d06dd90e9fe12James Lemieux } 354651693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains(UIProvider.AccountColumns.MIME_TYPE)) { 354751693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook values.put(UIProvider.AccountColumns.MIME_TYPE, EMAIL_APP_MIME_TYPE); 354851693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 354951693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains(UIProvider.AccountColumns.COLOR)) { 355051693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook values.put(UIProvider.AccountColumns.COLOR, ACCOUNT_COLOR); 355151693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 355251693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook 3553988ad6e002810d5da713f0cda20aecf00cccb9caTony Mantler // TODO: if we're getting the values out of MailPrefs then we don't need to be passing the 3554988ad6e002810d5da713f0cda20aecf00cccb9caTony Mantler // values this way 35552f9c66d08b13c1ed4eb7d2f70baa98116ac5fcfbScott Kennedy final MailPrefs mailPrefs = MailPrefs.get(getContext()); 355651693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains(UIProvider.AccountColumns.SettingsColumns.CONFIRM_DELETE)) { 355751693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook values.put(UIProvider.AccountColumns.SettingsColumns.CONFIRM_DELETE, 3558988ad6e002810d5da713f0cda20aecf00cccb9caTony Mantler mailPrefs.getConfirmDelete() ? "1" : "0"); 355951693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 356051693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains(UIProvider.AccountColumns.SettingsColumns.CONFIRM_SEND)) { 356151693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook values.put(UIProvider.AccountColumns.SettingsColumns.CONFIRM_SEND, 3562988ad6e002810d5da713f0cda20aecf00cccb9caTony Mantler mailPrefs.getConfirmSend() ? "1" : "0"); 356351693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 3564b225298b13eb47c6251d73c28506b0a7ad56bf5cMarc Blank if (projectionColumns.contains(UIProvider.AccountColumns.SettingsColumns.SWIPE)) { 3565b225298b13eb47c6251d73c28506b0a7ad56bf5cMarc Blank values.put(UIProvider.AccountColumns.SettingsColumns.SWIPE, 3566643846abbd1ae60454fc8191992afffd08114e98Scott Kennedy mailPrefs.getConversationListSwipeActionInteger(false)); 3567b225298b13eb47c6251d73c28506b0a7ad56bf5cMarc Blank } 356851693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains( 35699f1cff0659e4b9a179690d9c31f7a9bf56aad228Alice Yang UIProvider.AccountColumns.SettingsColumns.CONV_LIST_ICON)) { 35709f1cff0659e4b9a179690d9c31f7a9bf56aad228Alice Yang values.put(UIProvider.AccountColumns.SettingsColumns.CONV_LIST_ICON, 3571ccf730fbe53c3bffb0154d0666e9fcbb5e82f551Paul Westbrook getConversationListIcon(mailPrefs)); 357251693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 357351693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains(UIProvider.AccountColumns.SettingsColumns.AUTO_ADVANCE)) { 357451693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook values.put(UIProvider.AccountColumns.SettingsColumns.AUTO_ADVANCE, 3575988ad6e002810d5da713f0cda20aecf00cccb9caTony Mantler Integer.toString(mailPrefs.getAutoAdvanceMode())); 357651693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 3577b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy // Set default inbox, if we've got an inbox; otherwise, say initial sync needed 35781079b6e9628910e726881233f62808976d5d3be1Scott Kennedy final long inboxMailboxId = 35791079b6e9628910e726881233f62808976d5d3be1Scott Kennedy Mailbox.findMailboxOfType(context, accountId, Mailbox.TYPE_INBOX); 358051693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains(UIProvider.AccountColumns.SettingsColumns.DEFAULT_INBOX) && 35811079b6e9628910e726881233f62808976d5d3be1Scott Kennedy inboxMailboxId != Mailbox.NO_MAILBOX) { 3582f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(UIProvider.AccountColumns.SettingsColumns.DEFAULT_INBOX, 35831079b6e9628910e726881233f62808976d5d3be1Scott Kennedy uiUriString("uifolder", inboxMailboxId)); 35840d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler } else { 35850d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler values.put(UIProvider.AccountColumns.SettingsColumns.DEFAULT_INBOX, 35860d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler uiUriString("uiinbox", accountId)); 358751693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 358851693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains( 358951693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook UIProvider.AccountColumns.SettingsColumns.DEFAULT_INBOX_NAME) && 35901079b6e9628910e726881233f62808976d5d3be1Scott Kennedy inboxMailboxId != Mailbox.NO_MAILBOX) { 3591a0fef46aea16c1783f681bb0053eeb3f53d975abVikram Aggarwal values.put(UIProvider.AccountColumns.SettingsColumns.DEFAULT_INBOX_NAME, 35921079b6e9628910e726881233f62808976d5d3be1Scott Kennedy Mailbox.getDisplayName(context, inboxMailboxId)); 359351693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 359451693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook if (projectionColumns.contains(UIProvider.AccountColumns.SYNC_STATUS)) { 35951079b6e9628910e726881233f62808976d5d3be1Scott Kennedy if (inboxMailboxId != Mailbox.NO_MAILBOX) { 359651693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook values.put(UIProvider.AccountColumns.SYNC_STATUS, UIProvider.SyncStatus.NO_SYNC); 359751693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } else { 359851693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook values.put(UIProvider.AccountColumns.SYNC_STATUS, 359951693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook UIProvider.SyncStatus.INITIAL_SYNC_NEEDED); 360051693c5a4ca3553f0a02a91fe1805fb895380e3ePaul Westbrook } 3601f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3602b7e0834121d564982c0389c87df775ba311429d4Tony Mantler if (projectionColumns.contains(UIProvider.AccountColumns.UPDATE_SETTINGS_URI)) { 3603b7e0834121d564982c0389c87df775ba311429d4Tony Mantler values.put(UIProvider.AccountColumns.UPDATE_SETTINGS_URI, 3604b7e0834121d564982c0389c87df775ba311429d4Tony Mantler uiUriString("uiacctsettings", -1)); 3605b7e0834121d564982c0389c87df775ba311429d4Tony Mantler } 3606837aba39d513ffcf42c73b35c6e0edf78d1a0c97James Lemieux if (projectionColumns.contains(UIProvider.AccountColumns.ENABLE_MESSAGE_TRANSFORMS)) { 3607837aba39d513ffcf42c73b35c6e0edf78d1a0c97James Lemieux // Email is now sanitized, which grants the ability to inject beautifying javascript. 3608837aba39d513ffcf42c73b35c6e0edf78d1a0c97James Lemieux values.put(UIProvider.AccountColumns.ENABLE_MESSAGE_TRANSFORMS, 1); 3609837aba39d513ffcf42c73b35c6e0edf78d1a0c97James Lemieux } 36108209d6c081243d58cf9957c1900e550b440af431Martin Hibdon if (projectionColumns.contains(UIProvider.AccountColumns.SECURITY_HOLD)) { 36118209d6c081243d58cf9957c1900e550b440af431Martin Hibdon final int hold = ((account != null && 36128209d6c081243d58cf9957c1900e550b440af431Martin Hibdon ((account.getFlags() & Account.FLAGS_SECURITY_HOLD) == 0)) ? 0 : 1); 36138209d6c081243d58cf9957c1900e550b440af431Martin Hibdon values.put(UIProvider.AccountColumns.SECURITY_HOLD, hold); 36148209d6c081243d58cf9957c1900e550b440af431Martin Hibdon } 36158209d6c081243d58cf9957c1900e550b440af431Martin Hibdon if (projectionColumns.contains(UIProvider.AccountColumns.ACCOUNT_SECURITY_URI)) { 36168209d6c081243d58cf9957c1900e550b440af431Martin Hibdon values.put(UIProvider.AccountColumns.ACCOUNT_SECURITY_URI, 36178209d6c081243d58cf9957c1900e550b440af431Martin Hibdon (account == null ? "" : AccountSecurity.getUpdateSecurityUri( 36188209d6c081243d58cf9957c1900e550b440af431Martin Hibdon account.getId(), true).toString())); 36198209d6c081243d58cf9957c1900e550b440af431Martin Hibdon } 3620e0015b2800eeefbf8aaf322645038907f37e62f1Vikram Aggarwal if (projectionColumns.contains( 3621803631497c493dffbb65897d974c170008f1d096Andrew Sapperstein UIProvider.AccountColumns.SettingsColumns.IMPORTANCE_MARKERS_ENABLED)) { 3622803631497c493dffbb65897d974c170008f1d096Andrew Sapperstein // Email doesn't support priority inbox, so always state importance markers disabled. 3623803631497c493dffbb65897d974c170008f1d096Andrew Sapperstein values.put(UIProvider.AccountColumns.SettingsColumns.IMPORTANCE_MARKERS_ENABLED, "0"); 3624803631497c493dffbb65897d974c170008f1d096Andrew Sapperstein } 3625803631497c493dffbb65897d974c170008f1d096Andrew Sapperstein if (projectionColumns.contains( 3626803631497c493dffbb65897d974c170008f1d096Andrew Sapperstein UIProvider.AccountColumns.SettingsColumns.SHOW_CHEVRONS_ENABLED)) { 3627803631497c493dffbb65897d974c170008f1d096Andrew Sapperstein // Email doesn't support priority inbox, so always state show chevrons disabled. 3628803631497c493dffbb65897d974c170008f1d096Andrew Sapperstein values.put(UIProvider.AccountColumns.SettingsColumns.SHOW_CHEVRONS_ENABLED, "0"); 3629e0015b2800eeefbf8aaf322645038907f37e62f1Vikram Aggarwal } 363026164054710375519ba7468987971a7a3340ba7eMarc Blank if (projectionColumns.contains( 363126164054710375519ba7468987971a7a3340ba7eMarc Blank UIProvider.AccountColumns.SettingsColumns.SETUP_INTENT_URI)) { 363281b0f74efa39d80b0aa18686c96499faf0e2691fMarc Blank // Set the setup intent if needed 363381b0f74efa39d80b0aa18686c96499faf0e2691fMarc Blank // TODO We should clarify/document the trash/setup relationship 363426164054710375519ba7468987971a7a3340ba7eMarc Blank long trashId = Mailbox.findMailboxOfType(context, accountId, Mailbox.TYPE_TRASH); 363526164054710375519ba7468987971a7a3340ba7eMarc Blank if (trashId == Mailbox.NO_MAILBOX) { 36369e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu info = EmailServiceUtils.getServiceInfoForAccount(context, accountId); 363781b0f74efa39d80b0aa18686c96499faf0e2691fMarc Blank if (info != null && info.requiresSetup) { 3638fdb1635868e9591c3bcaf107360a7eae2e09fe18Marc Blank values.put(UIProvider.AccountColumns.SettingsColumns.SETUP_INTENT_URI, 3639fdb1635868e9591c3bcaf107360a7eae2e09fe18Marc Blank getExternalUriString("setup", id)); 3640fdb1635868e9591c3bcaf107360a7eae2e09fe18Marc Blank } 364126164054710375519ba7468987971a7a3340ba7eMarc Blank } 364226164054710375519ba7468987971a7a3340ba7eMarc Blank } 3643e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy if (projectionColumns.contains(UIProvider.AccountColumns.TYPE)) { 3644e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy final String type; 36459e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu if (info == null) { 36469e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu info = EmailServiceUtils.getServiceInfoForAccount(context, accountId); 36479e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu } 36489e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu if (info != null) { 36499e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu type = info.accountType; 3650e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy } else { 3651e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy type = "unknown"; 3652e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy } 3653e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy 3654e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy values.put(UIProvider.AccountColumns.TYPE, type); 3655e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy } 36561079b6e9628910e726881233f62808976d5d3be1Scott Kennedy if (projectionColumns.contains(UIProvider.AccountColumns.SettingsColumns.MOVE_TO_INBOX) && 36571079b6e9628910e726881233f62808976d5d3be1Scott Kennedy inboxMailboxId != Mailbox.NO_MAILBOX) { 36581079b6e9628910e726881233f62808976d5d3be1Scott Kennedy values.put(UIProvider.AccountColumns.SettingsColumns.MOVE_TO_INBOX, 36591079b6e9628910e726881233f62808976d5d3be1Scott Kennedy uiUriString("uifolder", inboxMailboxId)); 36601079b6e9628910e726881233f62808976d5d3be1Scott Kennedy } 3661f1284d4d550230a4e13247a9513f03a7f3fd2347Alice Yang if (projectionColumns.contains(UIProvider.AccountColumns.SYNC_AUTHORITY)) { 3662f1284d4d550230a4e13247a9513f03a7f3fd2347Alice Yang values.put(UIProvider.AccountColumns.SYNC_AUTHORITY, EmailContent.AUTHORITY); 3663f1284d4d550230a4e13247a9513f03a7f3fd2347Alice Yang } 3664c6953b77552d4cb71776cf0537dc226029381628Tony Mantler if (projectionColumns.contains(UIProvider.AccountColumns.QUICK_RESPONSE_URI)) { 3665c6953b77552d4cb71776cf0537dc226029381628Tony Mantler values.put(UIProvider.AccountColumns.QUICK_RESPONSE_URI, 3666c6953b77552d4cb71776cf0537dc226029381628Tony Mantler combinedUriString("quickresponse/account", id)); 3667c6953b77552d4cb71776cf0537dc226029381628Tony Mantler } 3668876c8e1408c119f6dd771fdf13a9b95ea62f704aTony Mantler if (projectionColumns.contains(UIProvider.AccountColumns.SETTINGS_FRAGMENT_CLASS)) { 3669876c8e1408c119f6dd771fdf13a9b95ea62f704aTony Mantler values.put(UIProvider.AccountColumns.SETTINGS_FRAGMENT_CLASS, 3670bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook PREFERENCE_FRAGMENT_CLASS_NAME); 3671876c8e1408c119f6dd771fdf13a9b95ea62f704aTony Mantler } 3672b424ffa65b809094e6b9109e2131b718ec9eae76Tony Mantler if (projectionColumns.contains(UIProvider.AccountColumns.SettingsColumns.REPLY_BEHAVIOR)) { 3673b424ffa65b809094e6b9109e2131b718ec9eae76Tony Mantler values.put(UIProvider.AccountColumns.SettingsColumns.REPLY_BEHAVIOR, 3674b424ffa65b809094e6b9109e2131b718ec9eae76Tony Mantler mailPrefs.getDefaultReplyAll() 3675b424ffa65b809094e6b9109e2131b718ec9eae76Tony Mantler ? UIProvider.DefaultReplyBehavior.REPLY_ALL 3676b424ffa65b809094e6b9109e2131b718ec9eae76Tony Mantler : UIProvider.DefaultReplyBehavior.REPLY); 3677b424ffa65b809094e6b9109e2131b718ec9eae76Tony Mantler } 367865b3850706c0fb5c7d575584186a1f3051ba82f1Tony Mantler if (projectionColumns.contains(UIProvider.AccountColumns.SettingsColumns.SHOW_IMAGES)) { 367965b3850706c0fb5c7d575584186a1f3051ba82f1Tony Mantler values.put(UIProvider.AccountColumns.SettingsColumns.SHOW_IMAGES, 368065b3850706c0fb5c7d575584186a1f3051ba82f1Tony Mantler Settings.ShowImages.ASK_FIRST); 368165b3850706c0fb5c7d575584186a1f3051ba82f1Tony Mantler } 3682e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy 36835a3d863a43405132d562650603adc0a7bfb87fbcPaul Westbrook final StringBuilder sb = genSelect(getAccountListMap(getContext()), uiProjection, values); 36843dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler sb.append(" FROM " + Account.TABLE_NAME + " WHERE " + AccountColumns._ID + "=?"); 3685f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return sb.toString(); 3686f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3687f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3688f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3689f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate a Uri string for a combined mailbox uri 3690f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param type the uri command type (e.g. "uimessages") 3691f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param id the id of the item (e.g. an account, mailbox, or message id) 3692f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return a Uri string 3693f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3694f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static String combinedUriString(String type, String id) { 3695f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return "content://" + EmailContent.AUTHORITY + "/" + type + "/" + id; 3696f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3697f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 36983a82ad59928864931b826c46413831d7431057f9Mark Wei public static final long COMBINED_ACCOUNT_ID = 0x10000000; 3699f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3700f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 3701f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate an id for a combined mailbox of a given type 3702f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param type the mailbox type for the combined mailbox 3703f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the id, as a String 3704f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 3705f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static String combinedMailboxId(int type) { 3706f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return Long.toString(Account.ACCOUNT_ID_COMBINED_VIEW + type); 3707f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3708f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 37093a82ad59928864931b826c46413831d7431057f9Mark Wei public static long getVirtualMailboxId(long accountId, int type) { 3710f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return (accountId << 32) + type; 3711f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3712f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3713f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static boolean isVirtualMailbox(long mailboxId) { 3714f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return mailboxId >= 0x100000000L; 3715f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3716f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3717f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static boolean isCombinedMailbox(long mailboxId) { 3718f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return (mailboxId >> 32) == COMBINED_ACCOUNT_ID; 3719f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3720f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3721f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static long getVirtualMailboxAccountId(long mailboxId) { 3722f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return mailboxId >> 32; 3723f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3724f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3725f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static String getVirtualMailboxAccountIdString(long mailboxId) { 3726f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return Long.toString(mailboxId >> 32); 3727f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3728f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3729f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static int getVirtualMailboxType(long mailboxId) { 3730f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return (int)(mailboxId & 0xF); 3731f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3732f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3733f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private void addCombinedAccountRow(MatrixCursor mc) { 3734229c070b0b177793032ce9249cb77f6ca98e5aa4Scott Kennedy final long lastUsedAccountId = 3735229c070b0b177793032ce9249cb77f6ca98e5aa4Scott Kennedy Preferences.getPreferences(getContext()).getLastUsedAccountId(); 3736229c070b0b177793032ce9249cb77f6ca98e5aa4Scott Kennedy final long id = Account.getDefaultAccountId(getContext(), lastUsedAccountId); 3737f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (id == Account.NO_ACCOUNT) return; 3738b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook 3739b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook // Build a map of the requested columns to the appropriate positions 3740b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook final ImmutableMap.Builder<String, Integer> builder = 3741b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook new ImmutableMap.Builder<String, Integer>(); 3742b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook final String[] columnNames = mc.getColumnNames(); 3743b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook for (int i = 0; i < columnNames.length; i++) { 3744b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook builder.put(columnNames[i], i); 3745b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3746b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook final Map<String, Integer> colPosMap = builder.build(); 3747b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook 3748bed61a78a08f0a82c2aae12787ad64b4cd566c08Scott Kennedy final MailPrefs mailPrefs = MailPrefs.get(getContext()); 3749b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook final Object[] values = new Object[columnNames.length]; 3750b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(BaseColumns._ID)) { 3751b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(BaseColumns._ID)] = 0; 3752b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3753b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.CAPABILITIES)) { 3754b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.CAPABILITIES)] = 3755aa2ca51477039788c4e69db3579a51baffbb9079James Lemieux AccountCapabilities.UNDO | 3756aa2ca51477039788c4e69db3579a51baffbb9079James Lemieux AccountCapabilities.VIRTUAL_ACCOUNT | 3757aa2ca51477039788c4e69db3579a51baffbb9079James Lemieux AccountCapabilities.CLIENT_SANITIZED_HTML; 3758b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3759b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.FOLDER_LIST_URI)) { 3760b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.FOLDER_LIST_URI)] = 3761b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook combinedUriString("uifolders", COMBINED_ACCOUNT_ID_STRING); 3762b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3763b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.NAME)) { 3764b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.NAME)] = getContext().getString( 37657349fbff64328100cb5bd878f4d400ccc611ec80Tony Mantler R.string.mailbox_list_account_selector_combined_view); 37667349fbff64328100cb5bd878f4d400ccc611ec80Tony Mantler } 37677349fbff64328100cb5bd878f4d400ccc611ec80Tony Mantler if (colPosMap.containsKey(UIProvider.AccountColumns.ACCOUNT_MANAGER_NAME)) { 37687349fbff64328100cb5bd878f4d400ccc611ec80Tony Mantler values[colPosMap.get(UIProvider.AccountColumns.ACCOUNT_MANAGER_NAME)] = 37697349fbff64328100cb5bd878f4d400ccc611ec80Tony Mantler getContext().getString(R.string.mailbox_list_account_selector_combined_view); 3770b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3771045aa05777a097717c1a915e66eb9ab671e02d56Ray Chen if (colPosMap.containsKey(UIProvider.AccountColumns.ACCOUNT_ID)) { 3772045aa05777a097717c1a915e66eb9ab671e02d56Ray Chen values[colPosMap.get(UIProvider.AccountColumns.ACCOUNT_ID)] = "Account Id"; 3773045aa05777a097717c1a915e66eb9ab671e02d56Ray Chen } 3774e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy if (colPosMap.containsKey(UIProvider.AccountColumns.TYPE)) { 3775e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy values[colPosMap.get(UIProvider.AccountColumns.TYPE)] = "unknown"; 3776e0d4cab353b84fd632d5609d4780f597c8d56092Scott Kennedy } 3777b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.UNDO_URI)) { 3778b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.UNDO_URI)] = 3779d0e7d88f43bcd7d612a880f3525ef40dbe8f461aYu Ping Hu "'content://" + EmailContent.AUTHORITY + "/uiundo'"; 3780b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3781b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.URI)) { 3782b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.URI)] = 3783b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook combinedUriString("uiaccount", COMBINED_ACCOUNT_ID_STRING); 3784b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3785b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.MIME_TYPE)) { 3786b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.MIME_TYPE)] = 3787b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook EMAIL_APP_MIME_TYPE; 3788b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 37898209d6c081243d58cf9957c1900e550b440af431Martin Hibdon if (colPosMap.containsKey(UIProvider.AccountColumns.SECURITY_HOLD)) { 37908209d6c081243d58cf9957c1900e550b440af431Martin Hibdon values[colPosMap.get(UIProvider.AccountColumns.SECURITY_HOLD)] = 0; 37918209d6c081243d58cf9957c1900e550b440af431Martin Hibdon } 37928209d6c081243d58cf9957c1900e550b440af431Martin Hibdon if (colPosMap.containsKey(UIProvider.AccountColumns.ACCOUNT_SECURITY_URI)) { 37938209d6c081243d58cf9957c1900e550b440af431Martin Hibdon values[colPosMap.get(UIProvider.AccountColumns.ACCOUNT_SECURITY_URI)] = ""; 37948209d6c081243d58cf9957c1900e550b440af431Martin Hibdon } 3795b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.SETTINGS_INTENT_URI)) { 3796b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.SETTINGS_INTENT_URI)] = 3797b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook getExternalUriString("settings", COMBINED_ACCOUNT_ID_STRING); 3798b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3799b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.COMPOSE_URI)) { 3800b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.COMPOSE_URI)] = 3801b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook getExternalUriStringEmail2("compose", Long.toString(id)); 3802b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3803b7e0834121d564982c0389c87df775ba311429d4Tony Mantler if (colPosMap.containsKey(UIProvider.AccountColumns.UPDATE_SETTINGS_URI)) { 3804b7e0834121d564982c0389c87df775ba311429d4Tony Mantler values[colPosMap.get(UIProvider.AccountColumns.UPDATE_SETTINGS_URI)] = 3805b7e0834121d564982c0389c87df775ba311429d4Tony Mantler uiUriString("uiacctsettings", -1); 3806b7e0834121d564982c0389c87df775ba311429d4Tony Mantler } 3807f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3808b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.SettingsColumns.AUTO_ADVANCE)) { 3809b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.SettingsColumns.AUTO_ADVANCE)] = 3810988ad6e002810d5da713f0cda20aecf00cccb9caTony Mantler Integer.toString(mailPrefs.getAutoAdvanceMode()); 3811b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3812b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.SettingsColumns.SNAP_HEADERS)) { 3813b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.SettingsColumns.SNAP_HEADERS)] = 3814b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook Integer.toString(UIProvider.SnapHeaderValue.ALWAYS); 3815b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3816f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank //.add(UIProvider.SettingsColumns.SIGNATURE, AccountColumns.SIGNATURE) 3817b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.SettingsColumns.REPLY_BEHAVIOR)) { 3818b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.SettingsColumns.REPLY_BEHAVIOR)] = 3819bed61a78a08f0a82c2aae12787ad64b4cd566c08Scott Kennedy Integer.toString(mailPrefs.getDefaultReplyAll() 3820bed61a78a08f0a82c2aae12787ad64b4cd566c08Scott Kennedy ? UIProvider.DefaultReplyBehavior.REPLY_ALL 3821bed61a78a08f0a82c2aae12787ad64b4cd566c08Scott Kennedy : UIProvider.DefaultReplyBehavior.REPLY); 3822b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 38239f1cff0659e4b9a179690d9c31f7a9bf56aad228Alice Yang if (colPosMap.containsKey(UIProvider.AccountColumns.SettingsColumns.CONV_LIST_ICON)) { 38249f1cff0659e4b9a179690d9c31f7a9bf56aad228Alice Yang values[colPosMap.get(UIProvider.AccountColumns.SettingsColumns.CONV_LIST_ICON)] = 3825ccf730fbe53c3bffb0154d0666e9fcbb5e82f551Paul Westbrook getConversationListIcon(mailPrefs); 3826b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3827b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.SettingsColumns.CONFIRM_DELETE)) { 3828b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.SettingsColumns.CONFIRM_DELETE)] = 3829988ad6e002810d5da713f0cda20aecf00cccb9caTony Mantler mailPrefs.getConfirmDelete() ? 1 : 0; 3830b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3831b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.SettingsColumns.CONFIRM_ARCHIVE)) { 3832b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get( 3833b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook UIProvider.AccountColumns.SettingsColumns.CONFIRM_ARCHIVE)] = 0; 3834b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3835b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.SettingsColumns.CONFIRM_SEND)) { 3836b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.SettingsColumns.CONFIRM_SEND)] = 3837988ad6e002810d5da713f0cda20aecf00cccb9caTony Mantler mailPrefs.getConfirmSend() ? 1 : 0; 3838b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 3839b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook if (colPosMap.containsKey(UIProvider.AccountColumns.SettingsColumns.DEFAULT_INBOX)) { 3840b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook values[colPosMap.get(UIProvider.AccountColumns.SettingsColumns.DEFAULT_INBOX)] = 3841b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook combinedUriString("uifolder", combinedMailboxId(Mailbox.TYPE_INBOX)); 3842b74f2204672ae01e1b2954f5714031d369c332cbPaul Westbrook } 38431079b6e9628910e726881233f62808976d5d3be1Scott Kennedy if (colPosMap.containsKey(UIProvider.AccountColumns.SettingsColumns.MOVE_TO_INBOX)) { 38441079b6e9628910e726881233f62808976d5d3be1Scott Kennedy values[colPosMap.get(UIProvider.AccountColumns.SettingsColumns.MOVE_TO_INBOX)] = 38451079b6e9628910e726881233f62808976d5d3be1Scott Kennedy combinedUriString("uifolder", combinedMailboxId(Mailbox.TYPE_INBOX)); 38461079b6e9628910e726881233f62808976d5d3be1Scott Kennedy } 384724a489c3de70a02bccbf2cfc54b36a385d72c337Alice Yang if (colPosMap.containsKey(UIProvider.AccountColumns.SettingsColumns.SHOW_IMAGES)) { 384824a489c3de70a02bccbf2cfc54b36a385d72c337Alice Yang values[colPosMap.get(UIProvider.AccountColumns.SettingsColumns.SHOW_IMAGES)] = 384924a489c3de70a02bccbf2cfc54b36a385d72c337Alice Yang Settings.ShowImages.ASK_FIRST; 385024a489c3de70a02bccbf2cfc54b36a385d72c337Alice Yang } 3851f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3852f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mc.addRow(values); 3853f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3854f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 38559e521deb6bb525b33365cc2926cb2d0faa7095e2Scott Kennedy private static int getConversationListIcon(MailPrefs mailPrefs) { 3856ccf730fbe53c3bffb0154d0666e9fcbb5e82f551Paul Westbrook return mailPrefs.getShowSenderImages() ? 3857ccf730fbe53c3bffb0154d0666e9fcbb5e82f551Paul Westbrook UIProvider.ConversationListIcon.SENDER_IMAGE : 3858ccf730fbe53c3bffb0154d0666e9fcbb5e82f551Paul Westbrook UIProvider.ConversationListIcon.NONE; 3859ccf730fbe53c3bffb0154d0666e9fcbb5e82f551Paul Westbrook } 3860ccf730fbe53c3bffb0154d0666e9fcbb5e82f551Paul Westbrook 3861e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler private Cursor getVirtualMailboxCursor(long mailboxId, String[] projection) { 3862e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler MatrixCursor mc = new MatrixCursorWithCachedColumns(projection, 1); 3863f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mc.addRow(getVirtualMailboxRow(getVirtualMailboxAccountId(mailboxId), 3864e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler getVirtualMailboxType(mailboxId), projection)); 3865f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return mc; 3866f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3867f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3868e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler private Object[] getVirtualMailboxRow(long accountId, int mailboxType, String[] projection) { 3869ddca2a0dcbcd27d2d17b5d5273eee2004fbcdf7cScott Kennedy final long id = getVirtualMailboxId(accountId, mailboxType); 3870ddca2a0dcbcd27d2d17b5d5273eee2004fbcdf7cScott Kennedy final String idString = Long.toString(id); 3871e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler Object[] values = new Object[projection.length]; 3872e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler // Not all column values are filled in here, as some are not applicable to virtual mailboxes 3873e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler // The remainder are left null 3874e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler for (int i = 0; i < projection.length; i++) { 3875e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler final String column = projection[i]; 3876e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler if (column.equals(UIProvider.FolderColumns._ID)) { 3877e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler values[i] = id; 3878e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else if (column.equals(UIProvider.FolderColumns.URI)) { 3879e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler values[i] = combinedUriString("uifolder", idString); 3880e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else if (column.equals(UIProvider.FolderColumns.NAME)) { 3881cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein // default empty string since all of these should use resource strings 3882e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler values[i] = getFolderDisplayName(getFolderTypeFromMailboxType(mailboxType), ""); 3883e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else if (column.equals(UIProvider.FolderColumns.HAS_CHILDREN)) { 3884e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler values[i] = 0; 3885e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else if (column.equals(UIProvider.FolderColumns.CAPABILITIES)) { 3886e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler values[i] = UIProvider.FolderCapabilities.DELETE 3887e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler | UIProvider.FolderCapabilities.IS_VIRTUAL; 3888e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else if (column.equals(UIProvider.FolderColumns.CONVERSATION_LIST_URI)) { 3889e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler values[i] = combinedUriString("uimessages", idString); 3890e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else if (column.equals(UIProvider.FolderColumns.UNREAD_COUNT)) { 3891e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler if (mailboxType == Mailbox.TYPE_INBOX && accountId == COMBINED_ACCOUNT_ID) { 3892ddca2a0dcbcd27d2d17b5d5273eee2004fbcdf7cScott Kennedy final int unreadCount = EmailContent.count(getContext(), Message.CONTENT_URI, 38933dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler MessageColumns.MAILBOX_KEY + " IN (SELECT " + MailboxColumns._ID 3894ddca2a0dcbcd27d2d17b5d5273eee2004fbcdf7cScott Kennedy + " FROM " + Mailbox.TABLE_NAME + " WHERE " + MailboxColumns.TYPE 3895ddca2a0dcbcd27d2d17b5d5273eee2004fbcdf7cScott Kennedy + "=" + Mailbox.TYPE_INBOX + ") AND " + MessageColumns.FLAG_READ + "=0", 3896ddca2a0dcbcd27d2d17b5d5273eee2004fbcdf7cScott Kennedy null); 3897e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler values[i] = unreadCount; 3898e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else if (mailboxType == Mailbox.TYPE_UNREAD) { 3899e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler final String accountKeyClause; 3900e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler final String[] whereArgs; 3901e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler if (accountId == COMBINED_ACCOUNT_ID) { 3902e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler accountKeyClause = ""; 3903e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler whereArgs = null; 3904e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else { 3905e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler accountKeyClause = MessageColumns.ACCOUNT_KEY + "= ? AND "; 3906e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler whereArgs = new String[] { Long.toString(accountId) }; 3907e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } 3908e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler final int unreadCount = EmailContent.count(getContext(), Message.CONTENT_URI, 3909e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler accountKeyClause + MessageColumns.FLAG_READ + "=0 AND " 39103dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler + MessageColumns.MAILBOX_KEY + " NOT IN (SELECT " + MailboxColumns._ID 3911e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler + " FROM " + Mailbox.TABLE_NAME + " WHERE " + MailboxColumns.TYPE + "=" 3912e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler + Mailbox.TYPE_TRASH + ")", whereArgs); 3913e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler values[i] = unreadCount; 3914e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else if (mailboxType == Mailbox.TYPE_STARRED) { 3915e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler final String accountKeyClause; 3916e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler final String[] whereArgs; 3917e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler if (accountId == COMBINED_ACCOUNT_ID) { 3918e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler accountKeyClause = ""; 3919e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler whereArgs = null; 3920e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else { 3921e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler accountKeyClause = MessageColumns.ACCOUNT_KEY + "= ? AND "; 3922e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler whereArgs = new String[] { Long.toString(accountId) }; 3923e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } 3924e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler final int starredCount = EmailContent.count(getContext(), Message.CONTENT_URI, 3925e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler accountKeyClause + MessageColumns.FLAG_FAVORITE + "=1", whereArgs); 3926e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler values[i] = starredCount; 3927ddca2a0dcbcd27d2d17b5d5273eee2004fbcdf7cScott Kennedy } 3928e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else if (column.equals(UIProvider.FolderColumns.ICON_RES_ID)) { 3929e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler if (mailboxType == Mailbox.TYPE_INBOX) { 3930ebae672af4a423c57557e317f3befa9d318193e9Tony Mantler values[i] = R.drawable.ic_drawer_inbox_24dp; 3931e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else if (mailboxType == Mailbox.TYPE_UNREAD) { 3932ebae672af4a423c57557e317f3befa9d318193e9Tony Mantler values[i] = R.drawable.ic_drawer_unread_24dp; 3933e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler } else if (mailboxType == Mailbox.TYPE_STARRED) { 3934ebae672af4a423c57557e317f3befa9d318193e9Tony Mantler values[i] = R.drawable.ic_drawer_starred_24dp; 3935ddca2a0dcbcd27d2d17b5d5273eee2004fbcdf7cScott Kennedy } 3936ddca2a0dcbcd27d2d17b5d5273eee2004fbcdf7cScott Kennedy } 3937ddca2a0dcbcd27d2d17b5d5273eee2004fbcdf7cScott Kennedy } 3938f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return values; 3939f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3940f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 39414038f464dee0a33f1e7a58102857c24edf7e0eb2Paul Westbrook private Cursor uiAccounts(String[] uiProjection, boolean suppressCombined) { 39423e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook final Context context = getContext(); 39433e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook final SQLiteDatabase db = getDatabase(context); 39443e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook final Cursor accountIdCursor = 3945f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank db.rawQuery("select _id from " + Account.TABLE_NAME, new String[0]); 39463e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook final MatrixCursor mc; 3947f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank try { 39483e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook boolean combinedAccount = false; 39494038f464dee0a33f1e7a58102857c24edf7e0eb2Paul Westbrook if (!suppressCombined && accountIdCursor.getCount() > 1) { 39503e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook combinedAccount = true; 39513e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook } 39523e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook final Bundle extras = new Bundle(); 39533e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook // Email always returns the accurate number of accounts 39543e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook extras.putInt(AccountCursorExtraKeys.ACCOUNTS_LOADED, 1); 39553e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook mc = new MatrixCursorWithExtra(uiProjection, accountIdCursor.getCount(), extras); 39563e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook final Object[] values = new Object[uiProjection.length]; 3957f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank while (accountIdCursor.moveToNext()) { 39583e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook final String id = accountIdCursor.getString(0); 39593e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook final Cursor accountCursor = 3960f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank db.rawQuery(genQueryAccount(uiProjection, id), new String[] {id}); 39613e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook try { 39623e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook if (accountCursor.moveToNext()) { 39633e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook for (int i = 0; i < uiProjection.length; i++) { 39643e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook values[i] = accountCursor.getString(i); 39653e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook } 39663e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook mc.addRow(values); 3967f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 39683e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook } finally { 39693e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook accountCursor.close(); 3970f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3971f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 39722651bcc7be2c5fbce23faa0b0d12db63caee5a45Marc Blank if (combinedAccount) { 39732651bcc7be2c5fbce23faa0b0d12db63caee5a45Marc Blank addCombinedAccountRow(mc); 39742651bcc7be2c5fbce23faa0b0d12db63caee5a45Marc Blank } 3975f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } finally { 3976f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank accountIdCursor.close(); 3977f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 397897a198292e665fff5d27d727d415f35b0a0633e4Marc Blank mc.setNotificationUri(context.getContentResolver(), UIPROVIDER_ALL_ACCOUNTS_NOTIFIER); 39793e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook 3980f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return mc; 3981f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 3982f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 3983c6953b77552d4cb71776cf0537dc226029381628Tony Mantler private Cursor uiQuickResponseAccount(String[] uiProjection, String account) { 3984c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final Context context = getContext(); 3985c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final SQLiteDatabase db = getDatabase(context); 3986c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final StringBuilder sb = genSelect(getQuickResponseMap(), uiProjection); 3987c6953b77552d4cb71776cf0537dc226029381628Tony Mantler sb.append(" FROM " + QuickResponse.TABLE_NAME); 3988c6953b77552d4cb71776cf0537dc226029381628Tony Mantler sb.append(" WHERE " + QuickResponse.ACCOUNT_KEY + "=?"); 3989c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final String query = sb.toString(); 3990c6953b77552d4cb71776cf0537dc226029381628Tony Mantler return db.rawQuery(query, new String[] {account}); 3991c6953b77552d4cb71776cf0537dc226029381628Tony Mantler } 3992c6953b77552d4cb71776cf0537dc226029381628Tony Mantler 3993c6953b77552d4cb71776cf0537dc226029381628Tony Mantler private Cursor uiQuickResponseId(String[] uiProjection, String id) { 3994c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final Context context = getContext(); 3995c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final SQLiteDatabase db = getDatabase(context); 3996c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final StringBuilder sb = genSelect(getQuickResponseMap(), uiProjection); 3997c6953b77552d4cb71776cf0537dc226029381628Tony Mantler sb.append(" FROM " + QuickResponse.TABLE_NAME); 39983dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler sb.append(" WHERE " + QuickResponse._ID + "=?"); 3999c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final String query = sb.toString(); 4000c6953b77552d4cb71776cf0537dc226029381628Tony Mantler return db.rawQuery(query, new String[] {id}); 4001c6953b77552d4cb71776cf0537dc226029381628Tony Mantler } 4002c6953b77552d4cb71776cf0537dc226029381628Tony Mantler 4003c6953b77552d4cb71776cf0537dc226029381628Tony Mantler private Cursor uiQuickResponse(String[] uiProjection) { 4004c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final Context context = getContext(); 4005c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final SQLiteDatabase db = getDatabase(context); 4006c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final StringBuilder sb = genSelect(getQuickResponseMap(), uiProjection); 4007c6953b77552d4cb71776cf0537dc226029381628Tony Mantler sb.append(" FROM " + QuickResponse.TABLE_NAME); 4008c6953b77552d4cb71776cf0537dc226029381628Tony Mantler final String query = sb.toString(); 4009c6953b77552d4cb71776cf0537dc226029381628Tony Mantler return db.rawQuery(query, new String[0]); 4010c6953b77552d4cb71776cf0537dc226029381628Tony Mantler } 4011c6953b77552d4cb71776cf0537dc226029381628Tony Mantler 4012f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 4013f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate the "attachment list" SQLite query, given a projection from UnifiedEmail 4014f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 4015f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 40166eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein * @param contentTypeQueryParameters list of mimeTypes, used as a filter for the attachments 40176eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein * or null if there are no query parameters 4018f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 4019f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 4020b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static String genQueryAttachments(String[] uiProjection, 40216eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein List<String> contentTypeQueryParameters) { 4022478417a79440904b8a9c45fd3e4ec84db339a755Andrew Sapperstein // MAKE SURE THESE VALUES STAY IN SYNC WITH GEN QUERY ATTACHMENT 4023478417a79440904b8a9c45fd3e4ec84db339a755Andrew Sapperstein ContentValues values = new ContentValues(1); 4024478417a79440904b8a9c45fd3e4ec84db339a755Andrew Sapperstein values.put(UIProvider.AttachmentColumns.SUPPORTS_DOWNLOAD_AGAIN, 1); 4025478417a79440904b8a9c45fd3e4ec84db339a755Andrew Sapperstein StringBuilder sb = genSelect(getAttachmentMap(), uiProjection, values); 4026582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler sb.append(" FROM ") 4027582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(Attachment.TABLE_NAME) 4028582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(" WHERE ") 4029582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(AttachmentColumns.MESSAGE_KEY) 4030582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(" =? "); 40316eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein 40326eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein // Filter for certain content types. 40336eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein // The filter works by adding LIKE operators for each 40346eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein // content type you wish to request. Content types 40356eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein // are filtered by performing a case-insensitive "starts with" 40366eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein // filter. IE, "image/" would return "image/png" as well as "image/jpeg". 40376eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein if (contentTypeQueryParameters != null && !contentTypeQueryParameters.isEmpty()) { 40386eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein final int size = contentTypeQueryParameters.size(); 40396eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein sb.append("AND ("); 40406eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein for (int i = 0; i < size; i++) { 40416eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein final String contentType = contentTypeQueryParameters.get(i); 4042582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler sb.append(AttachmentColumns.MIME_TYPE) 4043582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(" LIKE '") 4044582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(contentType) 4045582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append("%'"); 40466eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein 40476eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein if (i != size - 1) { 40486eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein sb.append(" OR "); 40496eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein } 40506eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein } 40516eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein sb.append(")"); 40526eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein } 4053f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return sb.toString(); 4054f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4055f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4056f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 4057f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate the "single attachment" SQLite query, given a projection from UnifiedEmail 4058f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 4059f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 4060f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 4061f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 40628cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private String genQueryAttachment(String[] uiProjection) { 4063478417a79440904b8a9c45fd3e4ec84db339a755Andrew Sapperstein // MAKE SURE THESE VALUES STAY IN SYNC WITH GEN QUERY ATTACHMENTS 40648cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux final ContentValues values = new ContentValues(2); 40658cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux values.put(AttachmentColumns.CONTENT_URI, createAttachmentUriColumnSQL()); 4066478417a79440904b8a9c45fd3e4ec84db339a755Andrew Sapperstein values.put(UIProvider.AttachmentColumns.SUPPORTS_DOWNLOAD_AGAIN, 1); 40678cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux 40688cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux return genSelect(getAttachmentMap(), uiProjection, values) 40698cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux .append(" FROM ").append(Attachment.TABLE_NAME) 4070582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(" WHERE ") 40718cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux .append(AttachmentColumns._ID).append(" =? ") 40728cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux .toString(); 40738cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux } 40748cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux 40758cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux /** 40768cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux * Generate the "single attachment by Content ID" SQLite query, given a projection from 40778cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux * UnifiedEmail 40788cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux * 40798cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux * @param uiProjection as passed from UnifiedEmail 40808cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux * @return the SQLite query to be executed on the EmailProvider database 40818cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux */ 40828cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private String genQueryAttachmentByMessageIDAndCid(String[] uiProjection) { 40838cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux final ContentValues values = new ContentValues(2); 40848cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux values.put(AttachmentColumns.CONTENT_URI, createAttachmentUriColumnSQL()); 40858cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux values.put(UIProvider.AttachmentColumns.SUPPORTS_DOWNLOAD_AGAIN, 1); 40868cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux 40878cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux return genSelect(getAttachmentMap(), uiProjection, values) 40888cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux .append(" FROM ").append(Attachment.TABLE_NAME) 40898cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux .append(" WHERE ") 40908cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux .append(AttachmentColumns.MESSAGE_KEY).append(" =? ") 40918cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux .append(" AND ") 40928cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux .append(AttachmentColumns.CONTENT_ID).append(" =? ") 40938cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux .toString(); 40948cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux } 40958cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux 40968cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux /** 40978cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux * @return a fragment of SQL that is the expression which, when evaluated for a particular 40988cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux * Attachment row, produces the Content URI for the attachment 40998cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux */ 41008cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux private static String createAttachmentUriColumnSQL() { 41018cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux final String uriPrefix = Attachment.ATTACHMENT_PROVIDER_URI_PREFIX; 41028cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux final String accountKey = AttachmentColumns.ACCOUNT_KEY; 41038cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux final String id = AttachmentColumns._ID; 41048cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux final String raw = AttachmentUtilities.FORMAT_RAW; 41058cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux final String contentUri = String.format("%s/' || %s || '/' || %s || '/%s", uriPrefix, 41068cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux accountKey, id, raw); 41078cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux 41088cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux return "@CASE " + 41098cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux "WHEN contentUri IS NULL THEN '" + contentUri + "' " + 41108cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux "WHEN contentUri IS NOT NULL THEN contentUri " + 41118cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux "END"; 4112f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4113f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4114f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 4115f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Generate the "subfolder list" SQLite query, given a projection from UnifiedEmail 4116f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 4117f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection as passed from UnifiedEmail 4118f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the SQLite query to be executed on the EmailProvider database 4119f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 4120b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static String genQuerySubfolders(String[] uiProjection) { 4121e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank StringBuilder sb = genSelect(getFolderListMap(), uiProjection); 4122f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank sb.append(" FROM " + Mailbox.TABLE_NAME + " WHERE " + MailboxColumns.PARENT_KEY + 4123f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank " =? ORDER BY "); 4124f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank sb.append(MAILBOX_ORDER_BY); 4125f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return sb.toString(); 4126f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4127f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4128f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String COMBINED_ACCOUNT_ID_STRING = Long.toString(COMBINED_ACCOUNT_ID); 4129f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4130f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 4131f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Returns a cursor over all the folders for a specific URI which corresponds to a single 4132f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * account. 4133582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler * @param uri uri to query 4134582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler * @param uiProjection projection 4135582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler * @return query result cursor 4136f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 413796192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler private Cursor uiFolders(final Uri uri, final String[] uiProjection) { 413896192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler final Context context = getContext(); 413996192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler final SQLiteDatabase db = getDatabase(context); 414096192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler final String id = uri.getPathSegments().get(1); 414196192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler 414296192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler final Uri notifyUri = 414396192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler UIPROVIDER_FOLDERLIST_NOTIFIER.buildUpon().appendEncodedPath(id).build(); 414496192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler 414596192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler final Cursor vc = uiVirtualMailboxes(id, uiProjection); 414696192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler vc.setNotificationUri(context.getContentResolver(), notifyUri); 4147f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (id.equals(COMBINED_ACCOUNT_ID_STRING)) { 414896192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler return vc; 4149f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 41501004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu Cursor c = db.rawQuery(genQueryAccountMailboxes(UIProvider.FOLDERS_PROJECTION), 41511004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu new String[] {id}); 41521004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu c = getFolderListCursor(c, Long.valueOf(id), uiProjection); 4153c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu c.setNotificationUri(context.getContentResolver(), notifyUri); 41540d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler if (c.getCount() > 0) { 41550d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler Cursor[] cursors = new Cursor[]{vc, c}; 41560d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler return new MergeCursor(cursors); 41570d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler } else { 41580d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler return c; 41590d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler } 4160f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4161f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4162f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 416396192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler private Cursor uiVirtualMailboxes(final String id, final String[] uiProjection) { 416496192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler final MatrixCursor mc = new MatrixCursorWithCachedColumns(uiProjection); 416596192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler 416696192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler if (id.equals(COMBINED_ACCOUNT_ID_STRING)) { 4167e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler mc.addRow(getVirtualMailboxRow(COMBINED_ACCOUNT_ID, Mailbox.TYPE_INBOX, uiProjection)); 4168e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler mc.addRow( 4169e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler getVirtualMailboxRow(COMBINED_ACCOUNT_ID, Mailbox.TYPE_STARRED, uiProjection)); 4170e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler mc.addRow(getVirtualMailboxRow(COMBINED_ACCOUNT_ID, Mailbox.TYPE_UNREAD, uiProjection)); 417196192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler } else { 417296192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler final long acctId = Long.parseLong(id); 4173e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler mc.addRow(getVirtualMailboxRow(acctId, Mailbox.TYPE_STARRED, uiProjection)); 4174e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler mc.addRow(getVirtualMailboxRow(acctId, Mailbox.TYPE_UNREAD, uiProjection)); 417596192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler } 417696192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler 417796192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler return mc; 417896192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler } 417996192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler 4180f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 4181f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Returns an array of the default recent folders for a given URI which is unique for an 4182f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * account. Some accounts might not have default recent folders, in which case an empty array 4183f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * is returned. 4184582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler * @param id account id 4185582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler * @return array of URIs 4186f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 4187f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private Uri[] defaultRecentFolders(final String id) { 41884524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee Uri[] recentFolders = new Uri[0]; 4189f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final SQLiteDatabase db = getDatabase(getContext()); 4190f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (id.equals(COMBINED_ACCOUNT_ID_STRING)) { 4191f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // We don't have default recents for the combined view. 41924524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee return recentFolders; 4193f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4194f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // We search for the types we want, and find corresponding IDs. 4195f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final String[] idAndType = { BaseColumns._ID, UIProvider.FolderColumns.TYPE }; 4196f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4197f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Sent, Drafts, and Starred are the default recents. 4198e714bb9d153cfe13a7f0932e7d67ea08fa5a1d98Marc Blank final StringBuilder sb = genSelect(getFolderListMap(), idAndType); 4199582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler sb.append(" FROM ") 4200582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(Mailbox.TABLE_NAME) 4201582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(" WHERE ") 4202582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(MailboxColumns.ACCOUNT_KEY) 4203582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(" = ") 4204582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(id) 4205582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(" AND ") 4206582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(MailboxColumns.TYPE) 4207582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(" IN (") 4208582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(Mailbox.TYPE_SENT) 4209582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(", ") 4210582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(Mailbox.TYPE_DRAFTS) 4211582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(", ") 4212582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(Mailbox.TYPE_STARRED) 4213582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler .append(")"); 4214f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank LogUtils.d(TAG, "defaultRecentFolders: Query is %s", sb); 4215f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final Cursor c = db.rawQuery(sb.toString(), null); 42164524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee try { 42174524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee if (c == null || c.getCount() <= 0 || !c.moveToFirst()) { 42184524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee return recentFolders; 42194524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee } 42204524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee // Read all the IDs of the mailboxes, and turn them into URIs. 42214524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee recentFolders = new Uri[c.getCount()]; 42224524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee int i = 0; 42234524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee do { 42244524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee final long folderId = c.getLong(0); 42254524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee recentFolders[i] = uiUri("uifolder", folderId); 42264524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee LogUtils.d(TAG, "Default recent folder: %d, with uri %s", folderId, 42274524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee recentFolders[i]); 42284524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee ++i; 42294524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee } while (c.moveToNext()); 42304524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee } finally { 42314524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee if (c != null) { 42324524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee c.close(); 42334524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee } 42344524dccde80bdecb31b3e2cc05638fb8bee4e2cbAnthony Lee } 4235f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return recentFolders; 4236f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4237f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4238f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 4239f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein * Convenience method to create a {@link Folder} 4240582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler * @param context to get a {@link ContentResolver} 4241f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein * @param mailboxId id of the {@link Mailbox} that we want 4242f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein * @return the {@link Folder} or null 4243f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein */ 4244f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein public static Folder getFolder(Context context, long mailboxId) { 4245f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein final ContentResolver resolver = context.getContentResolver(); 4246f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein final Cursor fc = resolver.query(EmailProvider.uiUri("uifolder", mailboxId), 4247f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein UIProvider.FOLDERS_PROJECTION, null, null, null); 4248f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein 4249f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein if (fc == null) { 4250f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein LogUtils.e(TAG, "Null folder cursor for mailboxId %d", mailboxId); 4251f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein return null; 4252f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein } 4253f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein 4254f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein Folder uiFolder = null; 4255f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein try { 4256f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein if (fc.moveToFirst()) { 4257f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein uiFolder = new Folder(fc); 4258f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein } 4259f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein } finally { 4260f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein fc.close(); 4261f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein } 4262f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein return uiFolder; 4263f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein } 4264f3618c23208c7db065847aa3d529b5aad87062c0Andrew Sapperstein 4265114e314968f507b4237e693d279befe261b00f02Marc Blank static class AttachmentsCursor extends CursorWrapper { 4266114e314968f507b4237e693d279befe261b00f02Marc Blank private final int mContentUriIndex; 4267114e314968f507b4237e693d279befe261b00f02Marc Blank private final int mUriIndex; 4268114e314968f507b4237e693d279befe261b00f02Marc Blank private final Context mContext; 4269e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler private final String[] mContentUriStrings; 4270114e314968f507b4237e693d279befe261b00f02Marc Blank 4271114e314968f507b4237e693d279befe261b00f02Marc Blank public AttachmentsCursor(Context context, Cursor cursor) { 4272114e314968f507b4237e693d279befe261b00f02Marc Blank super(cursor); 4273114e314968f507b4237e693d279befe261b00f02Marc Blank mContentUriIndex = cursor.getColumnIndex(UIProvider.AttachmentColumns.CONTENT_URI); 4274114e314968f507b4237e693d279befe261b00f02Marc Blank mUriIndex = cursor.getColumnIndex(UIProvider.AttachmentColumns.URI); 4275114e314968f507b4237e693d279befe261b00f02Marc Blank mContext = context; 4276e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler mContentUriStrings = new String[cursor.getCount()]; 4277e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler if (mContentUriIndex == -1) { 4278e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler // Nothing to do here, move along 4279e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler return; 4280e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler } 4281e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler while (cursor.moveToNext()) { 4282e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler final int index = cursor.getPosition(); 428311472650d1fce7548939d311c4434128930c18baPaul Westbrook final Uri uri = Uri.parse(getString(mUriIndex)); 428411472650d1fce7548939d311c4434128930c18baPaul Westbrook final long id = Long.parseLong(uri.getLastPathSegment()); 428511472650d1fce7548939d311c4434128930c18baPaul Westbrook final Attachment att = Attachment.restoreAttachmentWithId(mContext, id); 4286e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler 4287e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler if (att == null) { 4288e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler mContentUriStrings[index] = ""; 4289e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler continue; 4290e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler } 4291e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler 4292f484751e060620ddf4e2dfe38f2b9f46f472ac9dMartin Hibdon if (!TextUtils.isEmpty(att.getCachedFileUri())) { 4293e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler mContentUriStrings[index] = att.getCachedFileUri(); 4294e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler continue; 4295f484751e060620ddf4e2dfe38f2b9f46f472ac9dMartin Hibdon } 429611472650d1fce7548939d311c4434128930c18baPaul Westbrook 429711472650d1fce7548939d311c4434128930c18baPaul Westbrook final String contentUri; 429811472650d1fce7548939d311c4434128930c18baPaul Westbrook // Until the package installer can handle opening apks from a content:// uri, for 429911472650d1fce7548939d311c4434128930c18baPaul Westbrook // any apk that was successfully saved in external storage, return the 430011472650d1fce7548939d311c4434128930c18baPaul Westbrook // content uri from the attachment 430111472650d1fce7548939d311c4434128930c18baPaul Westbrook if (att.mUiDestination == UIProvider.AttachmentDestination.EXTERNAL && 430211472650d1fce7548939d311c4434128930c18baPaul Westbrook att.mUiState == UIProvider.AttachmentState.SAVED && 430311472650d1fce7548939d311c4434128930c18baPaul Westbrook TextUtils.equals(att.mMimeType, MimeType.ANDROID_ARCHIVE)) { 430411472650d1fce7548939d311c4434128930c18baPaul Westbrook contentUri = att.getContentUri(); 430511472650d1fce7548939d311c4434128930c18baPaul Westbrook } else { 43062aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler final String attUriString = att.getContentUri(); 43072aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler final String authority; 43082aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler if (!TextUtils.isEmpty(attUriString)) { 43092aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler authority = Uri.parse(attUriString).getAuthority(); 43102aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler } else { 43112aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler authority = null; 43122aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler } 43132aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler if (TextUtils.equals(authority, Attachment.ATTACHMENT_PROVIDER_AUTHORITY)) { 43142aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler contentUri = attUriString; 43152aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler } else { 43162aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler contentUri = AttachmentUtilities.getAttachmentUri(att.mAccountKey, id) 43172aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler .toString(); 43182aeb498d4e9b14e7365abb72dc76317d5a961a42Tony Mantler } 431911472650d1fce7548939d311c4434128930c18baPaul Westbrook } 4320e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler mContentUriStrings[index] = contentUri; 4321f484751e060620ddf4e2dfe38f2b9f46f472ac9dMartin Hibdon 4322e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler } 4323e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler cursor.moveToPosition(-1); 4324e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler } 4325e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler 4326e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler @Override 4327e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler public String getString(int column) { 4328e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler if (column == mContentUriIndex) { 4329e292027fa7ec3f7d12aa7228d2c62b7c863581beTony Mantler return mContentUriStrings[getPosition()]; 4330114e314968f507b4237e693d279befe261b00f02Marc Blank } else { 4331114e314968f507b4237e693d279befe261b00f02Marc Blank return super.getString(column); 4332114e314968f507b4237e693d279befe261b00f02Marc Blank } 4333114e314968f507b4237e693d279befe261b00f02Marc Blank } 4334114e314968f507b4237e693d279befe261b00f02Marc Blank } 4335114e314968f507b4237e693d279befe261b00f02Marc Blank 4336f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 4337a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank * For debugging purposes; shouldn't be used in production code 4338a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank */ 4339582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler @SuppressWarnings("unused") 4340a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank static class CloseDetectingCursor extends CursorWrapper { 4341a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank 4342a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank public CloseDetectingCursor(Cursor cursor) { 4343a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank super(cursor); 4344a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank } 4345a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank 4346eaf7e3bce7a7f8f31c5677db188dec74072a43caMarc Blank @Override 4347a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank public void close() { 4348a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank super.close(); 4349560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.d(TAG, "Closing cursor", new Error()); 4350a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank } 4351a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank } 4352a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank 4353a6885ba97d9d45d3496c67b8142418cbdefee89bMarc Blank /** 4354cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * Converts a mailbox in a row of the mailboxCursor into a row 4355cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * in the supplied {@link MatrixCursor} in the format required for {@link Folder}. 4356cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * As a convenience, the modified {@link MatrixCursor} is also returned. 4357cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * @param mc the {@link MatrixCursor} into which the mailbox data will be converted 4358cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * @param projectionLength the length of the projection for this Cursor 4359cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * @param mailboxCursor the cursor supplying the mailbox data 4360cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * @param nameColumn column in the cursor containing the folder name value 4361cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * @param typeColumn column in the cursor containing the folder type value 4362cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * @return the {@link MatrixCursor} containing the transformed data. 4363cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein */ 4364cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein private Cursor getUiFolderCursorRowFromMailboxCursorRow( 4365cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein MatrixCursor mc, int projectionLength, Cursor mailboxCursor, 4366cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein int nameColumn, int typeColumn) { 4367cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein final MatrixCursor.RowBuilder builder = mc.newRow(); 4368cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein for (int i = 0; i < projectionLength; i++) { 4369cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein // If we are at the name column, get the type 4370cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein // and use it to use a properly translated string 4371cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein // from resources instead of the display name. 4372cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein // This ignores display names for system mailboxes. 4373cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein if (nameColumn == i) { 4374cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein // We implicitly assume that if name is requested, 4375cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein // type has also been requested. If not, this will 4376cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein // error in unknown ways. 4377cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein final int type = mailboxCursor.getInt(typeColumn); 4378cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein builder.add(getFolderDisplayName(type, mailboxCursor.getString(i))); 4379cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein } else { 4380cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein builder.add(mailboxCursor.getString(i)); 4381cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein } 4382cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein } 4383cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return mc; 4384cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein } 4385cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein 4386cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein /** 43871004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * Takes a uifolder cursor (that was generated with a full projection) and remaps values for 43881004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * columns that are difficult to generate in the SQL query. This currently includes: 43891004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * - Folder name (due to system folder localization). 43901004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * - Capabilities (due to this varying by account protocol). 43911004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * - Persistent id (due to needing to base64 encode it). 43921004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * - Load more uri (due to this varying by account protocol). 43931004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * TODO: This would be better as a CursorWrapper, rather than doing a copy. 43941004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * @param inputCursor A cursor containing all columns of {@link UIProvider.FolderColumns}. 43951004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * Strictly speaking doesn't need all, but simpler if we assume that. 43961004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * @param outputCursor A MatrixCursor which this function will populate. 43971004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * @param accountId The account id for the mailboxes in this query. 43981004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu * @param uiProjection The projection specified by the query. 43991004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu */ 44001004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu private void remapFolderCursor(final Cursor inputCursor, final MatrixCursor outputCursor, 44011004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final long accountId, final String[] uiProjection) { 44021004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Return early if our input cursor is empty. 44031004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu if (inputCursor == null || inputCursor.getCount() == 0) { 44041004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu return; 44051004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } 44061004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Get the column indices for the columns we need during remapping. 4407469c4263760373c1bc330251910ec28005051aa8James Lemieux // While we currently could assume the column indices for UIProvider.FOLDERS_PROJECTION 44081004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // and therefore avoid the calls to getColumnIndex, this at least tries to future-proof a 44091004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // bit. 44101004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Note that id and type MUST be present for this function to work correctly. 44111004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final int idColumn = inputCursor.getColumnIndex(BaseColumns._ID); 44121004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final int typeColumn = inputCursor.getColumnIndex(UIProvider.FolderColumns.TYPE); 44131004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final int nameColumn = inputCursor.getColumnIndex(UIProvider.FolderColumns.NAME); 44141004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final int capabilitiesColumn = 44151004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu inputCursor.getColumnIndex(UIProvider.FolderColumns.CAPABILITIES); 44161004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final int persistentIdColumn = 44171004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu inputCursor.getColumnIndex(UIProvider.FolderColumns.PERSISTENT_ID); 44181004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final int loadMoreUriColumn = 44191004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu inputCursor.getColumnIndex(UIProvider.FolderColumns.LOAD_MORE_URI); 44201004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu 44211004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Get the EmailServiceInfo for the current account. 44221004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final Context context = getContext(); 44231004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final String protocol = Account.getProtocol(context, accountId); 44241004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final EmailServiceInfo info = EmailServiceUtils.getServiceInfo(context, protocol); 44251004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu 44261004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Build the return cursor. We iterate over all rows of the input cursor and construct 44271004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // a row in the output using the columns in uiProjection. 44281004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu while (inputCursor.moveToNext()) { 44291004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final MatrixCursor.RowBuilder builder = outputCursor.newRow(); 4430469c4263760373c1bc330251910ec28005051aa8James Lemieux final int folderType = inputCursor.getInt(typeColumn); 44311004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu for (int i = 0; i < uiProjection.length; i++) { 44321004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Find the index in the input cursor corresponding the column requested in the 44331004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // output projection. 44341004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final int index = inputCursor.getColumnIndex(uiProjection[i]); 44351004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu if (index == -1) { 44361004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // We don't have this value, so put a blank in the output and move on. 44371004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu builder.add(null); 44381004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu continue; 44391004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } 44401004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final String value = inputCursor.getString(index); 44411004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // remapped indicates whether we've written a value to the output for this column. 44421004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final boolean remapped; 44431004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu if (nameColumn == index) { 44441004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Remap folder name for system folders. 4445469c4263760373c1bc330251910ec28005051aa8James Lemieux builder.add(getFolderDisplayName(folderType, value)); 44461004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu remapped = true; 44471004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } else if (capabilitiesColumn == index) { 44481004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Get the correct capabilities for this folder. 4449469c4263760373c1bc330251910ec28005051aa8James Lemieux final long mailboxID = inputCursor.getLong(idColumn); 4450469c4263760373c1bc330251910ec28005051aa8James Lemieux final int mailboxType = getMailboxTypeFromFolderType(folderType); 4451469c4263760373c1bc330251910ec28005051aa8James Lemieux builder.add(getFolderCapabilities(info, mailboxType, mailboxID)); 44521004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu remapped = true; 44531004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } else if (persistentIdColumn == index) { 44541004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Hash the persistent id. 44551004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu builder.add(Base64.encodeToString(value.getBytes(), 44561004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING)); 44571004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu remapped = true; 4458469c4263760373c1bc330251910ec28005051aa8James Lemieux } else if (loadMoreUriColumn == index && folderType != Mailbox.TYPE_SEARCH && 44591004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu (info == null || !info.offerLoadMore)) { 44601004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Blank the load more uri for account types that don't offer it. 44611004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // Note that all account types permit load more for search results. 44621004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu builder.add(null); 44631004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu remapped = true; 44641004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } else { 44651004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu remapped = false; 44661004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } 44671004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // If the above logic didn't write some other value to the output, use the value 44681004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu // from the input cursor. 44691004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu if (!remapped) { 44701004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu builder.add(value); 44711004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } 44721004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } 44731004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } 44741004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } 44751004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu 44761004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu private Cursor getFolderListCursor(final Cursor inputCursor, final long accountId, 44771004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final String[] uiProjection) { 44781004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu final MatrixCursor mc = new MatrixCursorWithCachedColumns(uiProjection); 44791004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu if (inputCursor != null) { 44801004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu try { 44811004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu remapFolderCursor(inputCursor, mc, accountId, uiProjection); 44821004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } finally { 44831004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu inputCursor.close(); 44841004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } 44851004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } 44861004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu return mc; 44871004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu } 44881004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu 44891004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu /** 4490cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * Returns a {@link String} from Resources corresponding 4491cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * to the {@link UIProvider.FolderType} requested. 4492cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * @param folderType {@link UIProvider.FolderType} value for the folder 4493cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * @param defaultName a {@link String} to use in case the {@link UIProvider.FolderType} 4494cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * provided is not a system folder. 4495cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * @return a {@link String} to use as the display name for the folder 4496cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein */ 4497cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein private String getFolderDisplayName(int folderType, String defaultName) { 4498582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler final int resId; 4499cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein switch (folderType) { 4500cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case UIProvider.FolderType.INBOX: 4501cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein resId = R.string.mailbox_name_display_inbox; 4502cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein break; 4503cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case UIProvider.FolderType.OUTBOX: 4504cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein resId = R.string.mailbox_name_display_outbox; 4505cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein break; 4506cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case UIProvider.FolderType.DRAFT: 4507cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein resId = R.string.mailbox_name_display_drafts; 4508cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein break; 4509cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case UIProvider.FolderType.TRASH: 4510cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein resId = R.string.mailbox_name_display_trash; 4511cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein break; 4512cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case UIProvider.FolderType.SENT: 4513cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein resId = R.string.mailbox_name_display_sent; 4514cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein break; 4515cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case UIProvider.FolderType.SPAM: 4516cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein resId = R.string.mailbox_name_display_junk; 4517cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein break; 4518cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case UIProvider.FolderType.STARRED: 4519cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein resId = R.string.mailbox_name_display_starred; 4520cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein break; 4521cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case UIProvider.FolderType.UNREAD: 4522cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein resId = R.string.mailbox_name_display_unread; 4523cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein break; 4524cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein default: 4525cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return defaultName; 4526cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein } 4527cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return getContext().getString(resId); 4528cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein } 4529cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein 4530cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein /** 4531cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * Converts a {@link Mailbox} type value to its {@link UIProvider.FolderType} 4532cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * equivalent. 4533cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * @param mailboxType a {@link Mailbox} type 4534cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein * @return a {@link UIProvider.FolderType} value 4535cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein */ 4536cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein private static int getFolderTypeFromMailboxType(int mailboxType) { 4537cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein switch (mailboxType) { 4538cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case Mailbox.TYPE_INBOX: 4539cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return UIProvider.FolderType.INBOX; 4540cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case Mailbox.TYPE_OUTBOX: 4541cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return UIProvider.FolderType.OUTBOX; 4542cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case Mailbox.TYPE_DRAFTS: 4543cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return UIProvider.FolderType.DRAFT; 4544cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case Mailbox.TYPE_TRASH: 4545cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return UIProvider.FolderType.TRASH; 4546cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case Mailbox.TYPE_SENT: 4547cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return UIProvider.FolderType.SENT; 4548cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case Mailbox.TYPE_JUNK: 4549cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return UIProvider.FolderType.SPAM; 4550cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case Mailbox.TYPE_STARRED: 4551cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return UIProvider.FolderType.STARRED; 4552cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein case Mailbox.TYPE_UNREAD: 4553cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return UIProvider.FolderType.UNREAD; 4554e743a06ddf7677706da7450100e19d0f4509a43cScott Kennedy case Mailbox.TYPE_SEARCH: 4555e743a06ddf7677706da7450100e19d0f4509a43cScott Kennedy // TODO Can the DEFAULT type be removed from SEARCH folders? 4556e743a06ddf7677706da7450100e19d0f4509a43cScott Kennedy return UIProvider.FolderType.DEFAULT | UIProvider.FolderType.SEARCH; 4557cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein default: 4558cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein return UIProvider.FolderType.DEFAULT; 4559cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein } 4560cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein } 4561cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein 4562cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein /** 4563469c4263760373c1bc330251910ec28005051aa8James Lemieux * Converts a {@link UIProvider.FolderType} type value to its {@link Mailbox} equivalent. 4564469c4263760373c1bc330251910ec28005051aa8James Lemieux * @param folderType a {@link UIProvider.FolderType} type 4565469c4263760373c1bc330251910ec28005051aa8James Lemieux * @return a {@link Mailbox} value 4566469c4263760373c1bc330251910ec28005051aa8James Lemieux */ 4567469c4263760373c1bc330251910ec28005051aa8James Lemieux private static int getMailboxTypeFromFolderType(int folderType) { 4568469c4263760373c1bc330251910ec28005051aa8James Lemieux switch (folderType) { 4569469c4263760373c1bc330251910ec28005051aa8James Lemieux case UIProvider.FolderType.DEFAULT: 4570469c4263760373c1bc330251910ec28005051aa8James Lemieux return Mailbox.TYPE_MAIL; 4571469c4263760373c1bc330251910ec28005051aa8James Lemieux case UIProvider.FolderType.INBOX: 4572469c4263760373c1bc330251910ec28005051aa8James Lemieux return Mailbox.TYPE_INBOX; 4573469c4263760373c1bc330251910ec28005051aa8James Lemieux case UIProvider.FolderType.OUTBOX: 4574469c4263760373c1bc330251910ec28005051aa8James Lemieux return Mailbox.TYPE_OUTBOX; 4575469c4263760373c1bc330251910ec28005051aa8James Lemieux case UIProvider.FolderType.DRAFT: 4576469c4263760373c1bc330251910ec28005051aa8James Lemieux return Mailbox.TYPE_DRAFTS; 4577469c4263760373c1bc330251910ec28005051aa8James Lemieux case UIProvider.FolderType.TRASH: 4578469c4263760373c1bc330251910ec28005051aa8James Lemieux return Mailbox.TYPE_TRASH; 4579469c4263760373c1bc330251910ec28005051aa8James Lemieux case UIProvider.FolderType.SENT: 4580469c4263760373c1bc330251910ec28005051aa8James Lemieux return Mailbox.TYPE_SENT; 4581469c4263760373c1bc330251910ec28005051aa8James Lemieux case UIProvider.FolderType.SPAM: 4582469c4263760373c1bc330251910ec28005051aa8James Lemieux return Mailbox.TYPE_JUNK; 4583469c4263760373c1bc330251910ec28005051aa8James Lemieux case UIProvider.FolderType.STARRED: 4584469c4263760373c1bc330251910ec28005051aa8James Lemieux return Mailbox.TYPE_STARRED; 4585469c4263760373c1bc330251910ec28005051aa8James Lemieux case UIProvider.FolderType.UNREAD: 4586469c4263760373c1bc330251910ec28005051aa8James Lemieux return Mailbox.TYPE_UNREAD; 4587469c4263760373c1bc330251910ec28005051aa8James Lemieux case UIProvider.FolderType.DEFAULT | UIProvider.FolderType.SEARCH: 4588469c4263760373c1bc330251910ec28005051aa8James Lemieux // TODO Can the DEFAULT type be removed from SEARCH folders? 4589469c4263760373c1bc330251910ec28005051aa8James Lemieux return Mailbox.TYPE_SEARCH; 4590469c4263760373c1bc330251910ec28005051aa8James Lemieux default: 4591469c4263760373c1bc330251910ec28005051aa8James Lemieux throw new IllegalArgumentException("Unable to map folder type: " + folderType); 4592469c4263760373c1bc330251910ec28005051aa8James Lemieux } 4593469c4263760373c1bc330251910ec28005051aa8James Lemieux } 4594469c4263760373c1bc330251910ec28005051aa8James Lemieux 4595469c4263760373c1bc330251910ec28005051aa8James Lemieux /** 45964cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler * We need a reasonably full projection for getFolderListCursor to work, but don't always want 45974cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler * to do the subquery needed for FolderColumns.UNREAD_SENDERS 45984cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler * @param uiProjection The projection we actually want 45994cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler * @return Full projection, possibly with or without FolderColumns.UNREAD_SENDERS 46004cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler */ 46014cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler private String[] folderProjectionFromUiProjection(final String[] uiProjection) { 46024cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler final Set<String> columns = ImmutableSet.copyOf(uiProjection); 46034cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler if (columns.contains(UIProvider.FolderColumns.UNREAD_SENDERS)) { 46044cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler return UIProvider.FOLDERS_PROJECTION_WITH_UNREAD_SENDERS; 46054cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler } else { 46064cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler return UIProvider.FOLDERS_PROJECTION; 46074cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler } 46084cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler } 46094cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler 46104cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler /** 4611f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Handle UnifiedEmail queries here (dispatched from query()) 4612f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * 4613f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param match the UriMatcher match for the original uri passed in from UnifiedEmail 4614f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uri the original uri passed in from UnifiedEmail 4615f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiProjection the projection passed in from UnifiedEmail 4616b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy * @param unseenOnly <code>true</code> to only return unseen messages (where supported) 4617f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the result Cursor 4618f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 4619b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private Cursor uiQuery(int match, Uri uri, String[] uiProjection, final boolean unseenOnly) { 4620f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Context context = getContext(); 4621f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ContentResolver resolver = context.getContentResolver(); 4622f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank SQLiteDatabase db = getDatabase(context); 4623f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Should we ever return null, or throw an exception?? 4624f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Cursor c = null; 4625f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank String id = uri.getPathSegments().get(1); 4626f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Uri notifyUri = null; 4627f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank switch(match) { 4628f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ALL_FOLDERS: 462996192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler notifyUri = 463096192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler UIPROVIDER_FOLDERLIST_NOTIFIER.buildUpon().appendEncodedPath(id).build(); 463196192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler final Cursor vc = uiVirtualMailboxes(id, uiProjection); 463296192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler if (id.equals(COMBINED_ACCOUNT_ID_STRING)) { 463396192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler // There's no real mailboxes, so just return the virtual ones 463496192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler c = vc; 463596192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler } else { 463696192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler // Return real and virtual mailboxes alike 463796192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler final Cursor rawc = db.rawQuery(genQueryAccountAllMailboxes(uiProjection), 463896192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler new String[] {id}); 463996192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler rawc.setNotificationUri(context.getContentResolver(), notifyUri); 464096192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler vc.setNotificationUri(context.getContentResolver(), notifyUri); 46410d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler if (rawc.getCount() > 0) { 46420d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler c = new MergeCursor(new Cursor[]{rawc, vc}); 46430d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler } else { 46440d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler c = rawc; 46450d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler } 464696192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler } 464796192ef342f182deadcfe8a245306f7f155e4a79Tony Mantler break; 46484cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler case UI_FULL_FOLDERS: { 46494cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler // We need a full projection for getFolderListCursor 46504cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler final String[] folderProjection = folderProjectionFromUiProjection(uiProjection); 46514cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler c = db.rawQuery(genQueryAccountAllMailboxes(folderProjection), new String[] {id}); 46521004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu c = getFolderListCursor(c, Long.valueOf(id), uiProjection); 4653c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu notifyUri = 4654c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu UIPROVIDER_FOLDERLIST_NOTIFIER.buildUpon().appendEncodedPath(id).build(); 4655f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 46564cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler } 4657f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_RECENT_FOLDERS: 4658f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c = db.rawQuery(genQueryRecentMailboxes(uiProjection), new String[] {id}); 4659f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUri = UIPROVIDER_RECENT_FOLDERS_NOTIFIER.buildUpon().appendPath(id).build(); 4660f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 46614cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler case UI_SUBFOLDERS: { 46624cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler // We need a full projection for getFolderListCursor 46634cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler final String[] folderProjection = folderProjectionFromUiProjection(uiProjection); 46644cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler c = db.rawQuery(genQuerySubfolders(folderProjection), new String[] {id}); 46651004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu c = getFolderListCursor(c, Mailbox.getAccountIdForMailbox(context, id), 46661004d74f2c2c8085d793bf8f0118d80fe934e830Yu Ping Hu uiProjection); 4667c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu // Get notifications for any folder changes on this account. This is broader than 4668c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu // we need but otherwise we'd need for every folder change to notify on all relevant 4669c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu // subtrees. For now we opt for simplicity. 4670c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu final long accountId = Mailbox.getAccountIdForMailbox(context, id); 4671c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu notifyUri = ContentUris.withAppendedId(UIPROVIDER_FOLDERLIST_NOTIFIER, accountId); 4672f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 46734cece307c4a7873bde2396d79121b53b48ca5ec0Tony Mantler } 4674f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_MESSAGES: 4675f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank long mailboxId = Long.parseLong(id); 467670500d2253732f4e26988659c27d1b4186926c54Yu Ping Hu final Folder folder = getFolder(context, mailboxId); 467770500d2253732f4e26988659c27d1b4186926c54Yu Ping Hu if (folder == null) { 46782c3328bfd745142f3365c676527daa853fe445d6Tony Mantler // This mailboxId is bogus. Return an empty cursor 46792c3328bfd745142f3365c676527daa853fe445d6Tony Mantler // TODO: Make callers of this query handle null cursors instead b/10819309 46802c3328bfd745142f3365c676527daa853fe445d6Tony Mantler return new MatrixCursor(uiProjection); 468170500d2253732f4e26988659c27d1b4186926c54Yu Ping Hu } 4682f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (isVirtualMailbox(mailboxId)) { 4683b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy c = getVirtualMailboxMessagesCursor(db, uiProjection, mailboxId, unseenOnly); 4684f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 4685b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy c = db.rawQuery( 4686b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy genQueryMailboxMessages(uiProjection, unseenOnly), new String[] {id}); 4687f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4688f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUri = UIPROVIDER_CONVERSATION_NOTIFIER.buildUpon().appendPath(id).build(); 468970500d2253732f4e26988659c27d1b4186926c54Yu Ping Hu c = new EmailConversationCursor(context, c, folder, mailboxId); 4690f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4691f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_MESSAGE: 46927c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank MessageQuery qq = genQueryViewMessage(uiProjection, id); 46937c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank String sql = qq.query; 46947c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank String attJson = qq.attachmentJson; 46957c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank // With attachments, we have another argument to bind 46967c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank if (attJson != null) { 46977c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank c = db.rawQuery(sql, new String[] {attJson, id}); 46987c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank } else { 46997c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank c = db.rawQuery(sql, new String[] {id}); 47007c8f1c125aa5cd79f1f5f6048f8443eb084a6b2eMarc Blank } 4701f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler if (c != null) { 47027525feb244db87eadf3a95baf3918438b0fbbb75Tony Mantler c = new EmailMessageCursor(getContext(), c, UIProvider.MessageColumns.BODY_HTML, 47032f288864b621cfb5aee44eda27df463460d33dd3Tony Mantler UIProvider.MessageColumns.BODY_TEXT); 4704f678a18b69c95ef1a448cb5cb7cd3699be7c5423Tony Mantler } 4705c637bff1989e768f1ffe0f898bd803a9c78d0514Tony Mantler notifyUri = UIPROVIDER_MESSAGE_NOTIFIER.buildUpon().appendPath(id).build(); 4706f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4707f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ATTACHMENTS: 47086eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein final List<String> contentTypeQueryParameters = 47096eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein uri.getQueryParameters(PhotoContract.ContentTypeParameters.CONTENT_TYPE); 47106eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein c = db.rawQuery(genQueryAttachments(uiProjection, contentTypeQueryParameters), 47116eee9e4f11d0dad2c2e965281c63146f7acd0d2fAndrew Sapperstein new String[] {id}); 4712114e314968f507b4237e693d279befe261b00f02Marc Blank c = new AttachmentsCursor(context, c); 4713f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUri = UIPROVIDER_ATTACHMENTS_NOTIFIER.buildUpon().appendPath(id).build(); 4714f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4715f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ATTACHMENT: 47168cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux c = db.rawQuery(genQueryAttachment(uiProjection), new String[] {id}); 4717f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUri = UIPROVIDER_ATTACHMENT_NOTIFIER.buildUpon().appendPath(id).build(); 4718f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 47198cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux case UI_ATTACHMENT_BY_CID: 47208cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux final String cid = uri.getPathSegments().get(2); 47218cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux final String[] selectionArgs = {id, cid}; 47228cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux c = db.rawQuery(genQueryAttachmentByMessageIDAndCid(uiProjection), selectionArgs); 47238cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux 47248cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux // we don't have easy access to the attachment ID (which is buried in the cursor 47258cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux // being returned), so we notify on the parent message object 47268cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux notifyUri = UIPROVIDER_ATTACHMENTS_NOTIFIER.buildUpon().appendPath(id).build(); 47278cfbfb50bb2cc944ce60ba510ffa5b62303615efJames Lemieux break; 4728f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_FOLDER: 47290d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler case UI_INBOX: 47300d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler if (match == UI_INBOX) { 47310d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler mailboxId = Mailbox.findMailboxOfType(context, Long.parseLong(id), 47320d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler Mailbox.TYPE_INBOX); 47330d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler if (mailboxId == Mailbox.NO_MAILBOX) { 47340d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler LogUtils.d(LogUtils.TAG, "No inbox found for account %s", id); 47350d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler return null; 47360d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler } 47370d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler LogUtils.d(LogUtils.TAG, "Found inbox id %d", mailboxId); 47380d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler } else { 47390d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler mailboxId = Long.parseLong(id); 47400d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler } 47410d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler final String mailboxIdString = Long.toString(mailboxId); 4742f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (isVirtualMailbox(mailboxId)) { 4743e046d47c5346e1255c401a40fcb22b90e1e22a23Tony Mantler c = getVirtualMailboxCursor(mailboxId, uiProjection); 47440d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler notifyUri = UIPROVIDER_FOLDER_NOTIFIER.buildUpon().appendPath(mailboxIdString) 47450d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler .build(); 4746f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 47470d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler c = db.rawQuery(genQueryMailbox(uiProjection, mailboxIdString), 47480d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler new String[]{mailboxIdString}); 4749cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein final List<String> projectionList = Arrays.asList(uiProjection); 4750cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein final int nameColumn = projectionList.indexOf(UIProvider.FolderColumns.NAME); 4751cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein final int typeColumn = projectionList.indexOf(UIProvider.FolderColumns.TYPE); 4752cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein if (c.moveToFirst()) { 47532eecdd1a50676eaae98b75d1d74de697cff39dd7Tony Mantler final Cursor closeThis = c; 47542eecdd1a50676eaae98b75d1d74de697cff39dd7Tony Mantler try { 47552eecdd1a50676eaae98b75d1d74de697cff39dd7Tony Mantler c = getUiFolderCursorRowFromMailboxCursorRow( 47562eecdd1a50676eaae98b75d1d74de697cff39dd7Tony Mantler new MatrixCursorWithCachedColumns(uiProjection), 47572eecdd1a50676eaae98b75d1d74de697cff39dd7Tony Mantler uiProjection.length, c, nameColumn, typeColumn); 47582eecdd1a50676eaae98b75d1d74de697cff39dd7Tony Mantler } finally { 47592eecdd1a50676eaae98b75d1d74de697cff39dd7Tony Mantler closeThis.close(); 47602eecdd1a50676eaae98b75d1d74de697cff39dd7Tony Mantler } 4761cdee4b0c11400d766ae826e6c01d234c2769554fAndrew Sapperstein } 47620d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler notifyUri = UIPROVIDER_FOLDER_NOTIFIER.buildUpon().appendPath(mailboxIdString) 47630d7c7091253bebc4b66b1713417cdd1f769b8340Tony Mantler .build(); 4764f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4765f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4766f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_ACCOUNT: 4767f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (id.equals(COMBINED_ACCOUNT_ID_STRING)) { 47687fdde9bb4a24e931618a7a64227e2194c89034daScott Kennedy MatrixCursor mc = new MatrixCursorWithCachedColumns(uiProjection, 1); 4769f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank addCombinedAccountRow(mc); 4770f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c = mc; 4771f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 4772f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c = db.rawQuery(genQueryAccount(uiProjection, id), new String[] {id}); 4773f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4774f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUri = UIPROVIDER_ACCOUNT_NOTIFIER.buildUpon().appendPath(id).build(); 4775f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4776f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case UI_CONVERSATION: 4777f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c = db.rawQuery(genQueryConversation(uiProjection), new String[] {id}); 4778f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4779f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4780f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (notifyUri != null) { 4781f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c.setNotificationUri(resolver, notifyUri); 4782f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4783f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return c; 4784f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4785f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4786f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 4787f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Convert a UIProvider attachment to an EmailProvider attachment (for sending); we only need 4788f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * a few of the fields 4789f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uiAtt the UIProvider attachment to convert 47909a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook * @param cachedFile the path to the cached file to 4791f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the EmailProvider attachment 4792f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 47939a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook // TODO(pwestbro): once the Attachment contains the cached uri, the second parameter can be 47949a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook // removed 4795fc8a57bb29087a4c582a3fdb0ca338d9fdfe1f02Martin Hibdon // TODO(mhibdon): if the UI Attachment contained the account key, the third parameter could 4796f484751e060620ddf4e2dfe38f2b9f46f472ac9dMartin Hibdon // be removed. 4797b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static Attachment convertUiAttachmentToAttachment( 4798f484751e060620ddf4e2dfe38f2b9f46f472ac9dMartin Hibdon com.android.mail.providers.Attachment uiAtt, String cachedFile, long accountKey) { 47999a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final Attachment att = new Attachment(); 4800f484751e060620ddf4e2dfe38f2b9f46f472ac9dMartin Hibdon 48016e5bccf2c984039da5ae1dc08cffa665b73b6474Marc Blank att.setContentUri(uiAtt.contentUri.toString()); 48025a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook 48035a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook if (!TextUtils.isEmpty(cachedFile)) { 48045a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook // Generate the content provider uri for this cached file 48055a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook final Uri.Builder cachedFileBuilder = Uri.parse( 48065a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook "content://" + EmailContent.AUTHORITY + "/attachment/cachedFile").buildUpon(); 48075a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook cachedFileBuilder.appendQueryParameter(Attachment.CACHED_FILE_QUERY_PARAM, cachedFile); 48085a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook att.setCachedFileUri(cachedFileBuilder.build().toString()); 48095a3aebbd2dd8cdd4d7c1a76ce3085cd6a314c0d0Paul Westbrook } 4810f484751e060620ddf4e2dfe38f2b9f46f472ac9dMartin Hibdon att.mAccountKey = accountKey; 4811ea2edb637036a7368b6ef82a0aafdb1a790e26e9Mark Wei att.mFileName = uiAtt.getName(); 4812ea2edb637036a7368b6ef82a0aafdb1a790e26e9Mark Wei att.mMimeType = uiAtt.getContentType(); 4813f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank att.mSize = uiAtt.size; 4814f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return att; 4815f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4816f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4817f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 4818f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Create a mailbox given the account and mailboxType. 4819f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 4820f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private Mailbox createMailbox(long accountId, int mailboxType) { 4821f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Context context = getContext(); 48229ae81e2af07219bfad26c882516343e83c16d926Yu Ping Hu Mailbox box = Mailbox.newSystemMailbox(context, accountId, mailboxType); 4823f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Make sure drafts and save will show up in recents... 4824f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // If these already exist (from old Email app), they will have touch times 4825f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank switch (mailboxType) { 4826f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case Mailbox.TYPE_DRAFTS: 4827f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank box.mLastTouchedTime = Mailbox.DRAFTS_DEFAULT_TOUCH_TIME; 4828f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4829f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case Mailbox.TYPE_SENT: 4830f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank box.mLastTouchedTime = Mailbox.SENT_DEFAULT_TOUCH_TIME; 4831f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4832f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4833f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank box.save(context); 4834f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return box; 4835f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4836f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4837f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 4838f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Given an account name and a mailbox type, return that mailbox, creating it if necessary 4839b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy * @param accountId the account id to use 4840f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param mailboxType the type of mailbox we're trying to find 4841f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the mailbox of the given type for the account in the uri, or null if not found 4842f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 48430eb47994a328fe450c54e483b894138fd449d9c9Yu Ping Hu private Mailbox getMailboxByAccountIdAndType(final long accountId, final int mailboxType) { 48440eb47994a328fe450c54e483b894138fd449d9c9Yu Ping Hu Mailbox mailbox = Mailbox.restoreMailboxOfType(getContext(), accountId, mailboxType); 4845f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mailbox == null) { 48460eb47994a328fe450c54e483b894138fd449d9c9Yu Ping Hu mailbox = createMailbox(accountId, mailboxType); 4847f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4848f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return mailbox; 4849f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4850f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4851f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 4852f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Given a mailbox and the content values for a message, create/save the message in the mailbox 4853f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param mailbox the mailbox to use 48548e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu * @param extras the bundle containing the message fields 4855f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the uri of the newly created message 48568e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu * TODO(yph): The following fields are available in extras but unused, verify whether they 48578e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu * should be respected: 48588e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu * - UIProvider.MessageColumns.SNIPPET 48598e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu * - UIProvider.MessageColumns.REPLY_TO 48608e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu * - UIProvider.MessageColumns.FROM 4861f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 48628e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu private Uri uiSaveMessage(Message msg, Mailbox mailbox, Bundle extras) { 48639a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final Context context = getContext(); 4864f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Fill in the message 48659a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final Account account = Account.restoreAccountWithId(context, mailbox.mAccountKey); 4866f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (account == null) return null; 4867632ee24d48f308c855ddec8f013b674e5ade67e2Tony Mantler final String customFromAddress = 4868632ee24d48f308c855ddec8f013b674e5ade67e2Tony Mantler extras.getString(UIProvider.MessageColumns.CUSTOM_FROM_ADDRESS); 4869632ee24d48f308c855ddec8f013b674e5ade67e2Tony Mantler if (!TextUtils.isEmpty(customFromAddress)) { 4870632ee24d48f308c855ddec8f013b674e5ade67e2Tony Mantler msg.mFrom = customFromAddress; 4871632ee24d48f308c855ddec8f013b674e5ade67e2Tony Mantler } else { 4872632ee24d48f308c855ddec8f013b674e5ade67e2Tony Mantler msg.mFrom = account.getEmailAddress(); 4873632ee24d48f308c855ddec8f013b674e5ade67e2Tony Mantler } 4874f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.mTimeStamp = System.currentTimeMillis(); 48758e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu msg.mTo = extras.getString(UIProvider.MessageColumns.TO); 48768e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu msg.mCc = extras.getString(UIProvider.MessageColumns.CC); 48778e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu msg.mBcc = extras.getString(UIProvider.MessageColumns.BCC); 48788e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu msg.mSubject = extras.getString(UIProvider.MessageColumns.SUBJECT); 48798e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu msg.mText = extras.getString(UIProvider.MessageColumns.BODY_TEXT); 48808e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu msg.mHtml = extras.getString(UIProvider.MessageColumns.BODY_HTML); 4881f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.mMailboxKey = mailbox.mId; 4882f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.mAccountKey = mailbox.mAccountKey; 4883f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.mDisplayName = msg.mTo; 4884f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.mFlagLoaded = Message.FLAG_LOADED_COMPLETE; 4885f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.mFlagRead = true; 4886b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy msg.mFlagSeen = true; 48872d92d29c9f22f26c12a7bf95dca0da61cd6e0f8cTony Mantler msg.mQuotedTextStartPos = extras.getInt(UIProvider.MessageColumns.QUOTE_START_POS, 0); 4888f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank int flags = 0; 48898e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu final int draftType = extras.getInt(UIProvider.MessageColumns.DRAFT_TYPE); 4890f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank switch(draftType) { 4891f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case DraftType.FORWARD: 4892f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank flags |= Message.FLAG_TYPE_FORWARD; 4893f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4894f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case DraftType.REPLY_ALL: 4895f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank flags |= Message.FLAG_TYPE_REPLY_ALL; 4896b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy //$FALL-THROUGH$ 4897f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case DraftType.REPLY: 4898f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank flags |= Message.FLAG_TYPE_REPLY; 4899f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4900f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case DraftType.COMPOSE: 4901f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank flags |= Message.FLAG_TYPE_ORIGINAL; 4902f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 4903f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4904f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank int draftInfo = 0; 49058e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu if (extras.containsKey(UIProvider.MessageColumns.QUOTE_START_POS)) { 49068e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu draftInfo = extras.getInt(UIProvider.MessageColumns.QUOTE_START_POS); 49078e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu if (extras.getInt(UIProvider.MessageColumns.APPEND_REF_MESSAGE_CONTENT) != 0) { 4908f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank draftInfo |= Message.DRAFT_INFO_APPEND_REF_MESSAGE; 4909f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4910f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 49118e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu if (!extras.containsKey(UIProvider.MessageColumns.APPEND_REF_MESSAGE_CONTENT)) { 4912eaf7e3bce7a7f8f31c5677db188dec74072a43caMarc Blank flags |= Message.FLAG_NOT_INCLUDE_QUOTED_TEXT; 4913eaf7e3bce7a7f8f31c5677db188dec74072a43caMarc Blank } 4914f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.mDraftInfo = draftInfo; 4915eaf7e3bce7a7f8f31c5677db188dec74072a43caMarc Blank msg.mFlags = flags; 4916eaf7e3bce7a7f8f31c5677db188dec74072a43caMarc Blank 49178e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu final String ref = extras.getString(UIProvider.MessageColumns.REF_MESSAGE_ID); 491849cbb81332769c97a19cd388dcfd88957c072328Mindy Pereira if (ref != null && msg.mQuotedTextStartPos >= 0) { 4919f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank String refId = Uri.parse(ref).getLastPathSegment(); 4920f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank try { 4921582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler msg.mSourceKey = Long.parseLong(refId); 4922f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } catch (NumberFormatException e) { 4923f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // This will be zero; the default 4924f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4925f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4926f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 4927f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Get attachments from the ContentValues 49289a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final List<com.android.mail.providers.Attachment> uiAtts = 4929f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank com.android.mail.providers.Attachment.fromJSONArray( 49308e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu extras.getString(UIProvider.MessageColumns.ATTACHMENTS)); 49319a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final ArrayList<Attachment> atts = new ArrayList<Attachment>(); 4932f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank boolean hasUnloadedAttachments = false; 49338e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu Bundle attachmentFds = 49348e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu extras.getParcelable(UIProvider.SendOrSaveMethodParamKeys.OPENED_FD_MAP); 4935f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank for (com.android.mail.providers.Attachment uiAtt: uiAtts) { 49369a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final Uri attUri = uiAtt.uri; 4937f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (attUri != null && attUri.getAuthority().equals(EmailContent.AUTHORITY)) { 4938f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // If it's one of ours, retrieve the attachment and add it to the list 49399a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final long attId = Long.parseLong(attUri.getLastPathSegment()); 49409a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final Attachment att = Attachment.restoreAttachmentWithId(context, attId); 4941f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (att != null) { 4942f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // We must clone the attachment into a new one for this message; easiest to 4943f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // use a parcel here 49449a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final Parcel p = Parcel.obtain(); 4945f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank att.writeToParcel(p, 0); 4946f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank p.setDataPosition(0); 49479a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final Attachment attClone = new Attachment(p); 4948f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank p.recycle(); 4949f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Clear the messageKey (this is going to be a new attachment) 4950f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank attClone.mMessageKey = 0; 4951f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // If we're sending this, it's not loaded, and we're not smart forwarding 4952f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // add the download flag, so that ADS will start up 49536e5bccf2c984039da5ae1dc08cffa665b73b6474Marc Blank if (mailbox.mType == Mailbox.TYPE_OUTBOX && att.getContentUri() == null && 4954f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ((account.mFlags & Account.FLAGS_SUPPORTS_SMART_FORWARD) == 0)) { 4955f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank attClone.mFlags |= Attachment.FLAG_DOWNLOAD_FORWARD; 4956f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank hasUnloadedAttachments = true; 4957f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4958f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank atts.add(attClone); 4959f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4960f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 49619a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook // Cache the attachment. This will allow us to send it, if the permissions are 4962f484751e060620ddf4e2dfe38f2b9f46f472ac9dMartin Hibdon // revoked. 49639a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final String cachedFileUri = 49649a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook AttachmentUtils.cacheAttachmentUri(context, uiAtt, attachmentFds); 49659a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook 4966f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Convert external attachment to one of ours and add to the list 4967f484751e060620ddf4e2dfe38f2b9f46f472ac9dMartin Hibdon atts.add(convertUiAttachmentToAttachment(uiAtt, cachedFileUri, msg.mAccountKey)); 4968f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4969f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4970f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (!atts.isEmpty()) { 4971f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.mAttachments = atts; 4972f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.mFlagAttachment = true; 4973f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (hasUnloadedAttachments) { 4974f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Utility.showToast(context, R.string.message_view_attachment_background_load); 4975f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4976f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 4977f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Save it or update it... 4978f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (!msg.isSaved()) { 4979f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.save(context); 4980f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 4981f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // This is tricky due to how messages/attachments are saved; rather than putz with 4982f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // what's changed, we'll delete/re-add them 49839a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final ArrayList<ContentProviderOperation> ops = 49849a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook new ArrayList<ContentProviderOperation>(); 4985f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Delete all existing attachments 4986f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ops.add(ContentProviderOperation.newDelete( 4987f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, msg.mId)) 4988f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank .build()); 4989f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Delete the body 4990f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ops.add(ContentProviderOperation.newDelete(Body.CONTENT_URI) 49913dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler .withSelection(BodyColumns.MESSAGE_KEY + "=?", 49923dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler new String[] {Long.toString(msg.mId)}) 4993f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank .build()); 4994f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Add the ops for the message, atts, and body 4995f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank msg.addSaveOps(ops); 4996f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Do it! 4997f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank try { 4998f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank applyBatch(ops); 4999f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } catch (OperationApplicationException e) { 5000582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler LogUtils.d(TAG, "applyBatch exception"); 5001f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5002f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5003c637bff1989e768f1ffe0f898bd803a9c78d0514Tony Mantler notifyUIMessage(msg.mId); 5004c637bff1989e768f1ffe0f898bd803a9c78d0514Tony Mantler 5005f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mailbox.mType == Mailbox.TYPE_OUTBOX) { 50069e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu startSync(mailbox, 0); 50079a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final long originalMsgId = msg.mSourceKey; 5008f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (originalMsgId != 0) { 50099a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final Message originalMsg = Message.restoreMessageWithId(context, originalMsgId); 5010f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // If the original message exists, set its forwarded/replied to flags 5011f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (originalMsg != null) { 50129a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final ContentValues cv = new ContentValues(); 5013f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank flags = originalMsg.mFlags; 5014f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank switch(draftType) { 5015f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case DraftType.FORWARD: 5016f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank flags |= Message.FLAG_FORWARDED; 5017f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 5018f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case DraftType.REPLY_ALL: 5019f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case DraftType.REPLY: 5020f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank flags |= Message.FLAG_REPLIED_TO; 5021f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 5022f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 50233dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler cv.put(MessageColumns.FLAGS, flags); 5024f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank context.getContentResolver().update(ContentUris.withAppendedId( 5025f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Message.CONTENT_URI, originalMsgId), cv, null, null); 5026f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5027f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5028f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5029f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return uiUri("uimessage", msg.mId); 5030f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5031f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 50320eb47994a328fe450c54e483b894138fd449d9c9Yu Ping Hu private Uri uiSaveDraftMessage(final long accountId, final Bundle extras) { 50339a95253846ccc7a94dd7d4c618ec2d808e2a4000Paul Westbrook final Mailbox mailbox = 50340eb47994a328fe450c54e483b894138fd449d9c9Yu Ping Hu getMailboxByAccountIdAndType(accountId, Mailbox.TYPE_DRAFTS); 5035779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook if (mailbox == null) return null; 5036bcc204dd6fa9888630348d85ebda033401a4cb0cJay Shrauner Message msg = null; 50378e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu if (extras.containsKey(BaseColumns._ID)) { 50388e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu final long messageId = extras.getLong(BaseColumns._ID); 50398e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu msg = Message.restoreMessageWithId(getContext(), messageId); 5040bcc204dd6fa9888630348d85ebda033401a4cb0cJay Shrauner } 5041bcc204dd6fa9888630348d85ebda033401a4cb0cJay Shrauner if (msg == null) { 50428e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu msg = new Message(); 50438e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu } 50448e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu return uiSaveMessage(msg, mailbox, extras); 5045779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook } 5046779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook 50470eb47994a328fe450c54e483b894138fd449d9c9Yu Ping Hu private Uri uiSendDraftMessage(final long accountId, final Bundle extras) { 5048779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook final Message msg; 5049779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook if (extras.containsKey(BaseColumns._ID)) { 5050779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook final long messageId = extras.getLong(BaseColumns._ID); 5051779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook msg = Message.restoreMessageWithId(getContext(), messageId); 5052779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook } else { 5053779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook msg = new Message(); 5054779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook } 5055779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook 5056779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook if (msg == null) return null; 50570eb47994a328fe450c54e483b894138fd449d9c9Yu Ping Hu final Mailbox mailbox = getMailboxByAccountIdAndType(accountId, Mailbox.TYPE_OUTBOX); 5058779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook if (mailbox == null) return null; 5059f7055e261821af30874f6597757468eba6830539Yu Ping Hu // Make sure the sent mailbox exists, since it will be necessary soon. 5060f7055e261821af30874f6597757468eba6830539Yu Ping Hu // TODO(yph): move system mailbox creation to somewhere sane. 50610eb47994a328fe450c54e483b894138fd449d9c9Yu Ping Hu final Mailbox sentMailbox = getMailboxByAccountIdAndType(accountId, Mailbox.TYPE_SENT); 5062f7055e261821af30874f6597757468eba6830539Yu Ping Hu if (sentMailbox == null) return null; 50638e2c4056caffb9695fa7fdf3a90c1c4f056adb97Yu Ping Hu final Uri messageUri = uiSaveMessage(msg, mailbox, extras); 5064779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook // Kick observers 506505649dca2f59f28cd4295e041045a605badddb15Tony Mantler notifyUI(Mailbox.CONTENT_URI, null); 5066779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook return messageUri; 5067779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook } 5068779fe0200300978e28a0b8a904817bdc5e587cadPaul Westbrook 5069b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static void putIntegerLongOrBoolean(ContentValues values, String columnName, 5070b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy Object value) { 5071f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (value instanceof Integer) { 5072f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Integer intValue = (Integer)value; 5073f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(columnName, intValue); 5074f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else if (value instanceof Boolean) { 5075f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Boolean boolValue = (Boolean)value; 5076f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(columnName, boolValue ? 1 : 0); 5077f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else if (value instanceof Long) { 5078f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Long longValue = (Long)value; 5079f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(columnName, longValue); 5080f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5081f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5082f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5083f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 5084f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Update the timestamps for the folders specified and notifies on the recent folder URI. 5085582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler * @param folders array of folder Uris to update 5086f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return number of folders updated 5087f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 508805649dca2f59f28cd4295e041045a605badddb15Tony Mantler private int updateTimestamp(final Context context, String id, Uri[] folders){ 5089f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank int updated = 0; 5090f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final long now = System.currentTimeMillis(); 5091f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final ContentResolver resolver = context.getContentResolver(); 509205649dca2f59f28cd4295e041045a605badddb15Tony Mantler final ContentValues touchValues = new ContentValues(1); 50939e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler for (final Uri folder : folders) { 5094f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank touchValues.put(MailboxColumns.LAST_TOUCHED_TIME, now); 50959e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler LogUtils.d(TAG, "updateStamp: %s updated", folder); 50969e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler updated += resolver.update(folder, touchValues, null, null); 5097f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5098f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final Uri toNotify = 5099f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank UIPROVIDER_RECENT_FOLDERS_NOTIFIER.buildUpon().appendPath(id).build(); 5100f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank LogUtils.d(TAG, "updateTimestamp: Notifying on %s", toNotify); 510105649dca2f59f28cd4295e041045a605badddb15Tony Mantler notifyUI(toNotify, null); 5102f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return updated; 5103f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5104f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5105f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 5106f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Updates the recent folders. The values to be updated are specified as ContentValues pairs 5107f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * of (Folder URI, access timestamp). Returns nonzero if successful, always. 51089e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler * @param uri provider query uri 5109582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler * @param values uri, timestamp pairs 5110f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return nonzero value always. 5111f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 5112f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private int uiUpdateRecentFolders(Uri uri, ContentValues values) { 5113f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final int numFolders = values.size(); 5114f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final String id = uri.getPathSegments().get(1); 5115f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final Uri[] folders = new Uri[numFolders]; 5116f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final Context context = getContext(); 5117f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank int i = 0; 5118d8302b01faa8fc7f175c93e90458aa84e8a663c7Scott Kennedy for (final String uriString : values.keySet()) { 5119f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank folders[i] = Uri.parse(uriString); 5120f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5121f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return updateTimestamp(context, id, folders); 5122f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5123f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5124f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 5125f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Populates the recent folders according to the design. 51269e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler * @param uri provider query uri 5127f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the number of recent folders were populated. 5128f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 5129f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private int uiPopulateRecentFolders(Uri uri) { 5130f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final Context context = getContext(); 5131f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final String id = uri.getLastPathSegment(); 5132f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final Uri[] recentFolders = defaultRecentFolders(id); 5133f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final int numFolders = recentFolders.length; 5134f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (numFolders <= 0) { 5135f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return 0; 5136f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5137f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final int rowsUpdated = updateTimestamp(context, id, recentFolders); 5138f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank LogUtils.d(TAG, "uiPopulateRecentFolders: %d folders changed", rowsUpdated); 5139f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return rowsUpdated; 5140f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5141f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5142f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private int uiUpdateAttachment(Uri uri, ContentValues uiValues) { 51438f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei int result = 0; 5144f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Integer stateValue = uiValues.getAsInteger(UIProvider.AttachmentColumns.STATE); 5145f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (stateValue != null) { 5146f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // This is a command from UIProvider 5147f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank long attachmentId = Long.parseLong(uri.getLastPathSegment()); 5148f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Context context = getContext(); 5149f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Attachment attachment = 5150f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Attachment.restoreAttachmentWithId(context, attachmentId); 5151f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (attachment == null) { 5152f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Went away; ah, well... 51538f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei return result; 5154f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5155582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler int state = stateValue; 5156f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ContentValues values = new ContentValues(); 51578f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei if (state == UIProvider.AttachmentState.NOT_SAVED 51588f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei || state == UIProvider.AttachmentState.REDOWNLOADING) { 51598f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei // Set state, try to cancel request 51608f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei values.put(AttachmentColumns.UI_STATE, UIProvider.AttachmentState.NOT_SAVED); 51618f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei values.put(AttachmentColumns.FLAGS, 51628f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei attachment.mFlags &= ~Attachment.FLAG_DOWNLOAD_USER_REQUEST); 51638f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei attachment.update(context, values); 51648f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei result = 1; 51658f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei } 51668f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei if (state == UIProvider.AttachmentState.DOWNLOADING 51678f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei || state == UIProvider.AttachmentState.REDOWNLOADING) { 51688f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei // Set state and destination; request download 51698f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei values.put(AttachmentColumns.UI_STATE, UIProvider.AttachmentState.DOWNLOADING); 51708f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei Integer destinationValue = 5171f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank uiValues.getAsInteger(UIProvider.AttachmentColumns.DESTINATION); 51728f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei values.put(AttachmentColumns.UI_DESTINATION, 51738f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei destinationValue == null ? 0 : destinationValue); 51748f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei values.put(AttachmentColumns.FLAGS, 51758f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei attachment.mFlags | Attachment.FLAG_DOWNLOAD_USER_REQUEST); 51765ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon 51775ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon if (values.containsKey(AttachmentColumns.LOCATION) && 51785ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon TextUtils.isEmpty(values.getAsString(AttachmentColumns.LOCATION))) { 51795ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon LogUtils.w(TAG, new Throwable(), "attachment with blank location"); 51805ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon } 51815ed194434f875df551ebcaf673f5b9e8c385d652Martin Hibdon 51828f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei attachment.update(context, values); 51838f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei result = 1; 51848f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei } 51858f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei if (state == UIProvider.AttachmentState.SAVED) { 51868f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei // If this is an inline attachment, notify message has changed 51878f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei if (!TextUtils.isEmpty(attachment.mContentId)) { 51888f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei notifyUI(UIPROVIDER_MESSAGE_NOTIFIER, attachment.mMessageKey); 51898f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei } 51908f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei result = 1; 5191f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5192f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 51938f474dc02f01d7805716422625ef7b50fa0e4aefMark Wei return result; 5194f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5195f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5196b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private int uiUpdateFolder(final Context context, Uri uri, ContentValues uiValues) { 5197b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy // We need to mark seen separately 5198b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy if (uiValues.containsKey(UIProvider.ConversationColumns.SEEN)) { 5199b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final int seenValue = uiValues.getAsInteger(UIProvider.ConversationColumns.SEEN); 5200b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy 5201b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy if (seenValue == 1) { 5202b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final String mailboxId = uri.getLastPathSegment(); 5203b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final int rows = markAllSeen(context, mailboxId); 5204b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy 5205b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy if (uiValues.size() == 1) { 5206b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy // Nothing else to do, so return this value 5207b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy return rows; 5208b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy } 5209b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy } 5210b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy } 5211b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy 5212b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final Uri ourUri = convertToEmailProviderUri(uri, Mailbox.CONTENT_URI, true); 5213f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (ourUri == null) return 0; 5214f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ContentValues ourValues = new ContentValues(); 5215f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // This should only be called via update to "recent folders" 5216f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank for (String columnName: uiValues.keySet()) { 5217f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (columnName.equals(MailboxColumns.LAST_TOUCHED_TIME)) { 5218f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ourValues.put(MailboxColumns.LAST_TOUCHED_TIME, uiValues.getAsLong(columnName)); 5219f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5220f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5221f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return update(ourUri, ourValues, null, null); 5222f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5223f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5224b7e0834121d564982c0389c87df775ba311429d4Tony Mantler private int uiUpdateSettings(final Context c, final ContentValues uiValues) { 5225b7e0834121d564982c0389c87df775ba311429d4Tony Mantler final MailPrefs mailPrefs = MailPrefs.get(c); 5226b7e0834121d564982c0389c87df775ba311429d4Tony Mantler 5227b7e0834121d564982c0389c87df775ba311429d4Tony Mantler if (uiValues.containsKey(SettingsColumns.AUTO_ADVANCE)) { 5228b7e0834121d564982c0389c87df775ba311429d4Tony Mantler mailPrefs.setAutoAdvanceMode(uiValues.getAsInteger(SettingsColumns.AUTO_ADVANCE)); 5229b7e0834121d564982c0389c87df775ba311429d4Tony Mantler } 5230b7e0834121d564982c0389c87df775ba311429d4Tony Mantler if (uiValues.containsKey(SettingsColumns.CONVERSATION_VIEW_MODE)) { 5231b7e0834121d564982c0389c87df775ba311429d4Tony Mantler final int value = uiValues.getAsInteger(SettingsColumns.CONVERSATION_VIEW_MODE); 5232b7e0834121d564982c0389c87df775ba311429d4Tony Mantler final boolean overviewMode = value == UIProvider.ConversationViewMode.OVERVIEW; 5233b7e0834121d564982c0389c87df775ba311429d4Tony Mantler mailPrefs.setConversationOverviewMode(overviewMode); 5234b7e0834121d564982c0389c87df775ba311429d4Tony Mantler } 5235b7e0834121d564982c0389c87df775ba311429d4Tony Mantler 5236b7e0834121d564982c0389c87df775ba311429d4Tony Mantler c.getContentResolver().notifyChange(UIPROVIDER_ALL_ACCOUNTS_NOTIFIER, null, false); 5237b7e0834121d564982c0389c87df775ba311429d4Tony Mantler 5238b7e0834121d564982c0389c87df775ba311429d4Tony Mantler return 1; 5239b7e0834121d564982c0389c87df775ba311429d4Tony Mantler } 5240b7e0834121d564982c0389c87df775ba311429d4Tony Mantler 5241b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private int markAllSeen(final Context context, final String mailboxId) { 5242b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final SQLiteDatabase db = getDatabase(context); 5243b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final String table = Message.TABLE_NAME; 5244b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final ContentValues values = new ContentValues(1); 5245b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy values.put(MessageColumns.FLAG_SEEN, 1); 5246b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final String whereClause = MessageColumns.MAILBOX_KEY + " = ?"; 5247b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy final String[] whereArgs = new String[] {mailboxId}; 5248b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy 5249b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy return db.update(table, values, whereClause, whereArgs); 5250b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy } 5251b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy 5252f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private ContentValues convertUiMessageValues(Message message, ContentValues values) { 52535ed8b266a480ea413264abdb5042c58b29175df8Paul Westbrook final ContentValues ourValues = new ContentValues(); 525434d8a139ce9c7eb72ec92ba6861353f221301330Mindy Pereira for (String columnName : values.keySet()) { 52555ed8b266a480ea413264abdb5042c58b29175df8Paul Westbrook final Object val = values.get(columnName); 5256f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (columnName.equals(UIProvider.ConversationColumns.STARRED)) { 5257f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank putIntegerLongOrBoolean(ourValues, MessageColumns.FLAG_FAVORITE, val); 5258f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else if (columnName.equals(UIProvider.ConversationColumns.READ)) { 5259f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank putIntegerLongOrBoolean(ourValues, MessageColumns.FLAG_READ, val); 5260b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy } else if (columnName.equals(UIProvider.ConversationColumns.SEEN)) { 5261b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy putIntegerLongOrBoolean(ourValues, MessageColumns.FLAG_SEEN, val); 5262f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else if (columnName.equals(MessageColumns.MAILBOX_KEY)) { 5263f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank putIntegerLongOrBoolean(ourValues, MessageColumns.MAILBOX_KEY, val); 52645ed8b266a480ea413264abdb5042c58b29175df8Paul Westbrook } else if (columnName.equals(UIProvider.ConversationOperations.FOLDERS_UPDATED)) { 52655ed8b266a480ea413264abdb5042c58b29175df8Paul Westbrook // Skip this column, as the folders will also be specified the RAW_FOLDERS column 5266f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else if (columnName.equals(UIProvider.ConversationColumns.RAW_FOLDERS)) { 5267709b4633eda47f81a689c3be623660d74cdad904Mindy Pereira // Convert from folder list uri to mailbox key 526868a3607895963854637215a405145f190d6458f0Andy Huang final FolderList flist = FolderList.fromBlob(values.getAsByteArray(columnName)); 526968a3607895963854637215a405145f190d6458f0Andy Huang if (flist.folders.size() != 1) { 527068a3607895963854637215a405145f190d6458f0Andy Huang LogUtils.e(TAG, 527134d8a139ce9c7eb72ec92ba6861353f221301330Mindy Pereira "Incorrect number of folders for this message: Message is %s", 527234d8a139ce9c7eb72ec92ba6861353f221301330Mindy Pereira message.mId); 527334d8a139ce9c7eb72ec92ba6861353f221301330Mindy Pereira } else { 527468a3607895963854637215a405145f190d6458f0Andy Huang final Folder f = flist.folders.get(0); 5275281c6365fb95037ca284dd8c910538639e8b3dcbScott Kennedy final Uri uri = f.folderUri.fullUri; 527668a3607895963854637215a405145f190d6458f0Andy Huang final Long mailboxId = Long.parseLong(uri.getLastPathSegment()); 5277709b4633eda47f81a689c3be623660d74cdad904Mindy Pereira putIntegerLongOrBoolean(ourValues, MessageColumns.MAILBOX_KEY, mailboxId); 5278709b4633eda47f81a689c3be623660d74cdad904Mindy Pereira } 5279f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else if (columnName.equals(UIProvider.MessageColumns.ALWAYS_SHOW_IMAGES)) { 52801fa303478c61e0d703011996e358037eef523176James Lemieux Address[] fromList = Address.fromHeader(message.mFrom); 528138f22dbf08664b885b4cf063ea665c02edfb1c32Paul Westbrook final MailPrefs mailPrefs = MailPrefs.get(getContext()); 5282f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank for (Address sender : fromList) { 528338f22dbf08664b885b4cf063ea665c02edfb1c32Paul Westbrook final String email = sender.getAddress(); 528438f22dbf08664b885b4cf063ea665c02edfb1c32Paul Westbrook mailPrefs.setDisplayImagesFromSender(email, null); 5285f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5286947911082955d00014d1eccf04cd4b157d8cd8c6Paul Westbrook } else if (columnName.equals(UIProvider.ConversationColumns.VIEWED) || 5287947911082955d00014d1eccf04cd4b157d8cd8c6Paul Westbrook columnName.equals(UIProvider.ConversationOperations.Parameters.SUPPRESS_UNDO)) { 52887f7f7e6402eec1baab6bedcb58da61369cae4097Marc Blank // Ignore for now 5289fc5aae98e7a440ef9ab015efd4934123c2c15e76Scott Kennedy } else if (UIProvider.ConversationColumns.CONVERSATION_INFO.equals(columnName)) { 5290fc5aae98e7a440ef9ab015efd4934123c2c15e76Scott Kennedy // Email's conversation info is generated, not stored, so just ignore this update 5291f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 5292f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank throw new IllegalArgumentException("Can't update " + columnName + " in message"); 5293f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5294f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5295f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return ourValues; 5296f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5297f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5298b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static Uri convertToEmailProviderUri(Uri uri, Uri newBaseUri, boolean asProvider) { 52995ed8b266a480ea413264abdb5042c58b29175df8Paul Westbrook final String idString = uri.getLastPathSegment(); 5300f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank try { 53015ed8b266a480ea413264abdb5042c58b29175df8Paul Westbrook final long id = Long.parseLong(idString); 5302f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Uri ourUri = ContentUris.withAppendedId(newBaseUri, id); 5303f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (asProvider) { 5304f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ourUri = ourUri.buildUpon().appendQueryParameter(IS_UIPROVIDER, "true").build(); 5305f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5306f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return ourUri; 5307f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } catch (NumberFormatException e) { 5308f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return null; 5309f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5310f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5311f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5312f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private Message getMessageFromLastSegment(Uri uri) { 5313f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank long messageId = Long.parseLong(uri.getLastPathSegment()); 5314f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return Message.restoreMessageWithId(getContext(), messageId); 5315f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5316f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5317f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 5318f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Add an undo operation for the current sequence; if the sequence is newer than what we've had, 5319f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * clear out the undo list and start over 5320f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param uri the uri we're working on 5321f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param op the ContentProviderOperation to perform upon undo 5322f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 5323f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private void addToSequence(Uri uri, ContentProviderOperation op) { 5324f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank String sequenceString = uri.getQueryParameter(UIProvider.SEQUENCE_QUERY_PARAMETER); 5325f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (sequenceString != null) { 5326f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank int sequence = Integer.parseInt(sequenceString); 5327f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (sequence > mLastSequence) { 5328f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Reset sequence 5329f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mLastSequenceOps.clear(); 5330f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mLastSequence = sequence; 5331f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5332f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // TODO: Need something to indicate a change isn't ready (undoable) 5333f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mLastSequenceOps.add(op); 5334f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5335f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5336f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5337f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // TODO: This should depend on flags on the mailbox... 5338b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static boolean uploadsToServer(Context context, Mailbox m) { 5339f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (m.mType == Mailbox.TYPE_DRAFTS || m.mType == Mailbox.TYPE_OUTBOX || 5340f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank m.mType == Mailbox.TYPE_SEARCH) { 5341f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return false; 5342f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5343f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank String protocol = Account.getProtocol(context, m.mAccountKey); 5344f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank EmailServiceInfo info = EmailServiceUtils.getServiceInfo(context, protocol); 5345f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return (info != null && info.syncChanges); 5346f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5347f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5348f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private int uiUpdateMessage(Uri uri, ContentValues values) { 53497f7f7e6402eec1baab6bedcb58da61369cae4097Marc Blank return uiUpdateMessage(uri, values, false); 53507f7f7e6402eec1baab6bedcb58da61369cae4097Marc Blank } 53517f7f7e6402eec1baab6bedcb58da61369cae4097Marc Blank 53527f7f7e6402eec1baab6bedcb58da61369cae4097Marc Blank private int uiUpdateMessage(Uri uri, ContentValues values, boolean forceSync) { 5353f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Context context = getContext(); 5354f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Message msg = getMessageFromLastSegment(uri); 5355f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (msg == null) return 0; 5356f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Mailbox mailbox = Mailbox.restoreMailboxWithId(context, msg.mMailboxKey); 5357f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mailbox == null) return 0; 53587f7f7e6402eec1baab6bedcb58da61369cae4097Marc Blank Uri ourBaseUri = 53597f7f7e6402eec1baab6bedcb58da61369cae4097Marc Blank (forceSync || uploadsToServer(context, mailbox)) ? Message.SYNCED_CONTENT_URI : 53607f7f7e6402eec1baab6bedcb58da61369cae4097Marc Blank Message.CONTENT_URI; 5361f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Uri ourUri = convertToEmailProviderUri(uri, ourBaseUri, true); 5362f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (ourUri == null) return 0; 5363f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5364f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Special case - meeting response 5365f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (values.containsKey(UIProvider.MessageOperations.RESPOND_COLUMN)) { 53662075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu final EmailServiceProxy service = 53672075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu EmailServiceUtils.getServiceForAccount(context, mailbox.mAccountKey); 5368f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank try { 5369f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank service.sendMeetingResponse(msg.mId, 5370f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.getAsInteger(UIProvider.MessageOperations.RESPOND_COLUMN)); 5371f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Delete the message immediately 5372f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank uiDeleteMessage(uri); 5373f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Utility.showToast(context, R.string.confirm_response); 5374f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Notify box has changed so the deletion is reflected in the UI 5375f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUIConversationMailbox(mailbox.mId); 5376f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } catch (RemoteException e) { 53779e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler LogUtils.d(TAG, "Remote exception while sending meeting response"); 5378f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5379f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return 1; 5380f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5381f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 53826edccbf1f1371157cfa6e503d8353a474aafd2a1Yu Ping Hu // Another special case - deleting a draft. 53836edccbf1f1371157cfa6e503d8353a474aafd2a1Yu Ping Hu final String operation = values.getAsString( 53846edccbf1f1371157cfa6e503d8353a474aafd2a1Yu Ping Hu UIProvider.ConversationOperations.OPERATION_KEY); 538599e882e22d92f4d359c71b5affdff33119f13163Jin Cao // TODO: for now let's just default to delete for MOVE_FAILED_TO_DRAFT operation 538699e882e22d92f4d359c71b5affdff33119f13163Jin Cao if (UIProvider.ConversationOperations.DISCARD_DRAFTS.equals(operation) || 538799e882e22d92f4d359c71b5affdff33119f13163Jin Cao UIProvider.ConversationOperations.MOVE_FAILED_TO_DRAFTS.equals(operation)) { 53886edccbf1f1371157cfa6e503d8353a474aafd2a1Yu Ping Hu uiDeleteMessage(uri); 53896edccbf1f1371157cfa6e503d8353a474aafd2a1Yu Ping Hu return 1; 53906edccbf1f1371157cfa6e503d8353a474aafd2a1Yu Ping Hu } 53916edccbf1f1371157cfa6e503d8353a474aafd2a1Yu Ping Hu 5392f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ContentValues undoValues = new ContentValues(); 5393f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ContentValues ourValues = convertUiMessageValues(msg, values); 5394f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank for (String columnName: ourValues.keySet()) { 5395f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (columnName.equals(MessageColumns.MAILBOX_KEY)) { 5396f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank undoValues.put(MessageColumns.MAILBOX_KEY, msg.mMailboxKey); 5397f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else if (columnName.equals(MessageColumns.FLAG_READ)) { 5398f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank undoValues.put(MessageColumns.FLAG_READ, msg.mFlagRead); 5399b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy } else if (columnName.equals(MessageColumns.FLAG_SEEN)) { 5400b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy undoValues.put(MessageColumns.FLAG_SEEN, msg.mFlagSeen); 5401f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else if (columnName.equals(MessageColumns.FLAG_FAVORITE)) { 5402f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank undoValues.put(MessageColumns.FLAG_FAVORITE, msg.mFlagFavorite); 5403f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5404f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 54051b8e0fa23f6e9957f0b8753dd3f5b95d3f5d98eaScott Kennedy if (undoValues.size() == 0) { 5406f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return -1; 5407f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5408c7636b8a47b39a482414cf7a9695846956add963Paul Westbrook final Boolean suppressUndo = 5409c7636b8a47b39a482414cf7a9695846956add963Paul Westbrook values.getAsBoolean(UIProvider.ConversationOperations.Parameters.SUPPRESS_UNDO); 5410582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler if (suppressUndo == null || !suppressUndo) { 5411c7636b8a47b39a482414cf7a9695846956add963Paul Westbrook final ContentProviderOperation op = 5412c7636b8a47b39a482414cf7a9695846956add963Paul Westbrook ContentProviderOperation.newUpdate(convertToEmailProviderUri( 5413c7636b8a47b39a482414cf7a9695846956add963Paul Westbrook uri, ourBaseUri, false)) 5414c7636b8a47b39a482414cf7a9695846956add963Paul Westbrook .withValues(undoValues) 5415c7636b8a47b39a482414cf7a9695846956add963Paul Westbrook .build(); 5416c7636b8a47b39a482414cf7a9695846956add963Paul Westbrook addToSequence(uri, op); 5417c7636b8a47b39a482414cf7a9695846956add963Paul Westbrook } 5418c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu 5419f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return update(ourUri, ourValues, null, null); 5420f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5421f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5422c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu /** 5423c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu * Projection for use with getting mailbox & account keys for a message. 5424c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu */ 5425c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu private static final String[] MESSAGE_KEYS_PROJECTION = 5426c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu { MessageColumns.MAILBOX_KEY, MessageColumns.ACCOUNT_KEY }; 5427c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu private static final int MESSAGE_KEYS_MAILBOX_KEY_COLUMN = 0; 5428c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu private static final int MESSAGE_KEYS_ACCOUNT_KEY_COLUMN = 1; 5429c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu 5430c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu /** 5431c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu * Notify necessary UI components in response to a message update. 5432c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu * @param uri The {@link Uri} for this message update. 5433c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu * @param messageId The id of the message that's been updated. 5434c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu * @param values The {@link ContentValues} that were updated in the message. 5435c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu */ 5436c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu private void handleMessageUpdateNotifications(final Uri uri, final String messageId, 5437c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu final ContentValues values) { 5438c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu if (!uri.getBooleanQueryParameter(IS_UIPROVIDER, false)) { 5439c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu notifyUIConversation(uri); 5440c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } 544162604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler notifyUIMessage(messageId); 5442c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu // TODO: Ideally, also test that the values actually changed. 5443c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu if (values.containsKey(MessageColumns.FLAG_READ) || 5444c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu values.containsKey(MessageColumns.MAILBOX_KEY)) { 5445c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu final Cursor c = query( 5446c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu Message.CONTENT_URI.buildUpon().appendEncodedPath(messageId).build(), 5447c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu MESSAGE_KEYS_PROJECTION, null, null, null); 5448c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu if (c != null) { 5449c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu try { 5450c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu if (c.moveToFirst()) { 5451c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu notifyUIFolder(c.getLong(MESSAGE_KEYS_MAILBOX_KEY_COLUMN), 5452c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu c.getLong(MESSAGE_KEYS_ACCOUNT_KEY_COLUMN)); 5453c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } 5454c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } finally { 5455c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu c.close(); 5456c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } 5457c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } 5458c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } 5459c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu } 5460c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu 54619e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler /** 54629e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler * Perform a "Delete" operation 54639e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler * @param uri message to delete 54649e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler * @return number of rows affected 54659e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler */ 5466f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private int uiDeleteMessage(Uri uri) { 5467c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank final Context context = getContext(); 5468f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Message msg = getMessageFromLastSegment(uri); 5469f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (msg == null) return 0; 5470f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Mailbox mailbox = Mailbox.restoreMailboxWithId(context, msg.mMailboxKey); 5471f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mailbox == null) return 0; 5472f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mailbox.mType == Mailbox.TYPE_TRASH || mailbox.mType == Mailbox.TYPE_DRAFTS) { 5473f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // We actually delete these, including attachments 5474f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank AttachmentUtilities.deleteAllAttachmentFiles(context, msg.mAccountKey, msg.mId); 54759e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler final int r = context.getContentResolver().delete( 5476c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg.mId), null, null); 54779e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler notifyUIFolder(mailbox.mId, mailbox.mAccountKey); 5478d17359c2b4e39baa426c7bce09f1a5d293378c77Tony Mantler notifyUIMessage(msg.mId); 54799e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler return r; 5480f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5481f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Mailbox trashMailbox = 5482f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Mailbox.restoreMailboxOfType(context, msg.mAccountKey, Mailbox.TYPE_TRASH); 5483c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank if (trashMailbox == null) { 5484c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank return 0; 5485c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } 5486f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ContentValues values = new ContentValues(); 5487f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank values.put(MessageColumns.MAILBOX_KEY, trashMailbox.mId); 54889e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler final int r = uiUpdateMessage(uri, values, true); 5489fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu notifyUIFolder(mailbox.mId, mailbox.mAccountKey); 5490d17359c2b4e39baa426c7bce09f1a5d293378c77Tony Mantler notifyUIMessage(msg.mId); 54919e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler return r; 5492f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5493f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5494e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler /** 5495e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler * Hard delete all synced messages in a particular mailbox 5496e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler * @param uri Mailbox to empty (Trash, or maybe Spam/Junk later) 5497e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler * @return number of rows affected 5498e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler */ 5499e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler private int uiPurgeFolder(Uri uri) { 5500e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler final Context context = getContext(); 5501e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler final long mailboxId = Long.parseLong(uri.getLastPathSegment()); 5502e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler final SQLiteDatabase db = getDatabase(context); 5503e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler 5504e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler // Find the account ID (needed in a few calls) 5505e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler final Cursor mailboxCursor = db.query( 5506e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler Mailbox.TABLE_NAME, new String[] { MailboxColumns.ACCOUNT_KEY }, 55073dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler Mailbox._ID + "=" + mailboxId, null, null, null, null); 5508e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler if (mailboxCursor == null || !mailboxCursor.moveToFirst()) { 5509e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler LogUtils.wtf(LogUtils.TAG, "Null or empty cursor when trying to purge mailbox %d", 5510e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler mailboxId); 5511e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler return 0; 5512e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler } 5513e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler final long accountId = mailboxCursor.getLong(mailboxCursor.getColumnIndex( 5514e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler MailboxColumns.ACCOUNT_KEY)); 5515e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler 5516e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler // Find all the messages in the mailbox 5517e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler final String[] messageProjection = 55183dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler new String[] { MessageColumns._ID }; 5519e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler final String messageWhere = MessageColumns.MAILBOX_KEY + "=" + mailboxId; 5520e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler final Cursor messageCursor = db.query(Message.TABLE_NAME, messageProjection, messageWhere, 5521e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler null, null, null, null); 5522e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler int deletedCount = 0; 5523e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler 5524e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler // Kill them with fire 5525e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler while (messageCursor != null && messageCursor.moveToNext()) { 5526e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler final long messageId = messageCursor.getLong(messageCursor.getColumnIndex( 55273dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler MessageColumns._ID)); 5528e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler AttachmentUtilities.deleteAllAttachmentFiles(context, accountId, messageId); 5529e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler deletedCount += context.getContentResolver().delete( 5530e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, messageId), null, null); 5531e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler notifyUIMessage(messageId); 5532e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler } 5533e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler 5534e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler notifyUIFolder(mailboxId, accountId); 5535e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler return deletedCount; 5536e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler } 5537e8c4c2226878eb21f958cf7d065e8e5d11df7bf7Tony Mantler 55389e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler public static final String PICKER_UI_ACCOUNT = "picker_ui_account"; 55399e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler public static final String PICKER_MAILBOX_TYPE = "picker_mailbox_type"; 55409e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler // Currently unused 55419e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler //public static final String PICKER_MESSAGE_ID = "picker_message_id"; 55429e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler public static final String PICKER_HEADER_ID = "picker_header_id"; 55439e9caaee7c20c538b00f791e54d5d2744c17c1efTony Mantler 5544a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank private int pickFolder(Uri uri, int type, int headerId) { 5545c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank Context context = getContext(); 5546c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank Long acctId = Long.parseLong(uri.getLastPathSegment()); 5547c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank // For push imap, for example, we want the user to select the trash mailbox 5548c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank Cursor ac = query(uiUri("uiaccount", acctId), UIProvider.ACCOUNTS_PROJECTION, 5549c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank null, null, null); 5550c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank try { 5551c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank if (ac.moveToFirst()) { 5552c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank final com.android.mail.providers.Account uiAccount = 55537e75afadb152659e3a237c62e4d95cefb60e228dRay Chen com.android.mail.providers.Account.builder().buildFrom(ac); 5554c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank Intent intent = new Intent(context, FolderPickerActivity.class); 5555c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank intent.putExtra(PICKER_UI_ACCOUNT, uiAccount); 5556a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank intent.putExtra(PICKER_MAILBOX_TYPE, type); 5557a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank intent.putExtra(PICKER_HEADER_ID, headerId); 5558c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 5559c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank context.startActivity(intent); 5560c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank return 1; 5561c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } 5562c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank return 0; 5563c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } finally { 5564c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank ac.close(); 5565c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } 5566c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank } 5567c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank 5568a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank private int pickTrashFolder(Uri uri) { 5569a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank return pickFolder(uri, Mailbox.TYPE_TRASH, R.string.trash_folder_selection_title); 5570a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank } 5571a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank 5572a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank private int pickSentFolder(Uri uri) { 5573a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank return pickFolder(uri, Mailbox.TYPE_SENT, R.string.sent_folder_selection_title); 5574a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank } 5575a8b683cf3f2efe726220c0235368cf6ea899e3baMarc Blank 5576f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private Cursor uiUndo(String[] projection) { 5577f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // First see if we have any operations saved 5578f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // TODO: Make sure seq matches 5579f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (!mLastSequenceOps.isEmpty()) { 5580f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank try { 5581f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // TODO Always use this projection? Or what's passed in? 5582f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Not sure if UI wants it, but I'm making a cursor of convo uri's 55837fdde9bb4a24e931618a7a64227e2194c89034daScott Kennedy MatrixCursor c = new MatrixCursorWithCachedColumns( 5584f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank new String[] {UIProvider.ConversationColumns.URI}, 5585f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mLastSequenceOps.size()); 5586f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank for (ContentProviderOperation op: mLastSequenceOps) { 5587f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c.addRow(new String[] {op.getUri().toString()}); 5588f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5589f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Just apply the batch and we're done! 5590f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank applyBatch(mLastSequenceOps); 5591f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // But clear the operations 5592f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mLastSequenceOps.clear(); 5593f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return c; 5594f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } catch (OperationApplicationException e) { 5595582bc439ea4a7b9a965af50361504b68fc542896Tony Mantler LogUtils.d(TAG, "applyBatch exception"); 5596f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5597f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 55987fdde9bb4a24e931618a7a64227e2194c89034daScott Kennedy return new MatrixCursorWithCachedColumns(projection, 0); 5599f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5600f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5601f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private void notifyUIConversation(Uri uri) { 5602f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank String id = uri.getLastPathSegment(); 5603f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Message msg = Message.restoreMessageWithId(getContext(), Long.parseLong(id)); 5604f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (msg != null) { 5605f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUIConversationMailbox(msg.mMailboxKey); 5606f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5607f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5608f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5609f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 5610f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Notify about the Mailbox id passed in 5611f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @param id the Mailbox id to be notified 5612f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 5613f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private void notifyUIConversationMailbox(long id) { 5614f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUI(UIPROVIDER_CONVERSATION_NOTIFIER, Long.toString(id)); 5615f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Mailbox mailbox = Mailbox.restoreMailboxWithId(getContext(), id); 56160b6b83c6f90652b506c7761b923663c08f3af833Marc Blank if (mailbox == null) { 5617560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.w(TAG, "No mailbox for notification: " + id); 56180b6b83c6f90652b506c7761b923663c08f3af833Marc Blank return; 56190b6b83c6f90652b506c7761b923663c08f3af833Marc Blank } 5620f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Notify combined inbox... 5621f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mailbox.mType == Mailbox.TYPE_INBOX) { 5622f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUI(UIPROVIDER_CONVERSATION_NOTIFIER, 5623f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank EmailProvider.combinedMailboxId(Mailbox.TYPE_INBOX)); 5624f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5625f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyWidgets(id); 5626f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5627f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 56283e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook /** 5629c637bff1989e768f1ffe0f898bd803a9c78d0514Tony Mantler * Notify about the message id passed in 5630c637bff1989e768f1ffe0f898bd803a9c78d0514Tony Mantler * @param id the message id to be notified 5631c637bff1989e768f1ffe0f898bd803a9c78d0514Tony Mantler */ 5632c637bff1989e768f1ffe0f898bd803a9c78d0514Tony Mantler private void notifyUIMessage(long id) { 5633c637bff1989e768f1ffe0f898bd803a9c78d0514Tony Mantler notifyUI(UIPROVIDER_MESSAGE_NOTIFIER, id); 5634c637bff1989e768f1ffe0f898bd803a9c78d0514Tony Mantler } 5635c637bff1989e768f1ffe0f898bd803a9c78d0514Tony Mantler 5636c637bff1989e768f1ffe0f898bd803a9c78d0514Tony Mantler /** 563762604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler * Notify about the message id passed in 563862604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler * @param id the message id to be notified 563962604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler */ 564062604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler private void notifyUIMessage(String id) { 564162604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler notifyUI(UIPROVIDER_MESSAGE_NOTIFIER, id); 564262604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler } 564362604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler 564462604b1a4438e655ff9e21c5363fca9ad4700ebbTony Mantler /** 56453e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook * Notify about the Account id passed in 56463e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook * @param id the Account id to be notified 56473e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook */ 56483e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook private void notifyUIAccount(long id) { 56493e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook // Notify on the specific account 56503e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook notifyUI(UIPROVIDER_ACCOUNT_NOTIFIER, Long.toString(id)); 56513e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook 56523e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook // Notify on the all accounts list 56533e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook notifyUI(UIPROVIDER_ALL_ACCOUNTS_NOTIFIER, null); 56543e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook } 56553e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook 5656e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler // TODO: temporary workaround for ConversationCursor 5657e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler @Deprecated 5658e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler private static final int NOTIFY_FOLDER_LOOP_MESSAGE_ID = 0; 5659e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler @Deprecated 5660e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler private Handler mFolderNotifierHandler; 5661e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler 5662fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu /** 5663fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu * Notify about a folder update. Because folder changes can affect the conversation cursor's 5664fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu * extras, the conversation must also be notified here. 5665fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu * @param folderId the folder id to be notified 5666c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu * @param accountId the account id to be notified (for folder list notification). 5667fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu */ 5668c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu private void notifyUIFolder(final String folderId, final long accountId) { 5669fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu notifyUI(UIPROVIDER_CONVERSATION_NOTIFIER, folderId); 5670fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu notifyUI(UIPROVIDER_FOLDER_NOTIFIER, folderId); 5671c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu if (accountId != Account.NO_ACCOUNT) { 5672fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu notifyUI(UIPROVIDER_FOLDERLIST_NOTIFIER, accountId); 5673fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu } 5674fc906340f9a3ef0246f4d693f0a2afc15af8cd6cTony Mantler 5675fc906340f9a3ef0246f4d693f0a2afc15af8cd6cTony Mantler // Notify for combined account too 5676fc906340f9a3ef0246f4d693f0a2afc15af8cd6cTony Mantler // TODO: might be nice to only notify when an inbox changes 5677fc906340f9a3ef0246f4d693f0a2afc15af8cd6cTony Mantler notifyUI(UIPROVIDER_FOLDER_NOTIFIER, 5678fc906340f9a3ef0246f4d693f0a2afc15af8cd6cTony Mantler getVirtualMailboxId(COMBINED_ACCOUNT_ID, Mailbox.TYPE_INBOX)); 5679fc906340f9a3ef0246f4d693f0a2afc15af8cd6cTony Mantler notifyUI(UIPROVIDER_FOLDERLIST_NOTIFIER, COMBINED_ACCOUNT_ID); 5680e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler 5681e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler // TODO: temporary workaround for ConversationCursor 5682e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler synchronized (this) { 5683e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler if (mFolderNotifierHandler == null) { 5684e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler mFolderNotifierHandler = new Handler(Looper.getMainLooper(), 5685e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler new Callback() { 5686e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler @Override 5687e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler public boolean handleMessage(final android.os.Message message) { 5688e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler final String folderId = (String) message.obj; 5689e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler LogUtils.d(TAG, "Notifying conversation Uri %s twice", folderId); 5690e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler notifyUI(UIPROVIDER_CONVERSATION_NOTIFIER, folderId); 5691e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler return true; 5692e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler } 5693e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler }); 5694e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler } 5695e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler } 5696e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler mFolderNotifierHandler.removeMessages(NOTIFY_FOLDER_LOOP_MESSAGE_ID); 5697e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler android.os.Message message = android.os.Message.obtain(mFolderNotifierHandler, 5698e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler NOTIFY_FOLDER_LOOP_MESSAGE_ID); 5699e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler message.obj = folderId; 5700e12b22148fec2d8ec3ee2504b43cf8b0d9a780e7Tony Mantler mFolderNotifierHandler.sendMessageDelayed(message, 2000); 5701fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu } 5702fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu 5703c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu private void notifyUIFolder(final long folderId, final long accountId) { 5704c3ceed68948ef6720ae7b861955b4d341f331643Yu Ping Hu notifyUIFolder(Long.toString(folderId), accountId); 5705fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu } 5706fc0dae9cd74d6edb22464f3a0721a82f0b5f9893Yu Ping Hu 570705649dca2f59f28cd4295e041045a605badddb15Tony Mantler private void notifyUI(final Uri uri, final String id) { 57083e2fdd33e32599c8b7e817c2ca00d50ee3bba7bfPaul Westbrook final Uri notifyUri = (id != null) ? uri.buildUpon().appendPath(id).build() : uri; 570900219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler final Set<Uri> batchNotifications = getBatchNotificationsSet(); 571000219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler if (batchNotifications != null) { 571100219e9fb952a3efc08340bcbcad9d396413e076Tony Mantler batchNotifications.add(notifyUri); 571205649dca2f59f28cd4295e041045a605badddb15Tony Mantler } else { 571305649dca2f59f28cd4295e041045a605badddb15Tony Mantler getContext().getContentResolver().notifyChange(notifyUri, null); 571405649dca2f59f28cd4295e041045a605badddb15Tony Mantler } 5715f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5716f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5717f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private void notifyUI(Uri uri, long id) { 5718f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank notifyUI(uri, Long.toString(id)); 5719f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5720f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 572164cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu private Mailbox getMailbox(final Uri uri) { 572264cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu final long id = Long.parseLong(uri.getLastPathSegment()); 572364cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu return Mailbox.restoreMailboxWithId(getContext(), id); 572464cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu } 572564cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu 5726e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu /** 5727e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu * Create an android.accounts.Account object for this account. 5728e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu * @param accountId id of account to load. 5729e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu * @return an android.accounts.Account for this account, or null if we can't load it. 5730e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu */ 5731e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu private android.accounts.Account getAccountManagerAccount(final long accountId) { 5732e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu final Context context = getContext(); 5733e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu final Account account = Account.restoreAccountWithId(context, accountId); 5734e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu if (account == null) return null; 57355e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu return getAccountManagerAccount(context, account.mEmailAddress, 57365e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu account.getProtocol(context)); 57375e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 57385e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu 57395e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu /** 57405e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * Create an android.accounts.Account object for an emailAddress/protocol pair. 57415e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param context A {@link Context}. 57425e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param emailAddress The email address we're interested in. 57435e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param protocol The protocol we're intereted in. 57445e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @return an {@link android.accounts.Account} for this info. 57455e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu */ 57465e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private static android.accounts.Account getAccountManagerAccount(final Context context, 57475e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu final String emailAddress, final String protocol) { 57485e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu final EmailServiceInfo info = EmailServiceUtils.getServiceInfo(context, protocol); 574991e8e6f70921e65eabf128f14b5d43385b22f0a1Tony Mantler if (info == null) { 575091e8e6f70921e65eabf128f14b5d43385b22f0a1Tony Mantler return null; 575191e8e6f70921e65eabf128f14b5d43385b22f0a1Tony Mantler } 57525e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu return new android.accounts.Account(emailAddress, info.accountType); 5753e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu } 5754e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu 5755e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu /** 5756e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu * Update an account's periodic sync if the sync interval has changed. 5757e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu * @param accountId id for the account to update. 5758e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu * @param values the ContentValues for this update to the account. 5759e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu */ 5760e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu private void updateAccountSyncInterval(final long accountId, final ContentValues values) { 5761e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu final Integer syncInterval = values.getAsInteger(AccountColumns.SYNC_INTERVAL); 5762e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu if (syncInterval == null) { 5763e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu // No change to the sync interval. 5764e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu return; 5765e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu } 5766e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu final android.accounts.Account account = getAccountManagerAccount(accountId); 5767e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu if (account == null) { 5768e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu // Unable to load the account, or unknown protocol. 5769e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu return; 5770e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu } 5771e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu 57727afbeee47e1a82680c815f2fb8cfdba32d6b0b84Martin Hibdon LogUtils.d(TAG, "Setting sync interval for account %s to %d minutes", 57737afbeee47e1a82680c815f2fb8cfdba32d6b0b84Martin Hibdon accountId, syncInterval); 5774e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu 57756f2beeb59ae75ee26c78d99ded532acd87e1ff97Yu Ping Hu // First remove all existing periodic syncs. 57766f2beeb59ae75ee26c78d99ded532acd87e1ff97Yu Ping Hu final List<PeriodicSync> syncs = 57776f2beeb59ae75ee26c78d99ded532acd87e1ff97Yu Ping Hu ContentResolver.getPeriodicSyncs(account, EmailContent.AUTHORITY); 57786f2beeb59ae75ee26c78d99ded532acd87e1ff97Yu Ping Hu for (final PeriodicSync sync : syncs) { 57796f2beeb59ae75ee26c78d99ded532acd87e1ff97Yu Ping Hu ContentResolver.removePeriodicSync(account, EmailContent.AUTHORITY, sync.extras); 57806f2beeb59ae75ee26c78d99ded532acd87e1ff97Yu Ping Hu } 5781e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu 578205cf8a1c1f9b13aff75ec9e5c300fbf5c7aee27fYu Ping Hu // Only positive values of sync interval indicate periodic syncs. The value is in minutes, 578305cf8a1c1f9b13aff75ec9e5c300fbf5c7aee27fYu Ping Hu // while addPeriodicSync expects its time in seconds. 578405cf8a1c1f9b13aff75ec9e5c300fbf5c7aee27fYu Ping Hu if (syncInterval > 0) { 578505cf8a1c1f9b13aff75ec9e5c300fbf5c7aee27fYu Ping Hu ContentResolver.addPeriodicSync(account, EmailContent.AUTHORITY, Bundle.EMPTY, 578605cf8a1c1f9b13aff75ec9e5c300fbf5c7aee27fYu Ping Hu syncInterval * DateUtils.MINUTE_IN_MILLIS / DateUtils.SECOND_IN_MILLIS); 5787e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu } 5788e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu } 5789e669f28b0866e66c629103698ad14b22a204442fYu Ping Hu 57905e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu /** 57915e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * Request a sync. 57925e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param account The {@link android.accounts.Account} we want to sync. 57935e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param mailboxId The mailbox id we want to sync (or one of the special constants in 57945e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * {@link Mailbox}). 57955e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param deltaMessageCount If we're requesting a load more, the number of additional messages 57965e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * to sync. 57975e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu */ 57985e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private static void startSync(final android.accounts.Account account, final long mailboxId, 57995e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu final int deltaMessageCount) { 580056aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon final Bundle extras = Mailbox.createSyncBundle(mailboxId); 58019e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); 58029e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu extras.putBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, true); 58039e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu extras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true); 58049e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu if (deltaMessageCount != 0) { 58059e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu extras.putInt(Mailbox.SYNC_EXTRA_DELTA_MESSAGE_COUNT, deltaMessageCount); 58069e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu } 580771737836e6be308f752cb95c955a03146b039a9cYu Ping Hu extras.putString(EmailServiceStatus.SYNC_EXTRAS_CALLBACK_URI, 580871737836e6be308f752cb95c955a03146b039a9cYu Ping Hu EmailContent.CONTENT_URI.toString()); 580971737836e6be308f752cb95c955a03146b039a9cYu Ping Hu extras.putString(EmailServiceStatus.SYNC_EXTRAS_CALLBACK_METHOD, 581071737836e6be308f752cb95c955a03146b039a9cYu Ping Hu SYNC_STATUS_CALLBACK_METHOD); 58119e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu ContentResolver.requestSync(account, EmailContent.AUTHORITY, extras); 5812921c04d2ac5df091fb3c5cfa823e6dc2fc6cdf5aMartin Hibdon LogUtils.i(TAG, "requestSync EmailProvider startSync %s, %s", account.toString(), 5813921c04d2ac5df091fb3c5cfa823e6dc2fc6cdf5aMartin Hibdon extras.toString()); 58149e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu } 58159e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu 58165e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu /** 58175e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * Request a sync. 58185e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param mailbox The {@link Mailbox} we want to sync. 58195e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param deltaMessageCount If we're requesting a load more, the number of additional messages 58205e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * to sync. 58215e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu */ 58225e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private void startSync(final Mailbox mailbox, final int deltaMessageCount) { 58235e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu final android.accounts.Account account = getAccountManagerAccount(mailbox.mAccountKey); 582491e8e6f70921e65eabf128f14b5d43385b22f0a1Tony Mantler if (account != null) { 582591e8e6f70921e65eabf128f14b5d43385b22f0a1Tony Mantler startSync(account, mailbox.mId, deltaMessageCount); 582691e8e6f70921e65eabf128f14b5d43385b22f0a1Tony Mantler } 58275e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 58285e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu 58295e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu /** 58305e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * Restart any push operations for an account. 58315e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu * @param account The {@link android.accounts.Account} we're interested in. 58325e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu */ 58335e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu private static void restartPush(final android.accounts.Account account) { 583456aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon final Bundle extras = new Bundle(); 583556aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); 583656aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon extras.putBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, true); 583756aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon extras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true); 583856aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon extras.putBoolean(Mailbox.SYNC_EXTRA_PUSH_ONLY, true); 583956aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon extras.putString(EmailServiceStatus.SYNC_EXTRAS_CALLBACK_URI, 584056aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon EmailContent.CONTENT_URI.toString()); 584156aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon extras.putString(EmailServiceStatus.SYNC_EXTRAS_CALLBACK_METHOD, 584256aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon SYNC_STATUS_CALLBACK_METHOD); 584356aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon ContentResolver.requestSync(account, EmailContent.AUTHORITY, extras); 584456aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon LogUtils.i(TAG, "requestSync EmailProvider startSync %s, %s", account.toString(), 584556aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon extras.toString()); 58465e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu } 58475e8d8c1f80951fdb49e64bc123283e7914af07d1Yu Ping Hu 584864cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu private Cursor uiFolderRefresh(final Mailbox mailbox, final int deltaMessageCount) { 58499e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu if (mailbox != null) { 58508c989772dfba08438650575f1ac2bb952bd56158Alon Albert RefreshStatusMonitor.getInstance(getContext()) 58518c989772dfba08438650575f1ac2bb952bd56158Alon Albert .monitorRefreshStatus(mailbox.mId, new RefreshStatusMonitor.Callback() { 58528c989772dfba08438650575f1ac2bb952bd56158Alon Albert @Override 58538c989772dfba08438650575f1ac2bb952bd56158Alon Albert public void onRefreshCompleted(long mailboxId, int result) { 585440236a89316ab2151a8c93de0e286c2f1a9a8d37James Lemieux // all calls to this method assumed to be started by a user action 585540236a89316ab2151a8c93de0e286c2f1a9a8d37James Lemieux final int syncValue = UIProvider.createSyncValue(EmailContent.SYNC_STATUS_USER, 585640236a89316ab2151a8c93de0e286c2f1a9a8d37James Lemieux result); 58578c989772dfba08438650575f1ac2bb952bd56158Alon Albert final ContentValues values = new ContentValues(); 58588c989772dfba08438650575f1ac2bb952bd56158Alon Albert values.put(Mailbox.UI_SYNC_STATUS, UIProvider.SyncStatus.NO_SYNC); 585940236a89316ab2151a8c93de0e286c2f1a9a8d37James Lemieux values.put(Mailbox.UI_LAST_SYNC_RESULT, syncValue); 586040236a89316ab2151a8c93de0e286c2f1a9a8d37James Lemieux mDatabase.update(Mailbox.TABLE_NAME, values, WHERE_ID, 58618c989772dfba08438650575f1ac2bb952bd56158Alon Albert new String[] { String.valueOf(mailboxId) }); 58628c989772dfba08438650575f1ac2bb952bd56158Alon Albert notifyUIFolder(mailbox.mId, mailbox.mAccountKey); 58638c989772dfba08438650575f1ac2bb952bd56158Alon Albert } 58648c989772dfba08438650575f1ac2bb952bd56158Alon Albert 58658c989772dfba08438650575f1ac2bb952bd56158Alon Albert @Override 58668c989772dfba08438650575f1ac2bb952bd56158Alon Albert public void onTimeout(long mailboxId) { 58678c989772dfba08438650575f1ac2bb952bd56158Alon Albert // todo 58688c989772dfba08438650575f1ac2bb952bd56158Alon Albert } 58698c989772dfba08438650575f1ac2bb952bd56158Alon Albert }); 58709e7f5a2a33a31ff392d3116f6432b2f93ffe8e71Yu Ping Hu startSync(mailbox, deltaMessageCount); 5871f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5872f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return null; 5873f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5874f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5875f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank //Number of additional messages to load when a user selects "Load more..." in POP/IMAP boxes 5876f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank public static final int VISIBLE_LIMIT_INCREMENT = 10; 5877f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank //Number of additional messages to load when a user selects "Load more..." in a search 5878f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank public static final int SEARCH_MORE_INCREMENT = 10; 5879f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 588064cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu private Cursor uiFolderLoadMore(final Mailbox mailbox) { 5881f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mailbox == null) return null; 5882f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mailbox.mType == Mailbox.TYPE_SEARCH) { 5883f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Ask for 10 more messages 5884f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mSearchParams.mOffset += SEARCH_MORE_INCREMENT; 588564cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu runSearchQuery(getContext(), mailbox.mAccountKey, mailbox.mId); 5886f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 588764cc777f8b3f01fad0b14ad4277d85b7dcfdcd73Yu Ping Hu uiFolderRefresh(mailbox, VISIBLE_LIMIT_INCREMENT); 5888f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5889f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return null; 5890f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5891f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5892f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String SEARCH_MAILBOX_SERVER_ID = "__search_mailbox__"; 5893f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private SearchParams mSearchParams; 5894f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5895f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 5896f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Returns the search mailbox for the specified account, creating one if necessary 5897f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * @return the search mailbox for the passed in account 5898f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 5899f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private Mailbox getSearchMailbox(long accountId) { 5900f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Context context = getContext(); 5901f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Mailbox m = Mailbox.restoreMailboxOfType(context, accountId, Mailbox.TYPE_SEARCH); 5902f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (m == null) { 5903f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank m = new Mailbox(); 5904f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank m.mAccountKey = accountId; 5905f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank m.mServerId = SEARCH_MAILBOX_SERVER_ID; 5906f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank m.mFlagVisible = false; 5907f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank m.mDisplayName = SEARCH_MAILBOX_SERVER_ID; 5908a54ee609cdb79ad3abdda2d7180a29617fa38610Yu Ping Hu m.mSyncInterval = 0; 5909f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank m.mType = Mailbox.TYPE_SEARCH; 5910f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank m.mFlags = Mailbox.FLAG_HOLDS_MAIL; 5911f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank m.mParentKey = Mailbox.NO_MAILBOX; 5912f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank m.save(context); 5913f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5914f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return m; 5915f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5916f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5917f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private void runSearchQuery(final Context context, final long accountId, 5918f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final long searchMailboxId) { 59199d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook LogUtils.d(TAG, "runSearchQuery. account: %d mailbox id: %d", 59209d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook accountId, searchMailboxId); 59219d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook 5922f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Start the search running in the background 59239d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook new AsyncTask<Void, Void, Void>() { 5924f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank @Override 59259d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook public Void doInBackground(Void... params) { 59262075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu final EmailServiceProxy service = 59272075c97f608a853923980865b72147a5c8ef71f0Yu Ping Hu EmailServiceUtils.getServiceForAccount(context, accountId); 59289d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook if (service != null) { 59299d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook try { 59305d47ee0f87208ab22c317abc87f615b6254cc852Tony Mantler final int totalCount = 59319d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook service.searchMessages(accountId, mSearchParams, searchMailboxId); 59325d47ee0f87208ab22c317abc87f615b6254cc852Tony Mantler 59335d47ee0f87208ab22c317abc87f615b6254cc852Tony Mantler // Save away the total count 59345d47ee0f87208ab22c317abc87f615b6254cc852Tony Mantler final ContentValues cv = new ContentValues(1); 59355d47ee0f87208ab22c317abc87f615b6254cc852Tony Mantler cv.put(MailboxColumns.TOTAL_COUNT, totalCount); 59365d47ee0f87208ab22c317abc87f615b6254cc852Tony Mantler update(ContentUris.withAppendedId(Mailbox.CONTENT_URI, searchMailboxId), cv, 59375d47ee0f87208ab22c317abc87f615b6254cc852Tony Mantler null, null); 59389d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook LogUtils.d(TAG, "EmailProvider#runSearchQuery. TotalCount to UI: %d", 59395d47ee0f87208ab22c317abc87f615b6254cc852Tony Mantler totalCount); 59409d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook } catch (RemoteException e) { 5941560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.e("searchMessages", "RemoteException", e); 5942f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5943f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 59449d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook return null; 59459d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook } 59469d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 5947f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5948f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 59497dad461e9e0c17bc909da2afbd8023cf7059d931Martin Hibdon // This handles an initial search query. More results are loaded using uiFolderLoadMore. 5950f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private Cursor uiSearch(Uri uri, String[] projection) { 59519d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook LogUtils.d(TAG, "runSearchQuery in search %s", uri); 5952f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final long accountId = Long.parseLong(uri.getLastPathSegment()); 5953f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5954f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // TODO: Check the actual mailbox 5955f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Mailbox inbox = Mailbox.restoreMailboxOfType(getContext(), accountId, Mailbox.TYPE_INBOX); 5956c0e2b147e09dd0bf15f19e63807b1b3bab798f50Marc Blank if (inbox == null) { 5957560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.w(Logging.LOG_TAG, "In uiSearch, inbox doesn't exist for account " 5958560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy + accountId); 59599d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook 5960c0e2b147e09dd0bf15f19e63807b1b3bab798f50Marc Blank return null; 5961c0e2b147e09dd0bf15f19e63807b1b3bab798f50Marc Blank } 5962f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5963f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank String filter = uri.getQueryParameter(UIProvider.SearchQueryParameters.QUERY); 5964f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (filter == null) { 5965f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank throw new IllegalArgumentException("No query parameter in search query"); 5966f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 5967f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5968f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Find/create our search mailbox 5969f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Mailbox searchMailbox = getSearchMailbox(accountId); 5970f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final long searchMailboxId = searchMailbox.mId; 5971f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5972f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mSearchParams = new SearchParams(inbox.mId, filter, searchMailboxId); 5973f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 5974f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final Context context = getContext(); 5975f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mSearchParams.mOffset == 0) { 59767dad461e9e0c17bc909da2afbd8023cf7059d931Martin Hibdon // TODO: This conditional is unnecessary, just two lines earlier we created 59777dad461e9e0c17bc909da2afbd8023cf7059d931Martin Hibdon // mSearchParams using a constructor that never sets mOffset. 59789d5ed9e7a8d87408eb08f3124834e69ae3d9448cPaul Westbrook LogUtils.d(TAG, "deleting existing search results."); 597900fbbb24b3777160d5ba0157ff171aa2335632d7Martin Hibdon final ContentResolver resolver = context.getContentResolver(); 598000fbbb24b3777160d5ba0157ff171aa2335632d7Martin Hibdon final ContentValues cv = new ContentValues(3); 5981f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // For now, use the actual query as the name of the mailbox 5982f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank cv.put(Mailbox.DISPLAY_NAME, mSearchParams.mFilter); 598300fbbb24b3777160d5ba0157ff171aa2335632d7Martin Hibdon // We are about to do a sync on this folder, but if the UI is refreshed before the 598400fbbb24b3777160d5ba0157ff171aa2335632d7Martin Hibdon // service can start its query, we need it to see that there is a sync in progress. 598500fbbb24b3777160d5ba0157ff171aa2335632d7Martin Hibdon // Otherwise it could show the empty state, until the service gets around to setting 598600fbbb24b3777160d5ba0157ff171aa2335632d7Martin Hibdon // the syncState. 5987f61e098a4161dd52f1d81c577520ce96b617480dMartin Hibdon cv.put(Mailbox.UI_SYNC_STATUS, EmailContent.SYNC_STATUS_LIVE); 598800fbbb24b3777160d5ba0157ff171aa2335632d7Martin Hibdon // We don't know how many result we'll have yet, but we assume zero until we get 598900fbbb24b3777160d5ba0157ff171aa2335632d7Martin Hibdon // a response back from the server. Otherwise, we'll whatever count there was on the 599000fbbb24b3777160d5ba0157ff171aa2335632d7Martin Hibdon // previous search, and we'll display the "Load More" footer prior to having 599100fbbb24b3777160d5ba0157ff171aa2335632d7Martin Hibdon // any results. 599200fbbb24b3777160d5ba0157ff171aa2335632d7Martin Hibdon cv.put(Mailbox.TOTAL_COUNT, 0); 5993f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank resolver.update(ContentUris.withAppendedId(Mailbox.CONTENT_URI, searchMailboxId), 5994f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank cv, null, null); 599500fbbb24b3777160d5ba0157ff171aa2335632d7Martin Hibdon 599600fbbb24b3777160d5ba0157ff171aa2335632d7Martin Hibdon // Delete existing contents of search mailbox 599700fbbb24b3777160d5ba0157ff171aa2335632d7Martin Hibdon resolver.delete(Message.CONTENT_URI, MessageColumns.MAILBOX_KEY + "=" + searchMailboxId, 599800fbbb24b3777160d5ba0157ff171aa2335632d7Martin Hibdon null); 5999f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6000f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 6001f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Start the search running in the background 6002f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank runSearchQuery(context, accountId, searchMailboxId); 6003f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 6004f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // This will look just like a "normal" folder 6005f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return uiQuery(UI_FOLDER, ContentUris.withAppendedId(Mailbox.CONTENT_URI, 6006b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy searchMailbox.mId), projection, false); 6007f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6008f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 6009f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private static final String MAILBOXES_FOR_ACCOUNT_SELECTION = MailboxColumns.ACCOUNT_KEY + "=?"; 6010f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 6011f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank /** 6012f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank * Delete an account and clean it up 6013f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank */ 6014f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private int uiDeleteAccount(Uri uri) { 6015f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Context context = getContext(); 6016f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank long accountId = Long.parseLong(uri.getLastPathSegment()); 6017f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank try { 6018f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Get the account URI. 6019f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final Account account = Account.restoreAccountWithId(context, accountId); 6020f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (account == null) { 6021f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return 0; // Already deleted? 6022f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6023f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 6024f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank deleteAccountData(context, accountId); 6025f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 6026f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Now delete the account itself 6027f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank uri = ContentUris.withAppendedId(Account.CONTENT_URI, accountId); 6028f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank context.getContentResolver().delete(uri, null, null); 6029f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 6030f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Clean up 6031f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank AccountBackupRestore.backup(context); 6032f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank SecurityPolicy.getInstance(context).reducePolicies(); 6033bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook setServicesEnabledSync(context); 6034a60550e0eb08e0239d1fcea261b37ba592a35ba4Yu Ping Hu // TODO: We ought to reconcile accounts here, but some callers do this in a loop, 6035a60550e0eb08e0239d1fcea261b37ba592a35ba4Yu Ping Hu // which would be a problem when the first account reconciliation shuts us down. 6036f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return 1; 6037f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } catch (Exception e) { 6038560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.w(Logging.LOG_TAG, "Exception while deleting account", e); 6039f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6040f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return 0; 6041f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6042f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 6043f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private int uiDeleteAccountData(Uri uri) { 6044f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Context context = getContext(); 6045f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank long accountId = Long.parseLong(uri.getLastPathSegment()); 6046f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Get the account URI. 6047f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank final Account account = Account.restoreAccountWithId(context, accountId); 6048f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (account == null) { 6049f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return 0; // Already deleted? 6050f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6051f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank deleteAccountData(context, accountId); 6052f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank return 1; 6053f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6054f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 60555057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux /** 6056974ccb1735e5ef697a5c4adc3f627582a03c89ecJames Lemieux * The method will no longer be needed after platform L releases. As emails are received from 60575057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux * various protocols the email addresses are decoded and intended to be stored in the database 60585057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux * in decoded form. The problem is that Exchange is a separate .apk and the old Exchange .apk 60595057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux * still attempts to store <strong>encoded</strong> email addresses. So, we decode here at the 60605057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux * Provider before writing to the database to ensure the addresses are written in decoded form. 60615057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux * 60625057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux * @param values the values to be written into the Message table 60635057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux */ 60645057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux private static void decodeEmailAddresses(ContentValues values) { 60655057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux if (values.containsKey(Message.MessageColumns.TO_LIST)) { 60665057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux final String to = values.getAsString(Message.MessageColumns.TO_LIST); 60675057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux values.put(Message.MessageColumns.TO_LIST, Address.fromHeaderToString(to)); 60685057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux } 60695057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux 60705057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux if (values.containsKey(Message.MessageColumns.FROM_LIST)) { 60715057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux final String from = values.getAsString(Message.MessageColumns.FROM_LIST); 60725057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux values.put(Message.MessageColumns.FROM_LIST, Address.fromHeaderToString(from)); 60735057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux } 60745057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux 60755057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux if (values.containsKey(Message.MessageColumns.CC_LIST)) { 60765057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux final String cc = values.getAsString(Message.MessageColumns.CC_LIST); 60775057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux values.put(Message.MessageColumns.CC_LIST, Address.fromHeaderToString(cc)); 60785057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux } 60795057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux 60805057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux if (values.containsKey(Message.MessageColumns.BCC_LIST)) { 60815057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux final String bcc = values.getAsString(Message.MessageColumns.BCC_LIST); 60825057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux values.put(Message.MessageColumns.BCC_LIST, Address.fromHeaderToString(bcc)); 60835057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux } 60845057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux 60855057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux if (values.containsKey(Message.MessageColumns.REPLY_TO_LIST)) { 60865057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux final String replyTo = values.getAsString(Message.MessageColumns.REPLY_TO_LIST); 60875057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux values.put(Message.MessageColumns.REPLY_TO_LIST, 60885057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux Address.fromHeaderToString(replyTo)); 60895057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux } 60905057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux } 60915057d6dffb994b4d1d02c05e06f679de8ef05ea5James Lemieux 60929a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu /** Projection used for getting email address for an account. */ 60939a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu private static final String[] ACCOUNT_EMAIL_PROJECTION = { AccountColumns.EMAIL_ADDRESS }; 60949a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu 6095b34608228f0b55e401415b67b8150ca9e00cee7dScott Kennedy private static void deleteAccountData(Context context, long accountId) { 60969a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu // We will delete PIM data, but by the time the asynchronous call to do that happens, 60979a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu // the account may have been deleted from the DB. Therefore we have to get the email 60989a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu // address now and send that, rather than the account id. 60999a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu final String emailAddress = Utility.getFirstRowString(context, Account.CONTENT_URI, 61009a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu ACCOUNT_EMAIL_PROJECTION, Account.ID_SELECTION, 61019a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu new String[] {Long.toString(accountId)}, null, 0); 61029a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu if (emailAddress == null) { 61039a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu LogUtils.e(TAG, "Could not find email address for account %d", accountId); 61049a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu } 61059a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu 6106f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Delete synced attachments 6107f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank AttachmentUtilities.deleteAllAccountAttachmentFiles(context, accountId); 6108f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 6109aa0ca16a27e4a56a029e5cdebf96de5723bd84b6Yu Ping Hu // Delete all mailboxes. 6110f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank ContentResolver resolver = context.getContentResolver(); 6111f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank String[] accountIdArgs = new String[] { Long.toString(accountId) }; 6112aa0ca16a27e4a56a029e5cdebf96de5723bd84b6Yu Ping Hu resolver.delete(Mailbox.CONTENT_URI, MAILBOXES_FOR_ACCOUNT_SELECTION, accountIdArgs); 6113f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 6114aa0ca16a27e4a56a029e5cdebf96de5723bd84b6Yu Ping Hu // Delete account sync key. 6115aa0ca16a27e4a56a029e5cdebf96de5723bd84b6Yu Ping Hu final ContentValues cv = new ContentValues(); 61163dd85723a1af5537e23e4b05bdc361cce9cd42beTony Mantler cv.putNull(AccountColumns.SYNC_KEY); 6117f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank resolver.update(Account.CONTENT_URI, cv, Account.ID_SELECTION, accountIdArgs); 6118f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 6119c5f5a14ae9095f76d8e8c411cfd8f8e0e8970aa2Martin Hibdon // Delete PIM data (contacts, calendar), stop syncs, etc. if applicable 61209a1f00bee4c50c128df320a3795cfc8295d5e011Yu Ping Hu if (emailAddress != null) { 6121c5f5a14ae9095f76d8e8c411cfd8f8e0e8970aa2Martin Hibdon final IEmailService service = 6122c5f5a14ae9095f76d8e8c411cfd8f8e0e8970aa2Martin Hibdon EmailServiceUtils.getServiceForAccount(context, accountId); 6123c5f5a14ae9095f76d8e8c411cfd8f8e0e8970aa2Martin Hibdon if (service != null) { 6124c5f5a14ae9095f76d8e8c411cfd8f8e0e8970aa2Martin Hibdon try { 61257afbeee47e1a82680c815f2fb8cfdba32d6b0b84Martin Hibdon service.deleteExternalAccountPIMData(emailAddress); 6126c5f5a14ae9095f76d8e8c411cfd8f8e0e8970aa2Martin Hibdon } catch (final RemoteException e) { 6127c5f5a14ae9095f76d8e8c411cfd8f8e0e8970aa2Martin Hibdon // Can't do anything about this 6128c5f5a14ae9095f76d8e8c411cfd8f8e0e8970aa2Martin Hibdon } 6129c5f5a14ae9095f76d8e8c411cfd8f8e0e8970aa2Martin Hibdon } 6130f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6131f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6132f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 6133f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private int[] mSavedWidgetIds = new int[0]; 6134ea2edb637036a7368b6ef82a0aafdb1a790e26e9Mark Wei private final ArrayList<Long> mWidgetNotifyMailboxes = new ArrayList<Long>(); 6135f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private AppWidgetManager mAppWidgetManager; 6136f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private ComponentName mEmailComponent; 6137f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 6138f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank private void notifyWidgets(long mailboxId) { 6139f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Context context = getContext(); 6140f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Lazily initialize these 6141f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mAppWidgetManager == null) { 6142f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mAppWidgetManager = AppWidgetManager.getInstance(context); 614337aa460ef7ee4d996e04b24a181846879fb6b601Tony Mantler mEmailComponent = new ComponentName(context, WidgetProvider.getProviderName(context)); 6144f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6145f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 6146f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // See if we have to populate our array of mailboxes used in widgets 6147f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank int[] widgetIds = mAppWidgetManager.getAppWidgetIds(mEmailComponent); 6148f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (!Arrays.equals(widgetIds, mSavedWidgetIds)) { 6149f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mSavedWidgetIds = widgetIds; 6150f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank String[][] widgetInfos = BaseWidgetProvider.getWidgetInfo(context, widgetIds); 6151f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // widgetInfo now has pairs of account uri/folder uri 6152f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mWidgetNotifyMailboxes.clear(); 6153f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank for (String[] widgetInfo: widgetInfos) { 6154f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank try { 615537aa460ef7ee4d996e04b24a181846879fb6b601Tony Mantler if (widgetInfo == null || TextUtils.isEmpty(widgetInfo[1])) continue; 6156f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank long id = Long.parseLong(Uri.parse(widgetInfo[1]).getLastPathSegment()); 6157f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (!isCombinedMailbox(id)) { 6158f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // For a regular mailbox, just add it to the list 6159f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (!mWidgetNotifyMailboxes.contains(id)) { 6160f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mWidgetNotifyMailboxes.add(id); 6161f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6162f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } else { 6163f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank switch (getVirtualMailboxType(id)) { 6164f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // We only handle the combined inbox in widgets 6165f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank case Mailbox.TYPE_INBOX: 6166f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Cursor c = query(Mailbox.CONTENT_URI, Mailbox.ID_PROJECTION, 6167f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank MailboxColumns.TYPE + "=?", 6168f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank new String[] {Integer.toString(Mailbox.TYPE_INBOX)}, null); 6169f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank try { 6170f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank while (c.moveToNext()) { 6171f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank mWidgetNotifyMailboxes.add( 6172f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c.getLong(Mailbox.ID_PROJECTION_COLUMN)); 6173f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6174f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } finally { 6175f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank c.close(); 6176f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6177f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank break; 6178f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6179f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6180f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } catch (NumberFormatException e) { 6181f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // Move along 6182f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6183f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6184f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6185f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank 6186f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank // If our mailbox needs to be notified, do so... 6187f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank if (mWidgetNotifyMailboxes.contains(mailboxId)) { 6188f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank Intent intent = new Intent(Utils.ACTION_NOTIFY_DATASET_CHANGED); 6189f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank intent.putExtra(Utils.EXTRA_FOLDER_URI, uiUri("uifolder", mailboxId)); 6190f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank intent.setType(EMAIL_APP_MIME_TYPE); 6191f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank context.sendBroadcast(intent); 6192f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6193f419287f22ae44f25e1ba1f757ec33c7941bbfa8Marc Blank } 6194af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank 61959e521deb6bb525b33365cc2926cb2d0faa7095e2Scott Kennedy @Override 6196af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 6197af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank Context context = getContext(); 6198af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank writer.println("Installed services:"); 6199af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank for (EmailServiceInfo info: EmailServiceUtils.getServiceInfoList(context)) { 6200af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank writer.println(" " + info); 6201af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank } 6202af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank writer.println(); 6203af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank writer.println("Accounts: "); 6204af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank Cursor cursor = query(Account.CONTENT_URI, Account.CONTENT_PROJECTION, null, null, null); 6205af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank if (cursor.getCount() == 0) { 6206af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank writer.println(" None"); 6207af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank } 6208af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank try { 6209af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank while (cursor.moveToNext()) { 6210af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank Account account = new Account(); 6211af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank account.restore(cursor); 6212af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank writer.println(" Account " + account.mDisplayName); 6213af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank HostAuth hostAuth = 6214af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank HostAuth.restoreHostAuthWithId(context, account.mHostAuthKeyRecv); 6215af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank if (hostAuth != null) { 6216af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank writer.println(" Protocol = " + hostAuth.mProtocol + 6217af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank (TextUtils.isEmpty(account.mProtocolVersion) ? "" : " version " + 6218af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank account.mProtocolVersion)); 6219af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank } 6220af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank } 6221af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank } finally { 6222af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank cursor.close(); 6223af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank } 6224af092bd5f850653b0d237fb55ccc896f74dc7982Marc Blank } 6225feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert 6226feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert synchronized public Handler getDelayedSyncHandler() { 6227feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert if (mDelayedSyncHandler == null) { 6228feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert mDelayedSyncHandler = new Handler(getContext().getMainLooper(), new Callback() { 6229feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert @Override 6230feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert public boolean handleMessage(android.os.Message msg) { 6231feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert synchronized (mDelayedSyncRequests) { 6232feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert final SyncRequestMessage request = (SyncRequestMessage) msg.obj; 6233b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler // TODO: It's possible that the account is deleted by the time we get here 6234b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler // It would be nice if we could validate it before trying to sync 6235b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler final android.accounts.Account account = request.mAccount; 623656aba8d8436b083bfc1169dd8b988161d537f7e5Martin Hibdon final Bundle extras = Mailbox.createSyncBundle(request.mMailboxId); 6237b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler ContentResolver.requestSync(account, request.mAuthority, extras); 6238921c04d2ac5df091fb3c5cfa823e6dc2fc6cdf5aMartin Hibdon LogUtils.i(TAG, "requestSync getDelayedSyncHandler %s, %s", 6239921c04d2ac5df091fb3c5cfa823e6dc2fc6cdf5aMartin Hibdon account.toString(), extras.toString()); 6240feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert mDelayedSyncRequests.remove(request); 6241feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert return true; 6242feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 6243feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 6244feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert }); 6245feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 6246feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert return mDelayedSyncHandler; 6247feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 6248feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert 6249feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert private class SyncRequestMessage { 6250feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert private final String mAuthority; 6251b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler private final android.accounts.Account mAccount; 6252feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert private final long mMailboxId; 6253feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert 6254b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler private SyncRequestMessage(final String authority, final android.accounts.Account account, 6255b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler final long mailboxId) { 6256feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert mAuthority = authority; 6257b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler mAccount = account; 6258feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert mMailboxId = mailboxId; 6259feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 6260feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert 6261feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert @Override 6262feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert public boolean equals(Object o) { 6263feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert if (this == o) { 6264feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert return true; 6265feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 6266feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert if (o == null || getClass() != o.getClass()) { 6267feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert return false; 6268feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 6269feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert 6270feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert SyncRequestMessage that = (SyncRequestMessage) o; 6271feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert 6272b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler return mAccount.equals(that.mAccount) 6273b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler && mMailboxId == that.mMailboxId 6274b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler && mAuthority.equals(that.mAuthority); 6275feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 6276feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert 6277feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert @Override 6278feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert public int hashCode() { 6279feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert int result = mAuthority.hashCode(); 6280b38c7d1c37bba593b7aaba44a9ffccc8cf3a4108Tony Mantler result = 31 * result + mAccount.hashCode(); 6281feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert result = 31 * result + (int) (mMailboxId ^ (mMailboxId >>> 32)); 6282feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert return result; 6283feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 6284feb2c387b0332a28f1dc5e82205ed087277dff92Alon Albert } 6285c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler 6286c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler @Override 6287c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { 6288c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler if (PreferenceKeys.REMOVAL_ACTION.equals(key) || 6289c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler PreferenceKeys.CONVERSATION_LIST_SWIPE.equals(key) || 6290c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler PreferenceKeys.SHOW_SENDER_IMAGES.equals(key) || 6291c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler PreferenceKeys.DEFAULT_REPLY_ALL.equals(key) || 6292c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler PreferenceKeys.CONVERSATION_OVERVIEW_MODE.equals(key) || 6293c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler PreferenceKeys.AUTO_ADVANCE_MODE.equals(key) || 6294c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler PreferenceKeys.SNAP_HEADER_MODE.equals(key) || 6295c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler PreferenceKeys.CONFIRM_DELETE.equals(key) || 6296c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler PreferenceKeys.CONFIRM_ARCHIVE.equals(key) || 6297c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler PreferenceKeys.CONFIRM_SEND.equals(key)) { 6298c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler notifyUI(UIPROVIDER_ALL_ACCOUNTS_NOTIFIER, null); 6299c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler } 6300c8d8a8445e1d2e962d0db72fee73d778518f839bTony Mantler } 6301bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook 6302bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook /** 6303bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook * Asynchronous version of {@link #setServicesEnabledSync(Context)}. Use when calling from 6304bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook * UI thread (or lifecycle entry points.) 6305bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook */ 6306bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook public static void setServicesEnabledAsync(final Context context) { 6307bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook if (context.getResources().getBoolean(R.bool.enable_services)) { 6308bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook EmailAsyncTask.runAsyncParallel(new Runnable() { 6309bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook @Override 6310bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook public void run() { 6311bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook setServicesEnabledSync(context); 6312bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook } 6313bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook }); 6314bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook } 6315bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook } 6316bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook 6317bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook /** 6318bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook * Called throughout the application when the number of accounts has changed. This method 6319bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook * enables or disables the Compose activity, the boot receiver and the service based on 6320bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook * whether any accounts are configured. 6321bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook * 6322bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook * Blocking call - do not call from UI/lifecycle threads. 6323bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook * 6324bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook * @return true if there are any accounts configured. 6325bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook */ 6326bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook public static boolean setServicesEnabledSync(Context context) { 6327bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook // Make sure we're initialized 6328bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook EmailContent.init(context); 6329bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook Cursor c = null; 6330bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook try { 6331bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook c = context.getContentResolver().query( 6332bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook Account.CONTENT_URI, 6333bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook Account.ID_PROJECTION, 6334bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook null, null, null); 6335bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook boolean enable = c != null && c.getCount() > 0; 6336bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook setServicesEnabled(context, enable); 6337bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook return enable; 6338bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook } finally { 6339bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook if (c != null) { 6340bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook c.close(); 6341bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook } 6342bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook } 6343bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook } 6344bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook 6345bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook private static void setServicesEnabled(Context context, boolean enabled) { 6346bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook PackageManager pm = context.getPackageManager(); 6347bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook pm.setComponentEnabledSetting( 6348bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook new ComponentName(context, AttachmentService.class), 6349bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : 6350bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 6351bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook PackageManager.DONT_KILL_APP); 6352bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook 6353bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook // Start/stop the various services depending on whether there are any accounts 6354bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook // TODO: Make sure that the AttachmentService responds to this request as it 6355bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook // expects a particular set of data in the intents that it receives or it ignores. 6356bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook startOrStopService(enabled, context, new Intent(context, AttachmentService.class)); 6357bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook final NotificationController controller = 6358bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook NotificationControllerCreatorHolder.getInstance(context); 6359bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook 6360bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook if (controller != null) { 6361bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook controller.watchForMessages(); 6362bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook } 6363bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook } 6364bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook 6365bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook /** 6366bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook * Starts or stops the service as necessary. 6367bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook * @param enabled If {@code true}, the service will be started. Otherwise, it will be stopped. 6368bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook * @param context The context to manage the service with. 6369bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook * @param intent The intent of the service to be managed. 6370bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook */ 6371bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook private static void startOrStopService(boolean enabled, Context context, Intent intent) { 6372bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook if (enabled) { 6373bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook context.startService(intent); 6374bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook } else { 6375bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook context.stopService(intent); 6376bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook } 6377bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook } 6378bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook 6379bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook 6380bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook public static Uri getIncomingSettingsUri(long accountId) { 6381bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook final Uri.Builder baseUri = Uri.parse("auth://" + EmailContent.EMAIL_PACKAGE_NAME + 6382bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook ".ACCOUNT_SETTINGS/incoming/").buildUpon(); 6383bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook IntentUtilities.setAccountId(baseUri, accountId); 6384bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook return baseUri.build(); 6385bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook } 6386bb68c13afa630cae058eb40d3ce68644f3f3c8b9Paul Westbrook 6387f3d5b202360031979714c3e366c386bcc7e6a40eAndrew Stadler} 6388