ContactsProvider2.java revision dfab50ecd585e55769dea451cb3a47ff69b8b86d
14f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton/* 24f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Copyright (C) 2009 The Android Open Source Project 34f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * 44f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Licensed under the Apache License, Version 2.0 (the "License"); 54f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * you may not use this file except in compliance with the License. 64f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * You may obtain a copy of the License at 74f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * 84f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * http://www.apache.org/licenses/LICENSE-2.0 94f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * 104f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Unless required by applicable law or agreed to in writing, software 114f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * distributed under the License is distributed on an "AS IS" BASIS, 124f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * See the License for the specific language governing permissions and 144f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * limitations under the License 154f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton */ 164f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1728f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarpackage com.android.providers.contacts; 1828f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millar 1947106a03cd4587123f4fa24f3620baf55fed15d9Dave Santoroimport com.android.common.content.ProjectionMap; 2053214b3ed12b0ff9cb589b6559311f2ac142f2e3Bjorn Bringertimport com.android.common.content.SyncStateContentProviderHelper; 2197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactLookupKey.LookupKeySegment; 229d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.AccountsColumns; 2397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.AggregatedPresenceColumns; 2497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.AggregationExceptionColumns; 2597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.Clauses; 2697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.ContactsColumns; 2797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.ContactsStatusUpdatesColumns; 2897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.DataColumns; 2971340347b4862d4b1368a5d69d1667e2245952e4Daisuke Miyakawaimport com.android.providers.contacts.ContactsDatabaseHelper.DataUsageStatColumns; 309ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.DbProperties; 3197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.GroupsColumns; 3223ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.Joins; 3397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.NameLookupColumns; 3497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.NameLookupType; 3597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.PhoneLookupColumns; 361dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoroimport com.android.providers.contacts.ContactsDatabaseHelper.PhotoFilesColumns; 3797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.PresenceColumns; 389d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.Projections; 3997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.RawContactsColumns; 4003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.SearchIndexColumns; 4197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.SettingsColumns; 4297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.StatusUpdatesColumns; 433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmannimport com.android.providers.contacts.ContactsDatabaseHelper.StreamItemPhotosColumns; 44f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport com.android.providers.contacts.ContactsDatabaseHelper.StreamItemsColumns; 4597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.Tables; 469d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.ViewGroupsColumns; 47ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmannimport com.android.providers.contacts.ContactsDatabaseHelper.Views; 48d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmannimport com.android.providers.contacts.SearchIndexManager.FtsQueryBuilder; 4949ed71913609193a00059df944f6259e9397b0bdMakoto Onukiimport com.android.providers.contacts.aggregation.ContactAggregator; 5049ed71913609193a00059df944f6259e9397b0bdMakoto Onukiimport com.android.providers.contacts.aggregation.ContactAggregator.AggregationSuggestionParameter; 5181567f4a0f7c9c338506bd82f4d33e83c2ccf159Makoto Onukiimport com.android.providers.contacts.aggregation.util.CommonNicknameCache; 5249ed71913609193a00059df944f6259e9397b0bdMakoto Onukiimport com.android.providers.contacts.aggregation.ProfileAggregator; 53dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onukiimport com.android.providers.contacts.util.Clock; 542f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawaimport com.android.providers.contacts.util.DbQueryUtils; 5510178e5e0b9de566e04508b624a89860c61787d6Makoto Onukiimport com.android.providers.contacts.util.NeededForTesting; 5697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.vcard.VCardComposer; 5797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.android.vcard.VCardConfig; 5897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.google.android.collect.Lists; 5997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.google.android.collect.Maps; 6097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport com.google.android.collect.Sets; 61f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawaimport com.google.common.annotations.VisibleForTesting; 62084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onukiimport com.google.common.base.Preconditions; 6397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 64b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.accounts.Account; 65caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikovimport android.accounts.AccountManager; 665b4b305b9698526c6e82e0e01448b0a5642dd505Fred Quintanaimport android.accounts.OnAccountsUpdateListener; 67c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.app.SearchManager; 687898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brownimport android.content.CancellationSignal; 69568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.ContentProviderOperation; 70568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.ContentProviderResult; 716ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshiimport android.content.ContentResolver; 7235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.ContentUris; 7367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.ContentValues; 7467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.Context; 75627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikovimport android.content.IContentService; 76568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.OperationApplicationException; 773d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.content.SharedPreferences; 78627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikovimport android.content.SyncAdapterType; 7967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.UriMatcher; 800bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmannimport android.content.pm.PackageManager; 810bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmannimport android.content.pm.PackageManager.NameNotFoundException; 825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoroimport android.content.pm.ProviderInfo; 83f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringertimport android.content.res.AssetFileDescriptor; 843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmannimport android.content.res.Resources; 850bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmannimport android.content.res.Resources.NotFoundException; 86409605a187683155d9c6dbc2626b6419e3dd384eMakoto Onukiimport android.database.AbstractCursor; 874f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.Cursor; 88ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.database.DatabaseUtils; 8909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikovimport android.database.MatrixCursor; 9009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikovimport android.database.MatrixCursor.RowBuilder; 914f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteDatabase; 9208ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwoodimport android.database.sqlite.SQLiteDoneException; 934f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteQueryBuilder; 94f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.graphics.Bitmap; 95f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.graphics.BitmapFactory; 964f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.net.Uri; 97d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikovimport android.net.Uri.Builder; 98c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoroimport android.os.AsyncTask; 99bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Binder; 1006ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshiimport android.os.Bundle; 101bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Handler; 102bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.HandlerThread; 103bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Message; 104ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringertimport android.os.ParcelFileDescriptor; 105c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoroimport android.os.ParcelFileDescriptor.AutoCloseInputStream; 106bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Process; 107b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.os.RemoteException; 10815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikovimport android.os.StrictMode; 1090dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikovimport android.os.SystemClock; 1100e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport android.os.SystemProperties; 1113d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.preference.PreferenceManager; 112508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkeyimport android.provider.BaseColumns; 1133de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract; 114b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.provider.ContactsContract.AggregationExceptions; 11582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoroimport android.provider.ContactsContract.Authorization; 11697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Email; 11797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.GroupMembership; 11897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Im; 11997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Nickname; 1206d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Note; 12197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Organization; 12297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Phone; 12397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Photo; 1244928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.SipAddress; 12597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredName; 12697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal; 127ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikovimport android.provider.ContactsContract.ContactCounts; 1283de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Contacts; 1295b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikovimport android.provider.ContactsContract.Contacts.AggregationSuggestions; 1303de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Data; 13171340347b4862d4b1368a5d69d1667e2245952e4Daisuke Miyakawaimport android.provider.ContactsContract.DataUsageFeedback; 132d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikovimport android.provider.ContactsContract.Directory; 133f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.provider.ContactsContract.DisplayPhoto; 1343de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Groups; 1353de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.PhoneLookup; 1361dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoroimport android.provider.ContactsContract.PhotoFiles; 1370c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoroimport android.provider.ContactsContract.Profile; 13809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikovimport android.provider.ContactsContract.ProviderStatus; 1393de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.RawContacts; 1403711af1a5799a7ae0c8e761e13a67a9fb5878cc8Martijn Coenenimport android.provider.ContactsContract.RawContactsEntity; 141916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikovimport android.provider.ContactsContract.SearchSnippetColumns; 1423de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Settings; 14382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikovimport android.provider.ContactsContract.StatusUpdates; 1443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmannimport android.provider.ContactsContract.StreamItemPhotos; 145f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.provider.ContactsContract.StreamItems; 14697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.OpenableColumns; 14797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.SyncStateContract; 148a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.telephony.PhoneNumberUtils; 1499a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikovimport android.telephony.TelephonyManager; 150a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.text.TextUtils; 151c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.util.Log; 1524f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 153108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawaimport java.io.BufferedWriter; 154d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.ByteArrayOutputStream; 155f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport java.io.File; 15635997f3fdee2984b6d5373326110eda26929001aMakoto Onukiimport java.io.FileDescriptor; 157b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport java.io.FileNotFoundException; 158d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.IOException; 159d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.OutputStream; 160108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawaimport java.io.OutputStreamWriter; 16135997f3fdee2984b6d5373326110eda26929001aMakoto Onukiimport java.io.PrintWriter; 162108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawaimport java.io.Writer; 163d0eb93009559d095de0448907527aeb059801dc4Dave Santoroimport java.security.SecureRandom; 16442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmannimport java.text.SimpleDateFormat; 1657e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintanaimport java.util.ArrayList; 1665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport java.util.Collections; 16742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmannimport java.util.Date; 168b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport java.util.HashMap; 1690e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport java.util.HashSet; 1705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport java.util.List; 171622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkeyimport java.util.Locale; 172b5a4add17815167d20a90645779df34cdf45280dFred Quintanaimport java.util.Map; 1730e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport java.util.Set; 174ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikovimport java.util.concurrent.CountDownLatch; 1754f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1764f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton/** 1774f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Contacts content provider. The contract between this provider and applications 1784f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * is defined in {@link ContactsContract}. 1794f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton */ 180078f588cef389358adabc579de00747878f3c108Dave Santoropublic class ContactsProvider2 extends AbstractContactsProvider 181078f588cef389358adabc579de00747878f3c108Dave Santoro implements OnAccountsUpdateListener { 182caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 18315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_INITIALIZE = 0; 18415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_OPEN_WRITE_ACCESS = 1; 18515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_ACCOUNTS = 3; 18615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_LOCALE = 4; 18715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM = 5; 18805e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_SEARCH_INDEX = 6; 18905e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_PROVIDER_STATUS = 7; 19005e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_DIRECTORIES = 8; 19105e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_CHANGE_LOCALE = 9; 192f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int BACKGROUND_TASK_CLEANUP_PHOTOS = 10; 193619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 1943cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** Default for the maximum number of returned aggregation suggestions. */ 1953cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private static final int DEFAULT_MAX_SUGGESTIONS = 5; 1963cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 1973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** Limit for the maximum number of social stream items to store under a raw contact. */ 1983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int MAX_STREAM_ITEMS_PER_RAW_CONTACT = 5; 1993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 200f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** Rate limit (in ms) for photo cleanup. Do it at most once per day. */ 201f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int PHOTO_CLEANUP_RATE_LIMIT = 24 * 60 * 60 * 1000; 202f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 2033d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov /** 20482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * Default expiration duration for pre-authorized URIs. May be overridden from a secure 20582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * setting. 20682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro */ 20782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro private static final int DEFAULT_PREAUTHORIZED_URI_EXPIRATION = 5 * 60 * 1000; 20882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 20982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro /** 21082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * Random URI parameter that will be appended to preauthorized URIs for uniqueness. 21182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro */ 21282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro private static final String PREAUTHORIZED_URI_TOKEN = "perm_token"; 21382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 21451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov private static final String PREF_LOCALE = "locale"; 2153d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 2160dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov private static final int PROPERTY_AGGREGATION_ALGORITHM_VERSION = 2; 2170dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 2180e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff private static final String AGGREGATE_CONTACTS = "sync.contacts.aggregate"; 2190e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff 220b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki /** 221b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki * If set to "1", we don't remove account data when accounts have been removed. 222b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki * 223b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki * This should be used sparingly; even though there are data still available, the UI 224b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki * don't know anything about them, so they won't show up in the contact filter screen, and 225b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki * the contact card/editor may get confused to see unknown custom mimetypes. 226b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki * 227b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki * We can't spell it out because a property name must be less than 32 chars. 228b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki */ 229b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki private static final String DEBUG_PROPERTY_KEEP_STALE_ACCOUNT_DATA = 230b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki "debug.contacts.ksad"; 231b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki 2325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private static final ProfileAwareUriMatcher sUriMatcher = 2335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new ProfileAwareUriMatcher(UriMatcher.NO_MATCH); 2344f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2352f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa /** 2362f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa * Used to insert a column into strequent results, which enables SQL to sort the list using 2372f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa * the total times contacted. See also {@link #sStrequentFrequentProjectionMap}. 2382f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa */ 2392f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa private static final String TIMES_USED_SORT_COLUMN = "times_used_sort"; 2405e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 24145ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa private static final String FREQUENT_ORDER_BY = DataUsageStatColumns.TIMES_USED + " DESC," 24245ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; 24345ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa 2446e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori /* package */ static final String UPDATE_TIMES_CONTACTED_CONTACTS_TABLE = 2459b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori "UPDATE " + Tables.CONTACTS + " SET " + Contacts.TIMES_CONTACTED + "=" + 246dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " ifnull(" + Contacts.TIMES_CONTACTED + ",0)+1" + 247dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " WHERE " + Contacts._ID + "=?"; 2489b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori 2496e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori /* package */ static final String UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE = 2509b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori "UPDATE " + Tables.RAW_CONTACTS + " SET " + RawContacts.TIMES_CONTACTED + "=" + 251dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " ifnull(" + RawContacts.TIMES_CONTACTED + ",0)+1 " + 252dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " WHERE " + RawContacts.CONTACT_ID + "=?"; 2539b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori 254de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa /* package */ static final String PHONEBOOK_COLLATOR_NAME = "PHONEBOOK"; 255de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa 2563716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Regex for splitting query strings - we split on any group of non-alphanumeric characters, 2573716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // excluding the @ symbol. 2583716f1447ceb21180d1301790eabd8b9453f486dDave Santoro /* package */ static final String QUERY_TOKENIZER_REGEX = "[^\\w@]+"; 2593716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 260d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private static final int CONTACTS = 1000; 261d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private static final int CONTACTS_ID = 1001; 2625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_LOOKUP = 1002; 2635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_LOOKUP_ID = 1003; 264a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private static final int CONTACTS_ID_DATA = 1004; 2655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_FILTER = 1005; 2665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_STREQUENT = 1006; 2675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_STREQUENT_FILTER = 1007; 2685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_GROUP = 1008; 269a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private static final int CONTACTS_ID_PHOTO = 1009; 270bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_PHOTO = 1010; 271bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_ID_PHOTO = 1011; 272bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_ID_DISPLAY_PHOTO = 1012; 273bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_DISPLAY_PHOTO = 1013; 274bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_ID_DISPLAY_PHOTO = 1014; 275bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_AS_VCARD = 1015; 276bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_AS_MULTI_VCARD = 1016; 277bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_DATA = 1017; 278bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_ID_DATA = 1018; 279bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_ID_ENTITIES = 1019; 280bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_ENTITIES = 1020; 281bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_ID_ENTITIES = 1021; 282bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_ID_STREAM_ITEMS = 1022; 283bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_STREAM_ITEMS = 1023; 284bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_ID_STREAM_ITEMS = 1024; 285bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_FREQUENT = 1025; 286b6186821548995dce533ee502e82e9abf4c0aadcMakoto Onuki private static final int CONTACTS_DELETE_USAGE = 1026; 2874f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2885ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov private static final int RAW_CONTACTS = 2002; 2895ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov private static final int RAW_CONTACTS_ID = 2003; 290193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private static final int RAW_CONTACTS_ID_DATA = 2004; 291193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private static final int RAW_CONTACT_ID_ENTITY = 2005; 292f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int RAW_CONTACTS_ID_DISPLAY_PHOTO = 2006; 293f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int RAW_CONTACTS_ID_STREAM_ITEMS = 2007; 29482780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro private static final int RAW_CONTACTS_ID_STREAM_ITEMS_ID = 2008; 2954f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2966bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int DATA = 3000; 2976bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int DATA_ID = 3001; 298ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar private static final int PHONES = 3002; 29948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int PHONES_ID = 3003; 30048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int PHONES_FILTER = 3004; 30148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS = 3005; 30248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_ID = 3006; 30348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_LOOKUP = 3007; 30448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_FILTER = 3008; 30548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int POSTALS = 3009; 30648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int POSTALS_ID = 3010; 307e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa private static final int CALLABLES = 3011; 308e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa private static final int CALLABLES_ID = 3012; 309e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa private static final int CALLABLES_FILTER = 3013; 310a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 3116bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int PHONE_LOOKUP = 4000; 3126bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 313b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final int AGGREGATION_EXCEPTIONS = 6000; 314b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final int AGGREGATION_EXCEPTION_ID = 6001; 315b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 31682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private static final int STATUS_UPDATES = 7000; 31782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private static final int STATUS_UPDATES_ID = 7001; 3181f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 31931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov private static final int AGGREGATION_SUGGESTIONS = 8000; 32031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 321eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey private static final int SETTINGS = 9000; 322eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 323ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS = 10000; 324ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS_ID = 10001; 325ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS_SUMMARY = 10003; 326ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 32735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana private static final int SYNCSTATE = 11000; 328b5a4add17815167d20a90645779df34cdf45280dFred Quintana private static final int SYNCSTATE_ID = 11001; 3295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private static final int PROFILE_SYNCSTATE = 11002; 3305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private static final int PROFILE_SYNCSTATE_ID = 11003; 33135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 332c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov private static final int SEARCH_SUGGESTIONS = 12001; 333c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov private static final int SEARCH_SHORTCUT = 12002; 334c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 33546b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana private static final int RAW_CONTACT_ENTITIES = 15001; 33646b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 33709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private static final int PROVIDER_STATUS = 16001; 33809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 339d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final int DIRECTORIES = 17001; 340d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final int DIRECTORIES_ID = 17002; 341d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 3427a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private static final int COMPLETE_NAME = 18000; 3437a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 34424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE = 19000; 34524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_ENTITIES = 19001; 34624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_DATA = 19002; 34724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_DATA_ID = 19003; 34824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_AS_VCARD = 19004; 34924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS = 19005; 35024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID = 19006; 35124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID_DATA = 19007; 35224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID_ENTITIES = 19008; 3535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private static final int PROFILE_STATUS_UPDATES = 19009; 3543202ae2de5c5fec9f5f61003a0e6b608283e1961Dave Santoro private static final int PROFILE_RAW_CONTACT_ENTITIES = 19010; 35585077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro private static final int PROFILE_PHOTO = 19011; 35685077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro private static final int PROFILE_DISPLAY_PHOTO = 19012; 35724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 35846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final int DATA_USAGE_FEEDBACK_ID = 20001; 35946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 3603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS = 21000; 3613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_PHOTOS = 21001; 3623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID = 21002; 3633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID_PHOTOS = 21003; 3643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID_PHOTOS_ID = 21004; 3653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_LIMIT = 21005; 3663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 367193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private static final int DISPLAY_PHOTO_ID = 22000; 368f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int PHOTO_DIMENSIONS = 22001; 369f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 3705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Inserts into URIs in this map will direct to the profile database if the parent record's 3715d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // value (looked up from the ContentValues object with the key specified by the value in this 3725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // map) is in the profile ID-space (see {@link ProfileDatabaseHelper#PROFILE_ID_SPACE}). 3735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private static final Map<Integer, String> INSERT_URI_ID_VALUE_MAP = Maps.newHashMap(); 3745d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro static { 3755d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(DATA, Data.RAW_CONTACT_ID); 376193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki INSERT_URI_ID_VALUE_MAP.put(RAW_CONTACTS_ID_DATA, Data.RAW_CONTACT_ID); 3775d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(STATUS_UPDATES, StatusUpdates.DATA_ID); 3785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(STREAM_ITEMS, StreamItems.RAW_CONTACT_ID); 3795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(RAW_CONTACTS_ID_STREAM_ITEMS, StreamItems.RAW_CONTACT_ID); 3805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(STREAM_ITEMS_PHOTOS, StreamItemPhotos.STREAM_ITEM_ID); 3815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(STREAM_ITEMS_ID_PHOTOS, StreamItemPhotos.STREAM_ITEM_ID); 3825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 3835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 38436612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro // Any interactions that involve these URIs will also require the calling package to have either 38536612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro // android.permission.READ_SOCIAL_STREAM permission or android.permission.WRITE_SOCIAL_STREAM 38636612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro // permission, depending on the type of operation being performed. 38736612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro private static final List<Integer> SOCIAL_STREAM_URIS = Lists.newArrayList( 38836612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro CONTACTS_ID_STREAM_ITEMS, 38936612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro CONTACTS_LOOKUP_STREAM_ITEMS, 39036612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro CONTACTS_LOOKUP_ID_STREAM_ITEMS, 39136612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro RAW_CONTACTS_ID_STREAM_ITEMS, 39236612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro RAW_CONTACTS_ID_STREAM_ITEMS_ID, 39336612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro STREAM_ITEMS, 39436612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro STREAM_ITEMS_PHOTOS, 39536612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro STREAM_ITEMS_ID, 39636612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro STREAM_ITEMS_ID_PHOTOS, 39736612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro STREAM_ITEMS_ID_PHOTOS_ID 39836612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro ); 39936612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 400dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_FAVORITES_GROUPS_BY_RAW_CONTACT_ID = 401dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana RawContactsColumns.CONCRETE_ID + "=? AND " 4029d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + GroupsColumns.CONCRETE_ACCOUNT_ID + "=" + RawContactsColumns.CONCRETE_ACCOUNT_ID 4039d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + " AND " + Groups.FAVORITES + " != 0"; 404dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 405dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_AUTO_ADD_GROUPS_BY_RAW_CONTACT_ID = 406dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana RawContactsColumns.CONCRETE_ID + "=? AND " 4079d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + GroupsColumns.CONCRETE_ACCOUNT_ID + "=" + RawContactsColumns.CONCRETE_ACCOUNT_ID 4089d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + " AND " + Groups.AUTO_ADD + " != 0"; 409dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 410dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String[] PROJECTION_GROUP_ID 411dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana = new String[]{Tables.GROUPS + "." + Groups._ID}; 412dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 413dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_GROUPMEMBERSHIP_DATA = DataColumns.MIMETYPE_ID + "=? " 414dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "AND " + GroupMembership.GROUP_ROW_ID + "=? " 415dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "AND " + GroupMembership.RAW_CONTACT_ID + "=?"; 416dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 417dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_STARRED_FROM_RAW_CONTACTS = 418dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana "SELECT " + RawContacts.STARRED 419dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " FROM " + Tables.RAW_CONTACTS + " WHERE " + RawContacts._ID + "=?"; 420dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 421d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private interface DataContactsQuery { 422f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov public static final String TABLE = "data " 423f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov + "JOIN raw_contacts ON (data.raw_contact_id = raw_contacts._id) " 4249d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + "JOIN " + Tables.ACCOUNTS + " ON (" 4259d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + AccountsColumns.CONCRETE_ID + "=" + RawContactsColumns.CONCRETE_ACCOUNT_ID 4269d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + ")" 427f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov + "JOIN contacts ON (raw_contacts.contact_id = contacts._id)"; 42867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 42967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final String[] PROJECTION = new String[] { 4306cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov RawContactsColumns.CONCRETE_ID, 4319d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki AccountsColumns.CONCRETE_ACCOUNT_TYPE, 4329d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki AccountsColumns.CONCRETE_ACCOUNT_NAME, 4339d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki AccountsColumns.CONCRETE_DATA_SET, 4343cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DataColumns.CONCRETE_ID, 435f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov ContactsColumns.CONCRETE_ID 436ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey }; 437ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 438d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov public static final int RAW_CONTACT_ID = 0; 4396802030a777c0c3ba1dc029c534cca4784260632Dave Santoro public static final int ACCOUNT_TYPE = 1; 4406802030a777c0c3ba1dc029c534cca4784260632Dave Santoro public static final int ACCOUNT_NAME = 2; 44143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro public static final int DATA_SET = 3; 44243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro public static final int DATA_ID = 4; 44343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro public static final int CONTACT_ID = 5; 444ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 4451f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 446f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov interface RawContactsQuery { 4479d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki String TABLE = Tables.RAW_CONTACTS_JOIN_ACCOUNTS; 44819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 44919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka String[] COLUMNS = new String[] { 450ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov RawContacts.DELETED, 4519d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki RawContactsColumns.ACCOUNT_ID, 4529d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki AccountsColumns.CONCRETE_ACCOUNT_TYPE, 4539d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki AccountsColumns.CONCRETE_ACCOUNT_NAME, 4549d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki AccountsColumns.CONCRETE_DATA_SET, 45519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka }; 45619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 45719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka int DELETED = 0; 4589d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki int ACCOUNT_ID = 1; 4599d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki int ACCOUNT_TYPE = 2; 4609d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki int ACCOUNT_NAME = 3; 4619d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki int DATA_SET = 4; 46219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 46319cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 464c76cdd0723b99f478c9ba5329d14a971cd8dfb3dCostin Manolache public static final String DEFAULT_ACCOUNT_TYPE = "com.google"; 465caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 46671e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov /** Sql where statement for filtering on groups. */ 46771e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov private static final String CONTACTS_IN_GROUP_SELECT = 46871e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov Contacts._ID + " IN " 46971e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + RawContacts.CONTACT_ID 47071e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.RAW_CONTACTS 47171e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " WHERE " + RawContactsColumns.CONCRETE_ID + " IN " 47271e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + DataColumns.CONCRETE_RAW_CONTACT_ID 47371e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.DATA_JOIN_MIMETYPES 4747cf50494501938f175d288077145acf49da8f171Daniel Lehmann + " WHERE " + DataColumns.MIMETYPE_ID + "=?" 4757cf50494501938f175d288077145acf49da8f171Daniel Lehmann + " AND " + GroupMembership.GROUP_ROW_ID + "=" 47671e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + Tables.GROUPS + "." + Groups._ID 47771e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.GROUPS 47871e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " WHERE " + Groups.TITLE + "=?)))"; 47971e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov 480a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** Sql for updating DIRTY flag on multiple raw contacts */ 481a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov private static final String UPDATE_RAW_CONTACT_SET_DIRTY_SQL = 482a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov "UPDATE " + Tables.RAW_CONTACTS + 483a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " SET " + RawContacts.DIRTY + "=1" + 484a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " WHERE " + RawContacts._ID + " IN ("; 485a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 486a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** Sql for updating VERSION on multiple raw contacts */ 487a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov private static final String UPDATE_RAW_CONTACT_SET_VERSION_SQL = 488a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov "UPDATE " + Tables.RAW_CONTACTS + 489a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " SET " + RawContacts.VERSION + " = " + RawContacts.VERSION + " + 1" + 490a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " WHERE " + RawContacts._ID + " IN ("; 491a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 492c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov // Current contacts - those contacted within the last 3 days (in seconds) 493c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov private static final long EMAIL_FILTER_CURRENT = 3 * 24 * 60 * 60; 494c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 495c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov // Recent contacts - those contacted within the last 30 days (in seconds) 496c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov private static final long EMAIL_FILTER_RECENT = 30 * 24 * 60 * 60; 497c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 498f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa private static final String TIME_SINCE_LAST_USED = 499f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa "(strftime('%s', 'now') - " + DataUsageStatColumns.LAST_TIME_USED + "/1000)"; 500f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa 501c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov /* 502c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov * Sorting order for email address suggestions: first starred, then the rest. 5034c4ea154ba08f2c772d645a092c3ffa4497295dfDaisuke Miyakawa * Within the two groups: 5044c4ea154ba08f2c772d645a092c3ffa4497295dfDaisuke Miyakawa * - three buckets: very recently contacted, then fairly recently contacted, then the rest. 5054c4ea154ba08f2c772d645a092c3ffa4497295dfDaisuke Miyakawa * Within each of the bucket - descending count of times contacted (both for data row and for 5064c4ea154ba08f2c772d645a092c3ffa4497295dfDaisuke Miyakawa * contact row). 5074c4ea154ba08f2c772d645a092c3ffa4497295dfDaisuke Miyakawa * If all else fails, in_visible_group, alphabetical. 50846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * (Super)primary email address is returned before other addresses for the same contact. 509c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov */ 510c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov private static final String EMAIL_FILTER_SORT_ORDER = 5112262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa Contacts.STARRED + " DESC, " 512f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa + "(CASE WHEN " + TIME_SINCE_LAST_USED + " < " + EMAIL_FILTER_CURRENT 51346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + " THEN 0 " 514f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa + " WHEN " + TIME_SINCE_LAST_USED + " < " + EMAIL_FILTER_RECENT 51546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + " THEN 1 " 51646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + " ELSE 2 END), " 51746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + DataUsageStatColumns.TIMES_USED + " DESC, " 5184c4ea154ba08f2c772d645a092c3ffa4497295dfDaisuke Miyakawa + Contacts.IN_VISIBLE_GROUP + " DESC, " 51946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + Contacts.DISPLAY_NAME + ", " 52046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + Data.CONTACT_ID + ", " 521c591cc2ffecdd0038f787a133606752752294c13Daisuke Miyakawa + Data.IS_SUPER_PRIMARY + " DESC, " 522c591cc2ffecdd0038f787a133606752752294c13Daisuke Miyakawa + Data.IS_PRIMARY + " DESC"; 52346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 52446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** Currently same as {@link #EMAIL_FILTER_SORT_ORDER} */ 52546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final String PHONE_FILTER_SORT_ORDER = EMAIL_FILTER_SORT_ORDER; 526c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 527916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** Name lookup types used for contact filtering */ 528916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov private static final String CONTACT_LOOKUP_NAME_TYPES = 529916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov NameLookupType.NAME_COLLATION_KEY + "," + 530916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov NameLookupType.EMAIL_BASED_NICKNAME + "," + 53192ddc5cdc4d89ee2c6e861ae7b3a3a913ffa0100Dmitri Plotnikov NameLookupType.NICKNAME; 532916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 533f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov /** 534f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov * If any of these columns are used in a Data projection, there is no point in 535f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov * using the DISTINCT keyword, which can negatively affect performance. 536f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov */ 537f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov private static final String[] DISTINCT_DATA_PROHIBITING_COLUMNS = { 538f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data._ID, 539f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data.RAW_CONTACT_ID, 540f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data.NAME_RAW_CONTACT_ID, 541f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.ACCOUNT_NAME, 542f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.ACCOUNT_TYPE, 54343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.DATA_SET, 54443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 545f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.DIRTY, 546f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.NAME_VERIFIED, 547f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.SOURCE_ID, 548f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.VERSION, 549f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov }; 550916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 551f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsColumns = ProjectionMap.builder() 552f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CUSTOM_RINGTONE) 553f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME) 554f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME_ALTERNATIVE) 555f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME_SOURCE) 556f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.IN_VISIBLE_GROUP) 557f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.LAST_TIME_CONTACTED) 558f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.LOOKUP_KEY) 559f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHONETIC_NAME) 560f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHONETIC_NAME_STYLE) 561f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHOTO_ID) 562f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .add(Contacts.PHOTO_FILE_ID) 5633d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(Contacts.PHOTO_URI) 5643d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(Contacts.PHOTO_THUMBNAIL_URI) 565f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SEND_TO_VOICEMAIL) 566f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SORT_KEY_ALTERNATIVE) 567f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SORT_KEY_PRIMARY) 568f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.STARRED) 569f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.TIMES_CONTACTED) 570cf832869bcf91b8037d8b7f510a3a213b30764a3Dmitri Plotnikov .add(Contacts.HAS_PHONE_NUMBER) 571f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 572f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 573f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsPresenceColumns = ProjectionMap.builder() 574f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_PRESENCE, 575f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.PRESENCE) 576f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_CHAT_CAPABILITY, 577f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.CHAT_CAPABILITY) 578f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS, 579f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS) 580f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_TIMESTAMP, 581f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 582f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_RES_PACKAGE, 583f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 584f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_LABEL, 585f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_LABEL) 586f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_ICON, 587f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_ICON) 588f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 589f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 590f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sSnippetColumns = ProjectionMap.builder() 59103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov .add(SearchSnippetColumns.SNIPPET) 592f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 593f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 594f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactColumns = ProjectionMap.builder() 595f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.ACCOUNT_NAME) 596f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.ACCOUNT_TYPE) 59743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(RawContacts.DATA_SET) 59843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(RawContacts.ACCOUNT_TYPE_AND_DATA_SET) 599f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DIRTY) 600f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.NAME_VERIFIED) 601f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SOURCE_ID) 602f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.VERSION) 603f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 604f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 605f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactSyncColumns = ProjectionMap.builder() 606f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC1) 607f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC2) 608f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC3) 609f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC4) 610f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 611f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 612f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataColumns = ProjectionMap.builder() 613f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA1) 614f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA2) 615f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA3) 616f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA4) 617f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA5) 618f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA6) 619f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA7) 620f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA8) 621f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA9) 622f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA10) 623f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA11) 624f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA12) 625f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA13) 626f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA14) 627f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA15) 628f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA_VERSION) 629f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.IS_PRIMARY) 630f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.IS_SUPER_PRIMARY) 631f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.MIMETYPE) 632f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.RES_PACKAGE) 633f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC1) 634f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC2) 635f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC3) 636f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC4) 637f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(GroupMembership.GROUP_SOURCE_ID) 638f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 639f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 640f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactPresenceColumns = ProjectionMap.builder() 641f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_PRESENCE, 642f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + '.' + StatusUpdates.PRESENCE) 643f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_CHAT_CAPABILITY, 644f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + '.' + StatusUpdates.CHAT_CAPABILITY) 645f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS, 646f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS) 647f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_TIMESTAMP, 648f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 649f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_RES_PACKAGE, 650f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 651f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_LABEL, 652f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_LABEL) 653f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_ICON, 654f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_ICON) 655f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 656f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 657f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataPresenceColumns = ProjectionMap.builder() 658f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.PRESENCE, Tables.PRESENCE + "." + StatusUpdates.PRESENCE) 659f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.CHAT_CAPABILITY, Tables.PRESENCE + "." + StatusUpdates.CHAT_CAPABILITY) 660f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS, StatusUpdatesColumns.CONCRETE_STATUS) 661f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_TIMESTAMP, StatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 662f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_RES_PACKAGE, StatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 663f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_LABEL, StatusUpdatesColumns.CONCRETE_STATUS_LABEL) 664f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_ICON, StatusUpdatesColumns.CONCRETE_STATUS_ICON) 665f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 666f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 667038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana /** Contains just BaseColumns._COUNT */ 668f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sCountProjectionMap = ProjectionMap.builder() 669f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(BaseColumns._COUNT, "COUNT(*)") 670f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 671f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 672e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov /** Contains just the contacts columns */ 673f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsProjectionMap = ProjectionMap.builder() 674f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts._ID) 675f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.HAS_PHONE_NUMBER) 676f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.NAME_RAW_CONTACT_ID) 67724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(Contacts.IS_USER_PROFILE) 678f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 679f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsPresenceColumns) 680f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 681f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 682916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** Contains just the contacts columns */ 683f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsProjectionWithSnippetMap = ProjectionMap.builder() 684f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 685f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sSnippetColumns) 686f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 687916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 6885e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar /** Used for pushing starred contacts to the top of a times contacted list **/ 689f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStrequentStarredProjectionMap = ProjectionMap.builder() 690f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 6912f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, String.valueOf(Long.MAX_VALUE)) 692f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 693f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 694f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStrequentFrequentProjectionMap = ProjectionMap.builder() 695f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 6962f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, "SUM(" + DataUsageStatColumns.CONCRETE_TIMES_USED + ")") 697f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 698f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 6994928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa /** 7004928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Used for Strequent Uri with {@link ContactsContract#STREQUENT_PHONE_ONLY}, which allows 7014928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * users to obtain part of Data columns. Right now Starred part just returns NULL for 7024928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * those data columns (frequent part should return real ones in data table). 7034928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa **/ 7044928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa private static final ProjectionMap sStrequentPhoneOnlyStarredProjectionMap 7054928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa = ProjectionMap.builder() 7064928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .addAll(sContactsProjectionMap) 7074928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, String.valueOf(Long.MAX_VALUE)) 7084928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.NUMBER, "NULL") 7094928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.TYPE, "NULL") 7104928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.LABEL, "NULL") 7114928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .build(); 7124928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 7134928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa /** 7144928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Used for Strequent Uri with {@link ContactsContract#STREQUENT_PHONE_ONLY}, which allows 7154928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * users to obtain part of Data columns. We hard-code {@link Contacts#IS_USER_PROFILE} to NULL, 7164928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * because sContactsProjectionMap specifies a field that doesn't exist in the view behind the 7174928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * query that uses this projection map. 7184928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa **/ 7194928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa private static final ProjectionMap sStrequentPhoneOnlyFrequentProjectionMap 7204928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa = ProjectionMap.builder() 7214928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .addAll(sContactsProjectionMap) 7224928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(TIMES_USED_SORT_COLUMN, DataUsageStatColumns.CONCRETE_TIMES_USED) 7234928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.NUMBER) 7244928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.TYPE) 7254928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.LABEL) 7264928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Contacts.IS_USER_PROFILE, "NULL") 7274928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .build(); 7284928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 729f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey /** Contains just the contacts vCard columns */ 730f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsVCardProjectionMap = ProjectionMap.builder() 731fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen .add(Contacts._ID) 732f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(OpenableColumns.DISPLAY_NAME, Contacts.DISPLAY_NAME + " || '.vcf'") 733f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(OpenableColumns.SIZE, "NULL") 734f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 735f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 736ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov /** Contains just the raw contacts columns */ 737f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactsProjectionMap = ProjectionMap.builder() 738f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts._ID) 739f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 740f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DELETED) 741f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_PRIMARY) 742f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_ALTERNATIVE) 743f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_SOURCE) 744f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.PHONETIC_NAME) 745f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.PHONETIC_NAME_STYLE) 746f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SORT_KEY_PRIMARY) 747f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SORT_KEY_ALTERNATIVE) 748f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.TIMES_CONTACTED) 749f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.LAST_TIME_CONTACTED) 750f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CUSTOM_RINGTONE) 751f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SEND_TO_VOICEMAIL) 752f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.STARRED) 753f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.AGGREGATION_MODE) 75424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 755f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 756f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 757f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 758f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 759a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** Contains the columns from the raw entity view*/ 760f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawEntityProjectionMap = ProjectionMap.builder() 761f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts._ID) 762f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 763f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.Entity.DATA_ID) 764f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DELETED) 765f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.STARRED) 76624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 767f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 768f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 769f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 770f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 771f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 772a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** Contains the columns from the contact entity view*/ 773f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sEntityProjectionMap = ProjectionMap.builder() 774f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity._ID) 775f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.CONTACT_ID) 776f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.RAW_CONTACT_ID) 777f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.DATA_ID) 778f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.NAME_RAW_CONTACT_ID) 779f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.DELETED) 78024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(Contacts.IS_USER_PROFILE) 781f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 782f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 783f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 784f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 785f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 786f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 787f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 788f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 78958795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda /** Contains columns in PhoneLookup which are not contained in the data view. */ 79058795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda private static final ProjectionMap sSipLookupColumns = ProjectionMap.builder() 79158795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda .add(PhoneLookup.NUMBER, SipAddress.SIP_ADDRESS) 79258795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda .add(PhoneLookup.TYPE, "0") 79358795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda .add(PhoneLookup.LABEL, "NULL") 79458795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda .add(PhoneLookup.NORMALIZED_NUMBER, "NULL") 79558795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda .build(); 79658795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda 7974a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov /** Contains columns from the data view */ 798f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataProjectionMap = ProjectionMap.builder() 799f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data._ID) 800f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.RAW_CONTACT_ID) 801f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.CONTACT_ID) 802f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.NAME_RAW_CONTACT_ID) 80324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 804f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 805f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 806f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 807f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 808f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 809f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 810f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 81158795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda /** Contains columns from the data view used for SIP address lookup. */ 81258795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda private static final ProjectionMap sDataSipLookupProjectionMap = ProjectionMap.builder() 81358795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda .addAll(sDataProjectionMap) 81458795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda .addAll(sSipLookupColumns) 81558795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda .build(); 81658795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda 8175e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov /** Contains columns from the data view */ 818f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDistinctDataProjectionMap = ProjectionMap.builder() 819f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data._ID, "MIN(" + Data._ID + ")") 820f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 82124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 822f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 823f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 824f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 825f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 826f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 827f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 82858795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda /** Contains columns from the data view used for SIP address lookup. */ 82958795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda private static final ProjectionMap sDistinctDataSipLookupProjectionMap = ProjectionMap.builder() 83058795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda .addAll(sDistinctDataProjectionMap) 83158795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda .addAll(sSipLookupColumns) 83258795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda .build(); 83358795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda 8349261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** Contains the data and contacts columns, for joined tables */ 835f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sPhoneLookupProjectionMap = ProjectionMap.builder() 836f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup._ID, "contacts_view." + Contacts._ID) 837f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LOOKUP_KEY, "contacts_view." + Contacts.LOOKUP_KEY) 838f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.DISPLAY_NAME, "contacts_view." + Contacts.DISPLAY_NAME) 839f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LAST_TIME_CONTACTED, "contacts_view." + Contacts.LAST_TIME_CONTACTED) 840f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.TIMES_CONTACTED, "contacts_view." + Contacts.TIMES_CONTACTED) 841f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.STARRED, "contacts_view." + Contacts.STARRED) 842f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.IN_VISIBLE_GROUP, "contacts_view." + Contacts.IN_VISIBLE_GROUP) 843f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.PHOTO_ID, "contacts_view." + Contacts.PHOTO_ID) 8443d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(PhoneLookup.PHOTO_URI, "contacts_view." + Contacts.PHOTO_URI) 8453d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(PhoneLookup.PHOTO_THUMBNAIL_URI, "contacts_view." + Contacts.PHOTO_THUMBNAIL_URI) 846f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.CUSTOM_RINGTONE, "contacts_view." + Contacts.CUSTOM_RINGTONE) 847f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.HAS_PHONE_NUMBER, "contacts_view." + Contacts.HAS_PHONE_NUMBER) 848f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.SEND_TO_VOICEMAIL, "contacts_view." + Contacts.SEND_TO_VOICEMAIL) 849f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.NUMBER, Phone.NUMBER) 850f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.TYPE, Phone.TYPE) 851f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LABEL, Phone.LABEL) 8522530512f639c4979fd7371c7dd25dd67e8118124Bai Tao .add(PhoneLookup.NORMALIZED_NUMBER, Phone.NORMALIZED_NUMBER) 853f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 854f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 855ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** Contains the just the {@link Groups} columns */ 856f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sGroupsProjectionMap = ProjectionMap.builder() 857f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups._ID) 858f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.ACCOUNT_NAME) 859f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.ACCOUNT_TYPE) 86043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(Groups.DATA_SET) 86143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(Groups.ACCOUNT_TYPE_AND_DATA_SET) 862f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SOURCE_ID) 863f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.DIRTY) 864f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.VERSION) 865f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.RES_PACKAGE) 866f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.TITLE) 867f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.TITLE_RES) 868f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.GROUP_VISIBLE) 869f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYSTEM_ID) 870f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.DELETED) 871f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.NOTES) 872f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SHOULD_SYNC) 873f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.FAVORITES) 874f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.AUTO_ADD) 875c039cfb78c40730483fd71178df63ada5826a315Dmitri Plotnikov .add(Groups.GROUP_IS_READ_ONLY) 876f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC1) 877f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC2) 878f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC3) 879f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC4) 880f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 881f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 88223ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki /** 88323ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki * Contains {@link Groups} columns along with summary details. 88423ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki * 88523ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki * Note {@link Groups#SUMMARY_COUNT} doesn't exist in groups/view_groups. 88623ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki * When we detect this column being requested, we join {@link Joins#GROUP_MEMBER_COUNT} to 88723ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki * generate it. 88818b09495f5f37b38ff2e1c965e087dfde68c27fbMakoto Onuki * 88918b09495f5f37b38ff2e1c965e087dfde68c27fbMakoto Onuki * TODO Support SUMMARY_GROUP_COUNT_PER_ACCOUNT too. See also queryLocal(). 89023ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki */ 891f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sGroupsSummaryProjectionMap = ProjectionMap.builder() 892f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sGroupsProjectionMap) 89323ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki .add(Groups.SUMMARY_COUNT, "ifnull(group_member_count, 0)") 894f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SUMMARY_WITH_PHONES, 895f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa "(SELECT COUNT(" + ContactsColumns.CONCRETE_ID + ") FROM " 896f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Tables.CONTACTS_JOIN_RAW_CONTACTS_DATA_FILTERED_BY_GROUPMEMBERSHIP 897f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + " WHERE " + Contacts.HAS_PHONE_NUMBER + ")") 89818b09495f5f37b38ff2e1c965e087dfde68c27fbMakoto Onuki .add(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, "0") // Always returns 0 for now. 899f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 900f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 901373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov /** Contains the agg_exceptions columns */ 902f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sAggregationExceptionsProjectionMap = ProjectionMap.builder() 903f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptionColumns._ID, Tables.AGGREGATION_EXCEPTIONS + "._id") 904f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.TYPE) 905f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.RAW_CONTACT_ID1) 906f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.RAW_CONTACT_ID2) 907f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 908f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 909eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey /** Contains the agg_exceptions columns */ 910f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sSettingsProjectionMap = ProjectionMap.builder() 911f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ACCOUNT_NAME) 912f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ACCOUNT_TYPE) 913f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro .add(Settings.DATA_SET) 914f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_VISIBLE) 915f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.SHOULD_SYNC) 916f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ANY_UNSYNCED, 917f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(CASE WHEN MIN(" + Settings.SHOULD_SYNC 918f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + ",(SELECT " 919f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "(CASE WHEN MIN(" + Groups.SHOULD_SYNC + ") IS NULL" 920f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN 1" 921f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE MIN(" + Groups.SHOULD_SYNC + ")" 922f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " END)" 9239d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + " FROM " + Views.GROUPS 9249d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + " WHERE " + ViewGroupsColumns.CONCRETE_ACCOUNT_NAME + "=" 925f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + SettingsColumns.CONCRETE_ACCOUNT_NAME 9269d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + " AND " + ViewGroupsColumns.CONCRETE_ACCOUNT_TYPE + "=" 927f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro + SettingsColumns.CONCRETE_ACCOUNT_TYPE 9289d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + " AND ((" + ViewGroupsColumns.CONCRETE_DATA_SET + " IS NULL AND " 929f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro + SettingsColumns.CONCRETE_DATA_SET + " IS NULL) OR (" 9309d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + ViewGroupsColumns.CONCRETE_DATA_SET + "=" 931f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro + SettingsColumns.CONCRETE_DATA_SET + "))))=0" 932f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN 1" 933f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE 0" 934f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " END)") 935f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_COUNT, 936f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(SELECT COUNT(*)" 937f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM (SELECT 1" 938f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS 939f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID 940f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " HAVING " + Clauses.HAVING_NO_GROUPS 941f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "))") 942f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_WITH_PHONES, 943f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(SELECT COUNT(*)" 944f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM (SELECT 1" 945f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS 946f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " WHERE " + Contacts.HAS_PHONE_NUMBER 947f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID 948f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " HAVING " + Clauses.HAVING_NO_GROUPS 949f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "))") 950f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 951f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 95282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov /** Contains StatusUpdates columns */ 953f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStatusUpdatesProjectionMap = ProjectionMap.builder() 954f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PresenceColumns.RAW_CONTACT_ID) 955f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.DATA_ID, DataColumns.CONCRETE_ID) 956f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.IM_ACCOUNT) 957f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.IM_HANDLE) 958f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.PROTOCOL) 959f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // We cannot allow a null in the custom protocol field, because SQLite3 does not 960f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // properly enforce uniqueness of null values 961f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.CUSTOM_PROTOCOL, 962f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(CASE WHEN " + StatusUpdates.CUSTOM_PROTOCOL + "=''" 963f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN NULL" 964f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE " + StatusUpdates.CUSTOM_PROTOCOL + " END)") 965f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.PRESENCE) 966f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.CHAT_CAPABILITY) 967f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS) 968f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_TIMESTAMP) 969f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_RES_PACKAGE) 970f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_ICON) 971f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_LABEL) 972f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 973f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 9743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** Contains StreamItems columns */ 9753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final ProjectionMap sStreamItemsProjectionMap = ProjectionMap.builder() 9769b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems._ID) 9779b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems.CONTACT_ID) 978af10329f85c5d8c4196c495a9f0f9a6c6ecbc231Daniel Lehmann .add(StreamItems.CONTACT_LOOKUP_KEY) 9799b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems.ACCOUNT_NAME) 9809b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems.ACCOUNT_TYPE) 9819b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems.DATA_SET) 9823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RAW_CONTACT_ID) 9839b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems.RAW_CONTACT_SOURCE_ID) 9843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_PACKAGE) 9853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_ICON) 9863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_LABEL) 9873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.TEXT) 9883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.TIMESTAMP) 9893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.COMMENTS) 9900bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItems.SYNC1) 9910bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItems.SYNC2) 9920bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItems.SYNC3) 9930bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItems.SYNC4) 9943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .build(); 9953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 9963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final ProjectionMap sStreamItemPhotosProjectionMap = ProjectionMap.builder() 9973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos._ID, StreamItemPhotosColumns.CONCRETE_ID) 9983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RAW_CONTACT_ID) 9990bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItems.RAW_CONTACT_SOURCE_ID, RawContactsColumns.CONCRETE_SOURCE_ID) 10003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.STREAM_ITEM_ID) 10013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.SORT_INDEX) 10026802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .add(StreamItemPhotos.PHOTO_FILE_ID) 10036802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .add(StreamItemPhotos.PHOTO_URI, 10046802030a777c0c3ba1dc029c534cca4784260632Dave Santoro "'" + DisplayPhoto.CONTENT_URI + "'||'/'||" + StreamItemPhotos.PHOTO_FILE_ID) 10051dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.HEIGHT) 10061dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.WIDTH) 10071dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.FILESIZE) 10080bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItemPhotos.SYNC1) 10090bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItemPhotos.SYNC2) 10100bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItemPhotos.SYNC3) 10110bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItemPhotos.SYNC4) 10123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .build(); 10133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 1014d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** Contains {@link Directory} columns */ 1015f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDirectoryProjectionMap = ProjectionMap.builder() 1016f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory._ID) 1017f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.PACKAGE_NAME) 1018f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.TYPE_RESOURCE_ID) 1019f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.DISPLAY_NAME) 1020f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.DIRECTORY_AUTHORITY) 1021f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.ACCOUNT_TYPE) 1022f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.ACCOUNT_NAME) 1023f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.EXPORT_SUPPORT) 1024778d92d4dce5f76c649e2aca9d00d3f214cd7643Dmitri Plotnikov .add(Directory.SHORTCUT_SUPPORT) 1025778d92d4dce5f76c649e2aca9d00d3f214cd7643Dmitri Plotnikov .add(Directory.PHOTO_SUPPORT) 1026f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 10277e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 10289705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // where clause to update the status_updates table 10299705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private static final String WHERE_CLAUSE_FOR_STATUS_UPDATES_TABLE = 10309705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdatesColumns.DATA_ID + " IN (SELECT Distinct " + StatusUpdates.DATA_ID + 10319705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori " FROM " + Tables.STATUS_UPDATES + " LEFT OUTER JOIN " + Tables.PRESENCE + 10329705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori " ON " + StatusUpdatesColumns.DATA_ID + " = " + StatusUpdates.DATA_ID + " WHERE "; 10339705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 10342526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov private static final String[] EMPTY_STRING_ARRAY = new String[0]; 10352526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov 1036bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 1037bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Notification ID for failure to import contacts. 1038bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 1039bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private static final int LEGACY_IMPORT_FAILED_NOTIFICATION = 1; 104051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 104103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_START_MATCH = "["; 104203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_END_MATCH = "]"; 104303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_ELLIPSIS = "..."; 104403197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final int DEFAULT_SNIPPET_ARG_MAX_TOKENS = -10; 104503197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 1046193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private boolean mIsPhoneInitialized; 1047193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private boolean mIsPhone; 10489a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 1049193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private final StringBuilder mSb = new StringBuilder(); 1050193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private final String[] mSelectionArgs1 = new String[1]; 1051193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private final String[] mSelectionArgs2 = new String[2]; 1052dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki private final String[] mSelectionArgs3 = new String[3]; 1053dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki private final String[] mSelectionArgs4 = new String[4]; 1054193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private final ArrayList<String> mSelectionArgs = Lists.newArrayList(); 10552526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov 1056f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private Account mAccount; 1057f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 10584f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton static { 10594f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton // Contacts URI matching table 1060a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final UriMatcher matcher = sUriMatcher; 1061d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts", CONTACTS); 1062d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID); 1063a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_ID_DATA); 1064a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/entities", CONTACTS_ID_ENTITIES); 10653653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions", 10663653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov AGGREGATION_SUGGESTIONS); 10672d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions/*", 10682d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov AGGREGATION_SUGGESTIONS); 1069a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/photo", CONTACTS_ID_PHOTO); 1070f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/display_photo", 1071f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_ID_DISPLAY_PHOTO); 10723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/stream_items", 10733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_ID_STREAM_ITEMS); 1074c9e6d75562621a3dee26a99c2b082e2fd9b0c8b3Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter", CONTACTS_FILTER); 10755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter/*", CONTACTS_FILTER); 10765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*", CONTACTS_LOOKUP); 10772149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/data", CONTACTS_LOOKUP_DATA); 1078bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/photo", 1079bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro CONTACTS_LOOKUP_PHOTO); 10805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_LOOKUP_ID); 10812149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/data", 10822149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov CONTACTS_LOOKUP_ID_DATA); 1083bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/photo", 1084bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro CONTACTS_LOOKUP_ID_PHOTO); 1085f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/display_photo", 1086f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_LOOKUP_DISPLAY_PHOTO); 1087f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/display_photo", 1088f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_LOOKUP_ID_DISPLAY_PHOTO); 1089a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/entities", 1090a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov CONTACTS_LOOKUP_ENTITIES); 1091a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/entities", 1092a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov CONTACTS_LOOKUP_ID_ENTITIES); 10933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/stream_items", 10943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_LOOKUP_STREAM_ITEMS); 10953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/stream_items", 10963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_LOOKUP_ID_STREAM_ITEMS); 1097f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_vcard/*", CONTACTS_AS_VCARD); 109842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_multi_vcard/*", 109942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann CONTACTS_AS_MULTI_VCARD); 11005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/", CONTACTS_STREQUENT); 1101ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/filter/*", 1102ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov CONTACTS_STREQUENT_FILTER); 11035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/group/*", CONTACTS_GROUP); 110445ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "contacts/frequent", CONTACTS_FREQUENT); 1105b6186821548995dce533ee502e82e9abf4c0aadcMakoto Onuki matcher.addURI(ContactsContract.AUTHORITY, "contacts/delete_usage", CONTACTS_DELETE_USAGE); 11063653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov 11075ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS); 11085ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#", RAW_CONTACTS_ID); 1109193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/data", RAW_CONTACTS_ID_DATA); 1110f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/display_photo", 1111f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro RAW_CONTACTS_ID_DISPLAY_PHOTO); 1112193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/entity", RAW_CONTACT_ID_ENTITY); 11133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/stream_items", 11143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann RAW_CONTACTS_ID_STREAM_ITEMS); 111582780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/stream_items/#", 111682780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro RAW_CONTACTS_ID_STREAM_ITEMS_ID); 111746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 111846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana matcher.addURI(ContactsContract.AUTHORITY, "raw_contact_entities", RAW_CONTACT_ENTITIES); 1119b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 11204f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data", DATA); 11214f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID); 1122ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones", PHONES); 112348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/phones/#", PHONES_ID); 11245e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter", PHONES_FILTER); 1125ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter/*", PHONES_FILTER); 11264a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails", EMAILS); 112748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/#", EMAILS_ID); 11281dac83b8fa58944acfd00f44e717a7dddc659d2dDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup", EMAILS_LOOKUP); 11295e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup/*", EMAILS_LOOKUP); 11305e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter", EMAILS_FILTER); 11314a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter/*", EMAILS_FILTER); 1132ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/postals", POSTALS); 113348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/postals/#", POSTALS_ID); 113446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** "*" is in CSV form with data ids ("123,456,789") */ 113546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "data/usagefeedback/*", DATA_USAGE_FEEDBACK_ID); 1136e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "data/callables/", CALLABLES); 1137e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "data/callables/#", CALLABLES_ID); 1138e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "data/callables/filter", CALLABLES_FILTER); 1139e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "data/callables/filter/*", CALLABLES_FILTER); 11401f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1141ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups", GROUPS); 1142ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups/#", GROUPS_ID); 1143ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups_summary", GROUPS_SUMMARY); 1144ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 114535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH, SYNCSTATE); 1146b5a4add17815167d20a90645779df34cdf45280dFred Quintana matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH + "/#", 1147b5a4add17815167d20a90645779df34cdf45280dFred Quintana SYNCSTATE_ID); 11485d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/" + SyncStateContentProviderHelper.PATH, 11495d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PROFILE_SYNCSTATE); 11505d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, 11515d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro "profile/" + SyncStateContentProviderHelper.PATH + "/#", 11525d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PROFILE_SYNCSTATE_ID); 115335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1154a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "phone_lookup/*", PHONE_LOOKUP); 1155b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions", 1156b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTIONS); 1157b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions/*", 1158b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTION_ID); 11594f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1160eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "settings", SETTINGS); 1161eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 116282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "status_updates", STATUS_UPDATES); 116382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "status_updates/#", STATUS_UPDATES_ID); 11641f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1165c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, 1166c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SUGGESTIONS); 1167c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", 1168c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SUGGESTIONS); 11692d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*", 1170c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SHORTCUT); 1171c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 117209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "provider_status", PROVIDER_STATUS); 1173d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 1174d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "directories", DIRECTORIES); 1175d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "directories/#", DIRECTORIES_ID); 11767a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 11777a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "complete_name", COMPLETE_NAME); 117824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 117924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile", PROFILE); 118024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/entities", PROFILE_ENTITIES); 118124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/data", PROFILE_DATA); 118224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/data/#", PROFILE_DATA_ID); 118385077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/photo", PROFILE_PHOTO); 118485077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/display_photo", PROFILE_DISPLAY_PHOTO); 118524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/as_vcard", PROFILE_AS_VCARD); 118624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts", PROFILE_RAW_CONTACTS); 118724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#", 118824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID); 118924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#/data", 119024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID_DATA); 119124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#/entity", 119224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID_ENTITIES); 11935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/status_updates", 11945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PROFILE_STATUS_UPDATES); 11953202ae2de5c5fec9f5f61003a0e6b608283e1961Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contact_entities", 11963202ae2de5c5fec9f5f61003a0e6b608283e1961Dave Santoro PROFILE_RAW_CONTACT_ENTITIES); 119746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 11983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items", STREAM_ITEMS); 11993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/photo", STREAM_ITEMS_PHOTOS); 12003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#", STREAM_ITEMS_ID); 12013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#/photo", STREAM_ITEMS_ID_PHOTOS); 12023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#/photo/#", 12033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann STREAM_ITEMS_ID_PHOTOS_ID); 12043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items_limit", STREAM_ITEMS_LIMIT); 12053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 1206193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki matcher.addURI(ContactsContract.AUTHORITY, "display_photo/#", DISPLAY_PHOTO_ID); 1207f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "photo_dimensions", PHOTO_DIMENSIONS); 120819a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov } 120919a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov 1210d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static class DirectoryInfo { 1211d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String authority; 1212d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String accountName; 1213d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String accountType; 1214d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 1215d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 1216d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** 1217d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov * Cached information about contact directories. 1218d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov */ 12194458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov private HashMap<String, DirectoryInfo> mDirectoryCache = new HashMap<String, DirectoryInfo>(); 12204458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov private boolean mDirectoryCacheValid = false; 1221d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 12223cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** 12239d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * An entry in group id cache. 12249d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * 12259d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * TODO: Move this and {@link #mGroupIdCache} to {@link DataRowHandlerForGroupMembership}. 1226ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov */ 1227e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov public static class GroupIdCacheEntry { 12289d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki long accountId; 1229ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String sourceId; 1230ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov long groupId; 1231ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov } 1232a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov 12339d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki /** 12349d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * Map from group source IDs to lists of {@link GroupIdCacheEntry}s. 12359d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * 12369d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * We don't need a soft cache for groups - the assumption is that there will only 12379d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * be a small number of contact groups. The cache is keyed off source id. The value 12389d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * is a list of groups with this group id. 12399d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki */ 1240e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov private HashMap<String, ArrayList<GroupIdCacheEntry>> mGroupIdCache = Maps.newHashMap(); 1241e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov 124224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 12435d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Sub-provider for handling profile requests against the profile database. 12445d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 12455d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private ProfileProvider mProfileProvider; 1246f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 12474097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov private NameSplitter mNameSplitter; 1248f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov private NameLookupBuilder mNameLookupBuilder; 1249315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov 1250622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey private PostalSplitter mPostalSplitter; 1251622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey 125272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov private ContactDirectoryManager mContactDirectoryManager; 12535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 1254078f588cef389358adabc579de00747878f3c108Dave Santoro // The database tag to use for representing the contacts DB in contacts transactions. 1255078f588cef389358adabc579de00747878f3c108Dave Santoro /* package */ static final String CONTACTS_DB_TAG = "contacts"; 1256078f588cef389358adabc579de00747878f3c108Dave Santoro 1257078f588cef389358adabc579de00747878f3c108Dave Santoro // The database tag to use for representing the profile DB in contacts transactions. 1258078f588cef389358adabc579de00747878f3c108Dave Santoro /* package */ static final String PROFILE_DB_TAG = "profile"; 1259078f588cef389358adabc579de00747878f3c108Dave Santoro 12605d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 12615d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * The active (thread-local) database. This will be switched between a contacts-specific 12625d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * database and a profile-specific database, depending on what the current operation is 12635d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * targeted to. 12645d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 12655d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<SQLiteDatabase> mActiveDb = new ThreadLocal<SQLiteDatabase>(); 12665d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 12676efb7db26598b105342d02207e0ca1c8725c10daDave Santoro /** 12686efb7db26598b105342d02207e0ca1c8725c10daDave Santoro * The thread-local holder of the active transaction. Shared between this and the profile 12696efb7db26598b105342d02207e0ca1c8725c10daDave Santoro * provider, to keep transactions on both databases synchronized. 12706efb7db26598b105342d02207e0ca1c8725c10daDave Santoro */ 12716efb7db26598b105342d02207e0ca1c8725c10daDave Santoro private final ThreadLocal<ContactsTransaction> mTransactionHolder = 12726efb7db26598b105342d02207e0ca1c8725c10daDave Santoro new ThreadLocal<ContactsTransaction>(); 12736efb7db26598b105342d02207e0ca1c8725c10daDave Santoro 12745d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // This variable keeps track of whether the current operation is intended for the profile DB. 12755d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<Boolean> mInProfileMode = new ThreadLocal<Boolean>(); 12765d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 12775d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Separate data row handler instances for contact data and profile data. 12785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private HashMap<String, DataRowHandler> mDataRowHandlers; 12795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private HashMap<String, DataRowHandler> mProfileDataRowHandlers; 12805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 12815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Depending on whether the action being performed is for the profile, we will use one of two 12825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // database helper instances. 12835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<ContactsDatabaseHelper> mDbHelper = 12845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new ThreadLocal<ContactsDatabaseHelper>(); 12855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private ContactsDatabaseHelper mContactsHelper; 12865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private ProfileDatabaseHelper mProfileHelper; 12875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 12885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Depending on whether the action being performed is for the profile or not, we will use one of 12895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // two aggregator instances. 12905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<ContactAggregator> mAggregator = new ThreadLocal<ContactAggregator>(); 1291622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey private ContactAggregator mContactAggregator; 12925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private ContactAggregator mProfileAggregator; 12935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 12945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Depending on whether the action being performed is for the profile or not, we will use one of 12955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // two photo store instances (with their files stored in separate subdirectories). 12965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<PhotoStore> mPhotoStore = new ThreadLocal<PhotoStore>(); 12975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private PhotoStore mContactsPhotoStore; 12985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private PhotoStore mProfilePhotoStore; 12995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 13005d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // The active transaction context will switch depending on the operation being performed. 13015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Both transaction contexts will be cleared out when a batch transaction is started, and 13025d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // each will be processed separately when a batch transaction completes. 1303193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private final TransactionContext mContactTransactionContext = new TransactionContext(false); 1304193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private final TransactionContext mProfileTransactionContext = new TransactionContext(true); 13055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<TransactionContext> mTransactionContext = 13065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new ThreadLocal<TransactionContext>(); 13075d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 130882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Duration in milliseconds that pre-authorized URIs will remain valid. 130982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro private long mPreAuthorizedUriDuration; 131082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 131182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Map of single-use pre-authorized URIs to expiration times. 1312193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private final Map<Uri, Long> mPreAuthorizedUris = Maps.newHashMap(); 131382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 1314d0eb93009559d095de0448907527aeb059801dc4Dave Santoro // Random number generator. 1315193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private final SecureRandom mRandom = new SecureRandom(); 131682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 1317f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov private LegacyApiSupport mLegacyApiSupport; 1318a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov private GlobalSearchSupport mGlobalSearchSupport; 1319d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov private CommonNicknameCache mCommonNicknameCache; 1320f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov private SearchIndexManager mSearchIndexManager; 1321a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 1322193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private final ContentValues mValues = new ContentValues(); 1323193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private final HashMap<String, Boolean> mAccountWritability = Maps.newHashMap(); 132420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 132509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private int mProviderStatus = ProviderStatus.STATUS_NORMAL; 13263826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private boolean mProviderStatusUpdateNeeded; 132709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private long mEstimatedStorageRequirement = 0; 132815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private volatile CountDownLatch mReadAccessLatch; 132915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private volatile CountDownLatch mWriteAccessLatch; 133015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private boolean mAccountUpdateListenerRegistered; 1331bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private boolean mOkToOpenAccess = true; 133273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 13331a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey private boolean mVisibleTouched = false; 13341a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey 133581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov private boolean mSyncToNetwork; 133681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 13374cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao private Locale mCurrentLocale; 13383826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private int mContactsAccountCount; 1339d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov 1340bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private HandlerThread mBackgroundThread; 1341bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private Handler mBackgroundHandler; 1342bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1343f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private long mLastPhotoCleanup = 0; 1344f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 134535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki private FastScrollingIndexCache mFastScrollingIndexCache; 134635997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 134735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki // Stats about FastScrollingIndex. 134835997f3fdee2984b6d5373326110eda26929001aMakoto Onuki private int mFastScrollingIndexCacheRequestCount; 134935997f3fdee2984b6d5373326110eda26929001aMakoto Onuki private int mFastScrollingIndexCacheMissCount; 135035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki private long mTotalTimeFastScrollingIndexGenerate; 135135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 13524f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 13534f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public boolean onCreate() { 1354663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) { 1355663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki Log.d(Constants.PERFORMANCE_TAG, "ContactsProvider2.onCreate start"); 1356663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki } 1357de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov super.onCreate(); 1358ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov try { 1359ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov return initialize(); 1360ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } catch (RuntimeException e) { 1361ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov Log.e(TAG, "Cannot start provider", e); 1362887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki // In production code we don't want to throw here, so that phone will still work 1363887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki // in low storage situations. 1364887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki // See I5c88a3024ff1c5a06b5756b29a2d903f8f6a2531 1365887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki if (shouldThrowExceptionForInitializationError()) { 1366887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki throw e; 1367887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki } 1368ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov return false; 1369663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki } finally { 1370663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) { 1371663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki Log.d(Constants.PERFORMANCE_TAG, "ContactsProvider2.onCreate finish"); 1372663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki } 1373ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } 1374ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } 137535ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1376887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki protected boolean shouldThrowExceptionForInitializationError() { 1377887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki return false; 1378887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki } 1379887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki 1380ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov private boolean initialize() { 138115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov StrictMode.setThreadPolicy( 138215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()); 138315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 138435997f3fdee2984b6d5373326110eda26929001aMakoto Onuki mFastScrollingIndexCache = new FastScrollingIndexCache(getContext()); 138535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 1386078f588cef389358adabc579de00747878f3c108Dave Santoro mContactsHelper = getDatabaseHelper(getContext()); 13875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.set(mContactsHelper); 1388078f588cef389358adabc579de00747878f3c108Dave Santoro 1389078f588cef389358adabc579de00747878f3c108Dave Santoro // Set up the DB helper for keeping transactions serialized. 1390078f588cef389358adabc579de00747878f3c108Dave Santoro setDbHelperToSerializeOn(mContactsHelper, CONTACTS_DB_TAG); 1391078f588cef389358adabc579de00747878f3c108Dave Santoro 139272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov mContactDirectoryManager = new ContactDirectoryManager(this); 1393a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov mGlobalSearchSupport = new GlobalSearchSupport(this); 139465ce381c2bb7ddcc3e7d3b8f5f7095831be97603Dmitri Plotnikov 1395bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov // The provider is closed for business until fully initialized 139615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch = new CountDownLatch(1); 139715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch = new CountDownLatch(1); 139872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 1399bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundThread = new HandlerThread("ContactsProviderWorker", 1400bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov Process.THREAD_PRIORITY_BACKGROUND); 1401bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundThread.start(); 1402bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler = new Handler(mBackgroundThread.getLooper()) { 1403bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov @Override 1404bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov public void handleMessage(Message msg) { 1405bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov performBackgroundTask(msg.what, msg.obj); 1406bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1407bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov }; 14082a0d5f9c628e723261bc5198e0fd606076b76b74Dmitri Plotnikov 14095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Set up the sub-provider for handling profiles. 14105d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileProvider = getProfileProvider(); 1411c990980ab4beb7b81c3337526f1bdcd5d1a14730Dave Santoro mProfileProvider.setDbHelperToSerializeOn(mContactsHelper, CONTACTS_DB_TAG); 14125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro ProviderInfo profileInfo = new ProviderInfo(); 14135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro profileInfo.readPermission = "android.permission.READ_PROFILE"; 14145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro profileInfo.writePermission = "android.permission.WRITE_PROFILE"; 14155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileProvider.attachInfo(getContext(), profileInfo); 1416078f588cef389358adabc579de00747878f3c108Dave Santoro mProfileHelper = mProfileProvider.getDatabaseHelper(getContext()); 14175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 141882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Initialize the pre-authorized URI duration. 141982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro mPreAuthorizedUriDuration = android.provider.Settings.Secure.getLong( 142082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro getContext().getContentResolver(), 142182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro android.provider.Settings.Secure.CONTACTS_PREAUTH_URI_EXPIRATION, 142282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro DEFAULT_PREAUTHORIZED_URI_EXPIRATION); 142382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 142415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_INITIALIZE); 1425bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_ACCOUNTS); 1426bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_LOCALE); 1427bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM); 142805e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_SEARCH_INDEX); 1429bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_PROVIDER_STATUS); 143015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_OPEN_WRITE_ACCESS); 1431f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 14323826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 143349d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov return true; 14344f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 14354f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1436767e109d6f08749b9ed202c0b71f3459eaae2115Dmitri Plotnikov /** 143751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * (Re)allocates all locale-sensitive structures. 143851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov */ 143904b7ce026c73077d9d982742bc662ea4b3ac74e7Dmitri Plotnikov private void initForDefaultLocale() { 144015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Context context = getContext(); 14415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mLegacyApiSupport = new LegacyApiSupport(context, mContactsHelper, this, 14425d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mGlobalSearchSupport); 14434cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mCurrentLocale = getLocale(); 14445d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mNameSplitter = mContactsHelper.createNameSplitter(); 14454cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mNameLookupBuilder = new StructuredNameLookupBuilder(mNameSplitter); 14464cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mPostalSplitter = new PostalSplitter(mCurrentLocale); 14475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mCommonNicknameCache = new CommonNicknameCache(mContactsHelper.getReadableDatabase()); 1448cdd03b2ba03718a7fa85663a2438136284a1557cBai Tao ContactLocaleUtils.getIntance().setLocale(mCurrentLocale); 14495d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactAggregator = new ContactAggregator(this, mContactsHelper, 145015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov createPhotoPriorityResolver(context), mNameSplitter, mCommonNicknameCache); 14515b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov mContactAggregator.setEnabled(SystemProperties.getBoolean(AGGREGATE_CONTACTS, true)); 14525d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileAggregator = new ProfileAggregator(this, mProfileHelper, 14535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro createPhotoPriorityResolver(context), mNameSplitter, mCommonNicknameCache); 14545d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileAggregator.setEnabled(SystemProperties.getBoolean(AGGREGATE_CONTACTS, true)); 1455f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov mSearchIndexManager = new SearchIndexManager(this); 14565d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 14575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsPhotoStore = new PhotoStore(getContext().getFilesDir(), mContactsHelper); 14585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfilePhotoStore = new PhotoStore(new File(getContext().getFilesDir(), "profile"), 14595d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileHelper); 14605b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov 1461bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers = new HashMap<String, DataRowHandler>(); 14625d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro initDataRowHandlers(mDataRowHandlers, mContactsHelper, mContactAggregator, 14635d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsPhotoStore); 14645d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileDataRowHandlers = new HashMap<String, DataRowHandler>(); 14655d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro initDataRowHandlers(mProfileDataRowHandlers, mProfileHelper, mProfileAggregator, 14665d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfilePhotoStore); 14675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 14685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Set initial thread-local state variables for the Contacts DB. 14695d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 14705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 1471bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 14725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private void initDataRowHandlers(Map<String, DataRowHandler> handlerMap, 14735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro ContactsDatabaseHelper dbHelper, ContactAggregator contactAggregator, 14745d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PhotoStore photoStore) { 14755d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Context context = getContext(); 14765d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Email.CONTENT_ITEM_TYPE, 14775d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForEmail(context, dbHelper, contactAggregator)); 14785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Im.CONTENT_ITEM_TYPE, 14795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForIm(context, dbHelper, contactAggregator)); 14805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Organization.CONTENT_ITEM_TYPE, 14815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForOrganization(context, dbHelper, contactAggregator)); 14825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Phone.CONTENT_ITEM_TYPE, 14835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForPhoneNumber(context, dbHelper, contactAggregator)); 14845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Nickname.CONTENT_ITEM_TYPE, 14855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForNickname(context, dbHelper, contactAggregator)); 14865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(StructuredName.CONTENT_ITEM_TYPE, 14875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForStructuredName(context, dbHelper, contactAggregator, 1488bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mNameSplitter, mNameLookupBuilder)); 14895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(StructuredPostal.CONTENT_ITEM_TYPE, 14905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForStructuredPostal(context, dbHelper, contactAggregator, 1491bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mPostalSplitter)); 14925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(GroupMembership.CONTENT_ITEM_TYPE, 14935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForGroupMembership(context, dbHelper, contactAggregator, 1494bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mGroupIdCache)); 14955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Photo.CONTENT_ITEM_TYPE, 14965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForPhoto(context, dbHelper, contactAggregator, photoStore)); 14975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Note.CONTENT_ITEM_TYPE, 14985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForNote(context, dbHelper, contactAggregator)); 1499bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1500bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1501193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki @VisibleForTesting 1502193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki PhotoPriorityResolver createPhotoPriorityResolver(Context context) { 1503bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov return new PhotoPriorityResolver(context); 1504bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1505bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1506bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void scheduleBackgroundTask(int task) { 1507bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler.sendEmptyMessage(task); 1508bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1509bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1510bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void scheduleBackgroundTask(int task, Object arg) { 1511bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler.sendMessage(mBackgroundHandler.obtainMessage(task, arg)); 1512bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1513bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1514bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void performBackgroundTask(int task, Object arg) { 1515bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov switch (task) { 151615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov case BACKGROUND_TASK_INITIALIZE: { 151715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov initForDefaultLocale(); 151815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch.countDown(); 151915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch = null; 152015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov break; 152115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 152215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 152315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov case BACKGROUND_TASK_OPEN_WRITE_ACCESS: { 1524bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (mOkToOpenAccess) { 152515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch.countDown(); 152615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch = null; 1527bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1528bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1529bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1530bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1531bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_ACCOUNTS: { 153215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Context context = getContext(); 153315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (!mAccountUpdateListenerRegistered) { 153415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov AccountManager.get(context).addOnAccountsUpdatedListener(this, null, false); 153515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mAccountUpdateListenerRegistered = true; 153615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 153715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 15385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Update the accounts for both the contacts and profile DBs. 153915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Account[] accounts = AccountManager.get(context).getAccounts(); 15405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 1541bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov boolean accountsChanged = updateAccountsInBackground(accounts); 15425d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToProfileMode(); 15435d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro accountsChanged |= updateAccountsInBackground(accounts); 15445d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 1545bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateContactsAccountCount(accounts); 1546bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateDirectoriesInBackground(accountsChanged); 1547bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1548bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1549bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1550bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_LOCALE: { 1551bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateLocaleInBackground(); 1552bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1553bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1554bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1555fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov case BACKGROUND_TASK_CHANGE_LOCALE: { 1556fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov changeLocaleInBackground(); 1557fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov break; 1558fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1559fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 1560bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM: { 1561bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (isAggregationUpgradeNeeded()) { 1562bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov upgradeAggregationAlgorithmInBackground(); 1563bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1564bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1565bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1566bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 156705e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_SEARCH_INDEX: { 156805e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov updateSearchIndexInBackground(); 156905e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov break; 157005e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov } 157105e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov 1572bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_PROVIDER_STATUS: { 1573bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateProviderStatus(); 1574bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1575bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1576bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1577bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_DIRECTORIES: { 1578bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (arg != null) { 1579bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.onPackageChanged((String) arg); 1580bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1581bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1582bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1583f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1584f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case BACKGROUND_TASK_CLEANUP_PHOTOS: { 1585f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Check rate limit. 1586f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long now = System.currentTimeMillis(); 1587f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (now - mLastPhotoCleanup > PHOTO_CLEANUP_RATE_LIMIT) { 1588f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mLastPhotoCleanup = now; 15895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 15905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Clean up photo stores for both contacts and profiles. 15915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 15925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro cleanupPhotoStore(); 15935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToProfileMode(); 1594f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cleanupPhotoStore(); 1595f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro break; 1596f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1597f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1598bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 15994cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao } 16004cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao 160153fac8f99f3884c372c907a76766d27fa9e1d95fDmitri Plotnikov public void onLocaleChanged() { 16023826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != ProviderStatus.STATUS_NORMAL 16033826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov && mProviderStatus != ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS) { 16044f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov return; 16054f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov } 16064f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov 1607fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_CHANGE_LOCALE); 16084cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao } 160951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 161051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov /** 161151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * Verifies that the contacts database is properly configured for the current locale. 161251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * If not, changes the database locale to the current locale using an asynchronous task. 161351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * This needs to be done asynchronously because the process involves rebuilding 161451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * large data structures (name lookup, sort keys), which can take minutes on 161551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * a large set of contacts. 161651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov */ 1617bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void updateLocaleInBackground() { 1618f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov 1619f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov // The process is already running - postpone the change 1620f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov if (mProviderStatus == ProviderStatus.STATUS_CHANGING_LOCALE) { 1621f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov return; 1622f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov } 1623f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov 162451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); 162551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final String providerLocale = prefs.getString(PREF_LOCALE, null); 162651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final Locale currentLocale = mCurrentLocale; 162751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov if (currentLocale.toString().equals(providerLocale)) { 162851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov return; 162951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 163051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 163151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov int providerStatus = mProviderStatus; 163251f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_CHANGING_LOCALE); 16335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsHelper.setLocale(this, currentLocale); 16345d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileHelper.setLocale(this, currentLocale); 1635bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov prefs.edit().putString(PREF_LOCALE, currentLocale.toString()).apply(); 163635997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 1637bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov setProviderStatus(providerStatus); 1638bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 163951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 1640fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov /** 1641fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov * Reinitializes the provider for a new locale. 1642fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov */ 1643fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov private void changeLocaleInBackground() { 1644fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // Re-initializing the provider without stopping it. 1645fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // Locking the database will prevent inserts/updates/deletes from 1646fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // running at the same time, but queries may still be running 1647fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // on other threads. Those queries may return inconsistent results. 16485d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro SQLiteDatabase db = mContactsHelper.getWritableDatabase(); 16495d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro SQLiteDatabase profileDb = mProfileHelper.getWritableDatabase(); 1650fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.beginTransaction(); 16515d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro profileDb.beginTransaction(); 1652fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov try { 1653fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov initForDefaultLocale(); 1654fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.setTransactionSuccessful(); 16555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro profileDb.setTransactionSuccessful(); 1656fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } finally { 1657fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.endTransaction(); 16585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro profileDb.endTransaction(); 1659fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1660fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 1661fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov updateLocaleInBackground(); 1662fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1663fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 166405e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov protected void updateSearchIndexInBackground() { 166505e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov mSearchIndexManager.updateIndex(); 166605e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov } 166705e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov 1668bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void updateDirectoriesInBackground(boolean rescan) { 1669bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.scanAllPackages(rescan); 167051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 167151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 16723826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private void updateProviderStatus() { 16733826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != ProviderStatus.STATUS_NORMAL 16743826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov && mProviderStatus != ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS) { 16753826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return; 16763826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 16773826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 16783e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson // No accounts/no contacts status is true if there are no account and 16795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // there are no contacts or one profile contact 16803e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson if (mContactsAccountCount == 0) { 16815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long contactsNum = DatabaseUtils.queryNumEntries(mContactsHelper.getReadableDatabase(), 16823e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson Tables.CONTACTS, null); 16835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long profileNum = DatabaseUtils.queryNumEntries(mProfileHelper.getReadableDatabase(), 16845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Tables.CONTACTS, null); 16855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 16865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // TODO: Different status if there is a profile but no contacts? 16875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (contactsNum == 0 && profileNum <= 1) { 16883e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson setProviderStatus(ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS); 16893e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson } else { 16903e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson setProviderStatus(ProviderStatus.STATUS_NORMAL); 16913e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson } 16923826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } else { 16933826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_NORMAL); 16943826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 16953826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 16963826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 1697193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki @VisibleForTesting 1698f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro protected void cleanupPhotoStore() { 16995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 1700d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro mActiveDb.set(db); 17016802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 17026802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Assemble the set of photo store file IDs that are in use, and send those to the photo 1703f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // store. Any photos that aren't in that set will be deleted, and any photos that no 1704f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // longer exist in the photo store will be returned for us to clear out in the DB. 17057cf50494501938f175d288077145acf49da8f171Daniel Lehmann long photoMimeTypeId = mDbHelper.get().getMimeTypeId(Photo.CONTENT_ITEM_TYPE); 17066802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Cursor c = db.query(Views.DATA, new String[]{Data._ID, Photo.PHOTO_FILE_ID}, 17077cf50494501938f175d288077145acf49da8f171Daniel Lehmann DataColumns.MIMETYPE_ID + "=" + photoMimeTypeId + " AND " 1708f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro + Photo.PHOTO_FILE_ID + " IS NOT NULL", null, null, null, null); 17096802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Set<Long> usedPhotoFileIds = Sets.newHashSet(); 17106802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> photoFileIdToDataId = Maps.newHashMap(); 1711f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 1712f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro while (c.moveToNext()) { 17136802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long dataId = c.getLong(0); 17146802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = c.getLong(1); 17156802030a777c0c3ba1dc029c534cca4784260632Dave Santoro usedPhotoFileIds.add(photoFileId); 17166802030a777c0c3ba1dc029c534cca4784260632Dave Santoro photoFileIdToDataId.put(photoFileId, dataId); 17176802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 17186802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } finally { 17196802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.close(); 17206802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 17216802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 17226802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Also query for all social stream item photos. 1723c2714bbd397b09a20da476c89560e1caecdcce58Dave Santoro c = db.query(Tables.STREAM_ITEM_PHOTOS + " JOIN " + Tables.STREAM_ITEMS 1724887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki + " ON " + StreamItemPhotos.STREAM_ITEM_ID + "=" + StreamItemsColumns.CONCRETE_ID, 17256802030a777c0c3ba1dc029c534cca4784260632Dave Santoro new String[]{ 1726c2714bbd397b09a20da476c89560e1caecdcce58Dave Santoro StreamItemPhotosColumns.CONCRETE_ID, 1727c2714bbd397b09a20da476c89560e1caecdcce58Dave Santoro StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID, 1728887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki StreamItemPhotos.PHOTO_FILE_ID 17296802030a777c0c3ba1dc029c534cca4784260632Dave Santoro }, 17306802030a777c0c3ba1dc029c534cca4784260632Dave Santoro null, null, null, null, null); 17316802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> photoFileIdToStreamItemPhotoId = Maps.newHashMap(); 17326802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> streamItemPhotoIdToStreamItemId = Maps.newHashMap(); 17336802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 17346802030a777c0c3ba1dc029c534cca4784260632Dave Santoro while (c.moveToNext()) { 17356802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemPhotoId = c.getLong(0); 17366802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemId = c.getLong(1); 17376802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = c.getLong(2); 17386802030a777c0c3ba1dc029c534cca4784260632Dave Santoro usedPhotoFileIds.add(photoFileId); 17396802030a777c0c3ba1dc029c534cca4784260632Dave Santoro photoFileIdToStreamItemPhotoId.put(photoFileId, streamItemPhotoId); 17406802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemPhotoIdToStreamItemId.put(streamItemPhotoId, streamItemId); 1741f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1742f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 1743f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 1744f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1745f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1746f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Run the photo store cleanup. 17475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Set<Long> missingPhotoIds = mPhotoStore.get().cleanup(usedPhotoFileIds); 1748f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1749d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro // If any of the keys we're using no longer exist, clean them up. We need to do these 1750d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro // using internal APIs or direct DB access to avoid permission errors. 17516802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (!missingPhotoIds.isEmpty()) { 1752f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 1753d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro db.beginTransactionWithListener(this); 1754d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro for (long missingPhotoId : missingPhotoIds) { 1755d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro if (photoFileIdToDataId.containsKey(missingPhotoId)) { 1756d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro long dataId = photoFileIdToDataId.get(missingPhotoId); 1757d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro ContentValues updateValues = new ContentValues(); 1758d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro updateValues.putNull(Photo.PHOTO_FILE_ID); 1759d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro updateData(ContentUris.withAppendedId(Data.CONTENT_URI, dataId), 1760d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro updateValues, null, null, false); 1761d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } 1762d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro if (photoFileIdToStreamItemPhotoId.containsKey(missingPhotoId)) { 1763d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro // For missing photos that were in stream item photos, just delete the 1764d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro // stream item photo. 1765d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro long streamItemPhotoId = photoFileIdToStreamItemPhotoId.get(missingPhotoId); 1766d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro db.delete(Tables.STREAM_ITEM_PHOTOS, StreamItemPhotos._ID + "=?", 1767d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro new String[]{String.valueOf(streamItemPhotoId)}); 1768d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } 1769d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } 1770d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro db.setTransactionSuccessful(); 1771d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } catch (Exception e) { 1772d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro // Cleanup failure is not a fatal problem. We'll try again later. 1773d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro Log.e(TAG, "Failed to clean up outdated photo references", e); 1774d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } finally { 1775d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro db.endTransaction(); 1776f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1777f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1778f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1779f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 17806efb7db26598b105342d02207e0ca1c8725c10daDave Santoro @Override 1781b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov protected ContactsDatabaseHelper getDatabaseHelper(final Context context) { 1782b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return ContactsDatabaseHelper.getInstance(context); 178331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 178431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 17856efb7db26598b105342d02207e0ca1c8725c10daDave Santoro @Override 17866efb7db26598b105342d02207e0ca1c8725c10daDave Santoro protected ThreadLocal<ContactsTransaction> getTransactionHolder() { 17876efb7db26598b105342d02207e0ca1c8725c10daDave Santoro return mTransactionHolder; 17886efb7db26598b105342d02207e0ca1c8725c10daDave Santoro } 17896efb7db26598b105342d02207e0ca1c8725c10daDave Santoro 17905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro public ProfileProvider getProfileProvider() { 17915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return new ProfileProvider(this); 17925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 17935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 1794524913c66ce75ca8dec127ac88e3bc2249c246d9Dave Santoro @VisibleForTesting 1795f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /* package */ PhotoStore getPhotoStore() { 17965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mContactsPhotoStore; 1797f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1798f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1799d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro @VisibleForTesting 1800d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro /* package */ PhotoStore getProfilePhotoStore() { 1801d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro return mProfilePhotoStore; 1802d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } 1803d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro 1804c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki /** 1805c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki * Maximum dimension (height or width) of photo thumbnails. 1806c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki */ 1807c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki public int getMaxThumbnailDim() { 1808c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki return PhotoProcessor.getMaxThumbnailSize(); 180987614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro } 181087614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro 1811c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki /** 1812c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki * Maximum dimension (height or width) of display photos. Larger images will be scaled 1813c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki * to fit. 1814c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki */ 1815c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki public int getMaxDisplayPhotoDim() { 1816c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki return PhotoProcessor.getMaxDisplayPhotoSize(); 181787614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro } 181887614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro 1819013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov /* package */ NameSplitter getNameSplitter() { 1820013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov return mNameSplitter; 1821013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov } 1822013a0d6b3d392fb49d4618f2527b2ed3fec7d34fDmitri Plotnikov 18235df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov /* package */ NameLookupBuilder getNameLookupBuilder() { 18245df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov return mNameLookupBuilder; 18255df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov } 18265df7e46835c4f103b05407660b4769edd515760fDmitri Plotnikov 1827193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki @VisibleForTesting 1828ed78fd6df5e9f3a2d572162e5d374d1f4a625bddDmitri Plotnikov public ContactDirectoryManager getContactDirectoryManagerForTest() { 182972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov return mContactDirectoryManager; 183072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov } 183172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 1832193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki @VisibleForTesting 18335dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov protected Locale getLocale() { 18345dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov return Locale.getDefault(); 18355dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov } 18365dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov 18375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private boolean inProfileMode() { 18385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Boolean profileMode = mInProfileMode.get(); 18395d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return profileMode != null && profileMode; 18405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 18415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 1842a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /** 1843a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov * Wipes all data from the contacts database. 1844a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov */ 184510178e5e0b9de566e04508b624a89860c61787d6Makoto Onuki @NeededForTesting 184610178e5e0b9de566e04508b624a89860c61787d6Makoto Onuki void wipeData() { 184735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 18485d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsHelper.wipeData(); 18495d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileHelper.wipeData(); 18505d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsPhotoStore.clear(); 18515d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfilePhotoStore.clear(); 18523826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatus = ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS; 1853a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 1854a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 1855568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /** 185615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov * During intialization, this content provider will 1857568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * block all attempts to change contacts data. In particular, it will hold 1858568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * up all contact syncs. As soon as the import process is complete, all 1859568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * processes waiting to write to the provider are unblocked and can proceed 1860568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * to compete for the database transaction monitor. 1861568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov */ 186215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private void waitForAccess(CountDownLatch latch) { 186315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (latch == null) { 186415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov return; 186515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 186615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 186715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov while (true) { 186815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov try { 186915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov latch.await(); 187015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov return; 187115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } catch (InterruptedException e) { 187215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Thread.currentThread().interrupt(); 1873ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov } 1874568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1875568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1876568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 18775d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 18785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Determines whether the given URI should be directed to the profile 18795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * database rather than the contacts database. This is true under either 18805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * of three conditions: 18815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * 1. The URI itself is specifically for the profile. 18825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * 2. The URI contains ID references that are in the profile ID-space. 18835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * 3. The URI contains lookup key references that match the special profile lookup key. 18845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @param uri The URI to examine. 18855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @return Whether to direct the DB operation to the profile database. 18865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 18875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private boolean mapsToProfileDb(Uri uri) { 18885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return sUriMatcher.mapsToProfile(uri); 18895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 18905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 18915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 18925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Determines whether the given URI with the given values being inserted 18935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * should be directed to the profile database rather than the contacts 18945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * database. This is true if the URI already maps to the profile DB from 18955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * a call to {@link #mapsToProfileDb} or if the URI matches a URI that 18965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * specifies parent IDs via the ContentValues, and the given ContentValues 18975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * contains an ID in the profile ID-space. 18985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @param uri The URI to examine. 18995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @param values The values being inserted. 19005d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @return Whether to direct the DB insert to the profile database. 19015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 19025d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private boolean mapsToProfileDbWithInsertedValues(Uri uri, ContentValues values) { 19035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mapsToProfileDb(uri)) { 19045d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return true; 19055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 19065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro int match = sUriMatcher.match(uri); 19075d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (INSERT_URI_ID_VALUE_MAP.containsKey(match)) { 19085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String idField = INSERT_URI_ID_VALUE_MAP.get(match); 19095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (values.containsKey(idField)) { 19105d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long id = values.getAsLong(idField); 19115d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (ContactsContract.isProfileId(id)) { 19125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return true; 19135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 19145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 19155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 19165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return false; 19175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 19185d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 19195d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 19205d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Switches the provider's thread-local context variables to prepare for performing 19215d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * a profile operation. 19225d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 19236efb7db26598b105342d02207e0ca1c8725c10daDave Santoro protected void switchToProfileMode() { 19245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.set(mProfileHelper); 19255d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.set(mProfileTransactionContext); 19265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.set(mProfileAggregator); 19275d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mPhotoStore.set(mProfilePhotoStore); 19285d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mInProfileMode.set(true); 19295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 19305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 19315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 19325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Switches the provider's thread-local context variables to prepare for performing 19335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * a contacts operation. 19345d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 19356efb7db26598b105342d02207e0ca1c8725c10daDave Santoro protected void switchToContactMode() { 19365d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.set(mContactsHelper); 19375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.set(mContactTransactionContext); 19385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.set(mContactAggregator); 19395d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mPhotoStore.set(mContactsPhotoStore); 19405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mInProfileMode.set(false); 19415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 194236aa19fbab3722288b7f0917166ef6990ab7b52cDave Santoro // Clear out the active database; modification operations will set this to the contacts DB. 194336aa19fbab3722288b7f0917166ef6990ab7b52cDave Santoro mActiveDb.set(null); 19445d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 19455d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 1946568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1947568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public Uri insert(Uri uri, ContentValues values) { 194815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 194936612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 195036612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro // Enforce stream items access check if applicable. 195136612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro enforceSocialStreamWritePermission(uri); 195236612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 19535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mapsToProfileDbWithInsertedValues(uri, values)) { 1954078f588cef389358adabc579de00747878f3c108Dave Santoro switchToProfileMode(); 1955078f588cef389358adabc579de00747878f3c108Dave Santoro return mProfileProvider.insert(uri, values); 19565d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 19575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 19585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return super.insert(uri, values); 19595d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 1960568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1961568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1962568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1963568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 196415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (mWriteAccessLatch != null) { 196510178e5e0b9de566e04508b624a89860c61787d6Makoto Onuki // Update on PROVIDER_STATUS used to be used as a trigger to re-start legacy contact 196610178e5e0b9de566e04508b624a89860c61787d6Makoto Onuki // import. Now that we no longer support it, we just ignore it. 1967bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov int match = sUriMatcher.match(uri); 1968bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (match == PROVIDER_STATUS) { 196910178e5e0b9de566e04508b624a89860c61787d6Makoto Onuki return 0; 1970bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 1971bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 197215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 197336612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 197436612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro // Enforce stream items access check if applicable. 197536612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro enforceSocialStreamWritePermission(uri); 197636612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 19775d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mapsToProfileDb(uri)) { 1978078f588cef389358adabc579de00747878f3c108Dave Santoro switchToProfileMode(); 1979078f588cef389358adabc579de00747878f3c108Dave Santoro return mProfileProvider.update(uri, values, selection, selectionArgs); 19805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 19815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 19825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return super.update(uri, values, selection, selectionArgs); 19835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 1984568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1985568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 1986568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 1987568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public int delete(Uri uri, String selection, String[] selectionArgs) { 198815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 198936612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 199036612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro // Enforce stream items access check if applicable. 199136612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro enforceSocialStreamWritePermission(uri); 199236612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 19935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mapsToProfileDb(uri)) { 1994078f588cef389358adabc579de00747878f3c108Dave Santoro switchToProfileMode(); 1995078f588cef389358adabc579de00747878f3c108Dave Santoro return mProfileProvider.delete(uri, selection, selectionArgs); 19965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 19975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 19985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return super.delete(uri, selection, selectionArgs); 19995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20005d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 20025d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 20035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Replaces the current (thread-local) database to use for the operation with the given one. 20045d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @param db The database to use. 20055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 20065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /* package */ void substituteDb(SQLiteDatabase db) { 20075d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.set(db); 2008568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 2009568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 2010568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 201182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro public Bundle call(String method, String arg, Bundle extras) { 201282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro waitForAccess(mReadAccessLatch); 201382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro if (method.equals(Authorization.AUTHORIZATION_METHOD)) { 201482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro Uri uri = (Uri) extras.getParcelable(Authorization.KEY_URI_TO_AUTHORIZE); 201582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 201682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Check permissions on the caller. The URI can only be pre-authorized if the caller 201782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // already has the necessary permissions. 201882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro enforceSocialStreamReadPermission(uri); 201982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro if (mapsToProfileDb(uri)) { 202082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro mProfileProvider.enforceReadPermission(uri); 202182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 202282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 202382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // If there hasn't been a security violation yet, we're clear to pre-authorize the URI. 202482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro Uri authUri = preAuthorizeUri(uri); 202582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro Bundle response = new Bundle(); 202682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro response.putParcelable(Authorization.KEY_AUTHORIZED_URI, authUri); 202782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro return response; 202882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 202982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro return null; 203082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 203182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 203282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro /** 203382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * Pre-authorizes the given URI, adding an expiring permission token to it and placing that 203482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * in our map of pre-authorized URIs. 203582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * @param uri The URI to pre-authorize. 203682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * @return A pre-authorized URI that will not require special permissions to use. 203782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro */ 203882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro private Uri preAuthorizeUri(Uri uri) { 203982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro String token = String.valueOf(mRandom.nextLong()); 204082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro Uri authUri = uri.buildUpon() 204182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro .appendQueryParameter(PREAUTHORIZED_URI_TOKEN, token) 204282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro .build(); 204382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro long expiration = SystemClock.elapsedRealtime() + mPreAuthorizedUriDuration; 204482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro mPreAuthorizedUris.put(authUri, expiration); 204582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 204682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro return authUri; 204782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 204882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 204982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro /** 205082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * Checks whether the given URI has an unexpired permission token that would grant access to 205182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * query the content. If it does, the regular permission check should be skipped. 205282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * @param uri The URI being accessed. 205382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * @return Whether the URI is a pre-authorized URI that is still valid. 205482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro */ 205582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro public boolean isValidPreAuthorizedUri(Uri uri) { 205682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Only proceed if the URI has a permission token parameter. 205782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro if (uri.getQueryParameter(PREAUTHORIZED_URI_TOKEN) != null) { 205882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // First expire any pre-authorization URIs that are no longer valid. 205982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro long now = SystemClock.elapsedRealtime(); 206082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro Set<Uri> expiredUris = Sets.newHashSet(); 206182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro for (Uri preAuthUri : mPreAuthorizedUris.keySet()) { 206282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro if (mPreAuthorizedUris.get(preAuthUri) < now) { 206382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro expiredUris.add(preAuthUri); 206482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 206582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 206682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro for (Uri expiredUri : expiredUris) { 206782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro mPreAuthorizedUris.remove(expiredUri); 206882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 206982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 207082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Now check to see if the pre-authorized URI map contains the URI. 207182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro if (mPreAuthorizedUris.containsKey(uri)) { 207282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Unexpired token - skip the permission check. 207382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro return true; 207482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 207582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 207682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro return false; 207782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 207882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 207982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro @Override 2080078f588cef389358adabc579de00747878f3c108Dave Santoro protected boolean yield(ContactsTransaction transaction) { 2081078f588cef389358adabc579de00747878f3c108Dave Santoro // If there's a profile transaction in progress, and we're yielding, we need to 2082078f588cef389358adabc579de00747878f3c108Dave Santoro // end it. Unlike the Contacts DB yield (which re-starts a transaction at its 2083078f588cef389358adabc579de00747878f3c108Dave Santoro // conclusion), we can just go back into a state in which we have no active 2084078f588cef389358adabc579de00747878f3c108Dave Santoro // profile transaction, and let it be re-created as needed. We can't hold onto 2085078f588cef389358adabc579de00747878f3c108Dave Santoro // the transaction without risking a deadlock. 2086078f588cef389358adabc579de00747878f3c108Dave Santoro SQLiteDatabase profileDb = transaction.removeDbForTag(PROFILE_DB_TAG); 2087078f588cef389358adabc579de00747878f3c108Dave Santoro if (profileDb != null) { 2088078f588cef389358adabc579de00747878f3c108Dave Santoro profileDb.setTransactionSuccessful(); 2089078f588cef389358adabc579de00747878f3c108Dave Santoro profileDb.endTransaction(); 2090078f588cef389358adabc579de00747878f3c108Dave Santoro } 2091078f588cef389358adabc579de00747878f3c108Dave Santoro 2092078f588cef389358adabc579de00747878f3c108Dave Santoro // Now proceed with the Contacts DB yield. 2093078f588cef389358adabc579de00747878f3c108Dave Santoro SQLiteDatabase contactsDb = transaction.getDbForTag(CONTACTS_DB_TAG); 2094078f588cef389358adabc579de00747878f3c108Dave Santoro return contactsDb != null && contactsDb.yieldIfContendedSafely(SLEEP_AFTER_YIELD_DELAY); 2095078f588cef389358adabc579de00747878f3c108Dave Santoro } 2096078f588cef389358adabc579de00747878f3c108Dave Santoro 2097078f588cef389358adabc579de00747878f3c108Dave Santoro @Override 2098568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 2099568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov throws OperationApplicationException { 210015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 2101078f588cef389358adabc579de00747878f3c108Dave Santoro return super.applyBatch(operations); 2102568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 2103568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 21044f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 21057b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov public int bulkInsert(Uri uri, ContentValues[] values) { 21067b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov waitForAccess(mWriteAccessLatch); 2107078f588cef389358adabc579de00747878f3c108Dave Santoro return super.bulkInsert(uri, values); 21087b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov } 21097b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov 21107b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov @Override 2111078f588cef389358adabc579de00747878f3c108Dave Santoro public void onBegin() { 2112bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 2113fb25f3a5a86ca15de8507baf02a357a63032af62Makoto Onuki Log.v(TAG, "onBeginTransaction: " + (inProfileMode() ? "profile" : "contacts")); 2114b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 21155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (inProfileMode()) { 21165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileAggregator.clearPendingAggregations(); 21175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileTransactionContext.clear(); 21185d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 21195d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactAggregator.clearPendingAggregations(); 21205d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactTransactionContext.clear(); 21215d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 2122b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2123b5a4add17815167d20a90645779df34cdf45280dFred Quintana 2124285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov @Override 2125078f588cef389358adabc579de00747878f3c108Dave Santoro public void onCommit() { 2126bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 2127fb25f3a5a86ca15de8507baf02a357a63032af62Makoto Onuki Log.v(TAG, "beforeTransactionCommit: " + (inProfileMode() ? "profile" : "contacts")); 2128b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2129b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 21305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().aggregateInTransaction(mTransactionContext.get(), mActiveDb.get()); 21311a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (mVisibleTouched) { 21321a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = false; 21335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().updateAllVisible(); 213435997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 213535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki // Need to rebuild the fast-indxer bundle. 213635997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 21371a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey } 21383826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 2139bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 2140bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov 21413826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatusUpdateNeeded) { 21423826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateProviderStatus(); 21433826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = false; 21443826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 2145b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2146b5a4add17815167d20a90645779df34cdf45280dFred Quintana 2147078f588cef389358adabc579de00747878f3c108Dave Santoro @Override 2148078f588cef389358adabc579de00747878f3c108Dave Santoro public void onRollback() { 2149fb25f3a5a86ca15de8507baf02a357a63032af62Makoto Onuki if (VERBOSE_LOGGING) { 2150fb25f3a5a86ca15de8507baf02a357a63032af62Makoto Onuki Log.v(TAG, "beforeTransactionRollback: " + (inProfileMode() ? "profile" : "contacts")); 2151fb25f3a5a86ca15de8507baf02a357a63032af62Makoto Onuki } 2152fb25f3a5a86ca15de8507baf02a357a63032af62Makoto Onuki // mDbHelper may not be pointing at the "right" db helper due to a bug, 2153fb25f3a5a86ca15de8507baf02a357a63032af62Makoto Onuki // so we invalidate both for now. 2154fb25f3a5a86ca15de8507baf02a357a63032af62Makoto Onuki mContactsHelper.invalidateAllCache(); 2155fb25f3a5a86ca15de8507baf02a357a63032af62Makoto Onuki mProfileHelper.invalidateAllCache(); 2156078f588cef389358adabc579de00747878f3c108Dave Santoro } 2157078f588cef389358adabc579de00747878f3c108Dave Santoro 2158bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov private void updateSearchIndexInTransaction() { 21595d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Set<Long> staleContacts = mTransactionContext.get().getStaleSearchIndexContactIds(); 21605d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Set<Long> staleRawContacts = mTransactionContext.get().getStaleSearchIndexRawContactIds(); 2161bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov if (!staleContacts.isEmpty() || !staleRawContacts.isEmpty()) { 2162bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mSearchIndexManager.updateIndexForRawContacts(staleContacts, staleRawContacts); 21635d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().clearSearchIndexUpdates(); 2164bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov } 2165bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov } 2166bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov 2167b5a4add17815167d20a90645779df34cdf45280dFred Quintana private void flushTransactionalChanges() { 2168bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 2169b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "flushTransactionChanges"); 2170b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 21711129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov 21725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro for (long rawContactId : mTransactionContext.get().getInsertedRawContactIds()) { 21735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().updateRawContactDisplayName(mActiveDb.get(), rawContactId); 21745d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().onRawContactInsert(mTransactionContext.get(), mActiveDb.get(), 21755d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro rawContactId); 217624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 217724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 21785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Set<Long> dirtyRawContacts = mTransactionContext.get().getDirtyRawContactIds(); 2179d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov if (!dirtyRawContacts.isEmpty()) { 2180a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.setLength(0); 2181a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(UPDATE_RAW_CONTACT_SET_DIRTY_SQL); 2182d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov appendIds(mSb, dirtyRawContacts); 2183a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(")"); 21845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().execSQL(mSb.toString()); 2185a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov } 2186a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 21875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Set<Long> updatedRawContacts = mTransactionContext.get().getUpdatedRawContactIds(); 2188d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov if (!updatedRawContacts.isEmpty()) { 2189a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.setLength(0); 2190a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(UPDATE_RAW_CONTACT_SET_VERSION_SQL); 2191d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov appendIds(mSb, updatedRawContacts); 2192a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(")"); 21935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().execSQL(mSb.toString()); 2194b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2195b5a4add17815167d20a90645779df34cdf45280dFred Quintana 21965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Update sync states. 21975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro for (Map.Entry<Long, Object> entry : mTransactionContext.get().getUpdatedSyncStates()) { 2198b5a4add17815167d20a90645779df34cdf45280dFred Quintana long id = entry.getKey(); 21995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mDbHelper.get().getSyncState().update(mActiveDb.get(), id, entry.getValue()) <= 0) { 22009d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana throw new IllegalStateException( 22019d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana "unable to update sync state, does it still exist?"); 22029d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana } 2203b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2204b5a4add17815167d20a90645779df34cdf45280dFred Quintana 22055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().clear(); 2206b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2207b5a4add17815167d20a90645779df34cdf45280dFred Quintana 2208a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** 2209a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov * Appends comma separated ids. 2210a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov * @param ids Should not be empty 2211a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov */ 2212d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov private void appendIds(StringBuilder sb, Set<Long> ids) { 2213b5a4add17815167d20a90645779df34cdf45280dFred Quintana for (long id : ids) { 2214a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.append(id).append(','); 2215b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2216a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 2217a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.setLength(sb.length() - 1); // Yank the last comma 2218285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 2219285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 2220285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov @Override 2221cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov protected void notifyChange() { 222281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov notifyChange(mSyncToNetwork); 222381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = false; 222481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 222581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 222681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov protected void notifyChange(boolean syncToNetwork) { 222781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null, 222881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov syncToNetwork); 2229cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov } 2230568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 223151f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov protected void setProviderStatus(int status) { 22323826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != status) { 22333826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatus = status; 22343826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov getContext().getContentResolver().notifyChange(ProviderStatus.CONTENT_URI, null, false); 22353826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 223651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 223751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 2238f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov public DataRowHandler getDataRowHandler(final String mimeType) { 22395d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (inProfileMode()) { 22405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return getDataRowHandlerForProfile(mimeType); 22415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 22423cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DataRowHandler handler = mDataRowHandlers.get(mimeType); 22433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (handler == null) { 22446d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov handler = new DataRowHandlerForCustomMimetype( 22455d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro getContext(), mContactsHelper, mContactAggregator, mimeType); 22463cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mDataRowHandlers.put(mimeType, handler); 22473cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 22483cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return handler; 22493cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 22503cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 22515d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro public DataRowHandler getDataRowHandlerForProfile(final String mimeType) { 22525d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro DataRowHandler handler = mProfileDataRowHandlers.get(mimeType); 22535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (handler == null) { 22545d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handler = new DataRowHandlerForCustomMimetype( 22555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro getContext(), mProfileHelper, mProfileAggregator, mimeType); 22565d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileDataRowHandlers.put(mimeType, handler); 22575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 22585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return handler; 22595d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 22605d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 22614f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 2262de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected Uri insertInTransaction(Uri uri, ContentValues values) { 2263bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 22641129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov Log.v(TAG, "insertInTransaction: " + uri + " " + values); 2265b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2266f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana 22675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Default active DB to the contacts DB if none has been set. 22685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mActiveDb.get() == null) { 2269078f588cef389358adabc579de00747878f3c108Dave Santoro mActiveDb.set(mContactsHelper.getWritableDatabase()); 22705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 22715d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 2272f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 2273f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 2274f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana 2275a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 2276a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 227735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 2278a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton switch (match) { 227935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 22805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE: 22815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro id = mDbHelper.get().getSyncState().insert(mActiveDb.get(), values); 228235ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana break; 228335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 2284d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 228535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 2286d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov insertContact(values); 22876bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 22886bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 22896bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 229024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 229124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro throw new UnsupportedOperationException( 229224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro "The profile contact is created automatically"); 229324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 229424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2295d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case RAW_CONTACTS: 2296d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS: { 229735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 22985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro id = insertRawContact(uri, values, callerIsSyncAdapter); 2299f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2300a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2301a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2302a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2303193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki case RAW_CONTACTS_ID_DATA: 2304d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS_ID_DATA: { 230535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 2306193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki int segment = match == RAW_CONTACTS_ID_DATA ? 1 : 2; 2307d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro values.put(Data.RAW_CONTACT_ID, uri.getPathSegments().get(segment)); 2308f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana id = insertData(values, callerIsSyncAdapter); 2309f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2310a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2311a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2312a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 23133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case RAW_CONTACTS_ID_STREAM_ITEMS: { 23143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.put(StreamItems.RAW_CONTACT_ID, uri.getPathSegments().get(1)); 23153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItem(uri, values); 23163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 23173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 23183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 23193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 23200c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro case DATA: 23210c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro case PROFILE_DATA: { 232235997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 2323f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana id = insertData(values, callerIsSyncAdapter); 2324f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2325a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2326a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2327a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2328ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 2329f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov id = insertGroup(uri, values, callerIsSyncAdapter); 2330f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2331ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 2332ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 2333ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2334eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 23355aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey id = insertSettings(uri, values); 233643880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 2337eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 2338eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 2339eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 23405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case STATUS_UPDATES: 23415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_STATUS_UPDATES: { 234282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov id = insertStatusUpdate(values); 23431f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey break; 23441f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 23451f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 23463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 23473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItem(uri, values); 23483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 23493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 23503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 23513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 23523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 23533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItemPhoto(uri, values); 23543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 23553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 23563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 23573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 23583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 23593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.put(StreamItemPhotos.STREAM_ITEM_ID, uri.getPathSegments().get(1)); 23603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItemPhoto(uri, values); 23613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 23623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 23633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 23643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 2365a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton default: 236681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 2367f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.insert(uri, values); 2368a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2369a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 23707e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (id < 0) { 23717e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return null; 23727e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 23737e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 2374de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov return ContentUris.withAppendedId(uri, id); 2375a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2376a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2377a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 2378e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * If account is non-null then store it in the values. If the account is 2379e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * already specified in the values then it must be consistent with the 2380e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * account, if it is non-null. 2381e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * 2382e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @param uri Current {@link Uri} being operated on. 2383e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @param values {@link ContentValues} to read and possibly update. 2384e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @throws IllegalArgumentException when only one of 2385e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * {@link RawContacts#ACCOUNT_NAME} or 2386e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * {@link RawContacts#ACCOUNT_TYPE} is specified, leaving the 2387e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * other undefined. 2388e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @throws IllegalArgumentException when {@link RawContacts#ACCOUNT_NAME} 2389e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * and {@link RawContacts#ACCOUNT_TYPE} are inconsistent between 2390e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * the given {@link Uri} and {@link ContentValues}. 23917e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana */ 2392e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey private Account resolveAccount(Uri uri, ContentValues values) throws IllegalArgumentException { 2393f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 2394f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 2395e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 2396f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2397f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String valueAccountName = values.getAsString(RawContacts.ACCOUNT_NAME); 2398f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String valueAccountType = values.getAsString(RawContacts.ACCOUNT_TYPE); 2399e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialValues = TextUtils.isEmpty(valueAccountName) 2400e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey ^ TextUtils.isEmpty(valueAccountType); 2401e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2402e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri || partialValues) { 2403e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 24045d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 2405fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 2406e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 2407e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2408e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 2409e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 2410e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validUri = !TextUtils.isEmpty(accountName); 2411e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validValues = !TextUtils.isEmpty(valueAccountName); 2412e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2413e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validValues && validUri) { 2414e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Check that accounts match when both present 2415e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean accountMatch = TextUtils.equals(accountName, valueAccountName) 2416e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey && TextUtils.equals(accountType, valueAccountType); 2417e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (!accountMatch) { 24185d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 2419fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "When both specified, ACCOUNT_NAME and ACCOUNT_TYPE must match", uri)); 2420e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 2421e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else if (validUri) { 2422e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Fill values from Uri when not present 2423f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov values.put(RawContacts.ACCOUNT_NAME, accountName); 2424f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov values.put(RawContacts.ACCOUNT_TYPE, accountType); 2425e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else if (validValues) { 2426f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov accountName = valueAccountName; 2427f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov accountType = valueAccountType; 2428e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else { 2429e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return null; 2430f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 2431f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2432e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Use cached Account object when matches, otherwise create 2433f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (mAccount == null 2434f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov || !mAccount.name.equals(accountName) 2435f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov || !mAccount.type.equals(accountType)) { 2436f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mAccount = new Account(accountName, accountType); 2437035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana } 2438f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2439e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return mAccount; 24407e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 24417e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 24427e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 244343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * Resolves the account and builds an {@link AccountWithDataSet} based on the data set specified 244443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * in the URI or values (if any). 244543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * @param uri Current {@link Uri} being operated on. 244643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * @param values {@link ContentValues} to read and possibly update. 244743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro */ 244843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro private AccountWithDataSet resolveAccountWithDataSet(Uri uri, ContentValues values) { 24493593682b8d9213fde576a0cff54458ad50563980Dave Santoro final Account account = resolveAccount(uri, values); 245043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro AccountWithDataSet accountWithDataSet = null; 245143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (account != null) { 245243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String dataSet = getQueryParameter(uri, RawContacts.DATA_SET); 245343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (dataSet == null) { 24543593682b8d9213fde576a0cff54458ad50563980Dave Santoro dataSet = values.getAsString(RawContacts.DATA_SET); 2455a71dc460ca951c7aca591f3f470c160cde70a1e3Dave Santoro } else { 24563593682b8d9213fde576a0cff54458ad50563980Dave Santoro values.put(RawContacts.DATA_SET, dataSet); 245743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 24589ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki accountWithDataSet = AccountWithDataSet.get(account.name, account.type, dataSet); 245943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 246043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro return accountWithDataSet; 246143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 246243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 246343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro /** 24649d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * Same as {@link #resolveAccountWithDataSet}, but returns the account id for the 24659d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * {@link AccountWithDataSet}. Used for insert. 24669d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * 24679d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * May update the account cache; must be used only in a transaction. 24689d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki */ 24699d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki private long resolveAccountIdInTransaction(Uri uri, ContentValues values) { 24709d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki return mDbHelper.get().getOrCreateAccountIdInTransaction( 24719d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki resolveAccountWithDataSet(uri, mValues)); 24729d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 24739d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 24749d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki /** 2475d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov * Inserts an item in the contacts table 24766bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * 24776bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @param values the values for the new row 24786bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @return the row ID of the newly created row 24796bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov */ 2480d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private long insertContact(ContentValues values) { 2481de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov throw new UnsupportedOperationException("Aggregate contacts are created automatically"); 24826bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 24836bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 24846bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov /** 248524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Inserts an item in the raw contacts table 2486a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 2487f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * @param uri the values for the new row 2488f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * @param values the account this contact should be associated with. may be null. 2489dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana * @param callerIsSyncAdapter 2490a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 2491a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 24925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private long insertRawContact(Uri uri, ContentValues values, boolean callerIsSyncAdapter) { 2493f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.clear(); 2494f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putAll(values); 2495f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putNull(RawContacts.CONTACT_ID); 2496f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 24979d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final long accountId = resolveAccountIdInTransaction(uri, mValues); 24989d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mValues.remove(RawContacts.ACCOUNT_NAME); 24999d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mValues.remove(RawContacts.ACCOUNT_TYPE); 25009d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mValues.remove(RawContacts.DATA_SET); 25019d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mValues.put(RawContactsColumns.ACCOUNT_ID, accountId); 25027e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 25033d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov if (values.containsKey(RawContacts.DELETED) 25043d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov && values.getAsInteger(RawContacts.DELETED) != 0) { 2505f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED); 25063d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 25073d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 25085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long rawContactId = mActiveDb.get().insert(Tables.RAW_CONTACTS, 25095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro RawContacts.CONTACT_ID, mValues); 2510f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov int aggregationMode = RawContacts.AGGREGATION_MODE_DEFAULT; 25115d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mValues.containsKey(RawContacts.AGGREGATION_MODE)) { 2512f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov aggregationMode = mValues.getAsInteger(RawContacts.AGGREGATION_MODE); 2513f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 25145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().markNewForAggregation(rawContactId, aggregationMode); 2515285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 25165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Trigger creation of a Contact based on this RawContact at the end of transaction 25179d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mTransactionContext.get().rawContactInserted(rawContactId, accountId); 2518f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2519dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter) { 2520dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana addAutoAddMembership(rawContactId); 2521dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long starred = values.getAsLong(RawContacts.STARRED); 2522dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (starred != null && starred != 0) { 2523dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, starred != 0); 2524dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2525dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2526dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 25273826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 2528023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov return rawContactId; 2529a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2530a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2531dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void addAutoAddMembership(long rawContactId) { 2532dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long groupId = findGroupByRawContactId(SELECTION_AUTO_ADD_GROUPS_BY_RAW_CONTACT_ID, 2533dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana rawContactId); 2534dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (groupId != null) { 2535dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana insertDataGroupMembership(rawContactId, groupId); 2536dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2537dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2538dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2539dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private Long findGroupByRawContactId(String selection, long rawContactId) { 25405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.GROUPS + "," + Tables.RAW_CONTACTS, 25415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PROJECTION_GROUP_ID, selection, 2542dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{Long.toString(rawContactId)}, 2543dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana null /* groupBy */, null /* having */, null /* orderBy */); 2544dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana try { 2545dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana while (c.moveToNext()) { 2546dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return c.getLong(0); 2547dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2548dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return null; 2549dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } finally { 2550dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana c.close(); 2551dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2552dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2553dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2554dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void updateFavoritesMembership(long rawContactId, boolean isStarred) { 2555dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long groupId = findGroupByRawContactId(SELECTION_FAVORITES_GROUPS_BY_RAW_CONTACT_ID, 2556dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana rawContactId); 2557dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (groupId != null) { 2558dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (isStarred) { 2559dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana insertDataGroupMembership(rawContactId, groupId); 2560dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } else { 2561dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana deleteDataGroupMembership(rawContactId, groupId); 2562dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2563dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2564dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2565dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2566dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void insertDataGroupMembership(long rawContactId, long groupId) { 2567dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana ContentValues groupMembershipValues = new ContentValues(); 2568dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(GroupMembership.GROUP_ROW_ID, groupId); 2569dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(GroupMembership.RAW_CONTACT_ID, rawContactId); 2570dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(DataColumns.MIMETYPE_ID, 25715d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)); 25725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().insert(Tables.DATA, null, groupMembershipValues); 2573dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2574dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2575dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void deleteDataGroupMembership(long rawContactId, long groupId) { 2576dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final String[] selectionArgs = { 25775d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Long.toString(mDbHelper.get().getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)), 2578dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(groupId), 2579dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(rawContactId)}; 25805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().delete(Tables.DATA, SELECTION_GROUPMEMBERSHIP_DATA, selectionArgs); 2581dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2582dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2583a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 2584a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * Inserts an item in the data table 2585a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 2586a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @param values the values for the new row 2587a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 2588a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 2589f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private long insertData(ContentValues values, boolean callerIsSyncAdapter) { 2590a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 2591de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.clear(); 2592de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.putAll(values); 259367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 2594de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov long rawContactId = mValues.getAsLong(Data.RAW_CONTACT_ID); 259520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 2596de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Replace package with internal mapping 2597de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov final String packageName = mValues.getAsString(Data.RES_PACKAGE); 2598de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov if (packageName != null) { 25995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mValues.put(DataColumns.PACKAGE_ID, mDbHelper.get().getPackageId(packageName)); 2600de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov } 2601de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.remove(Data.RES_PACKAGE); 2602508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 2603de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Replace mimetype with internal mapping 2604de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov final String mimeType = mValues.getAsString(Data.MIMETYPE); 2605de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov if (TextUtils.isEmpty(mimeType)) { 2606de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov throw new IllegalArgumentException(Data.MIMETYPE + " is required"); 2607de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov } 26084097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov 26095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mValues.put(DataColumns.MIMETYPE_ID, mDbHelper.get().getMimeTypeId(mimeType)); 2610de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.remove(Data.MIMETYPE); 2611a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 2612a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 26135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro id = rowHandler.insert(mActiveDb.get(), mTransactionContext.get(), rawContactId, mValues); 2614f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 26155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().markRawContactDirty(rawContactId); 2616a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 26175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().rawContactUpdated(rawContactId); 2618a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton return id; 26194f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 26204f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 26213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 26223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Inserts an item in the stream_items table. The account is checked against the 26233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account in the raw contact for which the stream item is being inserted. If the 26243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * new stream item results in more stream items under this raw contact than the limit, 26253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the oldest one will be deleted (note that if the stream item inserted was the 26263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * oldest, it will be immediately deleted, and this will return 0). 26273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 26283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param uri the insertion URI 26293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param values the values for the new row 26303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return the stream item _ID of the newly created row, or 0 if it was not created 26313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 26323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long insertStreamItem(Uri uri, ContentValues values) { 26333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long id = 0; 26343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.clear(); 26353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.putAll(values); 26363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = mValues.getAsLong(StreamItems.RAW_CONTACT_ID); 26383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26396802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to insert accounts params - they don't exist in the stream items table. 26406802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_NAME); 26416802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_TYPE); 26426802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 26433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Insert the new stream item. 26445d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro id = mActiveDb.get().insert(Tables.STREAM_ITEMS, null, mValues); 26456802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (id == -1) { 26466802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Insertion failed. 26476802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return 0; 26486802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 26493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check to see if we're over the limit for stream items under this raw contact. 26513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // It's possible that the inserted stream item is older than the the existing 26523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // ones, in which case it may be deleted immediately (resetting the ID to 0). 26533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = cleanUpOldStreamItems(rawContactId, id); 26543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return id; 26563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26573b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26583b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 26593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Inserts an item in the stream_item_photos table. The account is checked against 26603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the account in the raw contact that owns the stream item being modified. 26613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 26623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param uri the insertion URI 26633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param values the values for the new row 26646802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @return the stream item photo _ID of the newly created row, or 0 if there was an issue 26656802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * with processing the photo or creating the row 26663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 26673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long insertStreamItemPhoto(Uri uri, ContentValues values) { 26683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long id = 0; 26693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.clear(); 26703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.putAll(values); 26713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long streamItemId = mValues.getAsLong(StreamItemPhotos.STREAM_ITEM_ID); 26733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (streamItemId != 0) { 26743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = lookupRawContactIdForStreamId(streamItemId); 26753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26766802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to insert accounts params - they don't exist in the stream item 26776802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // photos table. 26786802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_NAME); 26796802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_TYPE); 26803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26816802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo and store it. 26826802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (processStreamItemPhoto(mValues, false)) { 26836802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Insert the stream item photo. 26845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro id = mActiveDb.get().insert(Tables.STREAM_ITEM_PHOTOS, null, mValues); 26856802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 26863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return id; 26883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 26893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 26903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 26916802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * Processes the photo contained in the {@link ContactsContract.StreamItemPhotos#PHOTO} 26926802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * field of the given values, attempting to store it in the photo store. If successful, 26936802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * the resulting photo file ID will be added to the values for insert/update in the table. 26946802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * <p> 26956802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * If updating, it is valid for the picture to be empty or unspecified (the function will 26966802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * still return true). If inserting, a valid picture must be specified. 26976802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @param values The content values provided by the caller. 26986802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @param forUpdate Whether this photo is being processed for update (vs. insert). 26996802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @return Whether the insert or update should proceed. 27006802030a777c0c3ba1dc029c534cca4784260632Dave Santoro */ 27016802030a777c0c3ba1dc029c534cca4784260632Dave Santoro private boolean processStreamItemPhoto(ContentValues values, boolean forUpdate) { 27026802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (!values.containsKey(StreamItemPhotos.PHOTO)) { 27036802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return forUpdate; 27046802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 27056802030a777c0c3ba1dc029c534cca4784260632Dave Santoro byte[] photoBytes = values.getAsByteArray(StreamItemPhotos.PHOTO); 27066802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoBytes == null) { 27076802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return forUpdate; 27086802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 27096802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 27106802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo and store it. 27116802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 27125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long photoFileId = mPhotoStore.get().insert(new PhotoProcessor(photoBytes, 2713c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki getMaxDisplayPhotoDim(), getMaxThumbnailDim(), true), true); 27146802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoFileId != 0) { 27156802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.put(StreamItemPhotos.PHOTO_FILE_ID, photoFileId); 27166802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(StreamItemPhotos.PHOTO); 27176802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return true; 27186802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 27196802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Couldn't store the photo, return 0. 27206802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Log.e(TAG, "Could not process stream item photo for insert"); 27216802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return false; 27226802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 27236802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } catch (IOException ioe) { 27246802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Log.e(TAG, "Could not process stream item photo for insert", ioe); 27256802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return false; 27266802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 27276802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 27286802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 27296802030a777c0c3ba1dc029c534cca4784260632Dave Santoro /** 27303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Looks up the raw contact ID that owns the specified stream item. 27313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param streamItemId The ID of the stream item. 27323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The associated raw contact ID, or -1 if no such stream item exists. 27333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 27343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long lookupRawContactIdForStreamId(long streamItemId) { 27353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = -1; 27365d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.STREAM_ITEMS, 27375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new String[]{StreamItems.RAW_CONTACT_ID}, 27383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItems._ID + "=?", new String[]{String.valueOf(streamItemId)}, 27393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 27403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 27413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (c.moveToFirst()) { 27423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann rawContactId = c.getLong(0); 27433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 27443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 27453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 27463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 27473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return rawContactId; 27483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 27493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 27503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 275136612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro * If the given URI is reading stream items or stream photos, this will run a permission check 275236612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro * for the android.permission.READ_SOCIAL_STREAM permission - otherwise it will do nothing. 275336612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro * @param uri The URI to check. 275436612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro */ 275536612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro private void enforceSocialStreamReadPermission(Uri uri) { 275682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro if (SOCIAL_STREAM_URIS.contains(sUriMatcher.match(uri)) 275782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro && !isValidPreAuthorizedUri(uri)) { 275836612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro getContext().enforceCallingOrSelfPermission( 275936612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro "android.permission.READ_SOCIAL_STREAM", null); 276036612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro } 276136612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro } 276236612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 276336612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro /** 276436612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro * If the given URI is modifying stream items or stream photos, this will run a permission check 276536612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro * for the android.permission.WRITE_SOCIAL_STREAM permission - otherwise it will do nothing. 276636612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro * @param uri The URI to check. 276736612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro */ 276836612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro private void enforceSocialStreamWritePermission(Uri uri) { 276936612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro if (SOCIAL_STREAM_URIS.contains(sUriMatcher.match(uri))) { 277036612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro getContext().enforceCallingOrSelfPermission( 277136612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro "android.permission.WRITE_SOCIAL_STREAM", null); 277236612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro } 277336612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro } 277436612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 277536612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro /** 27763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Queries the database for stream items under the given raw contact. If there are 27773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * more entries than {@link ContactsProvider2#MAX_STREAM_ITEMS_PER_RAW_CONTACT}, 27783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the oldest entries (as determined by timestamp) will be deleted. 27793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param rawContactId The raw contact ID to examine for stream items. 27803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param insertedStreamItemId The ID of the stream item that was just inserted, 27813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * prompting this cleanup. Callers may pass 0 if no insertion prompted the 27823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * cleanup. 27833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The ID of the inserted stream item if it still exists after cleanup; 27843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 0 otherwise. 27853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 27863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long cleanUpOldStreamItems(long rawContactId, long insertedStreamItemId) { 27873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long postCleanupInsertedStreamId = insertedStreamItemId; 27885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.STREAM_ITEMS, new String[]{StreamItems._ID}, 27893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItems.RAW_CONTACT_ID + "=?", new String[]{String.valueOf(rawContactId)}, 27903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, StreamItems.TIMESTAMP + " DESC, " + StreamItems._ID + " DESC"); 27913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 27923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann int streamItemCount = c.getCount(); 27933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (streamItemCount <= MAX_STREAM_ITEMS_PER_RAW_CONTACT) { 27943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Still under the limit - nothing to clean up! 27953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return insertedStreamItemId; 27963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } else { 27973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.moveToLast(); 27983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.getPosition() >= MAX_STREAM_ITEMS_PER_RAW_CONTACT) { 27993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long streamItemId = c.getLong(0); 28003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (insertedStreamItemId == streamItemId) { 28013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // The stream item just inserted is being deleted. 28023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann postCleanupInsertedStreamId = 0; 28033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItem(c.getLong(0)); 28053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.moveToPrevious(); 28063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 28093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 28103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return postCleanupInsertedStreamId; 28123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 28149261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** 281520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov * Delete data row by row so that fixing of primaries etc work correctly. 281620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov */ 2817f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private int deleteData(String selection, String[] selectionArgs, boolean callerIsSyncAdapter) { 281820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov int count = 0; 281920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 2820de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 2821de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // so we don't need to worry about deleting data we don't have permission to read. 28220c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro Uri dataUri = inProfileMode() 28230c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro ? Uri.withAppendedPath(Profile.CONTENT_URI, RawContacts.Data.CONTENT_DIRECTORY) 28240c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro : Data.CONTENT_URI; 28250c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro Cursor c = query(dataUri, DataRowHandler.DataDeleteQuery.COLUMNS, 2826f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov selection, selectionArgs, null); 2827de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov try { 2828de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov while(c.moveToNext()) { 2829f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov long rawContactId = c.getLong(DataRowHandler.DataDeleteQuery.RAW_CONTACT_ID); 2830f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov String mimeType = c.getString(DataRowHandler.DataDeleteQuery.MIMETYPE); 2831a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 28325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro count += rowHandler.delete(mActiveDb.get(), mTransactionContext.get(), c); 2833f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 28345d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().markRawContactDirty(rawContactId); 283588e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov } 283620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 283720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 2838de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov c.close(); 283920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 284020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 284120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return count; 284220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 284320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 284488e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov /** 284588e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov * Delete a data row provided that it is one of the allowed mime types. 284688e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov */ 284720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov public int deleteData(long dataId, String[] allowedMimeTypes) { 2848f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov 284988e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 285088e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov // so we don't need to worry about deleting data we don't have permission to read. 28514da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(dataId); 2852f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Cursor c = query(Data.CONTENT_URI, DataRowHandler.DataDeleteQuery.COLUMNS, Data._ID + "=?", 28534da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1, null); 2854f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov 285520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov try { 285620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (!c.moveToFirst()) { 285720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return 0; 285820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 285920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 2860f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov String mimeType = c.getString(DataRowHandler.DataDeleteQuery.MIMETYPE); 286120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov boolean valid = false; 286220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov for (int i = 0; i < allowedMimeTypes.length; i++) { 286320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (TextUtils.equals(mimeType, allowedMimeTypes[i])) { 286420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov valid = true; 286520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov break; 286620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 286720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 286820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 286920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (!valid) { 28707a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana throw new IllegalArgumentException("Data type mismatch: expected " 287120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov + Lists.newArrayList(allowedMimeTypes)); 287220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 2873a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 28745d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return rowHandler.delete(mActiveDb.get(), mTransactionContext.get(), c); 287520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 287620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov c.close(); 287720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 287820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 287920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 288020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov /** 2881ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * Inserts an item in the groups table 2882ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey */ 2883f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private long insertGroup(Uri uri, ContentValues values, boolean callerIsSyncAdapter) { 2884f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.clear(); 2885f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putAll(values); 2886f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 28879d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final long accountId = mDbHelper.get().getOrCreateAccountIdInTransaction( 28889d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki resolveAccountWithDataSet(uri, mValues)); 28899d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mValues.remove(Groups.ACCOUNT_NAME); 28909d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mValues.remove(Groups.ACCOUNT_TYPE); 28919d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mValues.remove(Groups.DATA_SET); 28929d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mValues.put(GroupsColumns.ACCOUNT_ID, accountId); 2893ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2894ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Replace package with internal mapping 2895f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String packageName = mValues.getAsString(Groups.RES_PACKAGE); 289667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey if (packageName != null) { 28975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mValues.put(GroupsColumns.PACKAGE_ID, mDbHelper.get().getPackageId(packageName)); 289867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey } 2899f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.remove(Groups.RES_PACKAGE); 2900ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2901dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final boolean isFavoritesGroup = mValues.getAsLong(Groups.FAVORITES) != null 2902dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana ? mValues.getAsLong(Groups.FAVORITES) != 0 2903dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana : false; 2904dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2905f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 2906f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(Groups.DIRTY, 1); 290773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } 290873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 29095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long result = mActiveDb.get().insert(Tables.GROUPS, Groups.TITLE, mValues); 2910ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey 2911dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && isFavoritesGroup) { 29129d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // If the inserted group is a favorite group, add all starred raw contacts to it. 29139d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mSelectionArgs1[0] = Long.toString(accountId); 29145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.RAW_CONTACTS, 2915dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{RawContacts._ID, RawContacts.STARRED}, 29169d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki RawContactsColumns.CONCRETE_ACCOUNT_ID + "=?", mSelectionArgs1, 29179d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki null, null, null); 2918892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov try { 2919892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov while (c.moveToNext()) { 2920892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov if (c.getLong(1) != 0) { 2921892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov final long rawContactId = c.getLong(0); 2922892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov insertDataGroupMembership(rawContactId, result); 29235d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().markRawContactDirty(rawContactId); 2924892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov } 2925dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2926892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov } finally { 2927892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov c.close(); 2928dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2929dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2930dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2931f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (mValues.containsKey(Groups.GROUP_VISIBLE)) { 29321a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 2933ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey } 2934ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey 2935ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey return result; 2936ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 2937ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 29385aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private long insertSettings(Uri uri, ContentValues values) { 2939f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro // Before inserting, ensure that no settings record already exists for the 2940f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro // values being inserted (this used to be enforced by a primary key, but that no 2941f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro // longer works with the nullable data_set field added). 2942f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro String accountName = values.getAsString(Settings.ACCOUNT_NAME); 2943f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro String accountType = values.getAsString(Settings.ACCOUNT_TYPE); 2944f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro String dataSet = values.getAsString(Settings.DATA_SET); 2945f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro Uri.Builder settingsUri = Settings.CONTENT_URI.buildUpon(); 2946f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro if (accountName != null) { 2947f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro settingsUri.appendQueryParameter(Settings.ACCOUNT_NAME, accountName); 2948f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } 2949f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro if (accountType != null) { 2950f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro settingsUri.appendQueryParameter(Settings.ACCOUNT_TYPE, accountType); 2951f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } 2952f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro if (dataSet != null) { 2953f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro settingsUri.appendQueryParameter(Settings.DATA_SET, dataSet); 2954f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } 295515826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann Cursor c = queryLocal(settingsUri.build(), null, null, null, null, 0, null); 2956f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro try { 2957f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro if (c.getCount() > 0) { 29580e21a867a572679d64d79041eb574d13665178d4Dave Santoro // If a record was found, replace it with the new values. 29590e21a867a572679d64d79041eb574d13665178d4Dave Santoro String selection = null; 29600e21a867a572679d64d79041eb574d13665178d4Dave Santoro String[] selectionArgs = null; 29610e21a867a572679d64d79041eb574d13665178d4Dave Santoro if (accountName != null && accountType != null) { 29620e21a867a572679d64d79041eb574d13665178d4Dave Santoro selection = Settings.ACCOUNT_NAME + "=? AND " + Settings.ACCOUNT_TYPE + "=?"; 29630e21a867a572679d64d79041eb574d13665178d4Dave Santoro if (dataSet == null) { 29640e21a867a572679d64d79041eb574d13665178d4Dave Santoro selection += " AND " + Settings.DATA_SET + " IS NULL"; 29650e21a867a572679d64d79041eb574d13665178d4Dave Santoro selectionArgs = new String[] {accountName, accountType}; 29660e21a867a572679d64d79041eb574d13665178d4Dave Santoro } else { 29670e21a867a572679d64d79041eb574d13665178d4Dave Santoro selection += " AND " + Settings.DATA_SET + "=?"; 29680e21a867a572679d64d79041eb574d13665178d4Dave Santoro selectionArgs = new String[] {accountName, accountType, dataSet}; 29690e21a867a572679d64d79041eb574d13665178d4Dave Santoro } 29700e21a867a572679d64d79041eb574d13665178d4Dave Santoro } 29710e21a867a572679d64d79041eb574d13665178d4Dave Santoro return updateSettings(uri, values, selection, selectionArgs); 2972f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } 2973f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } finally { 2974f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro c.close(); 2975f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } 2976f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro 2977f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro // If we didn't find a duplicate, we're fine to insert. 29785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final long id = mActiveDb.get().insert(Tables.SETTINGS, null, values); 29795aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey 29801a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (values.containsKey(Settings.UNGROUPED_VISIBLE)) { 29811a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 2982e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 29831a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey 2984e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return id; 2985e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 2986e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 2987ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** 298882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov * Inserts a status update. 29891f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey */ 299082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov public long insertStatusUpdate(ContentValues values) { 299182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov final String handle = values.getAsString(StatusUpdates.IM_HANDLE); 29920a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov final Integer protocol = values.getAsInteger(StatusUpdates.PROTOCOL); 29934dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov String customProtocol = null; 29944dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov 29950a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (protocol != null && protocol == Im.PROTOCOL_CUSTOM) { 299682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov customProtocol = values.getAsString(StatusUpdates.CUSTOM_PROTOCOL); 29974dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov if (TextUtils.isEmpty(customProtocol)) { 29984dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov throw new IllegalArgumentException( 29994dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov "CUSTOM_PROTOCOL is required when PROTOCOL=PROTOCOL_CUSTOM"); 30004dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov } 30011f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 30021f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 3003dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton long rawContactId = -1; 3004dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton long contactId = -1; 300582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov Long dataId = values.getAsLong(StatusUpdates.DATA_ID); 30066802030a777c0c3ba1dc029c534cca4784260632Dave Santoro String accountType = null; 30076802030a777c0c3ba1dc029c534cca4784260632Dave Santoro String accountName = null; 3008f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov mSb.setLength(0); 30092526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.clear(); 3010dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (dataId != null) { 3011dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // Lookup the contact info for the given data row. 3012dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 30132526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(Tables.DATA + "." + Data._ID + "=?"); 30142526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(dataId)); 30151f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 3016dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // Lookup the data row to attach this presence update to 3017dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 30180a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (TextUtils.isEmpty(handle) || protocol == null) { 30190a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov throw new IllegalArgumentException("PROTOCOL and IM_HANDLE are required"); 30200a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 30210a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 3022dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // TODO: generalize to allow other providers to match against email 3023dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton boolean matchEmail = Im.PROTOCOL_GOOGLE_TALK == protocol; 3024dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 30255d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String mimeTypeIdIm = String.valueOf(mDbHelper.get().getMimeTypeIdForIm()); 3026dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (matchEmail) { 30275d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String mimeTypeIdEmail = String.valueOf(mDbHelper.get().getMimeTypeIdForEmail()); 3028f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 3029f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // The following hack forces SQLite to use the (mimetype_id,data1) index, otherwise 3030f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // the "OR" conjunction confuses it and it switches to a full scan of 3031f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // the raw_contacts table. 3032f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 3033f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // This code relies on the fact that Im.DATA and Email.DATA are in fact the same 3034f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // column - Data.DATA1 30352526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(DataColumns.MIMETYPE_ID + " IN (?,?)" + 30362526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Data.DATA1 + "=?" + 30372526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND ((" + DataColumns.MIMETYPE_ID + "=? AND " + Im.PROTOCOL + "=?"); 30382526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdEmail); 30392526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 30402526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(handle); 30412526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 30422526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(protocol)); 3043dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (customProtocol != null) { 30442526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + Im.CUSTOM_PROTOCOL + "=?"); 30452526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(customProtocol); 3046dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 30472526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(") OR (" + DataColumns.MIMETYPE_ID + "=?))"); 30482526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdEmail); 3049dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } else { 30502526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(DataColumns.MIMETYPE_ID + "=?" + 30512526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Im.PROTOCOL + "=?" + 30522526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Im.DATA + "=?"); 30532526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 30542526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(protocol)); 30552526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(handle); 3056dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (customProtocol != null) { 30572526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + Im.CUSTOM_PROTOCOL + "=?"); 30582526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(customProtocol); 3059dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 3060dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 30611f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 306282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.DATA_ID)) { 30632526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + DataColumns.CONCRETE_ID + "=?"); 30642526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(values.getAsString(StatusUpdates.DATA_ID)); 3065dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 306670b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov } 306770b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov 30681f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey Cursor cursor = null; 30691f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey try { 30705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro cursor = mActiveDb.get().query(DataContactsQuery.TABLE, DataContactsQuery.PROJECTION, 30712526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.toString(), mSelectionArgs.toArray(EMPTY_STRING_ARRAY), null, null, 30724394086494fe7909aaca70f56fb4bb08beebf303Dmitri Plotnikov Clauses.CONTACT_VISIBLE + " DESC, " + Data.RAW_CONTACT_ID); 30731f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey if (cursor.moveToFirst()) { 307467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey dataId = cursor.getLong(DataContactsQuery.DATA_ID); 30755ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov rawContactId = cursor.getLong(DataContactsQuery.RAW_CONTACT_ID); 30766802030a777c0c3ba1dc029c534cca4784260632Dave Santoro accountType = cursor.getString(DataContactsQuery.ACCOUNT_TYPE); 30776802030a777c0c3ba1dc029c534cca4784260632Dave Santoro accountName = cursor.getString(DataContactsQuery.ACCOUNT_NAME); 3078e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov contactId = cursor.getLong(DataContactsQuery.CONTACT_ID); 30791f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 30801f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // No contact found, return a null URI 30811f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey return -1; 30821f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 30831f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } finally { 308431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov if (cursor != null) { 308531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov cursor.close(); 308631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 30871f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 30881f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 308982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.PRESENCE)) { 3090a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (customProtocol == null) { 3091a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // We cannot allow a null in the custom protocol field, because SQLite3 does not 3092a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // properly enforce uniqueness of null values 3093a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov customProtocol = ""; 3094a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 3095a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov 3096a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.clear(); 309782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.DATA_ID, dataId); 3098a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.put(PresenceColumns.RAW_CONTACT_ID, rawContactId); 3099a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.put(PresenceColumns.CONTACT_ID, contactId); 310082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.PROTOCOL, protocol); 310182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.CUSTOM_PROTOCOL, customProtocol); 310282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.IM_HANDLE, handle); 310382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.IM_ACCOUNT)) { 310482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.IM_ACCOUNT, values.getAsString(StatusUpdates.IM_ACCOUNT)); 3105a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 310682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.PRESENCE, 310782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov values.getAsString(StatusUpdates.PRESENCE)); 3108aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori mValues.put(StatusUpdates.CHAT_CAPABILITY, 3109aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori values.getAsString(StatusUpdates.CHAT_CAPABILITY)); 31101f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 3111a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // Insert the presence update 31125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().replace(Tables.PRESENCE, null, mValues); 3113a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 3114e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov 31150a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 311682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.STATUS)) { 311782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov String status = values.getAsString(StatusUpdates.STATUS); 31180a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov String resPackage = values.getAsString(StatusUpdates.STATUS_RES_PACKAGE); 31190bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann Resources resources = getContext().getResources(); 31200bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann if (!TextUtils.isEmpty(resPackage)) { 31210bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann PackageManager pm = getContext().getPackageManager(); 31220bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann try { 31230bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann resources = pm.getResourcesForApplication(resPackage); 31240bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } catch (NameNotFoundException e) { 31250bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann Log.w(TAG, "Contact status update resource package not found: " 31260bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann + resPackage); 31270bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } 31280bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } 31290bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann Integer labelResourceId = values.getAsInteger(StatusUpdates.STATUS_LABEL); 31300a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 31310bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann if ((labelResourceId == null || labelResourceId == 0) && protocol != null) { 31320bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann labelResourceId = Im.getProtocolLabelResource(protocol); 31330a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 31340bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann String labelResource = getResourceName(resources, "string", labelResourceId); 31350a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 31360bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann Integer iconResourceId = values.getAsInteger(StatusUpdates.STATUS_ICON); 31370a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov // TODO compute the default icon based on the protocol 31380a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 31390bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann String iconResource = getResourceName(resources, "drawable", iconResourceId); 31400bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann 3141a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (TextUtils.isEmpty(status)) { 31425d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().deleteStatusUpdate(dataId); 3143a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } else { 31446802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Long timestamp = values.getAsLong(StatusUpdates.STATUS_TIMESTAMP); 31456802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (timestamp != null) { 31465d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().replaceStatusUpdate(dataId, timestamp, status, resPackage, 31470bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann iconResourceId, labelResourceId); 31486802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 31495d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().insertStatusUpdate(dataId, status, resPackage, iconResourceId, 31500bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann labelResourceId); 31516802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 31526802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 31536802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // For forward compatibility with the new stream item API, insert this status update 31546802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // there as well. If we already have a stream item from this source, update that 31556802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // one instead of inserting a new one (since the semantics of the old status update 31566802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // API is to only have a single record). 31576802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (rawContactId != -1 && !TextUtils.isEmpty(status)) { 31586802030a777c0c3ba1dc029c534cca4784260632Dave Santoro ContentValues streamItemValues = new ContentValues(); 31596802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RAW_CONTACT_ID, rawContactId); 3160d5ef5903570e533a501abe6a8e3d533fdb5318fcFlavio Lerda // Status updates are text only but stream items are HTML. 3161e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda streamItemValues.put(StreamItems.TEXT, statusUpdateToHtml(status)); 31626802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.COMMENTS, ""); 31636802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_PACKAGE, resPackage); 31646802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_ICON, iconResource); 31656802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_LABEL, labelResource); 31666802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.TIMESTAMP, 31676802030a777c0c3ba1dc029c534cca4784260632Dave Santoro timestamp == null ? System.currentTimeMillis() : timestamp); 31686802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 31696802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Note: The following is basically a workaround for the fact that status 31706802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // updates didn't do any sort of account enforcement, while social stream item 31716802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // updates do. We can't expect callers of the old API to start passing account 31726802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // information along, so we just populate the account params appropriately for 317343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // the raw contact. Data set is not relevant here, as we only check account 317443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // name and type. 31756802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (accountName != null && accountType != null) { 31766802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(RawContacts.ACCOUNT_NAME, accountName); 31776802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(RawContacts.ACCOUNT_TYPE, accountType); 31786802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 31796802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 31806802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Check for an existing stream item from this source, and insert or update. 31816802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Uri streamUri = StreamItems.CONTENT_URI; 318236612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro Cursor c = queryLocal(streamUri, new String[]{StreamItems._ID}, 31836802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItems.RAW_CONTACT_ID + "=?", 318436612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro new String[]{String.valueOf(rawContactId)}, 318515826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann null, -1 /* directory ID */, null); 31866802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 31876802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (c.getCount() > 0) { 31886802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.moveToFirst(); 318936612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro updateInTransaction(ContentUris.withAppendedId(streamUri, c.getLong(0)), 31906802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues, null, null); 31916802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 319236612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro insertInTransaction(streamUri, streamItemValues); 31936802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 31946802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } finally { 31956802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.close(); 31966802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 31976802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 3198e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 3199e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 3200bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov 3201a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (contactId != -1) { 32025d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().updateLastStatusUpdateId(contactId); 3203a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 3204a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov 3205a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov return dataId; 32061f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 32071f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 3208e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda /** Converts a status update to HTML. */ 3209e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda private String statusUpdateToHtml(String status) { 32104747809486541f7a3d342d3e1dd48fb5ea255ad6Flavio Lerda return TextUtils.htmlEncode(status); 3211e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda } 3212e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda 32130bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann private String getResourceName(Resources resources, String expectedType, Integer resourceId) { 32140bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann try { 32150bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann if (resourceId == null || resourceId == 0) return null; 32160bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann 32170bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann // Resource has an invalid type (e.g. a string as icon)? ignore 32180bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann final String resourceEntryName = resources.getResourceEntryName(resourceId); 32190bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann final String resourceTypeName = resources.getResourceTypeName(resourceId); 32200bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann if (!expectedType.equals(resourceTypeName)) { 32210bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann Log.w(TAG, "Resource " + resourceId + " (" + resourceEntryName + ") is of type " + 32220bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann resourceTypeName + " but " + expectedType + " is required."); 32230bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann return null; 32240bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } 32250bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann 32260bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann return resourceEntryName; 32270bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } catch (NotFoundException e) { 32280bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann return null; 32290bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } 32300bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } 32310bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann 32324f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 3233de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) { 3234bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 3235b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "deleteInTransaction: " + uri); 3236b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 32375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 32385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Default active DB to the contacts DB if none has been set. 32395d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mActiveDb.get() == null) { 3240078f588cef389358adabc579de00747878f3c108Dave Santoro mActiveDb.set(mContactsHelper.getWritableDatabase()); 32415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 32425d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 3243b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 3244f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 3245f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 3246508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey final int match = sUriMatcher.match(uri); 3247508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey switch (match) { 324835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 32495d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE: 32505d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mDbHelper.get().getSyncState().delete(mActiveDb.get(), selection, 32515d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs); 32525d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 32535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case SYNCSTATE_ID: { 32545d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String selectionWithId = 32555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 32565d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro + (selection == null ? "" : " AND (" + selection + ")"); 32575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mDbHelper.get().getSyncState().delete(mActiveDb.get(), selectionWithId, 32585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs); 32595d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 326035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 32615d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE_ID: { 3262b5a4add17815167d20a90645779df34cdf45280dFred Quintana String selectionWithId = 3263b5a4add17815167d20a90645779df34cdf45280dFred Quintana (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 3264b5a4add17815167d20a90645779df34cdf45280dFred Quintana + (selection == null ? "" : " AND (" + selection + ")"); 32655d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mProfileHelper.getSyncState().delete(mActiveDb.get(), selectionWithId, 32665d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs); 32675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 3268b5a4add17815167d20a90645779df34cdf45280dFred Quintana 3269cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov case CONTACTS: { 327035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 3271cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov // TODO 3272cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov return 0; 3273cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3274cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 3275d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 327635997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 3277d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 3278dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 32796bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 32806bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 32819fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann case CONTACTS_LOOKUP: { 328235997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 32832e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final List<String> pathSegments = uri.getPathSegments(); 32842e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final int segmentCount = pathSegments.size(); 32852e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey if (segmentCount < 3) { 32865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 3287fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 32882e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 32892e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final String lookupKey = pathSegments.get(2); 32905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final long contactId = lookupContactIdByLookupKey(mActiveDb.get(), lookupKey); 3291dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 32922e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 32932e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey 32949fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann case CONTACTS_LOOKUP_ID: { 329535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 32969fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // lookup contact by id and lookup key to see if they still match the actual record 32979fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final List<String> pathSegments = uri.getPathSegments(); 32989fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final String lookupKey = pathSegments.get(2); 32999fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 33009fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann setTablesAndProjectionMapForContacts(lookupQb, uri, null); 3301a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 33029fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann String[] args; 33039fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann if (selectionArgs == null) { 33049fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args = new String[2]; 33059fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } else { 33069fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args = new String[selectionArgs.length + 2]; 33079fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann System.arraycopy(selectionArgs, 0, args, 2, selectionArgs.length); 33089fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 33099fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args[0] = String.valueOf(contactId); 331060de6f6c3c70e53b603a47b0efc80993353a8368Daniel Lehmann args[1] = Uri.encode(lookupKey); 33119fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann lookupQb.appendWhere(Contacts._ID + "=? AND " + Contacts.LOOKUP_KEY + "=?"); 33125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = query(mActiveDb.get(), lookupQb, null, selection, args, null, null, 331315826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann null, null); 33149fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann try { 33159fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann if (c.getCount() == 1) { 33169fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // contact was unmodified so go ahead and delete it 3317dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 33189fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } else { 33199fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // row was changed (e.g. the merging might have changed), we got multiple 33209fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // rows or the supplied selection filtered the record out 33219fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann return 0; 33229fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 33239fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } finally { 33249fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann c.close(); 33259fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 33269fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 33279fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann 3328b6186821548995dce533ee502e82e9abf4c0aadcMakoto Onuki case CONTACTS_DELETE_USAGE: { 3329b6186821548995dce533ee502e82e9abf4c0aadcMakoto Onuki return deleteDataUsage(); 3330b6186821548995dce533ee502e82e9abf4c0aadcMakoto Onuki } 3331b6186821548995dce533ee502e82e9abf4c0aadcMakoto Onuki 3332d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case RAW_CONTACTS: 3333d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS: { 333435997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 33352971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana int numDeletes = 0; 33365f673b204620c4c241b3b39c6ac0ee063d22f13bMakoto Onuki Cursor c = mActiveDb.get().query(Views.RAW_CONTACTS, 3337fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov new String[]{RawContacts._ID, RawContacts.CONTACT_ID}, 33389d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki appendAccountIdToSelection(uri, selection), selectionArgs, 33399d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki null, null, null); 33402971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana try { 33412971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana while (c.moveToNext()) { 33422971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana final long rawContactId = c.getLong(0); 3343fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov long contactId = c.getLong(1); 3344fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov numDeletes += deleteRawContact(rawContactId, contactId, 3345fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov callerIsSyncAdapter); 33462971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 33472971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } finally { 33482971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana c.close(); 33492971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 33502971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana return numDeletes; 33512971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 33522971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana 3353d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case RAW_CONTACTS_ID: 3354d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS_ID: { 335535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 33562971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana final long rawContactId = ContentUris.parseId(uri); 33575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return deleteRawContact(rawContactId, mDbHelper.get().getContactId(rawContactId), 3358fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov callerIsSyncAdapter); 3359508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 3360508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 33610c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro case DATA: 33620c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro case PROFILE_DATA: { 336335997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 3364f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 3365944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong return deleteData(appendAccountToSelection(uri, selection), selectionArgs, 3366f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana callerIsSyncAdapter); 336720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 336820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 336948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case DATA_ID: 337048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 337148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 3372e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa case CALLABLES_ID: 3373d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case POSTALS_ID: 3374d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_DATA_ID: { 337535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 3376508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey long dataId = ContentUris.parseId(uri); 3377f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 33784da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(dataId); 33794da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov return deleteData(Data._ID + "=?", mSelectionArgs1, callerIsSyncAdapter); 3380ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3381ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3382ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 3383f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 33845aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey return deleteGroup(uri, ContentUris.parseId(uri), callerIsSyncAdapter); 33852971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 33862971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana 33872971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana case GROUPS: { 33882971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana int numDeletes = 0; 33895f673b204620c4c241b3b39c6ac0ee063d22f13bMakoto Onuki Cursor c = mActiveDb.get().query(Views.GROUPS, Projections.ID, 33909d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki appendAccountIdToSelection(uri, selection), selectionArgs, 33919d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki null, null, null); 33922971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana try { 33932971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana while (c.moveToNext()) { 33945aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey numDeletes += deleteGroup(uri, c.getLong(0), callerIsSyncAdapter); 33952971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 33962971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } finally { 33972971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana c.close(); 33982971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 339981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (numDeletes > 0) { 3400f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 340181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 34022971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana return numDeletes; 3403508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 3404508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 3405eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 340643880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 3407e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return deleteSettings(uri, appendAccountToSelection(uri, selection), selectionArgs); 3408eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 3409eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 34105d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case STATUS_UPDATES: 34115d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_STATUS_UPDATES: { 34120a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov return deleteStatusUpdates(selection, selectionArgs); 34131f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 34141f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 34153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 34163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 34173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItems(uri, new ContentValues(), selection, selectionArgs); 34183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 34193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 34203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 34213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 34223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItems(uri, new ContentValues(), 34239b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann StreamItems._ID + "=?", 34243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{uri.getLastPathSegment()}); 34253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 34263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 342782780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro case RAW_CONTACTS_ID_STREAM_ITEMS_ID: { 342882780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro mSyncToNetwork |= !callerIsSyncAdapter; 342982780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro String rawContactId = uri.getPathSegments().get(1); 343082780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro String streamItemId = uri.getLastPathSegment(); 343182780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro return deleteStreamItems(uri, new ContentValues(), 343282780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro StreamItems.RAW_CONTACT_ID + "=? AND " + StreamItems._ID + "=?", 343382780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro new String[]{rawContactId, streamItemId}); 343482780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro 343582780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro } 343682780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro 34373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 34383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 34395d9fcbaaa0007134564d63272470296f5d23b62aDave Santoro String streamItemId = uri.getPathSegments().get(1); 34405d9fcbaaa0007134564d63272470296f5d23b62aDave Santoro String selectionWithId = 34415d9fcbaaa0007134564d63272470296f5d23b62aDave Santoro (StreamItemPhotos.STREAM_ITEM_ID + "=" + streamItemId + " ") 34425d9fcbaaa0007134564d63272470296f5d23b62aDave Santoro + (selection == null ? "" : " AND (" + selection + ")"); 34435d9fcbaaa0007134564d63272470296f5d23b62aDave Santoro return deleteStreamItemPhotos(uri, new ContentValues(), 34445d9fcbaaa0007134564d63272470296f5d23b62aDave Santoro selectionWithId, selectionArgs); 34453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 34463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 34473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 34483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 34493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 34503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 34513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItemPhotos(uri, new ContentValues(), 34523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=? AND " 34533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + StreamItemPhotos.STREAM_ITEM_ID + "=?", 34543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{streamItemPhotoId, streamItemId}); 34553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 34563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 345781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov default: { 345881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 34593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return mLegacyApiSupport.delete(uri, selection, selectionArgs); 346081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3461508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 34624f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 34634f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 34641c8e40c18f92722b9bec6e8ce2e345a9828efa16Dmitri Plotnikov public int deleteGroup(Uri uri, long groupId, boolean callerIsSyncAdapter) { 3465ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov mGroupIdCache.clear(); 34665d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final long groupMembershipMimetypeId = mDbHelper.get() 346794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE); 34685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().delete(Tables.DATA, DataColumns.MIMETYPE_ID + "=" 346994021b213e4db367f60b30fcbfe9019e28571784Fred Quintana + groupMembershipMimetypeId + " AND " + GroupMembership.GROUP_ROW_ID + "=" 347094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana + groupId, null); 347194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 347294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana try { 3473f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (callerIsSyncAdapter) { 34745d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().delete(Tables.GROUPS, Groups._ID + "=" + groupId, null); 347594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } else { 347694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana mValues.clear(); 347794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana mValues.put(Groups.DELETED, 1); 3478f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mValues.put(Groups.DIRTY, 1); 34795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().update(Tables.GROUPS, mValues, Groups._ID + "=" + groupId, 34805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro null); 348194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 348294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } finally { 34831a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 348494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 348594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 348694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 34875aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private int deleteSettings(Uri uri, String selection, String[] selectionArgs) { 34885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final int count = mActiveDb.get().delete(Tables.SETTINGS, selection, selectionArgs); 34891a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 3490e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return count; 3491e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3492e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 3493dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int deleteContact(long contactId, boolean callerIsSyncAdapter) { 349496b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1[0] = Long.toString(contactId); 34955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.RAW_CONTACTS, new String[]{RawContacts._ID}, 349696b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker RawContacts.CONTACT_ID + "=?", mSelectionArgs1, 349796b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker null, null, null); 3498cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov try { 3499cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov while (c.moveToNext()) { 3500cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov long rawContactId = c.getLong(0); 3501dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana markRawContactAsDeleted(rawContactId, callerIsSyncAdapter); 3502cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3503cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } finally { 3504cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov c.close(); 3505cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3506cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 35073826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 35083826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 35095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().delete(Tables.CONTACTS, Contacts._ID + "=" + contactId, null); 3510cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3511cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 3512fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov public int deleteRawContact(long rawContactId, long contactId, boolean callerIsSyncAdapter) { 35135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().invalidateAggregationExceptionCache(); 35143826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 35153826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 351682780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro // Find and delete stream items associated with the raw contact. 351782780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro Cursor c = mActiveDb.get().query(Tables.STREAM_ITEMS, 351882780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro new String[]{StreamItems._ID}, 351982780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro StreamItems.RAW_CONTACT_ID + "=?", new String[]{String.valueOf(rawContactId)}, 352082780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro null, null, null); 352182780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro try { 352282780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro while (c.moveToNext()) { 352382780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro deleteStreamItem(c.getLong(0)); 352482780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro } 352582780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro } finally { 352682780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro c.close(); 352782780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro } 352882780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro 3529d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro if (callerIsSyncAdapter || rawContactIsLocal(rawContactId)) { 35305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().delete(Tables.PRESENCE, 35315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null); 35325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro int count = mActiveDb.get().delete(Tables.RAW_CONTACTS, 35335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro RawContacts._ID + "=" + rawContactId, null); 353441f76a59a31946f6d784dacf9f13d9a4c0bbe203Dave Santoro mAggregator.get().updateAggregateData(mTransactionContext.get(), contactId); 3535fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov return count; 353633b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } else { 35375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().removeContactIfSingleton(rawContactId); 3538dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return markRawContactAsDeleted(rawContactId, callerIsSyncAdapter); 353933b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 354033b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 354133b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov 3542d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro /** 3543d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro * Returns whether the given raw contact ID is local (i.e. has no account associated with it). 3544d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro */ 3545d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro private boolean rawContactIsLocal(long rawContactId) { 35469d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki Cursor c = mActiveDb.get().query(Tables.RAW_CONTACTS, Projections.LITERAL_ONE, 35479d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki RawContactsColumns.CONCRETE_ID + "=? AND " + 35489d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki RawContactsColumns.ACCOUNT_ID + "=" + Clauses.LOCAL_ACCOUNT_ID, 3549d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro new String[] {String.valueOf(rawContactId)}, null, null, null); 3550d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro try { 35519d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki return c.getCount() > 0; 3552d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro } finally { 3553d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro c.close(); 3554d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro } 3555d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro } 3556d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro 35570a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov private int deleteStatusUpdates(String selection, String[] selectionArgs) { 35589705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // delete from both tables: presence and status_updates 35599705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO should account type/name be appended to the where clause? 35609705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (VERBOSE_LOGGING) { 35619705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori Log.v(TAG, "deleting data from status_updates for " + selection); 35629705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 35635d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().delete(Tables.STATUS_UPDATES, getWhereClauseForStatusUpdatesTable(selection), 35649705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selectionArgs); 35655d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().delete(Tables.PRESENCE, selection, selectionArgs); 35660a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 35670a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 35683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItems(Uri uri, ContentValues values, String selection, 35693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 35709d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki int count = 0; 35719d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final Cursor c = mActiveDb.get().query(Views.STREAM_ITEMS, Projections.ID, 35729d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki selection, selectionArgs, null, null, null); 35739d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki try { 35749d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki c.moveToPosition(-1); 35759d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki while (c.moveToNext()) { 35769d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki count += deleteStreamItem(c.getLong(0)); 35779d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 35789d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } finally { 35799d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki c.close(); 35803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35819d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki return count; 35823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItem(long streamItemId) { 35853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItemPhotos(streamItemId); 35865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().delete(Tables.STREAM_ITEMS, StreamItems._ID + "=?", 35873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(streamItemId)}); 35883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItemPhotos(Uri uri, ContentValues values, String selection, 35913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 35925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().delete(Tables.STREAM_ITEM_PHOTOS, selection, selectionArgs); 35933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItemPhotos(long streamItemId) { 35963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Note that this does not enforce the modifying account. 35975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().delete(Tables.STREAM_ITEM_PHOTOS, 35985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro StreamItemPhotos.STREAM_ITEM_ID + "=?", 35993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(streamItemId)}); 36003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 36013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 3602dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int markRawContactAsDeleted(long rawContactId, boolean callerIsSyncAdapter) { 360381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 360481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 3605cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.clear(); 3606cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.DELETED, 1); 3607cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED); 3608cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContactsColumns.AGGREGATION_NEEDED, 1); 3609cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.putNull(RawContacts.CONTACT_ID); 3610cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.DIRTY, 1); 3611dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return updateRawContact(rawContactId, mValues, callerIsSyncAdapter); 3612cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3613cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 3614b6186821548995dce533ee502e82e9abf4c0aadcMakoto Onuki private int deleteDataUsage() { 3615a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki final SQLiteDatabase db = mActiveDb.get(); 3616a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki db.execSQL("UPDATE " + Tables.RAW_CONTACTS + " SET " + 3617a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki Contacts.TIMES_CONTACTED + "=0," + 3618a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki Contacts.LAST_TIME_CONTACTED + "=NULL" 3619a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki ); 3620a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki db.execSQL("UPDATE " + Tables.CONTACTS + " SET " + 3621a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki Contacts.TIMES_CONTACTED + "=0," + 3622a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki Contacts.LAST_TIME_CONTACTED + "=NULL" 3623a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki ); 3624a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki db.delete(Tables.DATA_USAGE_STAT, null, null); 3625a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki 3626a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki return 1; 3627a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki } 3628a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki 36294f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 3630de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected int updateInTransaction(Uri uri, ContentValues values, String selection, 3631de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov String[] selectionArgs) { 3632bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 3633b5a4add17815167d20a90645779df34cdf45280dFred Quintana Log.v(TAG, "updateInTransaction: " + uri); 3634b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3635b5a4add17815167d20a90645779df34cdf45280dFred Quintana 36365d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Default active DB to the contacts DB if none has been set. 36375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mActiveDb.get() == null) { 3638078f588cef389358adabc579de00747878f3c108Dave Santoro mActiveDb.set(mContactsHelper.getWritableDatabase()); 36395d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 36405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 364135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana int count = 0; 364200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 364300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar final int match = sUriMatcher.match(uri); 3644b5a4add17815167d20a90645779df34cdf45280dFred Quintana if (match == SYNCSTATE_ID && selection == null) { 3645b5a4add17815167d20a90645779df34cdf45280dFred Quintana long rowId = ContentUris.parseId(uri); 36461129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov Object data = values.get(ContactsContract.SyncState.DATA); 36475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().syncStateUpdated(rowId, data); 3648b5a4add17815167d20a90645779df34cdf45280dFred Quintana return 1; 3649b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3650b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 3651f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 3652f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 365300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar switch(match) { 365435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 36555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE: 36565d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mDbHelper.get().getSyncState().update(mActiveDb.get(), values, 3657b5a4add17815167d20a90645779df34cdf45280dFred Quintana appendAccountToSelection(uri, selection), selectionArgs); 3658b5a4add17815167d20a90645779df34cdf45280dFred Quintana 3659b5a4add17815167d20a90645779df34cdf45280dFred Quintana case SYNCSTATE_ID: { 3660b5a4add17815167d20a90645779df34cdf45280dFred Quintana selection = appendAccountToSelection(uri, selection); 3661b5a4add17815167d20a90645779df34cdf45280dFred Quintana String selectionWithId = 3662b5a4add17815167d20a90645779df34cdf45280dFred Quintana (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 3663b5a4add17815167d20a90645779df34cdf45280dFred Quintana + (selection == null ? "" : " AND (" + selection + ")"); 36645d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mDbHelper.get().getSyncState().update(mActiveDb.get(), values, 36655d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionWithId, selectionArgs); 36665d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 36675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 36685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE_ID: { 36695d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selection = appendAccountToSelection(uri, selection); 36705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String selectionWithId = 36715d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 36725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro + (selection == null ? "" : " AND (" + selection + ")"); 36735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mProfileHelper.getSyncState().update(mActiveDb.get(), values, 3674b5a4add17815167d20a90645779df34cdf45280dFred Quintana selectionWithId, selectionArgs); 3675b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 367635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 3677d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case CONTACTS: 3678d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE: { 367935997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 3680dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(values, selection, selectionArgs, callerIsSyncAdapter); 368100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 368200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 368300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 3684d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 368535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 3686dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(ContentUris.parseId(uri), values, callerIsSyncAdapter); 3687c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar break; 3688c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 3689c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 36902e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey case CONTACTS_LOOKUP: 36912e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey case CONTACTS_LOOKUP_ID: { 369235997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 36932e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final List<String> pathSegments = uri.getPathSegments(); 36942e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final int segmentCount = pathSegments.size(); 36952e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey if (segmentCount < 3) { 36965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 3697fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 36982e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 36992e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final String lookupKey = pathSegments.get(2); 37005d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final long contactId = lookupContactIdByLookupKey(mActiveDb.get(), lookupKey); 3701dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(contactId, values, callerIsSyncAdapter); 37022e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey break; 37032e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 37042e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey 3705193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki case RAW_CONTACTS_ID_DATA: 3706d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS_ID_DATA: { 370735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 3708193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki int segment = match == RAW_CONTACTS_ID_DATA ? 1 : 2; 3709d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro final String rawContactId = uri.getPathSegments().get(segment); 37107d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh String selectionWithId = (Data.RAW_CONTACT_ID + "=" + rawContactId + " ") 37117d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh + (selection == null ? "" : " AND " + selection); 37127d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 37137d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh count = updateData(uri, values, selectionWithId, selectionArgs, callerIsSyncAdapter); 37147d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 37157d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh break; 37167d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh } 37177d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 37180c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro case DATA: 37190c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro case PROFILE_DATA: { 372035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 3721944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong count = updateData(uri, values, appendAccountToSelection(uri, selection), 3722f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana selectionArgs, callerIsSyncAdapter); 372381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3724f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 372581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 372620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov break; 372720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 3728c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 372948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case DATA_ID: 373048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 373148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 3732e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa case CALLABLES_ID: 373348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 373435997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 3735f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana count = updateData(uri, values, selection, selectionArgs, callerIsSyncAdapter); 373681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3737f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 373881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 373900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 374000d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 37417e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 37425d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case RAW_CONTACTS: 37435d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_RAW_CONTACTS: { 374435997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 37459d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki selection = appendAccountIdToSelection(uri, selection); 3746dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateRawContacts(values, selection, selectionArgs, callerIsSyncAdapter); 37477e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 37487e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 37497e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 37505ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_ID: { 375135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 375233b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov long rawContactId = ContentUris.parseId(uri); 37534529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov if (selection != null) { 37544da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 37554da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov count = updateRawContacts(values, RawContacts._ID + "=?" 3756dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " AND(" + selection + ")", selectionArgs, 3757dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana callerIsSyncAdapter); 37584529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } else { 37594da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(rawContactId); 3760dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateRawContacts(values, RawContacts._ID + "=?", mSelectionArgs1, 3761dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana callerIsSyncAdapter); 37624529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 37637e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 37647e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 37657e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 3766ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 37679d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki count = updateGroups(uri, values, appendAccountIdToSelection(uri, selection), 3768f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana selectionArgs, callerIsSyncAdapter); 376981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3770f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 377181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3772ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 3773ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3774ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3775ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 3776ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long groupId = ContentUris.parseId(uri); 37774da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(groupId)); 37784da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov String selectionWithId = Groups._ID + "=? " 377973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov + (selection == null ? "" : " AND " + selection); 37805aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey count = updateGroups(uri, values, selectionWithId, selectionArgs, 37815aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey callerIsSyncAdapter); 378281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3783f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 378481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3785ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 3786ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3787ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3788127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 37895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro count = updateAggregationException(mActiveDb.get(), values); 3790b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 3791b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 3792b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 3793eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 3794e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey count = updateSettings(uri, values, appendAccountToSelection(uri, selection), 3795e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey selectionArgs); 379643880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 3797eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 3798eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 3799eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 38005d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case STATUS_UPDATES: 38015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_STATUS_UPDATES: { 38029705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori count = updateStatusUpdate(uri, values, selection, selectionArgs); 38039705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori break; 38049705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 38059705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 38063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 38073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItems(uri, values, selection, selectionArgs); 38083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 38093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 38103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 38113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 38129b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann count = updateStreamItems(uri, values, StreamItems._ID + "=?", 38133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{uri.getLastPathSegment()}); 38143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 38153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 38163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 381782780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro case RAW_CONTACTS_ID_STREAM_ITEMS_ID: { 381882780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro String rawContactId = uri.getPathSegments().get(1); 381982780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro String streamItemId = uri.getLastPathSegment(); 382082780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro count = updateStreamItems(uri, values, 382182780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro StreamItems.RAW_CONTACT_ID + "=? AND " + StreamItems._ID + "=?", 382282780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro new String[]{rawContactId, streamItemId}); 382382780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro break; 382482780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro } 382582780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro 38263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 38273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, selection, selectionArgs); 38283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 38293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 38303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 38313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 38323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 38333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, 38343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotos.STREAM_ITEM_ID + "=?", new String[]{streamItemId}); 38353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 38363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 38373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 38383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 38393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 38403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 38413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, 38423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=? AND " + 38433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=?", 38443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{streamItemPhotoId, streamItemId}); 38453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 38463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 38473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 384872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov case DIRECTORIES: { 3849bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.scanPackagesByUid(Binder.getCallingUid()); 385072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov count = 1; 3851d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 3852d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 3853d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 385446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa case DATA_USAGE_FEEDBACK_ID: { 385546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (handleDataUsageFeedback(uri)) { 385646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa count = 1; 385746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 385846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa count = 0; 385946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 386046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa break; 386146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 386246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 386381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov default: { 386481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 3865f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.update(uri, values, selection, selectionArgs); 386681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 386700d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 386800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 386900d71133c63c882fb41729ddc3a52f66fb155374Evan Millar return count; 38704f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 38714f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 38729705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private int updateStatusUpdate(Uri uri, ContentValues values, String selection, 38739705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori String[] selectionArgs) { 38749705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // update status_updates table, if status is provided 38759705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO should account type/name be appended to the where clause? 38769705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori int updateCount = 0; 38779705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContentValues settableValues = getSettableColumnsForStatusUpdatesTable(values); 38789705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (settableValues.size() > 0) { 38795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro updateCount = mActiveDb.get().update(Tables.STATUS_UPDATES, 38809705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori settableValues, 38819705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori getWhereClauseForStatusUpdatesTable(selection), 38829705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selectionArgs); 38839705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 38849705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 38859705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // now update the Presence table 38869705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori settableValues = getSettableColumnsForPresenceTable(values); 38879705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (settableValues.size() > 0) { 38885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro updateCount = mActiveDb.get().update(Tables.PRESENCE, settableValues, 38899705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selection, selectionArgs); 38909705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 38919705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO updateCount is not entirely a valid count of updated rows because 2 tables could 38929705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // potentially get updated in this method. 38939705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return updateCount; 38949705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 38959705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 38963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int updateStreamItems(Uri uri, ContentValues values, String selection, 38973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 38983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Stream items can't be moved to a new raw contact. 38993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.remove(StreamItems.RAW_CONTACT_ID); 39003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 39016802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to update accounts params - they don't exist in the stream items table. 39026802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_NAME); 39036802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_TYPE); 39046802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 39053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If there's been no exception, the update should be fine. 39065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().update(Tables.STREAM_ITEMS, values, selection, selectionArgs); 39073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 39083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 39093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int updateStreamItemPhotos(Uri uri, ContentValues values, String selection, 39103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 39113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Stream item photos can't be moved to a new stream item. 39123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.remove(StreamItemPhotos.STREAM_ITEM_ID); 39133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 39146802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to update accounts params - they don't exist in the stream item 39156802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // photos table. 39166802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_NAME); 39176802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_TYPE); 39186802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 39196802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo (since we're updating, it's valid for the photo to not be present). 39206802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (processStreamItemPhoto(values, true)) { 39216802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // If there's been no exception, the update should be fine. 39225d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().update(Tables.STREAM_ITEM_PHOTOS, values, selection, 39235d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs); 39246802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 39256802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return 0; 39263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 39273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 39289705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori /** 39299705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori * Build a where clause to select the rows to be updated in status_updates table. 39309705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori */ 39319705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private String getWhereClauseForStatusUpdatesTable(String selection) { 39329705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.setLength(0); 39339705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(WHERE_CLAUSE_FOR_STATUS_UPDATES_TABLE); 39349705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(selection); 39359705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(")"); 39369705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mSb.toString(); 39379705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 39389705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 39399705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private ContentValues getSettableColumnsForStatusUpdatesTable(ContentValues values) { 39409705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mValues.clear(); 39419705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS, values, 39429705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS); 39439705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_TIMESTAMP, values, 39449705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_TIMESTAMP); 39459705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_RES_PACKAGE, values, 39469705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_RES_PACKAGE); 39479705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_LABEL, values, 39489705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_LABEL); 39499705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_ICON, values, 39509705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_ICON); 39519705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mValues; 39529705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 39539705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 39549705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private ContentValues getSettableColumnsForPresenceTable(ContentValues values) { 39559705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mValues.clear(); 39569705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.PRESENCE, values, 39579705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.PRESENCE); 3958aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.CHAT_CAPABILITY, values, 3959aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori StatusUpdates.CHAT_CAPABILITY); 39609705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mValues; 39619705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 39629705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 39639d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki private interface GroupAccountQuery { 39649d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki String TABLE = Views.GROUPS; 39659d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 39669d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki String[] COLUMNS = new String[] { 39679d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki Groups._ID, 39689d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki Groups.ACCOUNT_TYPE, 39699d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki Groups.ACCOUNT_NAME, 39709d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki Groups.DATA_SET, 39719d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki }; 39729d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki int ID = 0; 39739d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki int ACCOUNT_TYPE = 1; 39749d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki int ACCOUNT_NAME = 2; 39759d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki int DATA_SET = 3; 39769d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 397773776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 39789d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki private int updateGroups(Uri uri, ContentValues originalValues, String selectionWithId, 39799d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki String[] selectionArgs, boolean callerIsSyncAdapter) { 3980ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov mGroupIdCache.clear(); 3981ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov 39829d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final SQLiteDatabase db = mActiveDb.get(); 39839d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final ContactsDatabaseHelper dbHelper = mDbHelper.get(); 39849d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 39859d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final ContentValues updatedValues = new ContentValues(); 39869d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki updatedValues.putAll(originalValues); 39879d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 39889d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (!callerIsSyncAdapter && !updatedValues.containsKey(Groups.DIRTY)) { 398973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.put(Groups.DIRTY, 1); 399073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } 39911a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (updatedValues.containsKey(Groups.GROUP_VISIBLE)) { 39921a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 399394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 399443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 39959d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // Prepare for account change 39969d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final boolean isAccountNameChanging = updatedValues.containsKey(Groups.ACCOUNT_NAME); 39979d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final boolean isAccountTypeChanging = updatedValues.containsKey(Groups.ACCOUNT_TYPE); 39989d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final boolean isDataSetChanging = updatedValues.containsKey(Groups.DATA_SET); 39999d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final boolean isAccountChanging = isAccountNameChanging || isAccountTypeChanging 40009d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki || isDataSetChanging; 40019d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final String updatedAccountName = updatedValues.getAsString(Groups.ACCOUNT_NAME); 40029d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final String updatedAccountType = updatedValues.getAsString(Groups.ACCOUNT_TYPE); 40039d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final String updatedDataSet = updatedValues.getAsString(Groups.DATA_SET); 40049d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 40059d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki updatedValues.remove(Groups.ACCOUNT_NAME); 40069d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki updatedValues.remove(Groups.ACCOUNT_TYPE); 40079d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki updatedValues.remove(Groups.DATA_SET); 40089d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 40099d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // We later call requestSync() on all affected accounts. 40109d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final Set<Account> affectedAccounts = Sets.newHashSet(); 40119d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 40129d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // Look for all affected rows, and change them row by row. 40139d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final Cursor c = db.query(GroupAccountQuery.TABLE, GroupAccountQuery.COLUMNS, 40149d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki selectionWithId, selectionArgs, null, null, null); 40159d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki int returnCount = 0; 40169d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki try { 40179d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki c.moveToPosition(-1); 40189d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki while (c.moveToNext()) { 40199d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final long groupId = c.getLong(GroupAccountQuery.ID); 40209d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 40219d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mSelectionArgs1[0] = Long.toString(groupId); 40229d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 40239d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final String accountName = isAccountNameChanging 40249d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki ? updatedAccountName : c.getString(GroupAccountQuery.ACCOUNT_NAME); 40259d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final String accountType = isAccountTypeChanging 40269d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki ? updatedAccountType : c.getString(GroupAccountQuery.ACCOUNT_TYPE); 40279d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final String dataSet = isDataSetChanging 40289d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki ? updatedDataSet : c.getString(GroupAccountQuery.DATA_SET); 40299d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 40309d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (isAccountChanging) { 40319d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final long accountId = dbHelper.getOrCreateAccountIdInTransaction( 40329d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki AccountWithDataSet.get(accountName, accountType, dataSet)); 40339d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki updatedValues.put(GroupsColumns.ACCOUNT_ID, accountId); 40349d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 40359d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 40369d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // Finally do the actual update. 40379d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final int count = db.update(Tables.GROUPS, updatedValues, 40389d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki GroupsColumns.CONCRETE_ID + "=?", mSelectionArgs1); 40399d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 40409d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if ((count > 0) 40419d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki && !TextUtils.isEmpty(accountName) 40429d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki && !TextUtils.isEmpty(accountType)) { 40439d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki affectedAccounts.add(new Account(accountName, accountType)); 40449d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 40459d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 40469d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki returnCount += count; 40479d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 40489d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } finally { 40499d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki c.close(); 40509d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 40519d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 405243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // TODO: This will not work for groups that have a data set specified, since the content 405343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // resolver will not be able to request a sync for the right source (unless it is updated 405443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // to key off account with data set). 40559d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // i.e. requestSync only takes Account, not AccountWithDataSet. 40566ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi if (updatedValues.containsKey(Groups.SHOULD_SYNC) 40571129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov && updatedValues.getAsInteger(Groups.SHOULD_SYNC) != 0) { 40589d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki for (Account account : affectedAccounts) { 40599d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki ContentResolver.requestSync(account, ContactsContract.AUTHORITY, new Bundle()); 40606ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 40616ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 40629d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki return returnCount; 406394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 406494021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 4065b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov private int updateSettings(Uri uri, ContentValues values, String selection, 4066b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov String[] selectionArgs) { 40675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final int count = mActiveDb.get().update(Tables.SETTINGS, values, selection, selectionArgs); 40681a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (values.containsKey(Settings.UNGROUPED_VISIBLE)) { 40691a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 4070e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 4071e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return count; 4072e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 4073e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 4074dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateRawContacts(ContentValues values, String selection, String[] selectionArgs, 4075dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 40764529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov if (values.containsKey(RawContacts.CONTACT_ID)) { 40774529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov throw new IllegalArgumentException(RawContacts.CONTACT_ID + " should not be included " + 40784529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov "in content values. Contact IDs are assigned automatically"); 40794529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 408073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 408197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov if (!callerIsSyncAdapter) { 408297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov selection = DatabaseUtils.concatenateWhere(selection, 408397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov RawContacts.RAW_CONTACT_IS_READ_ONLY + "=0"); 408497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov } 408597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 40864529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov int count = 0; 40875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor cursor = mActiveDb.get().query(Views.RAW_CONTACTS, 40889d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki Projections.ID, selection, 40894529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov selectionArgs, null, null, null); 40904529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov try { 40914529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov while (cursor.moveToNext()) { 40924529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov long rawContactId = cursor.getLong(0); 4093dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateRawContact(rawContactId, values, callerIsSyncAdapter); 40944529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov count++; 40954529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 40964529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } finally { 40974529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov cursor.close(); 40984529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 40994529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov 41004529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov return count; 41014529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 41024529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov 4103dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateRawContact(long rawContactId, ContentValues values, 4104dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 41059d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final String selection = RawContactsColumns.CONCRETE_ID + " = ?"; 410696b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1[0] = Long.toString(rawContactId); 41079d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 41089d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final ContactsDatabaseHelper dbHelper = mDbHelper.get(); 41099d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 411019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka final boolean requestUndoDelete = (values.containsKey(RawContacts.DELETED) 411119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka && values.getAsInteger(RawContacts.DELETED) == 0); 41129d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 41139d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final boolean isAccountNameChanging = values.containsKey(RawContacts.ACCOUNT_NAME); 41149d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final boolean isAccountTypeChanging = values.containsKey(RawContacts.ACCOUNT_TYPE); 41159d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final boolean isDataSetChanging = values.containsKey(RawContacts.DATA_SET); 41169d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final boolean isAccountChanging = isAccountNameChanging || isAccountTypeChanging 41179d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki || isDataSetChanging; 41189d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 411919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka int previousDeleted = 0; 41209d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki long accountId = 0; 41219d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki String oldAccountType = null; 41229d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki String oldAccountName = null; 41239d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki String oldDataSet = null; 41249d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 41259d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (requestUndoDelete || isAccountChanging) { 41265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor cursor = mActiveDb.get().query(RawContactsQuery.TABLE, RawContactsQuery.COLUMNS, 41275d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selection, mSelectionArgs1, null, null, null); 412819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka try { 412919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (cursor.moveToFirst()) { 413019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka previousDeleted = cursor.getInt(RawContactsQuery.DELETED); 41319d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki accountId = cursor.getLong(RawContactsQuery.ACCOUNT_ID); 41329d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki oldAccountType = cursor.getString(RawContactsQuery.ACCOUNT_TYPE); 41339d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki oldAccountName = cursor.getString(RawContactsQuery.ACCOUNT_NAME); 41349d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki oldDataSet = cursor.getString(RawContactsQuery.DATA_SET); 413519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 413619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } finally { 413719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka cursor.close(); 413819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 41399d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (isAccountChanging) { 41409d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // We can't change the original ContentValues, as it'll be re-used over all 41419d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // updateRawContact invocations in a transaction, so we need to create a new one. 41429d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // (However we don't want to use mValues here, because mValues may be used in some 41439d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // other methods that are called by this method.) 41449d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final ContentValues originalValues = values; 41459d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki values = new ContentValues(); 41469d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki values.clear(); 41479d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki values.putAll(originalValues); 41489d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 41499d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final AccountWithDataSet newAccountWithDataSet = AccountWithDataSet.get( 41509d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki isAccountNameChanging 41519d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki ? values.getAsString(RawContacts.ACCOUNT_NAME) : oldAccountName, 41529d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki isAccountTypeChanging 41539d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki ? values.getAsString(RawContacts.ACCOUNT_TYPE) : oldAccountType, 41549d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki isDataSetChanging 41559d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki ? values.getAsString(RawContacts.DATA_SET) : oldDataSet 41569d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki ); 41579d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki accountId = dbHelper.getOrCreateAccountIdInTransaction(newAccountWithDataSet); 41589d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 41599d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki values.put(RawContactsColumns.ACCOUNT_ID, accountId); 41609d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 41619d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki values.remove(RawContacts.ACCOUNT_NAME); 41629d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki values.remove(RawContacts.ACCOUNT_TYPE); 41639d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki values.remove(RawContacts.DATA_SET); 41649d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 41659d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 41669d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (requestUndoDelete) { 416719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka values.put(ContactsContract.RawContacts.AGGREGATION_MODE, 416819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT); 416919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 4170f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov 41715d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro int count = mActiveDb.get().update(Tables.RAW_CONTACTS, values, selection, mSelectionArgs1); 41725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count != 0) { 4173f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov if (values.containsKey(RawContacts.AGGREGATION_MODE)) { 4174f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov int aggregationMode = values.getAsInteger(RawContacts.AGGREGATION_MODE); 4175f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov 4176f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov // As per ContactsContract documentation, changing aggregation mode 4177f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov // to DEFAULT should not trigger aggregation 4178f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov if (aggregationMode != RawContacts.AGGREGATION_MODE_DEFAULT) { 41795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().markForAggregation(rawContactId, aggregationMode, false); 4180f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 4181f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 4182433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey if (values.containsKey(RawContacts.STARRED)) { 4183dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter) { 4184dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, 4185dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana values.getAsLong(RawContacts.STARRED) != 0); 4186dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 41875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().updateStarred(rawContactId); 4188dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } else { 4189dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // if this raw contact is being associated with an account, then update the 4190dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // favorites group membership based on whether or not this contact is starred. 4191dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // If it is starred, add a group membership, if one doesn't already exist 4192dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // otherwise delete any matching group memberships. 41939d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (!callerIsSyncAdapter && isAccountChanging) { 41945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro boolean starred = 0 != DatabaseUtils.longForQuery(mActiveDb.get(), 4195dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana SELECTION_STARRED_FROM_RAW_CONTACTS, 4196dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{Long.toString(rawContactId)}); 4197dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, starred); 4198dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4199dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4200dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 4201dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // if this raw contact is being associated with an account, then add a 4202dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // group membership to the group marked as AutoAdd, if any. 42039d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (!callerIsSyncAdapter && isAccountChanging) { 4204dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana addAutoAddMembership(rawContactId); 4205433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey } 4206dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 4207285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov if (values.containsKey(RawContacts.SOURCE_ID)) { 42085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().updateLookupKeyForRawContact(mActiveDb.get(), rawContactId); 4209285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 4210f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov if (values.containsKey(RawContacts.NAME_VERIFIED)) { 4211f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov 4212f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov // If setting NAME_VERIFIED for this raw contact, reset it for all 4213f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov // other raw contacts in the same aggregate 4214f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov if (values.getAsInteger(RawContacts.NAME_VERIFIED) != 0) { 42155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().resetNameVerifiedForOtherRawContacts(rawContactId); 4216f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov } 42175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().updateDisplayNameForRawContact(mActiveDb.get(), rawContactId); 4218f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov } 421919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (requestUndoDelete && previousDeleted == 1) { 42209d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // Note before the accounts refactoring, we used to use the *old* account here, 42219d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // which doesn't make sense, so now we pass the *new* account. 42229d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // (In practice it doesn't matter because there's probably no apps that undo-delete 42239d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // and change accounts at the same time.) 42249d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mTransactionContext.get().rawContactInserted(rawContactId, accountId); 422519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 42265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 42275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return count; 422833b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 422933b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov 4230321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana private int updateData(Uri uri, ContentValues values, String selection, 4231f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 423220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.clear(); 423320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.putAll(values); 423420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data._ID); 42355ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov mValues.remove(Data.RAW_CONTACT_ID); 423620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.MIMETYPE); 423720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 423820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov String packageName = values.getAsString(Data.RES_PACKAGE); 423920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (packageName != null) { 424020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.RES_PACKAGE); 42415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mValues.put(DataColumns.PACKAGE_ID, mDbHelper.get().getPackageId(packageName)); 424220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 424320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 424497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov if (!callerIsSyncAdapter) { 424597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov selection = DatabaseUtils.concatenateWhere(selection, 424697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov Data.IS_READ_ONLY + "=0"); 424797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov } 424897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 4249653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov int count = 0; 425020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 4251653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 4252653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov // so we don't need to worry about updating data we don't have permission to read. 42535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = queryLocal(uri, 4254f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro DataRowHandler.DataUpdateQuery.COLUMNS, 425515826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann selection, selectionArgs, null, -1 /* directory ID */, null); 4256653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov try { 4257653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov while(c.moveToNext()) { 4258f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana count += updateData(mValues, c, callerIsSyncAdapter); 425920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 4260653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov } finally { 4261653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov c.close(); 426220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 426320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 4264653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov return count; 426520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 426620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 4267f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private int updateData(ContentValues values, Cursor c, boolean callerIsSyncAdapter) { 4268653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov if (values.size() == 0) { 4269653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov return 0; 4270321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana } 4271653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov 4272f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final String mimeType = c.getString(DataRowHandler.DataUpdateQuery.MIMETYPE); 4273a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 4274f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro boolean updated = 42755d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro rowHandler.update(mActiveDb.get(), mTransactionContext.get(), values, c, 42765d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro callerIsSyncAdapter); 4277f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) { 4278f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 4279a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov } 4280f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return updated ? 1 : 0; 4281321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana } 4282321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana 42838c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov private int updateContactOptions(ContentValues values, String selection, 4284dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 42858c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov int count = 0; 42865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor cursor = mActiveDb.get().query(Views.CONTACTS, 42875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new String[] { Contacts._ID }, selection, selectionArgs, null, null, null); 42888c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov try { 42898c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov while (cursor.moveToNext()) { 42908c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov long contactId = cursor.getLong(0); 429124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 4292dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateContactOptions(contactId, values, callerIsSyncAdapter); 42938c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov count++; 42948c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 42958c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } finally { 42968c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov cursor.close(); 42978c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 42988c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 42998c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov return count; 43008c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 43018c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 4302dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateContactOptions(long contactId, ContentValues values, 4303dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 4304d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 43058c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.clear(); 4306b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE, 4307d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.CUSTOM_RINGTONE); 4308b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL, 4309d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.SEND_TO_VOICEMAIL); 4310b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED, 4311d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.LAST_TIME_CONTACTED); 4312b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED, 4313d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.TIMES_CONTACTED); 4314b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED, 4315d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.STARRED); 4316d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 4317d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov // Nothing to update - just return 43188c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov if (mValues.size() == 0) { 4319d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov return 0; 4320d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 4321d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 43228c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov if (mValues.containsKey(RawContacts.STARRED)) { 4323c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey // Mark dirty when changing starred to trigger sync 43248c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.put(RawContacts.DIRTY, 1); 4325c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey } 4326c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey 43274da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(contactId); 43285d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().update(Tables.RAW_CONTACTS, mValues, RawContacts.CONTACT_ID + "=?" 432997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov + " AND " + RawContacts.RAW_CONTACT_IS_READ_ONLY + "=0", mSelectionArgs1); 43308c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 4331dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (mValues.containsKey(RawContacts.STARRED) && !callerIsSyncAdapter) { 43325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor cursor = mActiveDb.get().query(Views.RAW_CONTACTS, 4333dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[] { RawContacts._ID }, RawContacts.CONTACT_ID + "=?", 4334dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mSelectionArgs1, null, null, null); 4335dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana try { 4336dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana while (cursor.moveToNext()) { 4337dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana long rawContactId = cursor.getLong(0); 4338dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, 4339dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mValues.getAsLong(RawContacts.STARRED) != 0); 4340dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4341dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } finally { 4342dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana cursor.close(); 4343dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4344dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4345dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 43468c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov // Copy changeable values to prevent automatically managed fields from 43478c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov // being explicitly updated by clients. 43488c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.clear(); 4349b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE, 43508c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.CUSTOM_RINGTONE); 4351b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL, 43528c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.SEND_TO_VOICEMAIL); 4353b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED, 43548c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.LAST_TIME_CONTACTED); 4355b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED, 43568c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.TIMES_CONTACTED); 4357b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED, 43588c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.STARRED); 43598c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 43605d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro int rslt = mActiveDb.get().update(Tables.CONTACTS, mValues, Contacts._ID + "=?", 43615d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mSelectionArgs1); 43626e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori 43639b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori if (values.containsKey(Contacts.LAST_TIME_CONTACTED) && 43649b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori !values.containsKey(Contacts.TIMES_CONTACTED)) { 43655d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().execSQL(UPDATE_TIMES_CONTACTED_CONTACTS_TABLE, mSelectionArgs1); 43665d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get().execSQL(UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE, mSelectionArgs1); 43679b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori } 43689b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori return rslt; 4369f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov } 4370d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 4371127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov private int updateAggregationException(SQLiteDatabase db, ContentValues values) { 4372127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov int exceptionType = values.getAsInteger(AggregationExceptions.TYPE); 43730c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov long rcId1 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID1); 43740c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov long rcId2 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID2); 437580c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov 4376ed089fd34d7b3baf29709eb4f2bc14fa35117660Dmitri Plotnikov long rawContactId1; 4377ed089fd34d7b3baf29709eb4f2bc14fa35117660Dmitri Plotnikov long rawContactId2; 43780c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov if (rcId1 < rcId2) { 43790c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId1 = rcId1; 43800c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId2 = rcId2; 43810c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov } else { 43820c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId2 = rcId1; 43830c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId1 = rcId2; 4384b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 4385127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 43860c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC) { 43874da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs2[0] = String.valueOf(rawContactId1); 43884da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs2[1] = String.valueOf(rawContactId2); 43890c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov db.delete(Tables.AGGREGATION_EXCEPTIONS, 43904da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov AggregationExceptions.RAW_CONTACT_ID1 + "=? AND " 43914da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov + AggregationExceptions.RAW_CONTACT_ID2 + "=?", mSelectionArgs2); 43920c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov } else { 43936bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov ContentValues exceptionValues = new ContentValues(3); 43946bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov exceptionValues.put(AggregationExceptions.TYPE, exceptionType); 43950c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1); 43960c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2); 43970c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov db.replace(Tables.AGGREGATION_EXCEPTIONS, AggregationExceptions._ID, 43980c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues); 4399127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 4400127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 44015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().invalidateAggregationExceptionCache(); 44025d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().markForAggregation(rawContactId1, 440369cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 44045d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().markForAggregation(rawContactId2, 440569cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 4406dea3ee5e7f84be2abfe35837a460cbe779d319dbDmitri Plotnikov 44075d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().aggregateContact(mTransactionContext.get(), db, rawContactId1); 44085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().aggregateContact(mTransactionContext.get(), db, rawContactId2); 4409127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 4410127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // The return value is fake - we just confirm that we made a change, not count actual 4411127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // rows changed. 4412127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov return 1; 4413b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 4414b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 441570d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong public void onAccountsUpdated(Account[] accounts) { 4416bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_ACCOUNTS); 44173826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 44183826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 44199ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki private static final String ACCOUNT_STRING_SEPARATOR_OUTER = "\u0001"; 44209ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki private static final String ACCOUNT_STRING_SEPARATOR_INNER = "\u0002"; 44219d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 44229ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki /** return serialized version of {@code accounts} */ 44239ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki @VisibleForTesting 44249ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki static String accountsToString(Set<Account> accounts) { 44259ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final StringBuilder sb = new StringBuilder(); 44269ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki for (Account account : accounts) { 44279ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki if (sb.length() > 0) { 44289ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki sb.append(ACCOUNT_STRING_SEPARATOR_OUTER); 44299ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 44309ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki sb.append(account.name); 44319ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki sb.append(ACCOUNT_STRING_SEPARATOR_INNER); 44329ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki sb.append(account.type); 44339ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 44349ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki return sb.toString(); 44359ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 44369d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 44379ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki /** 44389ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki * de-serialize string returned by {@link #accountsToString} and return it. 44399ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki * If {@code accountsString} is malformed it'll throw {@link IllegalArgumentException}. 44409ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki */ 44419ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki @VisibleForTesting 44429ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki static Set<Account> stringToAccounts(String accountsString) { 44439ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final Set<Account> ret = Sets.newHashSet(); 44449ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki if (accountsString.length() == 0) return ret; // no accounts 44459ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki try { 44469ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki for (String accountString : accountsString.split(ACCOUNT_STRING_SEPARATOR_OUTER)) { 44479ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki String[] nameAndType = accountString.split(ACCOUNT_STRING_SEPARATOR_INNER); 44489ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki ret.add(new Account(nameAndType[0], nameAndType[1])); 44499ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 44509ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki return ret; 44519ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } catch (RuntimeException ex) { 44529ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki throw new IllegalArgumentException("Malformed string", ex); 44539ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 44549ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 44559ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki 44569ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki /** 44579ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki * @return {@code true} if the given {@code currentSystemAccounts} are different from the 44589ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki * accounts we know, which are stored in the {@link DbProperties#KNOWN_ACCOUNTS} property. 44599ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki */ 44609ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki @VisibleForTesting 44619ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki boolean haveAccountsChanged(Account[] currentSystemAccounts) { 44629ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final ContactsDatabaseHelper dbHelper = mDbHelper.get(); 44639ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final Set<Account> knownAccountSet; 44649ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki try { 44659ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki knownAccountSet = stringToAccounts( 44669ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki dbHelper.getProperty(DbProperties.KNOWN_ACCOUNTS, "")); 44679ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } catch (IllegalArgumentException e) { 44689ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // Failed to get the last known accounts for an unknown reason. Let's just 44699ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // treat as if accounts have changed. 44709ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki return true; 44719ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 44729ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final Set<Account> currentAccounts = Sets.newHashSet(currentSystemAccounts); 44739ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki return !knownAccountSet.equals(currentAccounts); 44749ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 44759ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki 44769ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki @VisibleForTesting 44779ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki void saveAccounts(Account[] systemAccounts) { 44789ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final ContactsDatabaseHelper dbHelper = mDbHelper.get(); 44799ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki dbHelper.setProperty(DbProperties.KNOWN_ACCOUNTS, 44809ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki accountsToString(Sets.newHashSet(systemAccounts))); 44819ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 44829ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki 44839ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki private boolean updateAccountsInBackground(Account[] systemAccounts) { 44849ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki if (!haveAccountsChanged(systemAccounts)) { 44859ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki return false; 44869ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 4487b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki if ("1".equals(SystemProperties.get(DEBUG_PROPERTY_KEEP_STALE_ACCOUNT_DATA))) { 4488b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki Log.w(TAG, "Accounts changed, but not removing stale data for " + 4489b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki DEBUG_PROPERTY_KEEP_STALE_ACCOUNT_DATA); 4490b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki return true; 4491b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki } 44929ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki Log.i(TAG, "Accounts changed"); 449335997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 449435997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 449535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 44969d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final ContactsDatabaseHelper dbHelper = mDbHelper.get(); 44979d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final SQLiteDatabase db = dbHelper.getWritableDatabase(); 44985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.set(db); 44995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.beginTransaction(); 45005dccfb059f5df0e9fdba026bcfbed677f44922cdDave Santoro 45015dccfb059f5df0e9fdba026bcfbed677f44922cdDave Santoro // WARNING: This method can be run in either contacts mode or profile mode. It is 45025dccfb059f5df0e9fdba026bcfbed677f44922cdDave Santoro // absolutely imperative that no calls be made inside the following try block that can 45035dccfb059f5df0e9fdba026bcfbed677f44922cdDave Santoro // interact with the contacts DB. Otherwise it is quite possible for a deadlock to occur. 450470d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong try { 45059d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // First, remove stale rows from raw_contacts, groups, and related tables. 45069d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 45079d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // All accounts that are used in raw_contacts and/or groups. 45089d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final Set<AccountWithDataSet> knownAccountsWithDataSets 45099d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki = dbHelper.getAllAccountsWithDataSets(); 451048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 45119d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // Find the accounts that have been removed. 45129d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final List<AccountWithDataSet> accountsWithDataSetsToDelete = Lists.newArrayList(); 45139d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki for (AccountWithDataSet knownAccountWithDataSet : knownAccountsWithDataSets) { 45149d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (knownAccountWithDataSet.isLocalAccount() 45159d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki || knownAccountWithDataSet.inSystemAccounts(systemAccounts)) { 45169d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki continue; 451743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 45189d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki accountsWithDataSetsToDelete.add(knownAccountWithDataSet); 451970d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 452070d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong 452143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (!accountsWithDataSetsToDelete.isEmpty()) { 452243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro for (AccountWithDataSet accountWithDataSet : accountsWithDataSetsToDelete) { 452343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Log.d(TAG, "removing data for removed account " + accountWithDataSet); 45249d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final Long accountIdOrNull = dbHelper.getAccountIdOrNull(accountWithDataSet); 45259d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 45269d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // getAccountIdOrNull() really shouldn't return null here, but just in case... 45279d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (accountIdOrNull != null) { 45289d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final String[] accountIdParams = 45299d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki new String[] {Long.toString(accountIdOrNull)}; 45309d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki db.execSQL( 45319d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "DELETE FROM " + Tables.GROUPS + 45329d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " WHERE " + GroupsColumns.ACCOUNT_ID + " = ?", 45339d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki accountIdParams); 45349d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki db.execSQL( 45359d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "DELETE FROM " + Tables.PRESENCE + 45369d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " WHERE " + PresenceColumns.RAW_CONTACT_ID + " IN (" + 45379d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "SELECT " + RawContacts._ID + 45389d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " FROM " + Tables.RAW_CONTACTS + 45399d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " WHERE " + RawContactsColumns.ACCOUNT_ID + " = ?)", 45409d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki accountIdParams); 45419d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki db.execSQL( 45429d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "DELETE FROM " + Tables.STREAM_ITEM_PHOTOS + 45439d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " WHERE " + StreamItemPhotos.STREAM_ITEM_ID + " IN (" + 45449d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "SELECT " + StreamItems._ID + 45459d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " FROM " + Tables.STREAM_ITEMS + 45469d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " WHERE " + StreamItems.RAW_CONTACT_ID + " IN (" + 45479d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "SELECT " + RawContacts._ID + 45489d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " FROM " + Tables.RAW_CONTACTS + 45499d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " WHERE " + RawContactsColumns.ACCOUNT_ID + "=?))", 45509d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki accountIdParams); 45519d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki db.execSQL( 45529d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "DELETE FROM " + Tables.STREAM_ITEMS + 45539d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " WHERE " + StreamItems.RAW_CONTACT_ID + " IN (" + 45549d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "SELECT " + RawContacts._ID + 45559d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " FROM " + Tables.RAW_CONTACTS + 45569d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " WHERE " + RawContactsColumns.ACCOUNT_ID + " = ?)", 45579d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki accountIdParams); 45589d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki db.execSQL( 45599d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "DELETE FROM " + Tables.RAW_CONTACTS + 45609d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " WHERE " + RawContactsColumns.ACCOUNT_ID + " = ?", 45619d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki accountIdParams); 45629d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki db.execSQL( 45639d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "DELETE FROM " + Tables.ACCOUNTS + 45649d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " WHERE " + AccountsColumns._ID + "=?", 45659d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki accountIdParams); 45669d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 4567e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov } 4568e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov 456933fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov // Find all aggregated contacts that used to contain the raw contacts 457033fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov // we have just deleted and see if they are still referencing the deleted 4571e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov // names or photos. If so, fix up those contacts. 457233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov HashSet<Long> orphanContactIds = Sets.newHashSet(); 45735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor cursor = db.rawQuery("SELECT " + Contacts._ID + 457433fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " FROM " + Tables.CONTACTS + 457533fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " WHERE (" + Contacts.NAME_RAW_CONTACT_ID + " NOT NULL AND " + 457669cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov Contacts.NAME_RAW_CONTACT_ID + " NOT IN " + 457769cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov "(SELECT " + RawContacts._ID + 457869cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + "))" + 457933fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " OR (" + Contacts.PHOTO_ID + " NOT NULL AND " + 458033fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov Contacts.PHOTO_ID + " NOT IN " + 458169cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov "(SELECT " + Data._ID + 458269cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov " FROM " + Tables.DATA + "))", null); 458333fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov try { 458433fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov while (cursor.moveToNext()) { 458533fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov orphanContactIds.add(cursor.getLong(0)); 458633fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 458733fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } finally { 458833fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov cursor.close(); 458933fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 459033fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov 459133fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov for (Long contactId : orphanContactIds) { 45925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().updateAggregateData(mTransactionContext.get(), contactId); 459333fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 45949d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki dbHelper.updateAllVisible(); 45955dccfb059f5df0e9fdba026bcfbed677f44922cdDave Santoro 45965dccfb059f5df0e9fdba026bcfbed677f44922cdDave Santoro // Don't bother updating the search index if we're in profile mode - there is no 45975dccfb059f5df0e9fdba026bcfbed677f44922cdDave Santoro // search index for the profile DB, and updating it for the contacts DB in this case 45985dccfb059f5df0e9fdba026bcfbed677f44922cdDave Santoro // makes no sense and risks a deadlock. 45995dccfb059f5df0e9fdba026bcfbed677f44922cdDave Santoro if (!inProfileMode()) { 46009ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // TODO Fix it. It only updates index for contacts/raw_contacts that the 46019ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // current transaction context knows updated, but here in this method we don't 46029ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // update that information, so effectively it's no-op. 46039ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // We can probably just schedule BACKGROUND_TASK_UPDATE_SEARCH_INDEX. 46049ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // (But make sure it's not scheduled yet. We schedule this task in initialize() 46059ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // too.) 46065dccfb059f5df0e9fdba026bcfbed677f44922cdDave Santoro updateSearchIndexInTransaction(); 46075dccfb059f5df0e9fdba026bcfbed677f44922cdDave Santoro } 460833fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 460933fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov 46109d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // Second, remove stale rows from Tables.SETTINGS and Tables.DIRECTORIES 46119d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki removeStaleAccountRows(Tables.SETTINGS, Settings.ACCOUNT_NAME, Settings.ACCOUNT_TYPE, 46129d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki systemAccounts); 46139d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki removeStaleAccountRows(Tables.DIRECTORIES, Directory.ACCOUNT_NAME, 46149d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki Directory.ACCOUNT_TYPE, systemAccounts); 461543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 46169d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // Third, remaining tasks that must be done in a transaction. 46179d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // TODO: Should sync state take data set into consideration? 46189d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki dbHelper.getSyncState().onAccountsChanged(db, systemAccounts); 46199ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki 46209ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki saveAccounts(systemAccounts); 462143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 46225d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.setTransactionSuccessful(); 462370d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } finally { 46245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.endTransaction(); 462570d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 462673f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov mAccountWritability.clear(); 46273826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 46289d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki updateContactsAccountCount(systemAccounts); 46299d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki updateProviderStatus(); 46309d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki return true; 463170d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 4632619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 46333826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private void updateContactsAccountCount(Account[] accounts) { 46343826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov int count = 0; 46353826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov for (Account account : accounts) { 46363826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (isContactsAccount(account)) { 46373826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov count++; 46383826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 46393826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 46403826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mContactsAccountCount = count; 46413826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 46423826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 46433826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov protected boolean isContactsAccount(Account account) { 46443826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov final IContentService cs = ContentResolver.getContentService(); 46453826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov try { 46463826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return cs.getIsSyncable(account, ContactsContract.AUTHORITY) > 0; 46473826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } catch (RemoteException e) { 46483826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov Log.e(TAG, "Cannot obtain sync flag for account: " + account, e); 46493826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return false; 46503826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 46513826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 46523826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 465372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov public void onPackageChanged(String packageName) { 4654bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_DIRECTORIES, packageName); 4655d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4656d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 46579d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki public void removeStaleAccountRows(String table, String accountNameColumn, 46589d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki String accountTypeColumn, Account[] systemAccounts) { 46599d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 46609d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final Cursor c = db.rawQuery( 46619d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "SELECT DISTINCT " + accountNameColumn + 46629d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "," + accountTypeColumn + 466343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " FROM " + table, null); 4664627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov try { 46659d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki c.moveToPosition(-1); 4666627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov while (c.moveToNext()) { 46679d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final AccountWithDataSet accountWithDataSet = AccountWithDataSet.get( 46689d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki c.getString(0), c.getString(1), null); 46699d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (accountWithDataSet.isLocalAccount() 46709d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki || accountWithDataSet.inSystemAccounts(systemAccounts)) { 46719d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // Account still exists. 46729d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki continue; 4673627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 46749d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 46759d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki db.execSQL("DELETE FROM " + table + 46769d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " WHERE " + accountNameColumn + "=? AND " + 46779d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki accountTypeColumn + "=?", 46789d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki new String[] {accountWithDataSet.getAccountName(), 46799d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki accountWithDataSet.getAccountType()}); 4680627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4681627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } finally { 4682627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov c.close(); 4683627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4684627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4685627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov 46864f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 46874f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 46884f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton String sortOrder) { 468915826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann return query(uri, projection, selection, selectionArgs, sortOrder, null); 469015826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann } 469115826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann 469215826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann @Override 469315826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 46947898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown String sortOrder, CancellationSignal cancellationSignal) { 469547ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki if (VERBOSE_LOGGING) { 469647ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki Log.v(TAG, "query uri=" + uri + " selection=" + selection + " order=" + sortOrder); 469747ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki } 469815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 469915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mReadAccessLatch); 470015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 470136612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro // Enforce stream items access check if applicable. 470236612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro enforceSocialStreamReadPermission(uri); 470336612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 47045d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Query the profile DB if appropriate. 47055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mapsToProfileDb(uri)) { 47065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToProfileMode(); 470715826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann return mProfileProvider.query(uri, projection, selection, selectionArgs, sortOrder, 47087898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown cancellationSignal); 47095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 47105d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 47115d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Otherwise proceed with a normal query against the contacts DB. 47125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 47135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.set(mContactsHelper.getReadableDatabase()); 4714d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String directory = getQueryParameter(uri, ContactsContract.DIRECTORY_PARAM_KEY); 4715385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov if (directory == null) { 4716b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return addSnippetExtrasToCursor(uri, 471715826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann queryLocal(uri, projection, selection, selectionArgs, sortOrder, -1, 47187898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown cancellationSignal)); 4719385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } else if (directory.equals("0")) { 4720b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return addSnippetExtrasToCursor(uri, 47213716f1447ceb21180d1301790eabd8b9453f486dDave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, 47227898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown Directory.DEFAULT, cancellationSignal)); 4723d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } else if (directory.equals("1")) { 4724b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return addSnippetExtrasToCursor(uri, 47253716f1447ceb21180d1301790eabd8b9453f486dDave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, 47267898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown Directory.LOCAL_INVISIBLE, cancellationSignal)); 4727d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4728d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4729d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov DirectoryInfo directoryInfo = getDirectoryAuthority(directory); 4730d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo == null) { 4731a85745ab25f9ab8fd6fd29e174bf2fac5492e448Dmitri Plotnikov Log.e(TAG, "Invalid directory ID: " + uri); 4732a85745ab25f9ab8fd6fd29e174bf2fac5492e448Dmitri Plotnikov return null; 4733d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4734d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4735d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Builder builder = new Uri.Builder(); 4736d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.scheme(ContentResolver.SCHEME_CONTENT); 4737d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.authority(directoryInfo.authority); 4738d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.encodedPath(uri.getEncodedPath()); 4739d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo.accountName != null) { 4740d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, directoryInfo.accountName); 4741d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4742d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo.accountType != null) { 4743d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, directoryInfo.accountType); 4744d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 47452e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov 47462e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov String limit = getLimit(uri); 47472e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov if (limit != null) { 47482e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, limit); 47492e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov } 47502e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov 4751d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Uri directoryUri = builder.build(); 475209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 475309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov if (projection == null) { 475409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov projection = getDefaultProjection(uri); 475509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 475609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 4757332321f2832d52f50b9f8fc1f4006459000a4b21Dmitri Plotnikov Cursor cursor = getContext().getContentResolver().query(directoryUri, projection, selection, 4758d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov selectionArgs, sortOrder); 47596ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 47606ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov if (cursor == null) { 47616ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return null; 47626ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 47636ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 4764b6b22df3a64a80531d58f9cd60f2872fc2af92d1Dave Santoro // Load the cursor contents into a memory cursor (backed by a cursor window) and close the 4765b6b22df3a64a80531d58f9cd60f2872fc2af92d1Dave Santoro // underlying cursor. 4766b6b22df3a64a80531d58f9cd60f2872fc2af92d1Dave Santoro try { 4767b6b22df3a64a80531d58f9cd60f2872fc2af92d1Dave Santoro MemoryCursor memCursor = new MemoryCursor(null, cursor.getColumnNames()); 4768b6b22df3a64a80531d58f9cd60f2872fc2af92d1Dave Santoro memCursor.fillFromCursor(cursor); 4769b6b22df3a64a80531d58f9cd60f2872fc2af92d1Dave Santoro return memCursor; 4770b6b22df3a64a80531d58f9cd60f2872fc2af92d1Dave Santoro } finally { 4771b6b22df3a64a80531d58f9cd60f2872fc2af92d1Dave Santoro cursor.close(); 4772547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } 47733716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 47743716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 4775b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson private Cursor addSnippetExtrasToCursor(Uri uri, Cursor cursor) { 4776547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro 4777547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro // If the cursor doesn't contain a snippet column, don't bother wrapping it. 4778547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro if (cursor.getColumnIndex(SearchSnippetColumns.SNIPPET) < 0) { 4779b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return cursor; 4780547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } 4781547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro 47823716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String query = uri.getLastPathSegment(); 47833716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 4784b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson // Snippet data is needed for the snippeting on the client side, so store it in the cursor 4785b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson if (cursor instanceof AbstractCursor && deferredSnippetingRequested(uri)){ 4786b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson Bundle oldExtras = cursor.getExtras(); 4787b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson Bundle extras = new Bundle(); 4788b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson if (oldExtras != null) { 4789b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson extras.putAll(oldExtras); 4790b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 4791b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson extras.putString(ContactsContract.DEFERRED_SNIPPETING_QUERY, query); 4792b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson 4793b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson ((AbstractCursor) cursor).setExtras(extras); 47945517770250b3afa4fd88b6869c3244680821d222Dave Santoro } 4795b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return cursor; 4796b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 4797b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson 4798b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson private Cursor addDeferredSnippetingExtra(Cursor cursor) { 4799b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson if (cursor instanceof AbstractCursor){ 4800b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson Bundle oldExtras = cursor.getExtras(); 4801b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson Bundle extras = new Bundle(); 4802b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson if (oldExtras != null) { 4803b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson extras.putAll(oldExtras); 4804b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 4805b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson extras.putBoolean(ContactsContract.DEFERRED_SNIPPETING, true); 4806b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson ((AbstractCursor) cursor).setExtras(extras); 4807b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 4808b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return cursor; 48096ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 48106ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 4811d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final class DirectoryQuery { 4812d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final String[] COLUMNS = new String[] { 4813d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory._ID, 4814d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.DIRECTORY_AUTHORITY, 4815d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.ACCOUNT_NAME, 4816d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.ACCOUNT_TYPE 4817d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov }; 4818d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4819d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int DIRECTORY_ID = 0; 4820d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int AUTHORITY = 1; 4821d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int ACCOUNT_NAME = 2; 4822d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int ACCOUNT_TYPE = 3; 4823d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4824d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4825d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** 4826d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov * Reads and caches directory information for the database. 4827d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov */ 4828d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private DirectoryInfo getDirectoryAuthority(String directoryId) { 48294458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov synchronized (mDirectoryCache) { 48304458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov if (!mDirectoryCacheValid) { 48314458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCache.clear(); 48325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro SQLiteDatabase db = mDbHelper.get().getReadableDatabase(); 483349d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov Cursor cursor = db.query(Tables.DIRECTORIES, 48344458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov DirectoryQuery.COLUMNS, 48354458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov null, null, null, null, null); 48364458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov try { 48374458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov while (cursor.moveToNext()) { 48384458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov DirectoryInfo info = new DirectoryInfo(); 48394458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov String id = cursor.getString(DirectoryQuery.DIRECTORY_ID); 48404458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.authority = cursor.getString(DirectoryQuery.AUTHORITY); 48414458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.accountName = cursor.getString(DirectoryQuery.ACCOUNT_NAME); 48424458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.accountType = cursor.getString(DirectoryQuery.ACCOUNT_TYPE); 48434458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCache.put(id, info); 48444458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 48454458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } finally { 48464458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov cursor.close(); 4847d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 48484458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCacheValid = true; 4849d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4850d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 48514458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov return mDirectoryCache.get(directoryId); 48524458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 4853d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4854d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 485572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov public void resetDirectoryCache() { 48564458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov synchronized(mDirectoryCache) { 48574458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCacheValid = false; 48584458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 485972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov } 486072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 486135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki protected Cursor queryLocal(final Uri uri, final String[] projection, String selection, 486235997f3fdee2984b6d5373326110eda26929001aMakoto Onuki String[] selectionArgs, String sortOrder, final long directoryId, 486335997f3fdee2984b6d5373326110eda26929001aMakoto Onuki final CancellationSignal cancellationSignal) { 48640b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov 48655d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Default active DB to the contacts DB if none has been set. 48665d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mActiveDb.get() == null) { 4867078f588cef389358adabc579de00747878f3c108Dave Santoro mActiveDb.set(mContactsHelper.getReadableDatabase()); 48685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 486935ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 4870d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 48711f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey String groupBy = null; 4872c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov String limit = getLimit(uri); 4873b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson boolean snippetDeferred = false; 4874c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 48752ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki // The expression used in bundleLetterCountExtras() to get count. 48762ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki String addressBookIndexerCountExpression = null; 48772ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki 4878a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 48794f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 488035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 48815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE: 48825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mDbHelper.get().getSyncState().query(mActiveDb.get(), projection, selection, 48835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs, sortOrder); 488435ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 4885d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 4886763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 48879ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki appendLocalDirectoryAndAccountSelectionIfNeeded(qb, directoryId, uri); 4888619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey break; 4889619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 4890619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 4891d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 48924a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 4893763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 48944da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 48954da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 48966bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 48976bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 48986bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 48995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov case CONTACTS_LOOKUP: 49005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov case CONTACTS_LOOKUP_ID: { 49015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 49025870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int segmentCount = pathSegments.size(); 49035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segmentCount < 3) { 49045d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 4905fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 49065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 4907a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 49085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String lookupKey = pathSegments.get(2); 49095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segmentCount == 4) { 49105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 49115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 4912763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(lookupQb, uri, projection); 4913a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 49145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = queryWithContactIdAndLookupKey(lookupQb, mActiveDb.get(), uri, 4915a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 491615826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann Contacts._ID, contactId, Contacts.LOOKUP_KEY, lookupKey, 49177898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown cancellationSignal); 4918a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 49195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return c; 49205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 49215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 49225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 4923763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 49244da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 49255d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String.valueOf(lookupContactIdByLookupKey(mActiveDb.get(), lookupKey))); 49264da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 49275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 49285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 49295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 49302149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov case CONTACTS_LOOKUP_DATA: 4931bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro case CONTACTS_LOOKUP_ID_DATA: 4932bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro case CONTACTS_LOOKUP_PHOTO: 4933bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro case CONTACTS_LOOKUP_ID_PHOTO: { 49342149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 49352149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov int segmentCount = pathSegments.size(); 49362149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov if (segmentCount < 4) { 49375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 49382149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov "Missing a lookup key", uri)); 49392149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 49402149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov String lookupKey = pathSegments.get(2); 49412149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov if (segmentCount == 5) { 49422149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 49432149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 49442149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov setTablesAndProjectionMapForData(lookupQb, uri, projection, false); 4945bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro if (match == CONTACTS_LOOKUP_PHOTO || match == CONTACTS_LOOKUP_ID_PHOTO) { 4946cde9e5e83f7c3a6bf341f9f2fa2359a1ed127f95Daniel Lehmann lookupQb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID); 4947bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro } 4948a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(" AND "); 49495d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = queryWithContactIdAndLookupKey(lookupQb, mActiveDb.get(), uri, 4950a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 495115826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann Data.CONTACT_ID, contactId, Data.LOOKUP_KEY, lookupKey, 49527898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown cancellationSignal); 4953a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 49542149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov return c; 49552149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 49562149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 49572149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov // TODO see if the contact exists but has no data rows (rare) 49582149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 49592149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 49602149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 49615d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long contactId = lookupContactIdByLookupKey(mActiveDb.get(), lookupKey); 49622149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 496324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String.valueOf(contactId)); 4964bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro if (match == CONTACTS_LOOKUP_PHOTO || match == CONTACTS_LOOKUP_ID_PHOTO) { 4965bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro qb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID); 4966bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro } 49672149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov qb.appendWhere(" AND " + Data.CONTACT_ID + "=?"); 49682149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov break; 49692149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 49702149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 49713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_ID_STREAM_ITEMS: { 49723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = Long.parseLong(uri.getPathSegments().get(1)); 49733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 49743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 4975af10329f85c5d8c4196c495a9f0f9a6c6ecbc231Daniel Lehmann qb.appendWhere(StreamItems.CONTACT_ID + "=?"); 49763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 49773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 49783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 49793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_LOOKUP_STREAM_ITEMS: 49803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_LOOKUP_ID_STREAM_ITEMS: { 49813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<String> pathSegments = uri.getPathSegments(); 49823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann int segmentCount = pathSegments.size(); 49833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (segmentCount < 4) { 49845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 49853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann "Missing a lookup key", uri)); 49863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 49873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String lookupKey = pathSegments.get(2); 49883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (segmentCount == 5) { 49893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = Long.parseLong(pathSegments.get(3)); 49903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 49913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(lookupQb); 49925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = queryWithContactIdAndLookupKey(lookupQb, mActiveDb.get(), uri, 49933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann projection, selection, selectionArgs, sortOrder, groupBy, limit, 4994af10329f85c5d8c4196c495a9f0f9a6c6ecbc231Daniel Lehmann StreamItems.CONTACT_ID, contactId, 499515826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann StreamItems.CONTACT_LOOKUP_KEY, lookupKey, 49967898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown cancellationSignal); 49973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (c != null) { 49983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return c; 49993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 50003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 50013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 50023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 50035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long contactId = lookupContactIdByLookupKey(mActiveDb.get(), lookupKey); 50043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 50053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(RawContacts.CONTACT_ID + "=?"); 50063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 50073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 50083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 5009f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey case CONTACTS_AS_VCARD: { 501042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String lookupKey = Uri.encode(uri.getPathSegments().get(2)); 50115d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long contactId = lookupContactIdByLookupKey(mActiveDb.get(), lookupKey); 5012ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 5013f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey qb.setProjectionMap(sContactsVCardProjectionMap); 50144da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 501524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String.valueOf(contactId)); 50164da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 5017f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey break; 5018f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey } 5019f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey 502042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: { 502142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss"); 502242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann String currentDateString = dateFormat.format(new Date()).toString(); 50235d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mActiveDb.get().rawQuery( 502442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann "SELECT" + 502542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann " 'vcards_' || ? || '.vcf' AS " + OpenableColumns.DISPLAY_NAME + "," + 502642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann " NULL AS " + OpenableColumns.SIZE, 502742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann new String[] { currentDateString }); 502842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 502942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 5030ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_FILTER: { 5031916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov String filterParam = ""; 5032b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson boolean deferredSnipRequested = deferredSnippetingRequested(uri); 5033ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 5034916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov filterParam = uri.getLastPathSegment(); 5035ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5036fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki 5037fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki // If the query consists of a single word, we can do snippetizing after-the-fact for 5038fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki // a performance boost. Otherwise, we can't defer. 5039fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki snippetDeferred = isSingleWordQuery(filterParam) 5040fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki && deferredSnipRequested && snippetNeeded(projection); 50417ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov setTablesAndProjectionMapForContactsWithSnippet( 5042b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson qb, uri, projection, filterParam, directoryId, 5043fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki snippetDeferred); 5044ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 5045ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5046ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 5047ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_STREQUENT_FILTER: 5048ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_STREQUENT: { 50492f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Basically the resultant SQL should look like this: 50502f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // (SQL for listing starred items) 50512f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // UNION ALL 50522f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // (SQL for listing frequently contacted items) 50532f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // ORDER BY ... 50542f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 50552f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final boolean phoneOnly = readBooleanQueryParameter( 50562f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa uri, ContactsContract.STREQUENT_PHONE_ONLY, false); 50572f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (match == CONTACTS_STREQUENT_FILTER && uri.getPathSegments().size() > 3) { 50584a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov String filterParam = uri.getLastPathSegment(); 50594a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 5060e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov sb.append(Contacts._ID + " IN "); 50615e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov appendContactFilterAsNestedQuery(sb, filterParam); 50622f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa selection = DbQueryUtils.concatenateClauses(selection, sb.toString()); 50634a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 50644a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 50652f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa String[] subProjection = null; 50665e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar if (projection != null) { 50672f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa subProjection = appendProjectionArg(projection, TIMES_USED_SORT_COLUMN); 50685e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 50695e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 50704a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov // Build the first query for starred 50714928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, false); 50724928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(phoneOnly ? 50734928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa sStrequentPhoneOnlyStarredProjectionMap 50744928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa : sStrequentStarredProjectionMap); 50759dbfd650ccf93714f3266e80f9fbdbcb526ae7b3Daisuke Miyakawa if (phoneOnly) { 50765d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro qb.appendWhere(DbQueryUtils.concatenateClauses( 50775d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selection, Contacts.HAS_PHONE_NUMBER + "=1")); 50789dbfd650ccf93714f3266e80f9fbdbcb526ae7b3Daisuke Miyakawa } 50792f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.setStrict(true); 508072c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann final String starredInnerQuery = qb.buildQuery(subProjection, 508172c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann Contacts.STARRED + "=1", Contacts._ID, null, 508272c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC", null); 5083d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 50842f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Reset the builder. 5085d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb = new SQLiteQueryBuilder(); 50862f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.setStrict(true); 50874928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 508872c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann // Build the second query for frequent part. These JOINS can be very slow 508972c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann // if assembled in the wrong order. Be sure to test changes against huge databases. 509072c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann final String frequentInnerQuery; 50914928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa if (phoneOnly) { 50924928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa final StringBuilder tableBuilder = new StringBuilder(); 50934928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // In phone only mode, we need to look at view_data instead of 50944928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // contacts/raw_contacts to obtain actual phone numbers. One problem is that 50954928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // view_data is much larger than view_contacts, so our query might become much 50964928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // slower. 50974928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // 50984928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // To avoid the possible slow down, we start from data usage table and join 50994928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // view_data to the table, assuming data usage table is quite smaller than 51004928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // data rows (almost always it should be), and we don't want any phone 51014928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // numbers not used by the user. This way sqlite is able to drop a number of 51024928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // rows in view_data in the early stage of data lookup. 51034928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa tableBuilder.append(Tables.DATA_USAGE_STAT 51044928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + " INNER JOIN " + Views.DATA + " " + Tables.DATA 51054928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + " ON (" + DataUsageStatColumns.CONCRETE_DATA_ID + "=" 51064928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataColumns.CONCRETE_ID + " AND " 51074928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataUsageStatColumns.CONCRETE_USAGE_TYPE + "=" 51084928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataUsageStatColumns.USAGE_TYPE_INT_CALL + ")"); 51094928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa appendContactPresenceJoin(tableBuilder, projection, RawContacts.CONTACT_ID); 51104928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa appendContactStatusUpdateJoin(tableBuilder, projection, 51114928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa ContactsColumns.LAST_STATUS_UPDATE_ID); 51124928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 51134928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setTables(tableBuilder.toString()); 51144928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(sStrequentPhoneOnlyFrequentProjectionMap); 511572c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann final long phoneMimeTypeId = 511672c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann mDbHelper.get().getMimeTypeId(Phone.CONTENT_ITEM_TYPE); 511772c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann final long sipMimeTypeId = 511872c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann mDbHelper.get().getMimeTypeId(SipAddress.CONTENT_ITEM_TYPE); 51194928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 51204928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa selection, 5121db0e85645ffe5a79500b31390149507ac432a2d9Makoto Onuki "(" + Contacts.STARRED + "=0 OR " + Contacts.STARRED + " IS NULL", 512272c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann DataColumns.MIMETYPE_ID + " IN (" + 5123db0e85645ffe5a79500b31390149507ac432a2d9Makoto Onuki phoneMimeTypeId + ", " + sipMimeTypeId + ")) AND (" + 5124db0e85645ffe5a79500b31390149507ac432a2d9Makoto Onuki RawContacts.CONTACT_ID + " IN " + Tables.DEFAULT_DIRECTORY + ")")); 512572c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann frequentInnerQuery = 512672c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann qb.buildQuery(subProjection, null, null, null, 512772c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann TIMES_USED_SORT_COLUMN + " DESC", "25"); 51284928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa } else { 51294928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, true); 51304928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(sStrequentFrequentProjectionMap); 51314928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 51324928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa selection, 51335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro "(" + Contacts.STARRED + " =0 OR " + Contacts.STARRED + " IS NULL)")); 5134db0e85645ffe5a79500b31390149507ac432a2d9Makoto Onuki // Note frequentInnerQuery is a grouping query, so the "IN default_directory" 5135db0e85645ffe5a79500b31390149507ac432a2d9Makoto Onuki // selection needs to be in HAVING, not in WHERE. 5136db0e85645ffe5a79500b31390149507ac432a2d9Makoto Onuki final String HAVING = 5137db0e85645ffe5a79500b31390149507ac432a2d9Makoto Onuki RawContacts.CONTACT_ID + " IN " + Tables.DEFAULT_DIRECTORY; 513872c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann frequentInnerQuery = qb.buildQuery(subProjection, 5139db0e85645ffe5a79500b31390149507ac432a2d9Makoto Onuki null, Contacts._ID, HAVING, null, "25"); 51404928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa } 5141d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 514272c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann // We need to wrap the inner queries in an extra select, because they contain 514372c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann // their own SORT and LIMIT 514472c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann final String frequentQuery = "SELECT * FROM (" + frequentInnerQuery + ")"; 514572c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann final String starredQuery = "SELECT * FROM (" + starredInnerQuery + ")"; 514672c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann 5147d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar // Put them together 51482f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final String unionQuery = 514972c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann qb.buildUnionQuery(new String[] {starredQuery, frequentQuery}, null, null); 51502f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 51512f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Here, we need to use selection / selectionArgs (supplied from users) "twice", 51522f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // as we want them both for starred items and for frequently contacted items. 51532f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // 51542f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // e.g. if the user specify selection = "starred =?" and selectionArgs = "0", 51552f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // the resultant SQL should be like: 51562f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // SELECT ... WHERE starred =? AND ... 51572f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // UNION ALL 51582f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // SELECT ... WHERE starred =? AND ... 51592f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa String[] doubledSelectionArgs = null; 51602f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (selectionArgs != null) { 51612f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final int length = selectionArgs.length; 51622f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa doubledSelectionArgs = new String[length * 2]; 51637d7d0e95636344c01eb4e4d034791c199bee98e9Daisuke Miyakawa System.arraycopy(selectionArgs, 0, doubledSelectionArgs, 0, length); 51647d7d0e95636344c01eb4e4d034791c199bee98e9Daisuke Miyakawa System.arraycopy(selectionArgs, 0, doubledSelectionArgs, length, length); 51652f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 51662f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 51675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor cursor = mActiveDb.get().rawQuery(unionQuery, doubledSelectionArgs); 51682f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (cursor != null) { 51692f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa cursor.setNotificationUri(getContext().getContentResolver(), 5170d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar ContactsContract.AUTHORITY_URI); 5171d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 51722f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa return cursor; 5173d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 5174d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 517545ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa case CONTACTS_FREQUENT: { 517645ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, true); 517745ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa qb.setProjectionMap(sStrequentFrequentProjectionMap); 517845ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa groupBy = Contacts._ID; 517945ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa if (!TextUtils.isEmpty(sortOrder)) { 518045ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa sortOrder = FREQUENT_ORDER_BY + ", " + sortOrder; 518145ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } else { 518245ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa sortOrder = FREQUENT_ORDER_BY; 518345ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } 518445ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa break; 518545ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } 518645ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa 5187ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_GROUP: { 5188763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 5189b67163a1088f09c59f324350662eb18772fac6b6Evan Millar if (uri.getPathSegments().size() > 2) { 519071e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov qb.appendWhere(CONTACTS_IN_GROUP_SELECT); 51917cf50494501938f175d288077145acf49da8f171Daniel Lehmann String groupMimeTypeId = String.valueOf( 51927cf50494501938f175d288077145acf49da8f171Daniel Lehmann mDbHelper.get().getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)); 51934a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 51947cf50494501938f175d288077145acf49da8f171Daniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, groupMimeTypeId); 5195b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 5196b67163a1088f09c59f324350662eb18772fac6b6Evan Millar break; 5197b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 5198b67163a1088f09c59f324350662eb18772fac6b6Evan Millar 519924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 520024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForContacts(qb, uri, projection); 520124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 520224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 520324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 520424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_ENTITIES: { 520524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForEntities(qb, uri, projection); 520624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 520724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 520824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 520924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: { 5210ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 521124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.setProjectionMap(sContactsVCardProjectionMap); 521224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 521324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 521424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 5215a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_DATA: { 52164a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 521782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 52184da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 52194da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 52206bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 52216bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 522200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 5223a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_PHOTO: { 52243653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 522582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 52264da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 52274da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 52283653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID); 52293653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov break; 52303653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov } 52313653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov 5232a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_ENTITIES: { 5233a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 5234a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(qb, uri, projection); 5235a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 5236a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 5237a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov break; 5238a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5239a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 5240a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_LOOKUP_ENTITIES: 5241a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_LOOKUP_ID_ENTITIES: { 5242a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 5243a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov int segmentCount = pathSegments.size(); 5244a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (segmentCount < 4) { 52455d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 5246a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov "Missing a lookup key", uri)); 5247a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5248a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String lookupKey = pathSegments.get(2); 5249a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (segmentCount == 5) { 5250a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 5251a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 5252a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(lookupQb, uri, projection); 5253a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(" AND "); 5254a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 52555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = queryWithContactIdAndLookupKey(lookupQb, mActiveDb.get(), uri, 5256a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 5257a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.Entity.CONTACT_ID, contactId, 525815826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann Contacts.Entity.LOOKUP_KEY, lookupKey, 52597898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown cancellationSignal); 5260a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 5261a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return c; 5262a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5263a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5264a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 5265a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(qb, uri, projection); 5266a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 52675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String.valueOf(lookupContactIdByLookupKey(mActiveDb.get(), lookupKey))); 5268a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.appendWhere(" AND " + Contacts.Entity.CONTACT_ID + "=?"); 5269a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov break; 5270a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5271a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 52723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 52733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 52743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 52753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 52763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 52773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 52783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 52793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 52809b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann qb.appendWhere(StreamItems._ID + "=?"); 52813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 52823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 52833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 52843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_LIMIT: { 5285084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki return buildSingleRowResult(projection, new String[] {StreamItems.MAX_ITEMS}, 5286084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki new Object[] {MAX_STREAM_ITEMS_PER_RAW_CONTACT}); 52873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 52883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 52893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 52903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 52913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 52923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 52933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 52943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 52953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 52963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 52973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemId); 52983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=?"); 52993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 53003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 53013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 53023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 53033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 53043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 53053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 53063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemPhotoId); 53073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemId); 53083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=? AND " + 53093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=?"); 53103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 53113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 53123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 5313f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case PHOTO_DIMENSIONS: { 5314084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki return buildSingleRowResult(projection, 5315084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki new String[] {DisplayPhoto.DISPLAY_MAX_DIM, DisplayPhoto.THUMBNAIL_MAX_DIM}, 5316c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki new Object[] {getMaxDisplayPhotoDim(), getMaxThumbnailDim()}); 5317f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 5318f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 5319e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa case PHONES: 5320e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa case CALLABLES: { 5321e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa final String mimeTypeIsPhoneExpression = 5322e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa DataColumns.MIMETYPE_ID + "=" + mDbHelper.get().getMimeTypeIdForPhone(); 5323e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa final String mimeTypeIsSipExpression = 5324e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa DataColumns.MIMETYPE_ID + "=" + mDbHelper.get().getMimeTypeIdForSip(); 532582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 5326e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa if (match == CALLABLES) { 5327e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa qb.appendWhere(" AND ((" + mimeTypeIsPhoneExpression + 5328e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa ") OR (" + mimeTypeIsSipExpression + "))"); 5329e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa } else { 5330e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa qb.appendWhere(" AND " + mimeTypeIsPhoneExpression); 5331e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa } 53322ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki 53338ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa final boolean removeDuplicates = readBooleanQueryParameter( 53348ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa uri, ContactsContract.REMOVE_DUPLICATE_ENTRIES, false); 53358ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa if (removeDuplicates) { 53368ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa groupBy = RawContacts.CONTACT_ID + ", " + Data.DATA1; 53378ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa 53388ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa // In this case, because we dedupe phone numbers, the address book indexer needs 53398ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa // to take it into account too. (Otherwise headers will appear in wrong 53408ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa // positions.) 53418ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa // So use count(distinct pair(CONTACT_ID, PHONE NUMBER)) instead of count(*). 53428ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa // But because there's no such thing as pair() on sqlite, we use 53438ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa // CONTACT_ID || ',' || PHONE NUMBER instead. 53448ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa // This only slows down the query by 14% with 10,000 contacts. 53458ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa addressBookIndexerCountExpression = "DISTINCT " 53468ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa + RawContacts.CONTACT_ID + "||','||" + Data.DATA1; 53478ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa } 53482815f58f72f109790585931f601a63ddc02536a5Evan Millar break; 53492815f58f72f109790585931f601a63ddc02536a5Evan Millar } 53502815f58f72f109790585931f601a63ddc02536a5Evan Millar 5351e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa case PHONES_ID: 5352e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa case CALLABLES_ID: { 5353e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa final String mimeTypeIsPhoneExpression = 5354e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa DataColumns.MIMETYPE_ID + "=" + mDbHelper.get().getMimeTypeIdForPhone(); 5355e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa final String mimeTypeIsSipExpression = 5356e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa DataColumns.MIMETYPE_ID + "=" + mDbHelper.get().getMimeTypeIdForSip(); 535782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 53584da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 5359e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa if (match == CALLABLES_ID) { 5360e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa qb.appendWhere(" AND ((" + mimeTypeIsPhoneExpression + 5361e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa ") OR (" + mimeTypeIsSipExpression + "))"); 5362e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa } else { 5363e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa qb.appendWhere(" AND " + mimeTypeIsPhoneExpression); 5364e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa } 53654da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 536648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 536748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 536848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 5369e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa case PHONES_FILTER: 5370e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa case CALLABLES_FILTER: { 5371e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa final String mimeTypeIsPhoneExpression = 5372e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa DataColumns.MIMETYPE_ID + "=" + mDbHelper.get().getMimeTypeIdForPhone(); 5373e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa final String mimeTypeIsSipExpression = 5374e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa DataColumns.MIMETYPE_ID + "=" + mDbHelper.get().getMimeTypeIdForSip(); 5375e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa 537646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String typeParam = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 5377dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki final int typeInt = getDataUsageFeedbackType(typeParam, 5378dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki DataUsageStatColumns.USAGE_TYPE_INT_CALL); 537946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, true, typeInt); 5380e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa if (match == CALLABLES_FILTER) { 5381e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa qb.appendWhere(" AND ((" + mimeTypeIsPhoneExpression + 5382e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa ") OR (" + mimeTypeIsSipExpression + "))"); 5383e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa } else { 5384e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa qb.appendWhere(" AND " + mimeTypeIsPhoneExpression); 5385e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa } 5386e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa 5387ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 53884a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov String filterParam = uri.getLastPathSegment(); 53894a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 5390a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.append(" AND ("); 53915e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 539245d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov boolean hasCondition = false; 5393d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann final String ftsMatchQuery = SearchIndexManager.getFtsMatchQuery( 5394d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann filterParam, FtsQueryBuilder.UNSCOPED_NORMALIZING); 5395d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann if (ftsMatchQuery.length() > 0) { 5396155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(Data.RAW_CONTACT_ID + " IN " + 5397155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov "(SELECT " + RawContactsColumns.CONCRETE_ID + 5398155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.SEARCH_INDEX + 5399155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " JOIN " + Tables.RAW_CONTACTS + 5400155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " ON (" + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID 5401155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov + "=" + RawContactsColumns.CONCRETE_CONTACT_ID + ")" + 5402d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann " WHERE " + SearchIndexColumns.NAME + " MATCH '"); 5403d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann sb.append(ftsMatchQuery); 5404d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann sb.append("')"); 540545d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov hasCondition = true; 54065e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 54075e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 5408892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov String number = PhoneNumberUtils.normalizeNumber(filterParam); 5409892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov if (!TextUtils.isEmpty(number)) { 5410e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa if (hasCondition) { 54115e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(" OR "); 54125e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 54135e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(Data._ID + 5414892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov " IN (SELECT DISTINCT " + PhoneLookupColumns.DATA_ID 5415892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov + " FROM " + Tables.PHONE_LOOKUP 5416892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov + " WHERE " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 5417892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sb.append(number); 5418892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov sb.append("%')"); 541945d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov hasCondition = true; 542045d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov } 542145d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov 5422e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa if (!TextUtils.isEmpty(filterParam) && match == CALLABLES_FILTER) { 5423e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa // If the request is via Callable uri, Sip addresses matching the filter 5424e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa // parameter should be returned. 5425e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa if (hasCondition) { 5426e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa sb.append(" OR "); 5427e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa } 5428e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa sb.append("("); 5429e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa sb.append(mimeTypeIsSipExpression); 5430e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa sb.append(" AND ((" + Data.DATA1 + " LIKE "); 5431e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa DatabaseUtils.appendEscapedSQLString(sb, filterParam + '%'); 5432e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa sb.append(") OR (" + Data.DATA1 + " LIKE "); 5433e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa // Users may want SIP URIs starting from "sip:" 5434e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa DatabaseUtils.appendEscapedSQLString(sb, "sip:"+ filterParam + '%'); 5435e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa sb.append(")))"); 5436e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa hasCondition = true; 5437e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa } 5438e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa 543945d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov if (!hasCondition) { 544045d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov // If it is neither a phone number nor a name, the query should return 544145d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov // an empty cursor. Let's ensure that. 544245d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov sb.append("0"); 54435e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 54445e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(")"); 5445a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov qb.appendWhere(sb); 5446ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5447e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa if (match == CALLABLES_FILTER) { 5448e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa // If the row is for a phone number that has a normalized form, we should use 5449e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa // the normalized one as PHONES_FILTER does, while we shouldn't do that 5450e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa // if the row is for a sip address. 5451e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa String isPhoneAndHasNormalized = "(" 5452e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa + mimeTypeIsPhoneExpression + " AND " 5453fc42772538fc6f7e2e444cbe6b24e06a3fbf933dMakoto Onuki + Phone.NORMALIZED_NUMBER + " IS NOT NULL)"; 5454e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa groupBy = "(CASE WHEN " + isPhoneAndHasNormalized 5455fc42772538fc6f7e2e444cbe6b24e06a3fbf933dMakoto Onuki + " THEN " + Phone.NORMALIZED_NUMBER 5456fc42772538fc6f7e2e444cbe6b24e06a3fbf933dMakoto Onuki + " ELSE " + Phone.NUMBER + " END), " + RawContacts.CONTACT_ID; 5457e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa } else { 5458fc42772538fc6f7e2e444cbe6b24e06a3fbf933dMakoto Onuki groupBy = "(CASE WHEN " + Phone.NORMALIZED_NUMBER 5459fc42772538fc6f7e2e444cbe6b24e06a3fbf933dMakoto Onuki + " IS NOT NULL THEN " + Phone.NORMALIZED_NUMBER 546058567abca253f1efa2db5c39e17e42dca589e916Daisuke Miyakawa + " ELSE " + Phone.NUMBER + " END), " + RawContacts.CONTACT_ID; 5461e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa } 5462a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov if (sortOrder == null) { 546346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String accountPromotionSortOrder = getAccountPromotionSortOrder(uri); 546446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(accountPromotionSortOrder)) { 546546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = accountPromotionSortOrder + ", " + PHONE_FILTER_SORT_ORDER; 546646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 546746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = PHONE_FILTER_SORT_ORDER; 546846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 5469a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov } 5470ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 5471ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5472ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 54734a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov case EMAILS: { 547482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 54757cf50494501938f175d288077145acf49da8f171Daniel Lehmann qb.appendWhere(" AND " + DataColumns.MIMETYPE_ID + " = " 54767cf50494501938f175d288077145acf49da8f171Daniel Lehmann + mDbHelper.get().getMimeTypeIdForEmail()); 54778ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa 54788ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa final boolean removeDuplicates = readBooleanQueryParameter( 54798ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa uri, ContactsContract.REMOVE_DUPLICATE_ENTRIES, false); 54808ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa if (removeDuplicates) { 54818ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa groupBy = RawContacts.CONTACT_ID + ", " + Data.DATA1; 54828ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa 54838ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa // See PHONES for more detail. 54848ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa addressBookIndexerCountExpression = "DISTINCT " 54858ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa + RawContacts.CONTACT_ID + "||','||" + Data.DATA1; 54868ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa } 54874a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov break; 54884a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 54894a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 549048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: { 549182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 54924da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 54937cf50494501938f175d288077145acf49da8f171Daniel Lehmann qb.appendWhere(" AND " + DataColumns.MIMETYPE_ID + " = " 54947cf50494501938f175d288077145acf49da8f171Daniel Lehmann + mDbHelper.get().getMimeTypeIdForEmail() 54954da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov + " AND " + Data._ID + "=?"); 549648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 549748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 549848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 54995e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov case EMAILS_LOOKUP: { 550082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 55017cf50494501938f175d288077145acf49da8f171Daniel Lehmann qb.appendWhere(" AND " + DataColumns.MIMETYPE_ID + " = " 55027cf50494501938f175d288077145acf49da8f171Daniel Lehmann + mDbHelper.get().getMimeTypeIdForEmail()); 55034a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov if (uri.getPathSegments().size() > 2) { 550408768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov String email = uri.getLastPathSegment(); 55055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String address = mDbHelper.get().extractAddressFromEmailAddress(email); 550608768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, address); 550708768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov qb.appendWhere(" AND UPPER(" + Email.DATA + ")=UPPER(?)"); 55084a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 5509071d0e7bd3b2f3c9628dd655b09d147e668c3931Daniel Lehmann // unless told otherwise, we'll return visible before invisible contacts 5510071d0e7bd3b2f3c9628dd655b09d147e668c3931Daniel Lehmann if (sortOrder == null) { 5511071d0e7bd3b2f3c9628dd655b09d147e668c3931Daniel Lehmann sortOrder = "(" + RawContacts.CONTACT_ID + " IN " + 5512071d0e7bd3b2f3c9628dd655b09d147e668c3931Daniel Lehmann Tables.DEFAULT_DIRECTORY + ") DESC"; 5513071d0e7bd3b2f3c9628dd655b09d147e668c3931Daniel Lehmann } 5514ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 5515ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5516ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 55175e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov case EMAILS_FILTER: { 551846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String typeParam = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 5519dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki final int typeInt = getDataUsageFeedbackType(typeParam, 5520dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki DataUsageStatColumns.USAGE_TYPE_INT_LONG_TEXT); 552146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, true, typeInt); 552207ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov String filterParam = null; 55237d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa 552407ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (uri.getPathSegments().size() > 3) { 552507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov filterParam = uri.getLastPathSegment(); 552607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (TextUtils.isEmpty(filterParam)) { 552707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov filterParam = null; 552807ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } 552907ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } 55305e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 553107ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (filterParam == null) { 553207ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov // If the filter is unspecified, return nothing 553307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov qb.appendWhere(" AND 0"); 553407ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } else { 553507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov StringBuilder sb = new StringBuilder(); 553607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov sb.append(" AND " + Data._ID + " IN ("); 553707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov sb.append( 553807ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov "SELECT " + Data._ID + 553907ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov " FROM " + Tables.DATA + 55402a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov " WHERE " + DataColumns.MIMETYPE_ID + "="); 55415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro sb.append(mDbHelper.get().getMimeTypeIdForEmail()); 55422a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov sb.append(" AND " + Data.DATA1 + " LIKE "); 554307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, filterParam + '%'); 554420938cd6df602bf08c232b32fc047592c1561347Dmitri Plotnikov if (!filterParam.contains("@")) { 5545155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append( 5546155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " UNION SELECT " + Data._ID + 5547155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.DATA + 5548155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE +" + DataColumns.MIMETYPE_ID + "="); 55495d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro sb.append(mDbHelper.get().getMimeTypeIdForEmail()); 5550155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(" AND " + Data.RAW_CONTACT_ID + " IN " + 5551155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov "(SELECT " + RawContactsColumns.CONCRETE_ID + 5552155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.SEARCH_INDEX + 5553155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " JOIN " + Tables.RAW_CONTACTS + 5554155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " ON (" + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID 5555155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov + "=" + RawContactsColumns.CONCRETE_CONTACT_ID + ")" + 5556d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann " WHERE " + SearchIndexColumns.NAME + " MATCH '"); 5557d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann final String ftsMatchQuery = SearchIndexManager.getFtsMatchQuery( 5558d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann filterParam, FtsQueryBuilder.UNSCOPED_NORMALIZING); 5559d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann sb.append(ftsMatchQuery); 5560d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann sb.append("')"); 55615e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 55625e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(")"); 5563a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov qb.appendWhere(sb); 55645e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 55655e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov groupBy = Email.DATA + "," + RawContacts.CONTACT_ID; 5566a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov if (sortOrder == null) { 556746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String accountPromotionSortOrder = getAccountPromotionSortOrder(uri); 556846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(accountPromotionSortOrder)) { 556946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = accountPromotionSortOrder + ", " + EMAIL_FILTER_SORT_ORDER; 55707d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa } else { 55717d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa sortOrder = EMAIL_FILTER_SORT_ORDER; 55727d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa } 5573a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov } 55745e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov break; 55755e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 55765e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 5577ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case POSTALS: { 557882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 55797cf50494501938f175d288077145acf49da8f171Daniel Lehmann qb.appendWhere(" AND " + DataColumns.MIMETYPE_ID + " = " 55807cf50494501938f175d288077145acf49da8f171Daniel Lehmann + mDbHelper.get().getMimeTypeIdForStructuredPostal()); 55818ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa 55828ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa final boolean removeDuplicates = readBooleanQueryParameter( 55838ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa uri, ContactsContract.REMOVE_DUPLICATE_ENTRIES, false); 55848ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa if (removeDuplicates) { 55858ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa groupBy = RawContacts.CONTACT_ID + ", " + Data.DATA1; 55868ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa 55878ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa // See PHONES for more detail. 55888ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa addressBookIndexerCountExpression = "DISTINCT " 55898ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa + RawContacts.CONTACT_ID + "||','||" + Data.DATA1; 55908ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa } 5591ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 5592ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5593ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 559448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 559582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 55964da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 55977cf50494501938f175d288077145acf49da8f171Daniel Lehmann qb.appendWhere(" AND " + DataColumns.MIMETYPE_ID + " = " 55987cf50494501938f175d288077145acf49da8f171Daniel Lehmann + mDbHelper.get().getMimeTypeIdForStructuredPostal()); 55994da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 560048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 560148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 560248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 5603d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case RAW_CONTACTS: 5604d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS: { 5605763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForRawContacts(qb, uri); 56064f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 56074f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 56084f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 5609d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case RAW_CONTACTS_ID: 5610d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS_ID: { 56115ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov long rawContactId = ContentUris.parseId(uri); 5612763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForRawContacts(qb, uri); 56134da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 56144da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts._ID + "=?"); 56154f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 56164f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 56174f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 5618193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki case RAW_CONTACTS_ID_DATA: 5619d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS_ID_DATA: { 5620193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki int segment = match == RAW_CONTACTS_ID_DATA ? 1 : 2; 5621d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(segment)); 562282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 56234da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 56244da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data.RAW_CONTACT_ID + "=?"); 562524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 562624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 562724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 56283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case RAW_CONTACTS_ID_STREAM_ITEMS: { 56293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 56303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 56313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 56323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItems.RAW_CONTACT_ID + "=?"); 56333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 56343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 563524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 563682780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro case RAW_CONTACTS_ID_STREAM_ITEMS_ID: { 563782780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 563882780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro long streamItemId = Long.parseLong(uri.getPathSegments().get(3)); 563982780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro setTablesAndProjectionMapForStreamItems(qb); 564082780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(streamItemId)); 5641c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 564282780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro qb.appendWhere(StreamItems.RAW_CONTACT_ID + "=? AND " + 564382780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro StreamItems._ID + "=?"); 564482780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro break; 564582780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro } 564682780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro 564724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID_ENTITIES: { 564824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(2)); 564924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 565024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForRawEntities(qb, uri); 56515d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro qb.appendWhere(" AND " + RawContacts._ID + "=?"); 5652e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 5653e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 5654e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 5655d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case DATA: 5656d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_DATA: { 565782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 5658e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 5659e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 5660e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 5661d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case DATA_ID: 5662d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_DATA_ID: { 566382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 56644da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 56654da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 5666a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov break; 5667a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov } 5668a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov 566985077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro case PROFILE_PHOTO: { 567085077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 567185077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro qb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID); 567285077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro break; 567385077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } 567485077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro 5675a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case PHONE_LOOKUP: { 5676e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov // Phone lookup cannot be combined with a selection 5677e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov selection = null; 5678e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov selectionArgs = null; 567958795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda if (uri.getBooleanQueryParameter(PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS, false)) { 568058795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda if (TextUtils.isEmpty(sortOrder)) { 568158795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda // Default the sort order to something reasonable so we get consistent 568258795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda // results when callers don't request an ordering 568358795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda sortOrder = Contacts.DISPLAY_NAME + " ASC"; 568458795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda } 568558795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda 568658795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda String sipAddress = uri.getPathSegments().size() > 1 568758795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda ? Uri.decode(uri.getLastPathSegment()) : ""; 568858795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda setTablesAndProjectionMapForData(qb, uri, null, false, true); 568958795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda StringBuilder sb = new StringBuilder(); 569058795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda selectionArgs = mDbHelper.get().buildSipContactQuery(sb, sipAddress); 569158795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda selection = sb.toString(); 569258795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda } else { 569358795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda if (TextUtils.isEmpty(sortOrder)) { 569458795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda // Default the sort order to something reasonable so we get consistent 569558795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda // results when callers don't request an ordering 569658795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda sortOrder = " length(lookup.normalized_number) DESC"; 569758795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda } 569858795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda 569958795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda String number = uri.getPathSegments().size() > 1 570058795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda ? uri.getLastPathSegment() : ""; 570158795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda String numberE164 = PhoneNumberUtils.formatNumberToE164(number, 570258795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda mDbHelper.get().getCurrentCountryIso()); 570358795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda String normalizedNumber = 570458795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda PhoneNumberUtils.normalizeNumber(number); 570558795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda mDbHelper.get().buildPhoneLookupAndContactQuery( 570658795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda qb, normalizedNumber, numberE164); 570758795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda qb.setProjectionMap(sPhoneLookupProjectionMap); 570856abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro 570956abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro // Peek at the results of the first query (which attempts to use fully 571056abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro // normalized and internationalized numbers for comparison). If no results 571156abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro // were returned, fall back to doing a match of the trailing 7 digits. 571256abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro qb.setStrict(true); 571356abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro boolean foundResult = false; 571456abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro Cursor cursor = query(mActiveDb.get(), qb, projection, selection, selectionArgs, 57157898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown sortOrder, groupBy, limit, cancellationSignal); 571656abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro try { 571756abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro if (cursor.getCount() > 0) { 571856abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro foundResult = true; 571956abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro return cursor; 572056abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro } else { 572156abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro qb = new SQLiteQueryBuilder(); 572256abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro mDbHelper.get().buildMinimalPhoneLookupAndContactQuery( 572356abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro qb, normalizedNumber); 572456abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro qb.setProjectionMap(sPhoneLookupProjectionMap); 572556abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro } 572656abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro } finally { 572756abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro if (!foundResult) { 572856abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro // We'll be returning a different cursor, so close this one. 572956abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro cursor.close(); 573056abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro } 573156abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro } 573258795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda } 5733a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 5734a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 5735a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 5736ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 5737ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.GROUPS); 5738ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 57399ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki appendAccountIdFromParameter(qb, uri); 5740ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5741ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5742ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5743ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 5744ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.GROUPS); 5745ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 57464da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 57474da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Groups._ID + "=?"); 5748ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5749ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5750ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5751ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_SUMMARY: { 575223ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki String tables = Views.GROUPS + " AS " + Tables.GROUPS; 5753ac2a6e814edb3d5e5bcca28d7d3f3977a489c2edMakoto Onuki if (ContactsDatabaseHelper.isInProjection(projection, Groups.SUMMARY_COUNT)) { 575423ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki tables = tables + Joins.GROUP_MEMBER_COUNT; 575523ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki } 575618b09495f5f37b38ff2e1c965e087dfde68c27fbMakoto Onuki if (ContactsDatabaseHelper.isInProjection(projection, 575718b09495f5f37b38ff2e1c965e087dfde68c27fbMakoto Onuki Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT)) { 575818b09495f5f37b38ff2e1c965e087dfde68c27fbMakoto Onuki // TODO Add join for this column too (and update the projection map) 575918b09495f5f37b38ff2e1c965e087dfde68c27fbMakoto Onuki // TODO Also remove Groups.PARAM_RETURN_GROUP_COUNT_PER_ACCOUNT when it works. 576018b09495f5f37b38ff2e1c965e087dfde68c27fbMakoto Onuki Log.w(TAG, Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT + " is not supported yet"); 576118b09495f5f37b38ff2e1c965e087dfde68c27fbMakoto Onuki } 576223ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki qb.setTables(tables); 576318b09495f5f37b38ff2e1c965e087dfde68c27fbMakoto Onuki qb.setProjectionMap(sGroupsSummaryProjectionMap); 57649ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki appendAccountIdFromParameter(qb, uri); 5765f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa groupBy = GroupsColumns.CONCRETE_ID; 5766ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 5767ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 5768ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 5769b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 57700c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov qb.setTables(Tables.AGGREGATION_EXCEPTIONS); 5771b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov qb.setProjectionMap(sAggregationExceptionsProjectionMap); 5772b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 5773b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 5774b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 577531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov case AGGREGATION_SUGGESTIONS: { 5776d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 57772d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov String filter = null; 57782d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov if (uri.getPathSegments().size() > 3) { 57792d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov filter = uri.getPathSegments().get(3); 57802d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov } 578131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov final int maxSuggestions; 5782d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov if (limit != null) { 5783d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov maxSuggestions = Integer.parseInt(limit); 578431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } else { 578531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov maxSuggestions = DEFAULT_MAX_SUGGESTIONS; 578631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 578731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 57885b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov ArrayList<AggregationSuggestionParameter> parameters = null; 57895b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov List<String> query = uri.getQueryParameters("query"); 57905b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov if (query != null && !query.isEmpty()) { 57915b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameters = new ArrayList<AggregationSuggestionParameter>(query.size()); 57925b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov for (String parameter : query) { 57935b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov int offset = parameter.indexOf(':'); 57945b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameters.add(offset == -1 57955b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov ? new AggregationSuggestionParameter( 579676dfa406e2cde19c824983c37fc92c1c5bf63eecDaniel Lehmann AggregationSuggestions.PARAMETER_MATCH_NAME, 57975b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter) 57985b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov : new AggregationSuggestionParameter( 57995b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter.substring(0, offset), 58005b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter.substring(offset + 1))); 58015b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov } 58025b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov } 58035b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov 5804763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 58057581213e160c460671aebdb054b8afd2f138d99eDmitri Plotnikov 58065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mAggregator.get().queryAggregationSuggestions(qb, projection, contactId, 58075b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov maxSuggestions, filter, parameters); 580831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 580931b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 5810eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 5811eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey qb.setTables(Tables.SETTINGS); 5812eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey qb.setProjectionMap(sSettingsProjectionMap); 5813f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro appendAccountFromParameter(qb, uri); 5814e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 5815e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey // When requesting specific columns, this query requires 5816e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey // late-binding of the GroupMembership MIME-type. 58175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final String groupMembershipMimetypeId = Long.toString(mDbHelper.get() 5818e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)); 581982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (projection != null && projection.length != 0 && 58205d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().isInProjection(projection, Settings.UNGROUPED_COUNT)) { 5821e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId); 5822e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 582382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (projection != null && projection.length != 0 && 58245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().isInProjection( 58255d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro projection, Settings.UNGROUPED_WITH_PHONES)) { 5826e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId); 5827e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 5828e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 5829eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 5830eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 5831eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 58325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case STATUS_UPDATES: 58335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_STATUS_UPDATES: { 58340a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov setTableAndProjectionMapForStatusUpdates(qb, projection); 58355ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov break; 58365ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov } 58375ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov 583882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES_ID: { 58390a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov setTableAndProjectionMapForStatusUpdates(qb, projection); 58404da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 58414da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(DataColumns.CONCRETE_ID + "=?"); 58425ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov break; 58435ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov } 58445ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov 5845c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SUGGESTIONS: { 5846174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov return mGlobalSearchSupport.handleSearchSuggestionsQuery( 58475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get(), uri, projection, limit); 5848c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 5849c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 5850c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SHORTCUT: { 58512d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill String lookupKey = uri.getLastPathSegment(); 5852174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String filter = getQueryParameter( 5853174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov uri, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA); 5854174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov return mGlobalSearchSupport.handleSearchShortcutRefresh( 58555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.get(), projection, lookupKey, filter); 5856c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 5857c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 58583202ae2de5c5fec9f5f61003a0e6b608283e1961Dave Santoro case RAW_CONTACT_ENTITIES: 58593202ae2de5c5fec9f5f61003a0e6b608283e1961Dave Santoro case PROFILE_RAW_CONTACT_ENTITIES: { 5860a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForRawEntities(qb, uri); 586146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana break; 586246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 586346b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 5864193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki case RAW_CONTACT_ID_ENTITY: { 586546b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 5866a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForRawEntities(qb, uri); 58674da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 58684da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts._ID + "=?"); 586946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana break; 587046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 587146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 587209c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov case PROVIDER_STATUS: { 5873084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki return buildSingleRowResult(projection, 5874084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki new String[] {ProviderStatus.STATUS, ProviderStatus.DATA1}, 5875084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki new Object[] {mProviderStatus, mEstimatedStorageRequirement}); 587609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 587709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5878d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES : { 5879d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setTables(Tables.DIRECTORIES); 5880d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setProjectionMap(sDirectoryProjectionMap); 5881d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 5882d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 5883d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 5884d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES_ID : { 5885385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov long id = ContentUris.parseId(uri); 5886d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setTables(Tables.DIRECTORIES); 5887d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setProjectionMap(sDirectoryProjectionMap); 5888385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(id)); 5889d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.appendWhere(Directory._ID + "=?"); 5890d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 5891d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 5892d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 58937a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov case COMPLETE_NAME: { 58947a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov return completeName(uri, projection); 58957a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 58967a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 58974f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton default: 5898f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.query(uri, projection, selection, selectionArgs, 5899c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov sortOrder, limit); 59004f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 59014f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 590209e69522745551522c55dff27424496f255def46Daniel Lehmann qb.setStrict(true); 59037f786e5cbde9975b9632beb9b6d19eeef8a64cf1Dmitri Plotnikov 5904ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov Cursor cursor = 59055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro query(mActiveDb.get(), qb, projection, selection, selectionArgs, sortOrder, groupBy, 59067898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown limit, cancellationSignal); 5907b6b22df3a64a80531d58f9cd60f2872fc2af92d1Dave Santoro 5908ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (readBooleanQueryParameter(uri, ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, false)) { 590935997f3fdee2984b6d5373326110eda26929001aMakoto Onuki bundleFastScrollingIndexExtras(cursor, uri, mActiveDb.get(), qb, selection, 591035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki selectionArgs, sortOrder, addressBookIndexerCountExpression, 591135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki cancellationSignal); 5912ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 5913b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson if (snippetDeferred) { 5914b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson cursor = addDeferredSnippetingExtra(cursor); 5915b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 5916b6b22df3a64a80531d58f9cd60f2872fc2af92d1Dave Santoro 5917ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov return cursor; 59185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 59195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 59205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private Cursor query(final SQLiteDatabase db, SQLiteQueryBuilder qb, String[] projection, 59215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String selection, String[] selectionArgs, String sortOrder, String groupBy, 59227898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown String limit, CancellationSignal cancellationSignal) { 5923038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana if (projection != null && projection.length == 1 5924038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana && BaseColumns._COUNT.equals(projection[0])) { 5925038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana qb.setProjectionMap(sCountProjectionMap); 5926038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana } 59275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov final Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, null, 59287898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown sortOrder, limit, cancellationSignal); 59294f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton if (c != null) { 59304f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton c.setNotificationUri(getContext().getContentResolver(), ContactsContract.AUTHORITY_URI); 59314f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 59324f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton return c; 59334f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 59344f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 593509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 5936a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** 5937a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * Runs the query with the supplied contact ID and lookup ID. If the query succeeds, 5938a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * it returns the resulting cursor, otherwise it returns null and the calling 5939a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * method needs to resolve the lookup key and rerun the query. 59407898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown * @param cancellationSignal 5941a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov */ 5942a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private Cursor queryWithContactIdAndLookupKey(SQLiteQueryBuilder lookupQb, 5943a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov SQLiteDatabase db, Uri uri, 5944a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] projection, String selection, String[] selectionArgs, 5945a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String sortOrder, String groupBy, String limit, 594615826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann String contactIdColumn, long contactId, String lookupKeyColumn, String lookupKey, 59477898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown CancellationSignal cancellationSignal) { 5948a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] args; 5949a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (selectionArgs == null) { 5950a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args = new String[2]; 5951a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } else { 5952a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args = new String[selectionArgs.length + 2]; 5953a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov System.arraycopy(selectionArgs, 0, args, 2, selectionArgs.length); 5954a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5955a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args[0] = String.valueOf(contactId); 5956a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args[1] = Uri.encode(lookupKey); 5957a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(contactIdColumn + "=? AND " + lookupKeyColumn + "=?"); 5958a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = query(db, lookupQb, projection, selection, args, sortOrder, 59597898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown groupBy, limit, cancellationSignal); 5960a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c.getCount() != 0) { 5961a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return c; 5962a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5963a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 5964a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov c.close(); 5965a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return null; 5966a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 596709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 596835997f3fdee2984b6d5373326110eda26929001aMakoto Onuki private void invalidateFastScrollingIndexCache() { 596935997f3fdee2984b6d5373326110eda26929001aMakoto Onuki if (VERBOSE_LOGGING) { 597035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki Log.v(TAG, "invalidatemFastScrollingIndexCache"); 597135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki } 59725acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki 59735acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // FastScrollingIndexCache is thread-safe, no need to synchronize here. 59745acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki mFastScrollingIndexCache.invalidate(); 597535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki } 597635997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 597735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki /** 597835997f3fdee2984b6d5373326110eda26929001aMakoto Onuki * Add the "fast scrolling index" bundle, generated by {@link #getFastScrollingIndexExtras}, 597935997f3fdee2984b6d5373326110eda26929001aMakoto Onuki * to a cursor as extras. It first checks {@link FastScrollingIndexCache} to see if we 598035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki * already have a cached result. 598135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki */ 598235997f3fdee2984b6d5373326110eda26929001aMakoto Onuki private void bundleFastScrollingIndexExtras(Cursor cursor, Uri queryUri, 598335997f3fdee2984b6d5373326110eda26929001aMakoto Onuki final SQLiteDatabase db, SQLiteQueryBuilder qb, String selection, 598435997f3fdee2984b6d5373326110eda26929001aMakoto Onuki String[] selectionArgs, String sortOrder, String countExpression, 598535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki CancellationSignal cancellationSignal) { 598635997f3fdee2984b6d5373326110eda26929001aMakoto Onuki if (!(cursor instanceof AbstractCursor)) { 598735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki Log.w(TAG, "Unable to bundle extras. Cursor is not AbstractCursor."); 598835997f3fdee2984b6d5373326110eda26929001aMakoto Onuki return; 598935997f3fdee2984b6d5373326110eda26929001aMakoto Onuki } 599035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki Bundle b; 59915acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // Note even though FastScrollingIndexCache is thread-safe, we really need to put the 59925acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // put-get pair in a single synchronized block, so that even if multiple-threads request the 59935acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // same index at the same time (which actually happens on the phone app) we only execute 59945acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // the query once. 59955acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // 59965acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // This doesn't cause deadlock, because only reader threads get here but not writer 59975acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // threads. (Writer threads may call invalidateFastScrollingIndexCache(), but it doesn't 59985acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // synchronize on mFastScrollingIndexCache) 59995acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // 60005acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // All reader and writer threads share the single lock object internally in 60015acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // FastScrollingIndexCache, but the lock scope is limited within each put(), get() and 60025acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // invalidate() call, so it won't deadlock. 60035acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki 60045acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // Synchronizing on a non-static field is generally not a good idea, but nobody should 60055acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // modify mFastScrollingIndexCache once initialized, and it shouldn't be null at this point. 60065acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki synchronized (mFastScrollingIndexCache) { 600735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki // First, try the cache. 600835997f3fdee2984b6d5373326110eda26929001aMakoto Onuki mFastScrollingIndexCacheRequestCount++; 600935997f3fdee2984b6d5373326110eda26929001aMakoto Onuki b = mFastScrollingIndexCache.get(queryUri, selection, selectionArgs, sortOrder, 601035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki countExpression); 601135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 601235997f3fdee2984b6d5373326110eda26929001aMakoto Onuki if (b == null) { 601335997f3fdee2984b6d5373326110eda26929001aMakoto Onuki mFastScrollingIndexCacheMissCount++; 601435997f3fdee2984b6d5373326110eda26929001aMakoto Onuki // Not in the cache. Generate and put. 601535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki final long start = System.currentTimeMillis(); 601635997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 601735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki b = getFastScrollingIndexExtras(queryUri, db, qb, selection, selectionArgs, 60185acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki sortOrder, countExpression, cancellationSignal, getLocale()); 601935997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 602035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki final long end = System.currentTimeMillis(); 602135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki final int time = (int) (end - start); 602235997f3fdee2984b6d5373326110eda26929001aMakoto Onuki mTotalTimeFastScrollingIndexGenerate += time; 602335997f3fdee2984b6d5373326110eda26929001aMakoto Onuki if (VERBOSE_LOGGING) { 602435997f3fdee2984b6d5373326110eda26929001aMakoto Onuki Log.v(TAG, "getLetterCountExtraBundle took " + time + "ms"); 602535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki } 60265acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki mFastScrollingIndexCache.put(queryUri, selection, selectionArgs, sortOrder, 60275acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki countExpression, b); 602835997f3fdee2984b6d5373326110eda26929001aMakoto Onuki } 602935997f3fdee2984b6d5373326110eda26929001aMakoto Onuki } 603035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki ((AbstractCursor) cursor).setExtras(b); 603135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki } 603235997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 6033bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov private static final class AddressBookIndexQuery { 6034bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String LETTER = "letter"; 6035bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String TITLE = "title"; 6036bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String COUNT = "count"; 6037ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 6038bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String[] COLUMNS = new String[] { 6039bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov LETTER, TITLE, COUNT 6040ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov }; 6041ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 6042bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_LETTER = 0; 6043bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_TITLE = 1; 6044bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final int COLUMN_COUNT = 2; 6045bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 60465d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // The first letter of the sort key column is what is used for the index headings. 60475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro public static final String SECTION_HEADING = "SUBSTR(%1$s,1,1)"; 604824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 6049de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa public static final String ORDER_BY = LETTER + " COLLATE " + PHONEBOOK_COLLATOR_NAME; 6050ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 6051ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 6052ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov /** 605335997f3fdee2984b6d5373326110eda26929001aMakoto Onuki * Computes counts by the address book index titles and returns it as {@link Bundle} which 60545acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki * will be appended to a {@link Cursor} as extras. 6055ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov */ 605635997f3fdee2984b6d5373326110eda26929001aMakoto Onuki private static Bundle getFastScrollingIndexExtras(final Uri queryUri, final SQLiteDatabase db, 605735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki final SQLiteQueryBuilder qb, final String selection, final String[] selectionArgs, 60585acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki final String sortOrder, String countExpression, 60595acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki final CancellationSignal cancellationSignal, final Locale currentLocale) { 6060ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String sortKey; 6061ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 6062ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // The sort order suffix could be something like "DESC". 6063ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // We want to preserve it in the query even though we will change 6064ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // the sort column itself. 6065ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String sortOrderSuffix = ""; 6066ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (sortOrder != null) { 6067ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov int spaceIndex = sortOrder.indexOf(' '); 6068ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (spaceIndex != -1) { 6069ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = sortOrder.substring(0, spaceIndex); 6070ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortOrderSuffix = sortOrder.substring(spaceIndex); 6071ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } else { 6072ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = sortOrder; 6073ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 6074ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } else { 6075ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = Contacts.SORT_KEY_PRIMARY; 6076ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 6077ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 6078ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov HashMap<String, String> projectionMap = Maps.newHashMap(); 6079a99ffbd887e5120951845e5c60c32f459f71e9f2Makoto Onuki String sectionHeading = String.format(Locale.US, AddressBookIndexQuery.SECTION_HEADING, 6080a99ffbd887e5120951845e5c60c32f459f71e9f2Makoto Onuki sortKey); 6081bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov projectionMap.put(AddressBookIndexQuery.LETTER, 608224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro sectionHeading + " AS " + AddressBookIndexQuery.LETTER); 6083bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 60842ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki // If "what to count" is not specified, we just count all records. 60852ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki if (TextUtils.isEmpty(countExpression)) { 60862ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki countExpression = "*"; 60872ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki } 60882ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki 6089bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov /** 6090bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * Use the GET_PHONEBOOK_INDEX function, which is an android extension for SQLite3, 6091bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * to map the first letter of the sort key to a character that is traditionally 6092bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * used in phonebooks to represent that letter. For example, in Korean it will 6093bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * be the first consonant in the letter; for Japanese it will be Hiragana rather 6094bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov * than Katakana. 6095bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov */ 6096ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov projectionMap.put(AddressBookIndexQuery.TITLE, 609735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki "GET_PHONEBOOK_INDEX(" + sectionHeading + ",'" + currentLocale.toString() + "')" 6098bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov + " AS " + AddressBookIndexQuery.TITLE); 6099ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov projectionMap.put(AddressBookIndexQuery.COUNT, 61002ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki "COUNT(" + countExpression + ") AS " + AddressBookIndexQuery.COUNT); 6101ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov qb.setProjectionMap(projectionMap); 6102ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 6103f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov Cursor indexCursor = qb.query(db, AddressBookIndexQuery.COLUMNS, selection, selectionArgs, 6104ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov AddressBookIndexQuery.ORDER_BY, null /* having */, 610515826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann AddressBookIndexQuery.ORDER_BY + sortOrderSuffix, 61067898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown null, cancellationSignal); 6107ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 6108ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov try { 6109f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov int groupCount = indexCursor.getCount(); 6110ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String titles[] = new String[groupCount]; 6111ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov int counts[] = new int[groupCount]; 6112bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int indexCount = 0; 6113bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String currentTitle = null; 6114bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 6115bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // Since GET_PHONEBOOK_INDEX is a many-to-1 function, we may end up 6116bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // with multiple entries for the same title. The following code 6117bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov // collapses those duplicates. 6118ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov for (int i = 0; i < groupCount; i++) { 6119f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov indexCursor.moveToNext(); 6120bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String title = indexCursor.getString(AddressBookIndexQuery.COLUMN_TITLE); 612135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki if (title == null) { 612235997f3fdee2984b6d5373326110eda26929001aMakoto Onuki title = ""; 612335997f3fdee2984b6d5373326110eda26929001aMakoto Onuki } 6124bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int count = indexCursor.getInt(AddressBookIndexQuery.COLUMN_COUNT); 6125bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov if (indexCount == 0 || !TextUtils.equals(title, currentTitle)) { 6126bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov titles[indexCount] = currentTitle = title; 6127bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts[indexCount] = count; 6128bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov indexCount++; 6129bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } else { 6130bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts[indexCount - 1] += count; 6131bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } 6132bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } 6133bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 6134bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov if (indexCount < groupCount) { 6135bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov String[] newTitles = new String[indexCount]; 6136bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov System.arraycopy(titles, 0, newTitles, 0, indexCount); 6137bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov titles = newTitles; 6138bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 6139bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov int[] newCounts = new int[indexCount]; 6140bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov System.arraycopy(counts, 0, newCounts, 0, indexCount); 6141bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov counts = newCounts; 6142ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 61435acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki return FastScrollingIndexCache.buildExtraBundle(titles, counts); 6144ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } finally { 6145f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov indexCursor.close(); 6146ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 6147ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 6148ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 61492d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill /** 615092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * Returns the contact Id for the contact identified by the lookupKey. 615192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * Robust against changes in the lookup key: if the key has changed, will 615292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * look up the contact by the raw contact IDs or name encoded in the lookup 615392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * key. 61542d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill */ 61552d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill public long lookupContactIdByLookupKey(SQLiteDatabase db, String lookupKey) { 61565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ContactLookupKey key = new ContactLookupKey(); 61575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ArrayList<LookupKeySegment> segments = key.parse(lookupKey); 61585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 615992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov long contactId = -1; 61605d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_PROFILE)) { 61615d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // We should already be in a profile database context, so just look up a single contact. 61625d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro contactId = lookupSingleContactId(db); 61635d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 61645d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 616592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_SOURCE_ID)) { 616692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov contactId = lookupContactIdBySourceIds(db, segments); 616792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (contactId != -1) { 616892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return contactId; 616992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 617092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 617192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 617292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov boolean hasRawContactIds = 617392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID); 617492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (hasRawContactIds) { 617592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov contactId = lookupContactIdByRawContactIds(db, segments); 617692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (contactId != -1) { 617792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return contactId; 617892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 617992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 618092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 618192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (hasRawContactIds 618292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME)) { 61835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov contactId = lookupContactIdByDisplayNames(db, segments); 61845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 61855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 61865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return contactId; 61875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 61885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 61895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private long lookupSingleContactId(SQLiteDatabase db) { 61905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = db.query(Tables.CONTACTS, new String[] {Contacts._ID}, 61915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro null, null, null, null, null, "1"); 61925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro try { 61935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (c.moveToFirst()) { 61945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return c.getLong(0); 61955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 61965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return -1; 61975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 61985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } finally { 61995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro c.close(); 62005d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 62015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 62025d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 62035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private interface LookupBySourceIdQuery { 620443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String TABLE = Views.RAW_CONTACTS; 62055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 62065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String COLUMNS[] = { 62075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.CONTACT_ID, 620843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 62095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_NAME, 62105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.SOURCE_ID 62115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov }; 62125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 62135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int CONTACT_ID = 0; 621443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int ACCOUNT_TYPE_AND_DATA_SET = 1; 62155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_NAME = 2; 62165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int SOURCE_ID = 3; 62175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 62185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 62195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private long lookupContactIdBySourceIds(SQLiteDatabase db, 62205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ArrayList<LookupKeySegment> segments) { 62215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 62225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(RawContacts.SOURCE_ID + " IN ("); 62235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 62245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 622592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_SOURCE_ID) { 62265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, segment.key); 62275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(","); 62285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 62295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 62305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 62315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL"); 62325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 62335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Cursor c = db.query(LookupBySourceIdQuery.TABLE, LookupBySourceIdQuery.COLUMNS, 62345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.toString(), null, null, null, null); 62355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov try { 62365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov while (c.moveToNext()) { 623743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String accountTypeAndDataSet = 623843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro c.getString(LookupBySourceIdQuery.ACCOUNT_TYPE_AND_DATA_SET); 62395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountName = c.getString(LookupBySourceIdQuery.ACCOUNT_NAME); 62405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int accountHashCode = 624143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro ContactLookupKey.getAccountHashCode(accountTypeAndDataSet, accountName); 62425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String sourceId = c.getString(LookupBySourceIdQuery.SOURCE_ID); 62435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 62445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 624592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_SOURCE_ID 624692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 62475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov && segment.key.equals(sourceId)) { 62485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov segment.contactId = c.getLong(LookupBySourceIdQuery.CONTACT_ID); 62495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 62505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 62515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 62525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 62535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } finally { 62545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov c.close(); 62555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 62565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 62575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return getMostReferencedContactId(segments); 62585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 62595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 626092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private interface LookupByRawContactIdQuery { 626143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String TABLE = Views.RAW_CONTACTS; 62625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 62635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String COLUMNS[] = { 62645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.CONTACT_ID, 626543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 62665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_NAME, 626792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts._ID, 62685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov }; 62695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 62705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int CONTACT_ID = 0; 627143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int ACCOUNT_TYPE_AND_DATA_SET = 1; 62725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_NAME = 2; 627392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int ID = 3; 62745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 62755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 627692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private long lookupContactIdByRawContactIds(SQLiteDatabase db, 627792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov ArrayList<LookupKeySegment> segments) { 627892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 627992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(RawContacts._ID + " IN ("); 62805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 62815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 628292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) { 628392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(segment.rawContactId); 628492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(","); 62855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 62865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 628792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 628892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL"); 62895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 629092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov Cursor c = db.query(LookupByRawContactIdQuery.TABLE, LookupByRawContactIdQuery.COLUMNS, 629192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.toString(), null, null, null, null); 629292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov try { 629392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov while (c.moveToNext()) { 629443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String accountTypeAndDataSet = c.getString( 629543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro LookupByRawContactIdQuery.ACCOUNT_TYPE_AND_DATA_SET); 629692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String accountName = c.getString(LookupByRawContactIdQuery.ACCOUNT_NAME); 629792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int accountHashCode = 629843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro ContactLookupKey.getAccountHashCode(accountTypeAndDataSet, accountName); 629992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String rawContactId = c.getString(LookupByRawContactIdQuery.ID); 630092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 630192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov LookupKeySegment segment = segments.get(i); 630292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID 630392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 630492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && segment.rawContactId.equals(rawContactId)) { 630592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov segment.contactId = c.getLong(LookupByRawContactIdQuery.CONTACT_ID); 630692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov break; 630792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 630892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 630992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 631092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } finally { 631192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov c.close(); 63125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 63135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 631492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return getMostReferencedContactId(segments); 631592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 631692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 631792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private interface LookupByDisplayNameQuery { 631892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String TABLE = Tables.NAME_LOOKUP_JOIN_RAW_CONTACTS; 631992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 632092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String COLUMNS[] = { 632192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts.CONTACT_ID, 632243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 632392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts.ACCOUNT_NAME, 632492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov NameLookupColumns.NORMALIZED_NAME 632592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov }; 632692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 632792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int CONTACT_ID = 0; 632843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int ACCOUNT_TYPE_AND_DATA_SET = 1; 632992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int ACCOUNT_NAME = 2; 633092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int NORMALIZED_NAME = 3; 633192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 633292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 633392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private long lookupContactIdByDisplayNames(SQLiteDatabase db, 633492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov ArrayList<LookupKeySegment> segments) { 63355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 63365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(NameLookupColumns.NORMALIZED_NAME + " IN ("); 63375870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 63385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 633992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME 634092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) { 63415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, segment.key); 63425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(","); 63435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 63445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 63455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 63465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(") AND " + NameLookupColumns.NAME_TYPE + "=" + NameLookupType.NAME_COLLATION_KEY 63475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov + " AND " + RawContacts.CONTACT_ID + " NOT NULL"); 63485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 63495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Cursor c = db.query(LookupByDisplayNameQuery.TABLE, LookupByDisplayNameQuery.COLUMNS, 63505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.toString(), null, null, null, null); 63515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov try { 63525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov while (c.moveToNext()) { 635343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String accountTypeAndDataSet = 635443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro c.getString(LookupByDisplayNameQuery.ACCOUNT_TYPE_AND_DATA_SET); 63555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountName = c.getString(LookupByDisplayNameQuery.ACCOUNT_NAME); 63565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int accountHashCode = 635743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro ContactLookupKey.getAccountHashCode(accountTypeAndDataSet, accountName); 63585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String name = c.getString(LookupByDisplayNameQuery.NORMALIZED_NAME); 63595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 63605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 636192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if ((segment.lookupType == ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME 636292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) 636392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 63645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov && segment.key.equals(name)) { 63655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov segment.contactId = c.getLong(LookupByDisplayNameQuery.CONTACT_ID); 63665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 63675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 63685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 63695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 63705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } finally { 63715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov c.close(); 63725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 63735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 63745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return getMostReferencedContactId(segments); 63755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 63765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 637792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private boolean lookupKeyContainsType(ArrayList<LookupKeySegment> segments, int lookupType) { 637892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 637992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov LookupKeySegment segment = segments.get(i); 638092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == lookupType) { 638192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return true; 638292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 638392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 638492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 638592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return false; 638692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 638792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 63885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov /** 63895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov * Returns the contact ID that is mentioned the highest number of times. 63905870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov */ 63915870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private long getMostReferencedContactId(ArrayList<LookupKeySegment> segments) { 63925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Collections.sort(segments); 63935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 63945870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long bestContactId = -1; 63955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int bestRefCount = 0; 63965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 63975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long contactId = -1; 63985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int count = 0; 63995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 64005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int segmentCount = segments.size(); 64015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segmentCount; i++) { 64025870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 64035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segment.contactId != -1) { 64045870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segment.contactId == contactId) { 64055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov count++; 64065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } else { 64075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count > bestRefCount) { 64085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov bestContactId = contactId; 64095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov bestRefCount = count; 64105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 64115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov contactId = segment.contactId; 64125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov count = 1; 64135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 64145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 64155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 64165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count > bestRefCount) { 64175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return contactId; 64185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } else { 64195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return bestContactId; 64205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 64215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 64225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 6423763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, Uri uri, 6424763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar String[] projection) { 64254928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, false); 64262f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 64272f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 64282f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa /** 64294928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * @param includeDataUsageStat true when the table should include DataUsageStat table. 64304928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Note that this uses INNER JOIN instead of LEFT OUTER JOIN, so some of data in Contacts 64314928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * may be dropped. 64322f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa */ 64332f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, Uri uri, 64344928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa String[] projection, boolean includeDataUsageStat) { 643582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 643672c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann if (includeDataUsageStat) { 643772c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann sb.append(Views.DATA_USAGE_STAT + " AS " + Tables.DATA_USAGE_STAT); 643872c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann sb.append(" INNER JOIN "); 643972c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann } 644072c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann 6441ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.CONTACTS); 64422f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 64432f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Just for frequently contacted contacts in Strequent Uri handling. 64444928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa if (includeDataUsageStat) { 644572c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann sb.append(" ON (" + 64462f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa DbQueryUtils.concatenateClauses( 64472f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa DataUsageStatColumns.CONCRETE_TIMES_USED + " > 0", 64484928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa RawContacts.CONTACT_ID + "=" + Views.CONTACTS + "." + Contacts._ID) + 64492f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa ")"); 64502f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 64512f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 64527ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts._ID); 64537ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 6454916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov qb.setTables(sb.toString()); 6455916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov qb.setProjectionMap(sContactsProjectionMap); 6456916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov } 6457916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 6458916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** 6459916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov * Finds name lookup records matching the supplied filter, picks one arbitrary match per 6460916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov * contact and joins that with other contacts tables. 6461916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov */ 6462916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov private void setTablesAndProjectionMapForContactsWithSnippet(SQLiteQueryBuilder qb, Uri uri, 6463fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki String[] projection, String filter, long directoryId, boolean deferSnippeting) { 64647ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov 64657ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 6466ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.CONTACTS); 6467916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 646803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov if (filter != null) { 646903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov filter = filter.trim(); 647003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 647103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 647230cc766756461da8d53933f88ea01dd2272a90ebDmitri Plotnikov if (TextUtils.isEmpty(filter) || (directoryId != -1 && directoryId != Directory.DEFAULT)) { 647330cc766756461da8d53933f88ea01dd2272a90ebDmitri Plotnikov sb.append(" JOIN (SELECT NULL AS " + SearchSnippetColumns.SNIPPET + " WHERE 0)"); 64745e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } else { 6475fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki appendSearchIndexJoin(sb, uri, projection, filter, deferSnippeting); 64765e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 64777ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts._ID); 64787ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 647903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov qb.setTables(sb.toString()); 648003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov qb.setProjectionMap(sContactsProjectionWithSnippetMap); 648103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 6482916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 648303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private void appendSearchIndexJoin( 6484b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson StringBuilder sb, Uri uri, String[] projection, String filter, 6485fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki boolean deferSnippeting) { 6486916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 6487b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson if (snippetNeeded(projection)) { 648803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov String[] args = null; 648903197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov String snippetArgs = 649003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov getQueryParameter(uri, SearchSnippetColumns.SNIPPET_ARGS_PARAM_KEY); 649103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov if (snippetArgs != null) { 649203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov args = snippetArgs.split(","); 649303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 649403197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 64955e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String startMatch = args != null && args.length > 0 ? args[0] 64965e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_START_MATCH; 64975e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String endMatch = args != null && args.length > 1 ? args[1] 64985e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_END_MATCH; 64995e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String ellipsis = args != null && args.length > 2 ? args[2] 65005e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_ELLIPSIS; 65015e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov int maxTokens = args != null && args.length > 3 ? Integer.parseInt(args[3]) 65025e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_MAX_TOKENS; 65035e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 6504174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov appendSearchIndexJoin( 6505b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson sb, filter, true, startMatch, endMatch, ellipsis, maxTokens, 6506fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki deferSnippeting); 6507174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } else { 6508b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson appendSearchIndexJoin(sb, filter, false, null, null, null, 0, false); 6509174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 6510174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 6511174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 6512174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov public void appendSearchIndexJoin(StringBuilder sb, String filter, 6513174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean snippetNeeded, String startMatch, String endMatch, String ellipsis, 6514fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki int maxTokens, boolean deferSnippeting) { 6515174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean isEmailAddress = false; 6516174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String emailAddress = null; 6517174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean isPhoneNumber = false; 6518174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String phoneNumber = null; 6519174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String numberE164 = null; 6520174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 65213716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 6522174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (filter.indexOf('@') != -1) { 65235d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro emailAddress = mDbHelper.get().extractAddressFromEmailAddress(filter); 6524174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov isEmailAddress = !TextUtils.isEmpty(emailAddress); 6525174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } else { 6526174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov isPhoneNumber = isPhoneNumber(filter); 652704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (isPhoneNumber) { 652804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann phoneNumber = PhoneNumberUtils.normalizeNumber(filter); 652904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann numberE164 = PhoneNumberUtils.formatNumberToE164(phoneNumber, 65305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().getCountryIso()); 653104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 6532174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 6533174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 6534d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann final String SNIPPET_CONTACT_ID = "snippet_contact_id"; 6535d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann sb.append(" JOIN (SELECT " + SearchIndexColumns.CONTACT_ID + " AS " + SNIPPET_CONTACT_ID); 6536174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (snippetNeeded) { 65375e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(", "); 65385e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov if (isEmailAddress) { 65393d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append("ifnull("); 6540fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki if (!deferSnippeting) { 6541fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki // Add the snippet marker only when we're really creating snippet. 6542fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki DatabaseUtils.appendEscapedSQLString(sb, startMatch); 6543fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki sb.append("||"); 6544fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki } 6545fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki sb.append("(SELECT MIN(" + Email.ADDRESS + ")"); 654604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" FROM " + Tables.DATA_JOIN_RAW_CONTACTS); 654704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" WHERE " + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 654804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + RawContacts.CONTACT_ID + " AND " + Email.ADDRESS + " LIKE "); 654904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann DatabaseUtils.appendEscapedSQLString(sb, filter + "%"); 6550fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki sb.append(")"); 6551fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki if (!deferSnippeting) { 6552fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki sb.append("||"); 6553fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki DatabaseUtils.appendEscapedSQLString(sb, endMatch); 6554fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki } 65553d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append(","); 65563716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 6557fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki if (deferSnippeting) { 65583716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 65593716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 65603716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 65613716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 65623d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append(")"); 65633d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov } else if (isPhoneNumber) { 65643d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append("ifnull("); 6565fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki if (!deferSnippeting) { 6566fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki // Add the snippet marker only when we're really creating snippet. 6567fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki DatabaseUtils.appendEscapedSQLString(sb, startMatch); 6568fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki sb.append("||"); 6569fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki } 6570fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki sb.append("(SELECT MIN(" + Phone.NUMBER + ")"); 657104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" FROM " + 657204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann Tables.DATA_JOIN_RAW_CONTACTS + " JOIN " + Tables.PHONE_LOOKUP); 657304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" ON " + DataColumns.CONCRETE_ID); 657404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + Tables.PHONE_LOOKUP + "." + PhoneLookupColumns.DATA_ID); 657504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" WHERE " + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 657604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + RawContacts.CONTACT_ID); 657704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" AND " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 657804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(phoneNumber); 657904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("%'"); 658004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (!TextUtils.isEmpty(numberE164)) { 658104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" OR " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 658204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(numberE164); 658304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("%'"); 658404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 6585fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki sb.append(")"); 6586fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki if (! deferSnippeting) { 6587fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki sb.append("||"); 6588fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki DatabaseUtils.appendEscapedSQLString(sb, endMatch); 6589fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki } 65905e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 65913716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 6592fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki if (deferSnippeting) { 65933716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 65943716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 65953716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 65963716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 65975e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(")"); 659803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } else { 659904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann final String normalizedFilter = NameNormalizer.normalize(filter); 660004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (!TextUtils.isEmpty(normalizedFilter)) { 6601fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki if (deferSnippeting) { 66023716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 66033716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 66043716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("(CASE WHEN EXISTS (SELECT 1 FROM "); 66053716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.RAW_CONTACTS + " AS rc INNER JOIN "); 66063716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.NAME_LOOKUP + " AS nl ON (rc." + RawContacts._ID); 66073716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("=nl." + NameLookupColumns.RAW_CONTACT_ID); 66083716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(") WHERE nl." + NameLookupColumns.NORMALIZED_NAME); 66093716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(" GLOB '" + normalizedFilter + "*' AND "); 66103716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("nl." + NameLookupColumns.NAME_TYPE + "="); 66113716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(NameLookupType.NAME_COLLATION_KEY + " AND "); 66123716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 66133716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("=rc." + RawContacts.CONTACT_ID); 66143716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(") THEN NULL ELSE "); 66153716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 66163716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(" END)"); 66173716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 661804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } else { 661904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("NULL"); 662004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 662103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 66225e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" AS " + SearchSnippetColumns.SNIPPET); 66235e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 662403197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 66255e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" FROM " + Tables.SEARCH_INDEX); 66265e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" WHERE "); 6627d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann sb.append(Tables.SEARCH_INDEX + " MATCH '"); 66285e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov if (isEmailAddress) { 6629d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann // we know that the emailAddress contains a @. This phrase search should be 6630d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann // scoped against "content:" only, but unfortunately SQLite doesn't support 6631d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann // phrases and scoped columns at once. This is fine in this case however, because: 6632d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann // - We can't erronously match against name, as name is all-hex (so the @ can't match) 6633d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann // - We can't match against tokens, because phone-numbers can't contain @ 6634d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann final String sanitizedEmailAddress = 6635d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann emailAddress == null ? "" : sanitizeMatch(emailAddress); 6636d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann sb.append("\""); 6637d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann sb.append(sanitizedEmailAddress); 6638d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann sb.append("*\""); 66393d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov } else if (isPhoneNumber) { 6640d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann // normalized version of the phone number (phoneNumber can only have + and digits) 6641d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann final String phoneNumberCriteria = " OR tokens:" + phoneNumber + "*"; 6642d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann 6643d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann // international version of this number (numberE164 can only have + and digits) 6644d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann final String numberE164Criteria = 6645d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann (numberE164 != null && !TextUtils.equals(numberE164, phoneNumber)) 6646d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann ? " OR tokens:" + numberE164 + "*" 6647d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann : ""; 6648d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann 6649d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann // combine all criteria 6650d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann final String commonCriteria = 6651d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann phoneNumberCriteria + numberE164Criteria; 6652d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann 6653d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann // search in content 6654d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann sb.append(SearchIndexManager.getFtsMatchQuery(filter, 6655d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann FtsQueryBuilder.getDigitsQueryBuilder(commonCriteria))); 665603197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } else { 6657d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann // general case: not a phone number, not an email-address 6658d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann sb.append(SearchIndexManager.getFtsMatchQuery(filter, 6659d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann FtsQueryBuilder.SCOPED_NAME_NORMALIZING)); 66609c6ef008d92017108e3d10dcd8e2146eded9e148Dmitri Plotnikov } 66611322df8f90d80587748ad10539516635326c01e8Daniel Lehmann // Omit results in "Other Contacts". 66621322df8f90d80587748ad10539516635326c01e8Daniel Lehmann sb.append("' AND " + SNIPPET_CONTACT_ID + " IN " + Tables.DEFAULT_DIRECTORY + ")"); 66631322df8f90d80587748ad10539516635326c01e8Daniel Lehmann sb.append(" ON (" + Contacts._ID + "=" + SNIPPET_CONTACT_ID + ")"); 6664a1e177389debb74a51587720464a527a193bffc1Dmitri Plotnikov } 6665a1e177389debb74a51587720464a527a193bffc1Dmitri Plotnikov 6666d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann private static String sanitizeMatch(String filter) { 6667d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann return filter.replace("'", "").replace("*", "").replace("-", "").replace("\"", ""); 66682352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov } 66692352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov 66705e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov private void appendSnippetFunction( 66715e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov StringBuilder sb, String startMatch, String endMatch, String ellipsis, int maxTokens) { 66725e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append("snippet(" + Tables.SEARCH_INDEX + ","); 66735e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 66745e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 66755e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 66765e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 66775e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, ellipsis); 66785e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 66795e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov // The index of the column used for the snippet, "content" 66805e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(",1,"); 66815e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(maxTokens); 66825e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(")"); 66835e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 66845e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 6685763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar private void setTablesAndProjectionMapForRawContacts(SQLiteQueryBuilder qb, Uri uri) { 6686763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar StringBuilder sb = new StringBuilder(); 6687ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.RAW_CONTACTS); 6688763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar qb.setTables(sb.toString()); 6689763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar qb.setProjectionMap(sRawContactsProjectionMap); 66909ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki appendAccountIdFromParameter(qb, uri); 6691763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar } 6692763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar 6693a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void setTablesAndProjectionMapForRawEntities(SQLiteQueryBuilder qb, Uri uri) { 6694ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.RAW_ENTITIES); 6695a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sRawEntityProjectionMap); 66969ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki appendAccountIdFromParameter(qb, uri); 669746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 669846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 669982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri, 670082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov String[] projection, boolean distinct) { 670158795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda setTablesAndProjectionMapForData(qb, uri, projection, distinct, false, null); 670258795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda } 670358795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda 670458795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri, 670558795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda String[] projection, boolean distinct, boolean addSipLookupColumns) { 670658795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda setTablesAndProjectionMapForData(qb, uri, projection, distinct, addSipLookupColumns, null); 670746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 670846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 670946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 671046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * @param usageType when non-null {@link Tables#DATA_USAGE_STAT} is joined with the specified 671146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * type. 671246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 671346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri, 671446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String[] projection, boolean distinct, Integer usageType) { 671558795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda setTablesAndProjectionMapForData(qb, uri, projection, distinct, false, usageType); 671658795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda } 671758795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda 671858795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri, 671958795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda String[] projection, boolean distinct, boolean addSipLookupColumns, Integer usageType) { 672082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 6721ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.DATA); 672282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov sb.append(" data"); 672382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov 6724a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactPresenceJoin(sb, projection, RawContacts.CONTACT_ID); 6725a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 6726a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, DataColumns.CONCRETE_ID); 6727a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, DataColumns.CONCRETE_ID); 67283296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey 672946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (usageType != null) { 673046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa appendDataUsageStatJoin(sb, usageType, DataColumns.CONCRETE_ID); 673146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 673246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 673382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov qb.setTables(sb.toString()); 6734f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov 6735f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov boolean useDistinct = distinct 67365d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro || !mDbHelper.get().isInProjection(projection, DISTINCT_DATA_PROHIBITING_COLUMNS); 6737f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov qb.setDistinct(useDistinct); 673858795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda 673958795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda final ProjectionMap projectionMap; 674058795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda if (addSipLookupColumns) { 674158795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda projectionMap = useDistinct 674258795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda ? sDistinctDataSipLookupProjectionMap : sDataSipLookupProjectionMap; 674358795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda } else { 674458795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda projectionMap = useDistinct ? sDistinctDataProjectionMap : sDataProjectionMap; 674558795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda } 674658795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda 674758795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda qb.setProjectionMap(projectionMap); 67489ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki appendAccountIdFromParameter(qb, uri); 6749ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov } 6750ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov 67510a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov private void setTableAndProjectionMapForStatusUpdates(SQLiteQueryBuilder qb, 67520a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov String[] projection) { 67530a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StringBuilder sb = new StringBuilder(); 6754ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.DATA); 67550a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov sb.append(" data"); 6756a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, DataColumns.CONCRETE_ID); 6757a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, DataColumns.CONCRETE_ID); 67580a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 6759a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setTables(sb.toString()); 6760a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sStatusUpdatesProjectionMap); 6761a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6762a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 67633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void setTablesAndProjectionMapForStreamItems(SQLiteQueryBuilder qb) { 67649b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann qb.setTables(Views.STREAM_ITEMS); 67653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.setProjectionMap(sStreamItemsProjectionMap); 67663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 67673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 67683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void setTablesAndProjectionMapForStreamItemPhotos(SQLiteQueryBuilder qb) { 67691dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro qb.setTables(Tables.PHOTO_FILES 67701dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + " JOIN " + Tables.STREAM_ITEM_PHOTOS + " ON (" 67711dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemPhotosColumns.CONCRETE_PHOTO_FILE_ID + "=" 67721dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + PhotoFilesColumns.CONCRETE_ID 67731dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + ") JOIN " + Tables.STREAM_ITEMS + " ON (" 67741dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=" 67750bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann + StreamItemsColumns.CONCRETE_ID + ")" 67760bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann + " JOIN " + Tables.RAW_CONTACTS + " ON (" 67770bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann + StreamItemsColumns.CONCRETE_RAW_CONTACT_ID + "=" + RawContactsColumns.CONCRETE_ID 67780bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann + ")"); 67793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.setProjectionMap(sStreamItemPhotosProjectionMap); 67803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 67813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 6782a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void setTablesAndProjectionMapForEntities(SQLiteQueryBuilder qb, Uri uri, 6783a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] projection) { 6784a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 6785ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.ENTITIES); 6786a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" data"); 6787a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6788a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts.Entity.CONTACT_ID); 6789a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 6790a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, Contacts.Entity.DATA_ID); 6791a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, Contacts.Entity.DATA_ID); 6792a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6793a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setTables(sb.toString()); 6794a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sEntityProjectionMap); 67959ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki appendAccountIdFromParameter(qb, uri); 6796a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6797a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6798a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendContactStatusUpdateJoin(StringBuilder sb, String[] projection, 6799a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String lastStatusUpdateIdColumn) { 68005d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mDbHelper.get().isInProjection(projection, 6801a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS, 6802a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_RES_PACKAGE, 6803a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_ICON, 6804a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_LABEL, 6805a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_TIMESTAMP)) { 6806a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES + " " 6807a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + ContactsStatusUpdatesColumns.ALIAS + 6808a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + lastStatusUpdateIdColumn + "=" 6809a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + ContactsStatusUpdatesColumns.CONCRETE_DATA_ID + ")"); 68100a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 6811a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 68120a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 6813a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendDataStatusUpdateJoin(StringBuilder sb, String[] projection, 6814a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String dataIdColumn) { 68155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mDbHelper.get().isInProjection(projection, 68160a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS, 68170a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_RES_PACKAGE, 68180a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_ICON, 68190a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_LABEL, 68200a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_TIMESTAMP)) { 68210a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES + 6822a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + StatusUpdatesColumns.CONCRETE_DATA_ID + "=" 6823a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + dataIdColumn + ")"); 68240a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 6825a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6826a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 682746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private void appendDataUsageStatJoin(StringBuilder sb, int usageType, String dataIdColumn) { 682846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" LEFT OUTER JOIN " + Tables.DATA_USAGE_STAT + 682946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa " ON (" + DataUsageStatColumns.CONCRETE_DATA_ID + "=" + dataIdColumn + 683046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa " AND " + DataUsageStatColumns.CONCRETE_USAGE_TYPE + "=" + usageType + ")"); 683146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 683246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 6833a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendContactPresenceJoin(StringBuilder sb, String[] projection, 6834a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String contactIdColumn) { 68355d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mDbHelper.get().isInProjection(projection, 6836a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_PRESENCE, Contacts.CONTACT_CHAT_CAPABILITY)) { 6837a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.AGGREGATED_PRESENCE + 6838a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + contactIdColumn + " = " 6839a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + AggregatedPresenceColumns.CONCRETE_CONTACT_ID + ")"); 6840a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6841a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6842a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6843a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendDataPresenceJoin(StringBuilder sb, String[] projection, 6844a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String dataIdColumn) { 68455d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mDbHelper.get().isInProjection(projection, Data.PRESENCE, Data.CHAT_CAPABILITY)) { 6846a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.PRESENCE + 6847a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + StatusUpdates.DATA_ID + "=" + dataIdColumn + ")"); 6848a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6849a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6850a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 68519ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki private void appendLocalDirectoryAndAccountSelectionIfNeeded(SQLiteQueryBuilder qb, 68529ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki long directoryId, Uri uri) { 68539ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final StringBuilder sb = new StringBuilder(); 6854385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov if (directoryId == Directory.DEFAULT) { 68559ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki sb.append("(" + Contacts._ID + " IN " + Tables.DEFAULT_DIRECTORY + ")"); 6856385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } else if (directoryId == Directory.LOCAL_INVISIBLE){ 68579ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki sb.append("(" + Contacts._ID + " NOT IN " + Tables.DEFAULT_DIRECTORY + ")"); 68589ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } else { 68599ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki sb.append("(1)"); 686024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 68619ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki 68629ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final AccountWithDataSet accountWithDataSet = getAccountWithDataSetFromUri(uri); 68639ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // Accounts are valid by only checking one parameter, since we've 68649ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // already ruled out partial accounts. 68659ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final boolean validAccount = !TextUtils.isEmpty(accountWithDataSet.getAccountName()); 68669ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki if (validAccount) { 68679ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final Long accountId = mDbHelper.get().getAccountIdOrNull(accountWithDataSet); 68689ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki if (accountId == null) { 68699ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // No such account. 68709ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki sb.setLength(0); 68719ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki sb.append("(1=2)"); 68729ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } else { 68739ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki sb.append( 68749ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki " AND (" + Contacts._ID + " IN (" + 68759ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki "SELECT " + RawContacts.CONTACT_ID + " FROM " + Tables.RAW_CONTACTS + 68769ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki " WHERE " + RawContactsColumns.ACCOUNT_ID + "=" + accountId.toString() + 68779ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki "))"); 68789ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 68799ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 68809ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki qb.appendWhere(sb.toString()); 688124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 688224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 6883f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro private void appendAccountFromParameter(SQLiteQueryBuilder qb, Uri uri) { 68849ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final AccountWithDataSet accountWithDataSet = getAccountWithDataSetFromUri(uri); 6885e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6886e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 6887e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 68889ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final boolean validAccount = !TextUtils.isEmpty(accountWithDataSet.getAccountName()); 6889e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validAccount) { 68909ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki String toAppend = "(" + RawContacts.ACCOUNT_NAME + "=" 68919ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki + DatabaseUtils.sqlEscapeString(accountWithDataSet.getAccountName()) + " AND " 68924a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov + RawContacts.ACCOUNT_TYPE + "=" 68939ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki + DatabaseUtils.sqlEscapeString(accountWithDataSet.getAccountType()); 68949ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki if (accountWithDataSet.getDataSet() == null) { 6895f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro toAppend += " AND " + RawContacts.DATA_SET + " IS NULL"; 6896f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } else { 6897f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro toAppend += " AND " + RawContacts.DATA_SET + "=" + 68989ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki DatabaseUtils.sqlEscapeString(accountWithDataSet.getDataSet()); 689943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 69009ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki toAppend += ")"; 690143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro qb.appendWhere(toAppend); 69024a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } else { 69034a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov qb.appendWhere("1"); 69044a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 69054a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 69064a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 69079ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki private void appendAccountIdFromParameter(SQLiteQueryBuilder qb, Uri uri) { 69089ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final AccountWithDataSet accountWithDataSet = getAccountWithDataSetFromUri(uri); 69099ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki 69109ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // Accounts are valid by only checking one parameter, since we've 69119ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // already ruled out partial accounts. 69129ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final boolean validAccount = !TextUtils.isEmpty(accountWithDataSet.getAccountName()); 69139ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki if (validAccount) { 69149ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final Long accountId = mDbHelper.get().getAccountIdOrNull(accountWithDataSet); 69159ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki if (accountId == null) { 69169ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // No such account. 69179ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki qb.appendWhere("(1=2)"); 69189ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } else { 69199ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki qb.appendWhere( 69209ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki "(" + RawContactsColumns.ACCOUNT_ID + "=" + accountId.toString() + ")"); 69219ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 69229ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } else { 69239ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki qb.appendWhere("1"); 69249ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 69259ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 69269ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki 69279d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki private AccountWithDataSet getAccountWithDataSetFromUri(Uri uri) { 6928f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 6929f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 693043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro final String dataSet = getQueryParameter(uri, RawContacts.DATA_SET); 6931e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6932e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 6933e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri) { 6934e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 69355d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 6936fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 6937e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 69389d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki return AccountWithDataSet.get(accountName, accountType, dataSet); 69399d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 69409d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 69419d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki private String appendAccountToSelection(Uri uri, String selection) { 69429d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final AccountWithDataSet accountWithDataSet = getAccountWithDataSetFromUri(uri); 6943e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 6944e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 6945e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 69469d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final boolean validAccount = !TextUtils.isEmpty(accountWithDataSet.getAccountName()); 6947e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validAccount) { 69489d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki StringBuilder selectionSb = new StringBuilder(RawContacts.ACCOUNT_NAME + "="); 69499d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki selectionSb.append(DatabaseUtils.sqlEscapeString(accountWithDataSet.getAccountName())); 69509d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki selectionSb.append(" AND " + RawContacts.ACCOUNT_TYPE + "="); 69519d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki selectionSb.append(DatabaseUtils.sqlEscapeString(accountWithDataSet.getAccountType())); 69529d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (accountWithDataSet.getDataSet() == null) { 6953f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro selectionSb.append(" AND " + RawContacts.DATA_SET + " IS NULL"); 6954f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } else { 695543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro selectionSb.append(" AND " + RawContacts.DATA_SET + "=") 69569d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki .append(DatabaseUtils.sqlEscapeString(accountWithDataSet.getDataSet())); 69579d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 69589d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (!TextUtils.isEmpty(selection)) { 69599d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki selectionSb.append(" AND ("); 69609d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki selectionSb.append(selection); 69619d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki selectionSb.append(')'); 69629d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 69639d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki return selectionSb.toString(); 69649d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } else { 69659d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki return selection; 69669d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 69679d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 69689d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 69699d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki private String appendAccountIdToSelection(Uri uri, String selection) { 69709d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final AccountWithDataSet accountWithDataSet = getAccountWithDataSetFromUri(uri); 69719d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 69729d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // Accounts are valid by only checking one parameter, since we've 69739d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // already ruled out partial accounts. 69749d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final boolean validAccount = !TextUtils.isEmpty(accountWithDataSet.getAccountName()); 69759d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (validAccount) { 6976321b8325f2adc4b017237b4fe010a7f0f2b017adMakoto Onuki final StringBuilder selectionSb = new StringBuilder(); 6977321b8325f2adc4b017237b4fe010a7f0f2b017adMakoto Onuki 69789d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final Long accountId = mDbHelper.get().getAccountIdOrNull(accountWithDataSet); 69799d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (accountId == null) { 69809d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // No such account in the accounts table. This means, there's no rows to be 69819d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // selected. 6982321b8325f2adc4b017237b4fe010a7f0f2b017adMakoto Onuki // Note even in this case, we still need to append the original selection, because 6983321b8325f2adc4b017237b4fe010a7f0f2b017adMakoto Onuki // it may have query parameters. If we remove these we'll get the # of parameters 6984321b8325f2adc4b017237b4fe010a7f0f2b017adMakoto Onuki // mismatch exception. 6985321b8325f2adc4b017237b4fe010a7f0f2b017adMakoto Onuki selectionSb.append("(1=2)"); 6986321b8325f2adc4b017237b4fe010a7f0f2b017adMakoto Onuki } else { 6987321b8325f2adc4b017237b4fe010a7f0f2b017adMakoto Onuki selectionSb.append(RawContactsColumns.ACCOUNT_ID + "="); 6988321b8325f2adc4b017237b4fe010a7f0f2b017adMakoto Onuki selectionSb.append(Long.toString(accountId)); 698943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 69909d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 6991e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong if (!TextUtils.isEmpty(selection)) { 6992e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(" AND ("); 6993e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(selection); 6994e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(')'); 6995e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 6996e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong return selectionSb.toString(); 6997e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } else { 6998e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong return selection; 6999e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 7000e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 7001e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong 70027e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 7003c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * Gets the value of the "limit" URI query parameter. 7004c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * 7005c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * @return A string containing a non-negative integer, or <code>null</code> if 7006c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * the parameter is not set, or is set to an invalid value. 7007c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov */ 7008f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private String getLimit(Uri uri) { 70092e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov String limitParam = getQueryParameter(uri, ContactsContract.LIMIT_PARAM_KEY); 7010c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov if (limitParam == null) { 7011c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 7012c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 7013c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov // make sure that the limit is a non-negative integer 7014c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov try { 7015c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov int l = Integer.parseInt(limitParam); 7016c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov if (l < 0) { 7017c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov Log.w(TAG, "Invalid limit parameter: " + limitParam); 7018c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 7019c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 7020c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return String.valueOf(l); 7021c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } catch (NumberFormatException ex) { 7022c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov Log.w(TAG, "Invalid limit parameter: " + limitParam); 7023c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 7024c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 7025c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 7026c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 7027b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov @Override 7028f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException { 702947ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki boolean success = false; 703047ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki try { 703147ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki if (mode.equals("r")) { 703247ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki waitForAccess(mReadAccessLatch); 703347ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki } else { 703447ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki waitForAccess(mWriteAccessLatch); 703547ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki } 703647ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki final AssetFileDescriptor ret; 703747ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki if (mapsToProfileDb(uri)) { 703847ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki switchToProfileMode(); 703947ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki ret = mProfileProvider.openAssetFile(uri, mode); 704047ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki } else { 704147ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki switchToContactMode(); 704247ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki ret = openAssetFileLocal(uri, mode); 704347ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki } 704447ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki success = true; 704547ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki return ret; 704647ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki } finally { 704747ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki if (VERBOSE_LOGGING) { 704847ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki Log.v(TAG, "openAssetFile uri=" + uri + " mode=" + mode + " success=" + success); 704947ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki } 70505d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 70515d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 70525d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 70535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro public AssetFileDescriptor openAssetFileLocal(Uri uri, String mode) 70545d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throws FileNotFoundException { 70555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 70565d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Default active DB to the contacts DB if none has been set. 70575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mActiveDb.get() == null) { 7058078f588cef389358adabc579de00747878f3c108Dave Santoro if (mode.equals("r")) { 7059078f588cef389358adabc579de00747878f3c108Dave Santoro mActiveDb.set(mContactsHelper.getReadableDatabase()); 7060078f588cef389358adabc579de00747878f3c108Dave Santoro } else { 7061078f588cef389358adabc579de00747878f3c108Dave Santoro mActiveDb.set(mContactsHelper.getWritableDatabase()); 7062078f588cef389358adabc579de00747878f3c108Dave Santoro } 70635d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 7064415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 7065b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov int match = sUriMatcher.match(uri); 7066b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov switch (match) { 7067a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_PHOTO: { 7068bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro long contactId = Long.parseLong(uri.getPathSegments().get(1)); 70695d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return openPhotoAssetFile(mActiveDb.get(), uri, mode, 707024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Data._ID + "=" + Contacts.PHOTO_ID + " AND " + 707124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContacts.CONTACT_ID + "=?", 7072bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro new String[]{String.valueOf(contactId)}); 7073e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 7074b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 7075f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_ID_DISPLAY_PHOTO: { 7076f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 7077f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 7078f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by contact ID can only be read."); 7079f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7080f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long contactId = Long.parseLong(uri.getPathSegments().get(1)); 70815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = mActiveDb.get().query(Tables.CONTACTS, 7082f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{Contacts.PHOTO_FILE_ID}, 7083f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Contacts._ID + "=?", new String[]{String.valueOf(contactId)}, 7084f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null, null); 7085f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 708685077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro if (c.moveToFirst()) { 708785077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro long photoFileId = c.getLong(0); 708885077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro return openDisplayPhotoForRead(photoFileId); 708985077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } else { 709085077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro // No contact for this ID. 709185077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro throw new FileNotFoundException(uri.toString()); 709285077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } 709385077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } finally { 709485077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro c.close(); 709585077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } 709685077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } 709785077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro 709885077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro case PROFILE_DISPLAY_PHOTO: { 709985077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro if (!mode.equals("r")) { 710085077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro throw new IllegalArgumentException( 710185077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro "Display photos retrieved by contact ID can only be read."); 710285077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } 710385077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro Cursor c = mActiveDb.get().query(Tables.CONTACTS, 710485077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro new String[]{Contacts.PHOTO_FILE_ID}, null, null, null, null, null); 710585077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro try { 710685077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro if (c.moveToFirst()) { 710785077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro long photoFileId = c.getLong(0); 710885077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro return openDisplayPhotoForRead(photoFileId); 710985077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } else { 711085077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro // No profile record. 711185077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro throw new FileNotFoundException(uri.toString()); 711285077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } 7113f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 7114f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 7115f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7116f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7117f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7118bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro case CONTACTS_LOOKUP_PHOTO: 7119bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro case CONTACTS_LOOKUP_ID_PHOTO: 7120f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_DISPLAY_PHOTO: 7121f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_ID_DISPLAY_PHOTO: { 7122f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 7123f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 7124bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro "Photos retrieved by contact lookup key can only be read."); 7125f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7126f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro List<String> pathSegments = uri.getPathSegments(); 7127f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro int segmentCount = pathSegments.size(); 7128f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (segmentCount < 4) { 71295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 7130f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Missing a lookup key", uri)); 7131f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7132bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro 7133bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro boolean forDisplayPhoto = (match == CONTACTS_LOOKUP_ID_DISPLAY_PHOTO 7134bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro || match == CONTACTS_LOOKUP_DISPLAY_PHOTO); 7135f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String lookupKey = pathSegments.get(2); 7136bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro String[] projection = new String[]{Contacts.PHOTO_ID, Contacts.PHOTO_FILE_ID}; 7137f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (segmentCount == 5) { 7138f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long contactId = Long.parseLong(pathSegments.get(3)); 7139f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 7140f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForContacts(lookupQb, uri, projection); 71415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = queryWithContactIdAndLookupKey(lookupQb, mActiveDb.get(), uri, 7142f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro projection, null, null, null, null, null, 714315826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann Contacts._ID, contactId, Contacts.LOOKUP_KEY, lookupKey, null); 7144f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (c != null) { 7145f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 7146f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 7147bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro if (forDisplayPhoto) { 7148bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro long photoFileId = 7149bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro c.getLong(c.getColumnIndex(Contacts.PHOTO_FILE_ID)); 7150bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro return openDisplayPhotoForRead(photoFileId); 7151bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro } else { 7152bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro long photoId = c.getLong(c.getColumnIndex(Contacts.PHOTO_ID)); 7153bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro return openPhotoAssetFile(mActiveDb.get(), uri, mode, 7154bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro Data._ID + "=?", new String[]{String.valueOf(photoId)}); 7155bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro } 7156f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 7157f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 7158f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7159f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7160f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7161f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7162f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 7163f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForContacts(qb, uri, projection); 71645d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long contactId = lookupContactIdByLookupKey(mActiveDb.get(), lookupKey); 71655d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = qb.query(mActiveDb.get(), projection, Contacts._ID + "=?", 7166f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{String.valueOf(contactId)}, null, null, null); 7167f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 7168f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 7169bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro if (forDisplayPhoto) { 7170bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro long photoFileId = c.getLong(c.getColumnIndex(Contacts.PHOTO_FILE_ID)); 7171bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro return openDisplayPhotoForRead(photoFileId); 7172bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro } else { 7173bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro long photoId = c.getLong(c.getColumnIndex(Contacts.PHOTO_ID)); 7174bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro return openPhotoAssetFile(mActiveDb.get(), uri, mode, 7175bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro Data._ID + "=?", new String[]{String.valueOf(photoId)}); 7176bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro } 7177f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 7178f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 7179f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7180f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7181f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7182f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case RAW_CONTACTS_ID_DISPLAY_PHOTO: { 7183f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 7184f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro boolean writeable = !mode.equals("r"); 7185f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7186f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Find the primary photo data record for this raw contact. 7187f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 7188f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String[] projection = new String[]{Data._ID, Photo.PHOTO_FILE_ID}; 7189f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 71907cf50494501938f175d288077145acf49da8f171Daniel Lehmann long photoMimetypeId = mDbHelper.get().getMimeTypeId(Photo.CONTENT_ITEM_TYPE); 71915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = qb.query(mActiveDb.get(), projection, 71927cf50494501938f175d288077145acf49da8f171Daniel Lehmann Data.RAW_CONTACT_ID + "=? AND " + DataColumns.MIMETYPE_ID + "=?", 71937cf50494501938f175d288077145acf49da8f171Daniel Lehmann new String[]{String.valueOf(rawContactId), String.valueOf(photoMimetypeId)}, 7194f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null, Data.IS_PRIMARY + " DESC"); 7195f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long dataId = 0; 7196f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = 0; 7197f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 7198f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (c.getCount() >= 1) { 7199f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 7200f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro dataId = c.getLong(0); 7201f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro photoFileId = c.getLong(1); 7202f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7203f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 7204f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 7205f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7206f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7207f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // If writeable, open a writeable file descriptor that we can monitor. 7208f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // When the caller finishes writing content, we'll process the photo and 7209f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // update the data record. 7210f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (writeable) { 7211f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForWrite(rawContactId, dataId, uri, mode); 7212f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 7213f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 7214f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7215f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7216f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7217193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki case DISPLAY_PHOTO_ID: { 7218f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = ContentUris.parseId(uri); 7219f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 7220f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 7221f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by key can only be read."); 7222f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7223f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 7224f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7225f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7226e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov case DATA_ID: { 722724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long dataId = Long.parseLong(uri.getPathSegments().get(1)); 72287cf50494501938f175d288077145acf49da8f171Daniel Lehmann long photoMimetypeId = mDbHelper.get().getMimeTypeId(Photo.CONTENT_ITEM_TYPE); 72295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return openPhotoAssetFile(mActiveDb.get(), uri, mode, 72307cf50494501938f175d288077145acf49da8f171Daniel Lehmann Data._ID + "=? AND " + DataColumns.MIMETYPE_ID + "=" + photoMimetypeId, 723124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro new String[]{String.valueOf(dataId)}); 7232d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 7233d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 7234fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen case PROFILE_AS_VCARD: { 7235fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // When opening a contact as file, we pass back contents as a 7236fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // vCard-encoded stream. We build into a local buffer first, 7237fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // then pipe into MemoryFile once the exact size is known. 7238fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 7239fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(uri, localStream, null, null); 7240fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen return buildAssetFileDescriptor(localStream); 7241fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen } 724242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 7243fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen case CONTACTS_AS_VCARD: { 724442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // When opening a contact as file, we pass back contents as a 724542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // vCard-encoded stream. We build into a local buffer first, 724642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // then pipe into MemoryFile once the exact size is known. 724742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 7248fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(uri, localStream, null, null); 7249f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return buildAssetFileDescriptor(localStream); 725042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 725142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 725242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: { 725342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String lookupKeys = uri.getPathSegments().get(2); 725442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String[] loopupKeyList = lookupKeys.split(":"); 725542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final StringBuilder inBuilder = new StringBuilder(); 7256fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen Uri queryUri = Contacts.CONTENT_URI; 725742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann int index = 0; 7258fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen 7259d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann // SQLite has limits on how many parameters can be used 7260d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann // so the IDs are concatenated to a query string here instead 726142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann for (String lookupKey : loopupKeyList) { 726242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann if (index == 0) { 7263d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann inBuilder.append("("); 726442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } else { 7265d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann inBuilder.append(","); 726642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 72675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // TODO: Figure out what to do if the profile contact is in the list. 72685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long contactId = lookupContactIdByLookupKey(mActiveDb.get(), lookupKey); 726924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro inBuilder.append(contactId); 727042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann index++; 727142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 727242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann inBuilder.append(')'); 727342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String selection = Contacts._ID + " IN " + inBuilder.toString(); 7274d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 7275d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // When opening a contact as file, we pass back contents as a 7276d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // vCard-encoded stream. We build into a local buffer first, 7277d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // then pipe into MemoryFile once the exact size is known. 7278d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 7279fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(queryUri, localStream, selection, null); 7280f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return buildAssetFileDescriptor(localStream); 7281d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 7282b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 7283b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov default: 72845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new FileNotFoundException(mDbHelper.get().exceptionMessage( 72855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro "File does not exist", uri)); 7286b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 7287b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 7288b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 7289afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private AssetFileDescriptor openPhotoAssetFile(SQLiteDatabase db, Uri uri, String mode, 7290afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro String selection, String[] selectionArgs) 7291e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov throws FileNotFoundException { 7292e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov if (!"r".equals(mode)) { 72935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new FileNotFoundException(mDbHelper.get().exceptionMessage("Mode " + mode 7294e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov + " not supported.", uri)); 7295e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 7296e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov 7297e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov String sql = 7298ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann "SELECT " + Photo.PHOTO + " FROM " + Views.DATA + 7299e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov " WHERE " + selection; 730008ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood try { 7301f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor( 7302f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert DatabaseUtils.blobFileDescriptorForQuery(db, sql, selectionArgs)); 730308ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood } catch (SQLiteDoneException e) { 730408ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood // this will happen if the DB query returns no rows (i.e. contact does not exist) 730508ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood throw new FileNotFoundException(uri.toString()); 730608ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood } 7307e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 7308e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov 7309f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 7310f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Opens a display photo from the photo store for reading. 7311f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param photoFileId The display photo file ID 7312f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @return An asset file descriptor that allows the file to be read. 7313f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @throws FileNotFoundException If no photo file for the given ID exists. 7314f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 7315f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private AssetFileDescriptor openDisplayPhotoForRead(long photoFileId) 7316f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throws FileNotFoundException { 73175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PhotoStore.Entry entry = mPhotoStore.get().get(photoFileId); 7318f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (entry != null) { 7319d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro try { 7320d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro return makeAssetFileDescriptor( 7321d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro ParcelFileDescriptor.open(new File(entry.path), 7322d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro ParcelFileDescriptor.MODE_READ_ONLY), 7323d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro entry.size); 7324d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } catch (FileNotFoundException fnfe) { 7325d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 7326d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro throw fnfe; 7327d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } 7328f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 7329f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 7330f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new FileNotFoundException("No photo file found for ID " + photoFileId); 7331f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7332f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7333f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7334f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 7335f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Opens a file descriptor for a photo to be written. When the caller completes writing 7336f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * to the file (closing the output stream), the image will be parsed out and processed. 7337f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * If processing succeeds, the given raw contact ID's primary photo record will be 7338f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * populated with the inserted image (if no primary photo record exists, the data ID can 7339f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * be left as 0, and a new data record will be inserted). 7340f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param rawContactId Raw contact ID this photo entry should be associated with. 7341f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param dataId Data ID for a photo mimetype that will be updated with the inserted 7342f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * image. May be set to 0, in which case the inserted image will trigger creation 7343f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * of a new primary photo image data row for the raw contact. 7344f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param uri The URI being used to access this file. 7345f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param mode Read/write mode string. 7346f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @return An asset file descriptor the caller can use to write an image file for the 7347f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * raw contact. 7348f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 7349f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private AssetFileDescriptor openDisplayPhotoForWrite(long rawContactId, long dataId, Uri uri, 7350f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String mode) { 7351f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 7352c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro ParcelFileDescriptor[] pipeFds = ParcelFileDescriptor.createPipe(); 7353c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro PipeMonitor pipeMonitor = new PipeMonitor(rawContactId, dataId, pipeFds[0]); 7354c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro pipeMonitor.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Object[]) null); 7355c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro return new AssetFileDescriptor(pipeFds[1], 0, AssetFileDescriptor.UNKNOWN_LENGTH); 7356f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } catch (IOException ioe) { 7357f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Log.e(TAG, "Could not create temp image file in mode " + mode); 7358f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return null; 7359f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7360f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7361f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7362f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 7363c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro * Async task that monitors the given file descriptor (the read end of a pipe) for 7364c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro * the writer finishing. If the data from the pipe contains a valid image, the image 7365c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro * is either inserted into the given raw contact or updated in the given data row. 7366f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 7367c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro private class PipeMonitor extends AsyncTask<Object, Object, Object> { 7368c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro private final ParcelFileDescriptor mDescriptor; 7369f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final long mRawContactId; 7370f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final long mDataId; 7371c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro private PipeMonitor(long rawContactId, long dataId, ParcelFileDescriptor descriptor) { 7372f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mRawContactId = rawContactId; 7373f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mDataId = dataId; 7374c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro mDescriptor = descriptor; 7375f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7376f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7377f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro @Override 7378c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro protected Object doInBackground(Object... params) { 7379c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro AutoCloseInputStream is = new AutoCloseInputStream(mDescriptor); 7380f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 7381c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro Bitmap b = BitmapFactory.decodeStream(is); 7382f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (b != null) { 7383fa4db3db4146a26f154ef2e89352ad70a5415b8eDaniel Lehmann waitForAccess(mWriteAccessLatch); 7384c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki PhotoProcessor processor = new PhotoProcessor(b, getMaxDisplayPhotoDim(), 7385c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki getMaxThumbnailDim()); 7386f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7387f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Store the compressed photo in the photo store. 73885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PhotoStore photoStore = ContactsContract.isProfileId(mRawContactId) 73895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro ? mProfilePhotoStore 73905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro : mContactsPhotoStore; 73915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long photoFileId = photoStore.insert(processor); 7392f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7393c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro // Depending on whether we already had a data row to attach the photo 7394c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro // to, do an update or insert. 7395f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (mDataId != 0) { 7396f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Update the data record with the new photo. 7397f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues updateValues = new ContentValues(); 7398f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7399f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Signal that photo processing has already been handled. 7400f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(DataRowHandlerForPhoto.SKIP_PROCESSING_KEY, true); 7401f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7402f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (photoFileId != 0) { 7403f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(Photo.PHOTO_FILE_ID, photoFileId); 7404f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7405f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(Photo.PHOTO, processor.getThumbnailPhotoBytes()); 7406c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro update(ContentUris.withAppendedId(Data.CONTENT_URI, mDataId), 7407c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro updateValues, null, null); 7408f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 7409f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Insert a new primary data record with the photo. 7410f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues insertValues = new ContentValues(); 7411f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7412f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Signal that photo processing has already been handled. 7413f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(DataRowHandlerForPhoto.SKIP_PROCESSING_KEY, true); 7414f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7415f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 7416f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Data.IS_PRIMARY, 1); 7417f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (photoFileId != 0) { 7418f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Photo.PHOTO_FILE_ID, photoFileId); 7419f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7420f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Photo.PHOTO, processor.getThumbnailPhotoBytes()); 7421f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insert(RawContacts.CONTENT_URI.buildUpon() 7422f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendPath(String.valueOf(mRawContactId)) 7423f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendPath(RawContacts.Data.CONTENT_DIRECTORY).build(), 7424f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues); 7425f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7426c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro 7427f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7428c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro } catch (IOException e) { 7429c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro throw new RuntimeException(e); 7430f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7431c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro return null; 7432f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7433f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7434f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7435d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey private static final String CONTACT_MEMORY_FILE_NAME = "contactAssetFile"; 7436d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 7437d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey /** 7438f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert * Returns an {@link AssetFileDescriptor} backed by the 7439d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * contents of the given {@link ByteArrayOutputStream}. 7440d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey */ 7441f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor buildAssetFileDescriptor(ByteArrayOutputStream stream) { 7442d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey try { 7443d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey stream.flush(); 7444d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 7445d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final byte[] byteData = stream.toByteArray(); 7446d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 7447f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor( 7448f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert ParcelFileDescriptor.fromData(byteData, CONTACT_MEMORY_FILE_NAME), 7449f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert byteData.length); 7450d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } catch (IOException e) { 7451ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringert Log.w(TAG, "Problem writing stream into an ParcelFileDescriptor: " + e.toString()); 7452ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringert return null; 7453d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 7454d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 7455d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 7456f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor makeAssetFileDescriptor(ParcelFileDescriptor fd) { 7457f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor(fd, AssetFileDescriptor.UNKNOWN_LENGTH); 7458f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert } 7459f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert 7460f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor makeAssetFileDescriptor(ParcelFileDescriptor fd, long length) { 7461f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return fd != null ? new AssetFileDescriptor(fd, 0, length) : null; 7462f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert } 7463f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert 7464d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey /** 7465d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * Output {@link RawContacts} matching the requested selection in the vCard 7466d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * format to the given {@link OutputStream}. This method returns silently if 7467d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * any errors encountered. 7468d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey */ 7469fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen private void outputRawContactsAsVCard(Uri uri, OutputStream stream, 7470fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen String selection, String[] selectionArgs) { 7471d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final Context context = this.getContext(); 7472dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen int vcardconfig = VCardConfig.VCARD_TYPE_DEFAULT; 7473fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen if(uri.getBooleanQueryParameter( 7474fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen Contacts.QUERY_PARAMETER_VCARD_NO_PHOTO, false)) { 7475dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen vcardconfig |= VCardConfig.FLAG_REFRAIN_IMAGE_EXPORT; 7476dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen } 74777a2a564e9a72969999821142c821eb1b912f0d95Daisuke Miyakawa final VCardComposer composer = 7478dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen new VCardComposer(context, vcardconfig, false); 7479108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Writer writer = null; 74803711af1a5799a7ae0c8e761e13a67a9fb5878cc8Martijn Coenen final Uri rawContactsUri; 74813711af1a5799a7ae0c8e761e13a67a9fb5878cc8Martijn Coenen if (mapsToProfileDb(uri)) { 748282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Pre-authorize the URI, since the caller would have already gone through the 748382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // permission check to get here, but the pre-authorization at the top level wouldn't 748482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // carry over to the raw contact. 748582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro rawContactsUri = preAuthorizeUri(RawContactsEntity.PROFILE_CONTENT_URI); 74863711af1a5799a7ae0c8e761e13a67a9fb5878cc8Martijn Coenen } else { 74873711af1a5799a7ae0c8e761e13a67a9fb5878cc8Martijn Coenen rawContactsUri = RawContactsEntity.CONTENT_URI; 74883711af1a5799a7ae0c8e761e13a67a9fb5878cc8Martijn Coenen } 7489108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa try { 7490108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer = new BufferedWriter(new OutputStreamWriter(stream)); 74913711af1a5799a7ae0c8e761e13a67a9fb5878cc8Martijn Coenen if (!composer.init(uri, selection, selectionArgs, null, rawContactsUri)) { 7492108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.w(TAG, "Failed to init VCardComposer"); 7493108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa return; 7494108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 7495d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 7496108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa while (!composer.isAfterLast()) { 7497108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer.write(composer.createOneEntry()); 7498108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 7499108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } catch (IOException e) { 7500108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.e(TAG, "IOException: " + e); 7501108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } finally { 7502108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa composer.terminate(); 7503108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa if (writer != null) { 7504108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa try { 7505108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer.close(); 7506108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } catch (IOException e) { 7507108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.w(TAG, "IOException during closing output stream: " + e); 7508108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 7509d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 7510d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 7511d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 7512b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 75134f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 75144f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public String getType(Uri uri) { 7515415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 7516415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov waitForAccess(mReadAccessLatch); 7517415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 7518a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 75194f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 7520b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS: 7521be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov return Contacts.CONTENT_TYPE; 75222d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill case CONTACTS_LOOKUP: 7523b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS_ID: 7524b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS_LOOKUP_ID: 752524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: 7526b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Contacts.CONTENT_ITEM_TYPE; 7527f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey case CONTACTS_AS_VCARD: 752842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: 752924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: 7530f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey return Contacts.CONTENT_VCARD_TYPE; 7531f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov case CONTACTS_ID_PHOTO: 7532bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro case CONTACTS_LOOKUP_PHOTO: 7533bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro case CONTACTS_LOOKUP_ID_PHOTO: 7534f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_ID_DISPLAY_PHOTO: 7535f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_DISPLAY_PHOTO: 7536f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_ID_DISPLAY_PHOTO: 7537f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case RAW_CONTACTS_ID_DISPLAY_PHOTO: 7538193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki case DISPLAY_PHOTO_ID: 7539f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return "image/jpeg"; 7540b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case RAW_CONTACTS: 754124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: 7542be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov return RawContacts.CONTENT_TYPE; 7543b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case RAW_CONTACTS_ID: 754424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: 7545b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return RawContacts.CONTENT_ITEM_TYPE; 7546f481f22a9323fe338672f99b88b26c5f0725cd42David Brown case DATA: 754724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: 7548f481f22a9323fe338672f99b88b26c5f0725cd42David Brown return Data.CONTENT_TYPE; 7549508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey case DATA_ID: 75505d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long id = ContentUris.parseId(uri); 75515d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (ContactsContract.isProfileId(id)) { 75525d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mProfileHelper.getDataMimeType(id); 75535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 75545d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mContactsHelper.getDataMimeType(id); 75555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 755648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES: 755748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Phone.CONTENT_TYPE; 755848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 755948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Phone.CONTENT_ITEM_TYPE; 75609005e312949b4624aae6953dbdab2eaee1650835Dmitri Plotnikov case PHONE_LOOKUP: 75619005e312949b4624aae6953dbdab2eaee1650835Dmitri Plotnikov return PhoneLookup.CONTENT_TYPE; 756248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS: 756348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Email.CONTENT_TYPE; 756448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 756548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Email.CONTENT_ITEM_TYPE; 756648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS: 756748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return StructuredPostal.CONTENT_TYPE; 756848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: 756948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return StructuredPostal.CONTENT_ITEM_TYPE; 7570b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_EXCEPTIONS: 7571b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return AggregationExceptions.CONTENT_TYPE; 7572b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_EXCEPTION_ID: 7573b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return AggregationExceptions.CONTENT_ITEM_TYPE; 7574b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case SETTINGS: 7575b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Settings.CONTENT_TYPE; 7576b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_SUGGESTIONS: 7577b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Contacts.CONTENT_TYPE; 7578c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SUGGESTIONS: 7579c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return SearchManager.SUGGEST_MIME_TYPE; 7580c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SHORTCUT: 7581c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return SearchManager.SHORTCUT_MIME_TYPE; 7582d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES: 7583d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov return Directory.CONTENT_TYPE; 7584d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES_ID: 7585d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov return Directory.CONTENT_ITEM_TYPE; 7586af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki case STREAM_ITEMS: 7587af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki return StreamItems.CONTENT_TYPE; 7588af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki case STREAM_ITEMS_ID: 7589af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki return StreamItems.CONTENT_ITEM_TYPE; 7590af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki case STREAM_ITEMS_ID_PHOTOS: 7591af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki return StreamItems.StreamItemPhotos.CONTENT_TYPE; 7592af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki case STREAM_ITEMS_ID_PHOTOS_ID: 7593af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki return StreamItems.StreamItemPhotos.CONTENT_ITEM_TYPE; 7594af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki case STREAM_ITEMS_PHOTOS: 7595af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki throw new UnsupportedOperationException("Not supported for write-only URI " + uri); 759661efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov default: 759761efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov return mLegacyApiSupport.getType(uri); 75984f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 75994f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 76007e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 760109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov public String[] getDefaultProjection(Uri uri) { 760209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov final int match = sUriMatcher.match(uri); 760309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov switch (match) { 760409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS: 760509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_LOOKUP: 760609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_ID: 760709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_LOOKUP_ID: 760809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_SUGGESTIONS: 760924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: 761009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sContactsProjectionMap.getColumnNames(); 761109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 76128727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov case CONTACTS_ID_ENTITIES: 761324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_ENTITIES: 76148727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov return sEntityProjectionMap.getColumnNames(); 76158727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov 761609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_AS_VCARD: 761709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_AS_MULTI_VCARD: 761824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: 761909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sContactsVCardProjectionMap.getColumnNames(); 762009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 762109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case RAW_CONTACTS: 762209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case RAW_CONTACTS_ID: 762324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: 762424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: 762509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sRawContactsProjectionMap.getColumnNames(); 762609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 762709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DATA_ID: 762809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONES: 762909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONES_ID: 763009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case EMAILS: 763109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case EMAILS_ID: 763209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case POSTALS: 763309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case POSTALS_ID: 763424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: 763509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sDataProjectionMap.getColumnNames(); 763609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 763709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONE_LOOKUP: 763809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sPhoneLookupProjectionMap.getColumnNames(); 763909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 764009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_EXCEPTIONS: 764109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_EXCEPTION_ID: 764209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sAggregationExceptionsProjectionMap.getColumnNames(); 764309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 764409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case SETTINGS: 764509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sSettingsProjectionMap.getColumnNames(); 764609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 764709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DIRECTORIES: 764809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DIRECTORIES_ID: 764909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sDirectoryProjectionMap.getColumnNames(); 765009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 765109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov default: 765209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return null; 765309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 765409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 765509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 7656f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov private class StructuredNameLookupBuilder extends NameLookupBuilder { 7657f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 7658f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov public StructuredNameLookupBuilder(NameSplitter splitter) { 7659f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov super(splitter); 7660f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 7661f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 7662f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov @Override 7663f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov protected void insertNameLookup(long rawContactId, long dataId, int lookupType, 7664f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov String name) { 76655d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().insertNameLookup(rawContactId, dataId, lookupType, name); 7666f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 7667f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 7668f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov @Override 7669f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov protected String[] getCommonNicknameClusters(String normalizedName) { 7670d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov return mCommonNicknameCache.getCommonNicknameClusters(normalizedName); 7671f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 7672f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 7673f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 76742d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov public void appendContactFilterAsNestedQuery(StringBuilder sb, String filterParam) { 7675d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov sb.append("(" + 7676d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov "SELECT DISTINCT " + RawContacts.CONTACT_ID + 7677d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + 7678d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " JOIN " + Tables.NAME_LOOKUP + 7679d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " ON(" + RawContactsColumns.CONCRETE_ID + "=" 7680d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov + NameLookupColumns.RAW_CONTACT_ID + ")" + 7681d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " WHERE normalized_name GLOB '"); 7682e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov sb.append(NameNormalizer.normalize(filterParam)); 7683916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov sb.append("*' AND " + NameLookupColumns.NAME_TYPE + 7684916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov " IN(" + CONTACT_LOOKUP_NAME_TYPES + "))"); 7685e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 7686e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov 7687fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood public boolean isPhoneNumber(String query) { 7688fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood if (TextUtils.isEmpty(query)) { 7689fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood return false; 7690fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood } 7691fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood // assume a phone number if it has at least 1 digit 7692fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood return countPhoneNumberDigits(query) > 0; 7693fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood } 7694fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood 7695fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood /** 7696fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood * Returns the number of digitis in a phone number ignoring special characters such as '-'. 7697fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood * If the string is not a valid phone number, 0 is returned. 7698fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood */ 7699fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood public static int countPhoneNumberDigits(String query) { 7700fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood int numDigits = 0; 7701fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood int len = query.length(); 77029a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov for (int i = 0; i < len; i++) { 7703fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood char c = query.charAt(i); 7704fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood if (Character.isDigit(c)) { 7705fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood numDigits ++; 7706fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood } else if (c == '*' || c == '#' || c == 'N' || c == '.' || c == ';' 7707fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood || c == '-' || c == '(' || c == ')' || c == ' ') { 7708fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood // carry on 7709fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood } else if (c == '+' && numDigits == 0) { 7710fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood // plus before any digits is ok 7711fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood } else { 7712fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood return 0; // not a phone number 77139a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 77149a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 7715fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood return numDigits; 77169a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 77179a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 77184a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov /** 77197a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * Takes components of a name from the query parameters and returns a cursor with those 77207a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * components as well as all missing components. There is no database activity involved 77217a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * in this so the call can be made on the UI thread. 77227a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov */ 77237a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private Cursor completeName(Uri uri, String[] projection) { 77247a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov if (projection == null) { 77257a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov projection = sDataProjectionMap.getColumnNames(); 77267a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 77277a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 77287a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov ContentValues values = new ContentValues(); 7729f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov DataRowHandlerForStructuredName handler = (DataRowHandlerForStructuredName) 7730f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov getDataRowHandler(StructuredName.CONTENT_ITEM_TYPE); 77317a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 77327a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov copyQueryParamsToContentValues(values, uri, 77337a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.DISPLAY_NAME, 77347a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PREFIX, 77357a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.GIVEN_NAME, 77367a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.MIDDLE_NAME, 77377a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.FAMILY_NAME, 77387a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.SUFFIX, 77397a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_NAME, 77407a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_FAMILY_NAME, 77417a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_MIDDLE_NAME, 77427a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_GIVEN_NAME 77437a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov ); 77447a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 77457a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov handler.fixStructuredNameComponents(values, values); 77467a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 77477a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov MatrixCursor cursor = new MatrixCursor(projection); 77487a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov Object[] row = new Object[projection.length]; 77497a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov for (int i = 0; i < projection.length; i++) { 77507a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov row[i] = values.get(projection[i]); 77517a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 77527a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov cursor.addRow(row); 77537a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov return cursor; 77547a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 77557a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 77567a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private void copyQueryParamsToContentValues(ContentValues values, Uri uri, String... columns) { 77577a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov for (String column : columns) { 77587a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov String param = uri.getQueryParameter(column); 77597a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov if (param != null) { 77607a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov values.put(column, param); 77617a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 77627a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 77637a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 77647a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 77657a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 77667a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov /** 77674a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov * Inserts an argument at the beginning of the selection arg list. 77684a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov */ 77694a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov private String[] insertSelectionArg(String[] selectionArgs, String arg) { 7770b67163a1088f09c59f324350662eb18772fac6b6Evan Millar if (selectionArgs == null) { 7771b67163a1088f09c59f324350662eb18772fac6b6Evan Millar return new String[] {arg}; 7772b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } else { 7773b67163a1088f09c59f324350662eb18772fac6b6Evan Millar int newLength = selectionArgs.length + 1; 7774b67163a1088f09c59f324350662eb18772fac6b6Evan Millar String[] newSelectionArgs = new String[newLength]; 77754a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov newSelectionArgs[0] = arg; 77764a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov System.arraycopy(selectionArgs, 0, newSelectionArgs, 1, selectionArgs.length); 7777b67163a1088f09c59f324350662eb18772fac6b6Evan Millar return newSelectionArgs; 7778b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 7779b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 7780caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 77815e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar private String[] appendProjectionArg(String[] projection, String arg) { 77825e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar if (projection == null) { 77835e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar return null; 77845e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 77855e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar final int length = projection.length; 77865e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar String[] newProjection = new String[length + 1]; 77875e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar System.arraycopy(projection, 0, newProjection, 0, length); 77885e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar newProjection[length] = arg; 77895e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar return newProjection; 77905e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 77915e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 7792caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov protected Account getDefaultAccount() { 7793caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov AccountManager accountManager = AccountManager.get(getContext()); 7794caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov try { 77955f1f4a062ac34d75d2dbf586702cbeb121cf09caDmitri Plotnikov Account[] accounts = accountManager.getAccountsByType(DEFAULT_ACCOUNT_TYPE); 7796caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov if (accounts != null && accounts.length > 0) { 7797caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov return accounts[0]; 7798caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 7799caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } catch (Throwable e) { 78006f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov Log.e(TAG, "Cannot determine the default account for contacts compatibility", e); 7801caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 78026f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov return null; 7803caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 7804f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 780573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov /** 780643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * Returns true if the specified account type and data set is writable. 780773f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov */ 780849ed71913609193a00059df944f6259e9397b0bdMakoto Onuki public boolean isWritableAccountWithDataSet(String accountTypeAndDataSet) { 780943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (accountTypeAndDataSet == null) { 7810bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov return true; 7811bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov } 7812bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov 781343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Boolean writable = mAccountWritability.get(accountTypeAndDataSet); 781473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov if (writable != null) { 781573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov return writable; 781673f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov } 781773f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 7818627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov IContentService contentService = ContentResolver.getContentService(); 7819627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov try { 782043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // TODO(dsantoro): Need to update this logic to allow for sub-accounts. 7821627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov for (SyncAdapterType sync : contentService.getSyncAdapterTypes()) { 7822627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov if (ContactsContract.AUTHORITY.equals(sync.authority) && 782343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountTypeAndDataSet.equals(sync.accountType)) { 782473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov writable = sync.supportsUploading(); 782573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov break; 7826627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 7827627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 7828627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } catch (RemoteException e) { 7829627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov Log.e(TAG, "Could not acquire sync adapter types"); 7830627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 783173f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 783273f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov if (writable == null) { 783373f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov writable = false; 783473f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov } 783573f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 783643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro mAccountWritability.put(accountTypeAndDataSet, writable); 783773f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov return writable; 7838627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 7839b4e61e064b59e8076df81b061add9fb358fd2ed9Dmitri Plotnikov 7840d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 7841f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /* package */ static boolean readBooleanQueryParameter(Uri uri, String parameter, 7842f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov boolean defaultValue) { 7843f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7844f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov // Manually parse the query, which is much faster than calling uri.getQueryParameter 7845f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String query = uri.getEncodedQuery(); 7846f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query == null) { 7847f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return defaultValue; 7848f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7849f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7850f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int index = query.indexOf(parameter); 7851f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (index == -1) { 7852f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return defaultValue; 7853f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7854f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7855f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index += parameter.length(); 7856f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7857f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return !matchQueryParameter(query, index, "=0", false) 7858f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov && !matchQueryParameter(query, index, "=false", true); 7859f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7860f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7861f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private static boolean matchQueryParameter(String query, int index, String value, 7862f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov boolean ignoreCase) { 7863f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int length = value.length(); 7864f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return query.regionMatches(ignoreCase, index, value, 0, length) 7865f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov && (query.length() == index + length || query.charAt(index + length) == '&'); 7866f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7867f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7868f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /** 7869f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * A fast re-implementation of {@link Uri#getQueryParameter} 7870f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov */ 7871f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /* package */ static String getQueryParameter(Uri uri, String parameter) { 7872f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String query = uri.getEncodedQuery(); 7873f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query == null) { 7874f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 7875f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7876f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7877f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int queryLength = query.length(); 7878f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int parameterLength = parameter.length(); 7879f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7880f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String value; 7881f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int index = 0; 7882f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov while (true) { 7883f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index = query.indexOf(parameter, index); 7884f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (index == -1) { 7885f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 78865fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa } 78875fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa 78885fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // Should match against the whole parameter instead of its suffix. 78895fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // e.g. The parameter "param" must not be found in "some_param=val". 78905fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa if (index > 0) { 78915fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa char prevChar = query.charAt(index - 1); 78925fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa if (prevChar != '?' && prevChar != '&') { 78935fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // With "some_param=val1¶m=val2", we should find second "param" occurrence. 78945fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa index += parameterLength; 78955fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa continue; 78965fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa } 7897f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7898f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7899f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index += parameterLength; 7900f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7901f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (queryLength == index) { 7902f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 7903f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7904f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7905f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query.charAt(index) == '=') { 7906f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index++; 7907f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov break; 7908f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7909f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7910f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7911f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int ampIndex = query.indexOf('&', index); 7912f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (ampIndex == -1) { 7913f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov value = query.substring(index); 7914f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } else { 7915f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov value = query.substring(index, ampIndex); 7916f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 7917f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 7918f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return Uri.decode(value); 7919f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 79205dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov 79210dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov protected boolean isAggregationUpgradeNeeded() { 79220dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov if (!mContactAggregator.isEnabled()) { 79230dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov return false; 79240dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 79250dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 79265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro int version = Integer.parseInt(mContactsHelper.getProperty( 79279ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki DbProperties.AGGREGATION_ALGORITHM, "1")); 79280dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov return version < PROPERTY_AGGREGATION_ALGORITHM_VERSION; 79290dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 79300dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 7931bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void upgradeAggregationAlgorithmInBackground() { 79320dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Log.i(TAG, "Upgrading aggregation algorithm"); 79330dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov int count = 0; 7934565b62f354d8b6aadc760092a7dbf483f8bbbe17Makoto Onuki final long start = SystemClock.elapsedRealtime(); 79355d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro SQLiteDatabase db = null; 79360dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov try { 79375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 79385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db = mContactsHelper.getWritableDatabase(); 79395d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mActiveDb.set(db); 79405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.beginTransaction(); 79415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor cursor = db.query(true, 79420dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Tables.RAW_CONTACTS + " r1 JOIN " + Tables.RAW_CONTACTS + " r2", 79430dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov new String[]{"r1." + RawContacts._ID}, 79440dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov "r1." + RawContacts._ID + "!=r2." + RawContacts._ID + 79450dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov " AND r1." + RawContacts.CONTACT_ID + "=r2." + RawContacts.CONTACT_ID + 79469d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " AND r1." + RawContactsColumns.ACCOUNT_ID + 79479d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "=r2." + RawContactsColumns.ACCOUNT_ID, 79480dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov null, null, null, null, null); 79490dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov try { 79500dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov while (cursor.moveToNext()) { 79510dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov long rawContactId = cursor.getLong(0); 79520dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov mContactAggregator.markForAggregation(rawContactId, 79530dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 79540dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov count++; 79550dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 79560dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } finally { 79570dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov cursor.close(); 79580dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 79595d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactAggregator.aggregateInTransaction(mTransactionContext.get(), db); 7960bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 79615d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.setTransactionSuccessful(); 79629ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki mContactsHelper.setProperty(DbProperties.AGGREGATION_ALGORITHM, 79630dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov String.valueOf(PROPERTY_AGGREGATION_ALGORITHM_VERSION)); 79640dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } finally { 79655d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (db != null) { 79665d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.endTransaction(); 79675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 7968565b62f354d8b6aadc760092a7dbf483f8bbbe17Makoto Onuki final long end = SystemClock.elapsedRealtime(); 79690dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Log.i(TAG, "Aggregation algorithm upgraded for " + count 79700dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov + " contacts, in " + (end - start) + "ms"); 79710dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 79720dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 79739a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 7974193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki @VisibleForTesting 79759a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov boolean isPhone() { 7976193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki if (!mIsPhoneInitialized) { 7977193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki mIsPhone = new TelephonyManager(getContext()).isVoiceCapable(); 7978193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki mIsPhoneInitialized = true; 79799a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 7980193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki return mIsPhone; 79819a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 798246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 7983fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood boolean isVoiceCapable() { 7984fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood // this copied from com.android.phone.PhoneApp.onCreate(): 7985fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood 7986fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood // "voice capable" flag. 7987fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood // This flag currently comes from a resource (which is 7988fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood // overrideable on a per-product basis): 7989fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood return getContext().getResources() 7990fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood .getBoolean(com.android.internal.R.bool.config_voice_capable); 7991fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood // ...but this might eventually become a PackageManager "system 7992fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood // feature" instead, in which case we'd do something like: 7993fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood // return 7994fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood // getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS); 7995fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood } 7996fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood 799746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private boolean handleDataUsageFeedback(Uri uri) { 7998dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki final long currentTimeMillis = Clock.getInstance().currentTimeMillis(); 799946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String usageType = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 800046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] ids = uri.getLastPathSegment().trim().split(","); 8001dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki final ArrayList<Long> dataIds = new ArrayList<Long>(ids.length); 800246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 800346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa for (String id : ids) { 800446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa dataIds.add(Long.valueOf(id)); 800546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 800646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final boolean successful; 800746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (TextUtils.isEmpty(usageType)) { 800846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Log.w(TAG, "Method for data usage feedback isn't specified. Ignoring."); 800946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa successful = false; 801046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 801146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa successful = updateDataUsageStat(dataIds, usageType, currentTimeMillis) > 0; 801246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 801346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 801446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa // Handle old API. This doesn't affect the result of this entire method. 8015dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki final StringBuilder rawContactIdSelect = new StringBuilder(); 8016dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki rawContactIdSelect.append("SELECT " + Data.RAW_CONTACT_ID + " FROM " + Tables.DATA + 8017dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " WHERE " + Data._ID + " IN ("); 8018dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki for (int i = 0; i < ids.length; i++) { 8019dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki if (i > 0) rawContactIdSelect.append(","); 8020dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki rawContactIdSelect.append(ids[i]); 802146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 8022dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki rawContactIdSelect.append(")"); 802346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 8024dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki final SQLiteDatabase db = mActiveDb.get(); 8025dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki 8026dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs1[0] = String.valueOf(currentTimeMillis); 8027dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki 8028dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki db.execSQL("UPDATE " + Tables.RAW_CONTACTS + 8029dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " SET " + RawContacts.LAST_TIME_CONTACTED + "=?" + 8030dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki "," + RawContacts.TIMES_CONTACTED + "=" + 8031dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki "ifnull(" + RawContacts.TIMES_CONTACTED + ",0) + 1" + 8032dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " WHERE " + RawContacts._ID + " IN (" + rawContactIdSelect.toString() + ")" 8033dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki , mSelectionArgs1); 8034dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki db.execSQL("UPDATE " + Tables.CONTACTS + 8035dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " SET " + Contacts.LAST_TIME_CONTACTED + "=?" + 8036dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki "," + Contacts.TIMES_CONTACTED + "=" + 8037dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki "ifnull(" + Contacts.TIMES_CONTACTED + ",0) + 1" + 8038dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " WHERE " + Contacts._ID + " IN (SELECT " + RawContacts.CONTACT_ID + 8039dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " FROM " + Tables.RAW_CONTACTS + 8040dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " WHERE " + RawContacts._ID + " IN (" + rawContactIdSelect.toString() + "))" 8041dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki , mSelectionArgs1); 804246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return successful; 804346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 804446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 8045dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki private interface DataUsageStatQuery { 8046dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki String TABLE = Tables.DATA_USAGE_STAT; 8047dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki 8048dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki String[] COLUMNS = new String[] { 8049dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki DataUsageStatColumns._ID, 8050dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki }; 8051dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki int ID = 0; 8052dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki 8053dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki String SELECTION = DataUsageStatColumns.DATA_ID + " =? AND " 8054dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki + DataUsageStatColumns.USAGE_TYPE_INT + " =?"; 8055dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki } 8056dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki 805746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 805846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Update {@link Tables#DATA_USAGE_STAT}. 805946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * 806046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * @return the number of rows affected. 806146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 8062f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa @VisibleForTesting 8063f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa /* package */ int updateDataUsageStat( 8064f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa List<Long> dataIds, String type, long currentTimeMillis) { 8065dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki 8066dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki final SQLiteDatabase db = mActiveDb.get(); 8067dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki 8068dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki final String typeString = String.valueOf(getDataUsageFeedbackType(type, null)); 8069dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki final String currentTimeMillisString = String.valueOf(currentTimeMillis); 8070dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki 8071dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki for (long dataId : dataIds) { 8072dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki final String dataIdString = String.valueOf(dataId); 8073dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs2[0] = dataIdString; 8074dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs2[1] = typeString; 8075dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki final Cursor cursor = db.query(DataUsageStatQuery.TABLE, 8076dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki DataUsageStatQuery.COLUMNS, DataUsageStatQuery.SELECTION, 8077dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs2, null, null, null); 807846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 8079dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki if (cursor.moveToFirst()) { 8080dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki final long id = cursor.getLong(DataUsageStatQuery.ID); 8081dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki 8082dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs2[0] = currentTimeMillisString; 8083dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs2[1] = String.valueOf(id); 8084dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki 8085dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki db.execSQL("UPDATE " + Tables.DATA_USAGE_STAT + 8086dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " SET " + DataUsageStatColumns.TIMES_USED + "=" + 8087dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki "ifnull(" + DataUsageStatColumns.TIMES_USED +",0)+1" + 8088dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki "," + DataUsageStatColumns.LAST_TIME_USED + "=?" + 8089dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " WHERE " + DataUsageStatColumns._ID + "=?", 8090dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs2); 8091dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki } else { 8092dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs4[0] = dataIdString; 8093dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs4[1] = typeString; 8094dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs4[2] = "1"; // times used 8095dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs4[3] = currentTimeMillisString; 8096dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki db.execSQL("INSERT INTO " + Tables.DATA_USAGE_STAT + 8097dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki "(" + DataUsageStatColumns.DATA_ID + 8098dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki "," + DataUsageStatColumns.USAGE_TYPE_INT + 8099dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki "," + DataUsageStatColumns.TIMES_USED + 8100dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki "," + DataUsageStatColumns.LAST_TIME_USED + 8101dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki ") VALUES (?,?,?,?)", 8102dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs4); 810346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 810446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 8105dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki cursor.close(); 810646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 810746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 810846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 810946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return dataIds.size(); 811046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 811146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 811246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 811346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Returns a sort order String for promoting data rows (email addresses, phone numbers, etc.) 811446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * associated with a primary account. The primary account should be supplied from applications 811546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * with {@link ContactsContract#PRIMARY_ACCOUNT_NAME} and 811646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * {@link ContactsContract#PRIMARY_ACCOUNT_TYPE}. Null will be returned when the primary 811746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * account isn't available. 811846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 811946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private String getAccountPromotionSortOrder(Uri uri) { 812046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String primaryAccountName = 812146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa uri.getQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME); 812246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String primaryAccountType = 812346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa uri.getQueryParameter(ContactsContract.PRIMARY_ACCOUNT_TYPE); 812446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 812546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa // Data rows associated with primary account should be promoted. 812646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(primaryAccountName)) { 812746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa StringBuilder sb = new StringBuilder(); 812846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append("(CASE WHEN " + RawContacts.ACCOUNT_NAME + "="); 812946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DatabaseUtils.appendEscapedSQLString(sb, primaryAccountName); 813046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(primaryAccountType)) { 813146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" AND " + RawContacts.ACCOUNT_TYPE + "="); 813246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DatabaseUtils.appendEscapedSQLString(sb, primaryAccountType); 813346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 813446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" THEN 0 ELSE 1 END)"); 813546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return sb.toString(); 813646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 813746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return null; 813846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 813946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 8140b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson 8141b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson /** 8142b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson * Checks the URI for a deferred snippeting request 8143b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson * @return a boolean indicating if a deferred snippeting request is in the RI 8144b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson */ 8145b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson private boolean deferredSnippetingRequested(Uri uri) { 8146b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson String deferredSnippeting = 8147b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson getQueryParameter(uri, SearchSnippetColumns.DEFERRED_SNIPPETING_KEY); 8148b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return !TextUtils.isEmpty(deferredSnippeting) && deferredSnippeting.equals("1"); 8149b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 8150b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson 8151b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson /** 8152b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson * Checks if query is a single word or not. 8153b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson * @return a boolean indicating if the query is one word or not 8154b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson */ 8155b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson private boolean isSingleWordQuery(String query) { 8156b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return query.split(QUERY_TOKENIZER_REGEX).length == 1; 8157b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 8158b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson 8159b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson /** 8160b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson * Checks the projection for a SNIPPET column indicating that a snippet is needed 8161b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson * @return a boolean indicating if a snippet is needed or not. 8162b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson */ 8163b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson private boolean snippetNeeded(String [] projection) { 8164ac2a6e814edb3d5e5bcca28d7d3f3977a489c2edMakoto Onuki return ContactsDatabaseHelper.isInProjection(projection, SearchSnippetColumns.SNIPPET); 8165b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 81669ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki 81679ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki /** 8168084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki * Create a single row cursor for a simple, informational queries, such as 8169084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki * {@link ProviderStatus#CONTENT_URI}. 8170084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki */ 8171084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki @VisibleForTesting 8172084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki static Cursor buildSingleRowResult(String[] projection, String[] availableColumns, 8173084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki Object[] data) { 8174084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki Preconditions.checkArgument(availableColumns.length == data.length); 8175084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki if (projection == null) { 8176084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki projection = availableColumns; 8177084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki } 8178084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki final MatrixCursor c = new MatrixCursor(projection, 1); 8179084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki final RowBuilder row = c.newRow(); 8180084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki 8181084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki // It's O(n^2), but it's okay because we only have a few columns. 8182084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki for (int i = 0; i < c.getColumnCount(); i++) { 8183084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki final String column = c.getColumnName(i); 8184084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki 8185084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki boolean found = false; 8186084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki for (int j = 0; j < availableColumns.length; j++) { 8187084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki if (availableColumns[j].equals(column)) { 8188084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki row.add(data[j]); 8189084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki found = true; 8190084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki break; 8191084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki } 8192084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki } 8193084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki if (!found) { 8194084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki throw new IllegalArgumentException("Invalid column " + projection[i]); 8195084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki } 8196084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki } 8197084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki return c; 8198084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki } 8199084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki 8200084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki /** 82019ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki * @return the currently active {@link ContactsDatabaseHelper} for the current thread. 82029ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki */ 8203833072a525ea45426082d3bac0cd6ae1a8c36f22Makoto Onuki @NeededForTesting 82049ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki public ContactsDatabaseHelper getThreadActiveDatabaseHelperForTest() { 82059ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki return mDbHelper.get(); 82069ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 820735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 820835997f3fdee2984b6d5373326110eda26929001aMakoto Onuki @Override 820935997f3fdee2984b6d5373326110eda26929001aMakoto Onuki public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 821035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki pw.print("FastScrollingIndex stats:\n"); 821135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki pw.printf("request=%d miss=%d (%d%%) avg time=%dms\n", 821235997f3fdee2984b6d5373326110eda26929001aMakoto Onuki mFastScrollingIndexCacheRequestCount, 821335997f3fdee2984b6d5373326110eda26929001aMakoto Onuki mFastScrollingIndexCacheMissCount, 821435997f3fdee2984b6d5373326110eda26929001aMakoto Onuki safeDiv(mFastScrollingIndexCacheMissCount * 100, 821535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki mFastScrollingIndexCacheRequestCount), 821635997f3fdee2984b6d5373326110eda26929001aMakoto Onuki safeDiv(mTotalTimeFastScrollingIndexGenerate, mFastScrollingIndexCacheMissCount) 821735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki ); 821835997f3fdee2984b6d5373326110eda26929001aMakoto Onuki } 821935997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 822035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki private static final long safeDiv(long dividend, long divisor) { 822135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki return (divisor == 0) ? 0 : dividend / divisor; 822235997f3fdee2984b6d5373326110eda26929001aMakoto Onuki } 8223dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki 8224dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki private static final int getDataUsageFeedbackType(String type, Integer defaultType) { 8225dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki if (DataUsageFeedback.USAGE_TYPE_CALL.equals(type)) { 8226dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki return DataUsageStatColumns.USAGE_TYPE_INT_CALL; // 0 8227dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki } 8228dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki if (DataUsageFeedback.USAGE_TYPE_LONG_TEXT.equals(type)) { 8229dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki return DataUsageStatColumns.USAGE_TYPE_INT_LONG_TEXT; // 1 8230dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki } 8231dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki if (DataUsageFeedback.USAGE_TYPE_SHORT_TEXT.equals(type)) { 8232dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki return DataUsageStatColumns.USAGE_TYPE_INT_SHORT_TEXT; // 2 8233dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki } 8234dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki if (defaultType != null) { 8235dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki return defaultType; 8236dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki } 8237dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki throw new IllegalArgumentException("Invalid usage type " + type); 8238dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki } 82394f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton} 8240