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 19b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.accounts.Account; 20caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikovimport android.accounts.AccountManager; 215b4b305b9698526c6e82e0e01448b0a5642dd505Fred Quintanaimport android.accounts.OnAccountsUpdateListener; 22c9626e7befd591923c6af859ad079abba8a84e41Dianne Hackbornimport android.app.AppOpsManager; 23c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.app.SearchManager; 24568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.ContentProviderOperation; 25568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.ContentProviderResult; 266ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshiimport android.content.ContentResolver; 2735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintanaimport android.content.ContentUris; 2867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.ContentValues; 2967dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.Context; 30627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikovimport android.content.IContentService; 31568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikovimport android.content.OperationApplicationException; 323d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.content.SharedPreferences; 33627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikovimport android.content.SyncAdapterType; 3467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkeyimport android.content.UriMatcher; 350bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmannimport android.content.pm.PackageManager; 360bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmannimport android.content.pm.PackageManager.NameNotFoundException; 375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoroimport android.content.pm.ProviderInfo; 38f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringertimport android.content.res.AssetFileDescriptor; 393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmannimport android.content.res.Resources; 400bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmannimport android.content.res.Resources.NotFoundException; 41409605a187683155d9c6dbc2626b6419e3dd384eMakoto Onukiimport android.database.AbstractCursor; 424f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.Cursor; 43ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.database.DatabaseUtils; 4409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikovimport android.database.MatrixCursor; 4509c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikovimport android.database.MatrixCursor.RowBuilder; 464f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteDatabase; 4708ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwoodimport android.database.sqlite.SQLiteDoneException; 484f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.database.sqlite.SQLiteQueryBuilder; 49f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.graphics.Bitmap; 50f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.graphics.BitmapFactory; 514f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamiltonimport android.net.Uri; 52d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikovimport android.net.Uri.Builder; 53c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoroimport android.os.AsyncTask; 54bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Binder; 556ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshiimport android.os.Bundle; 5611c3f85ab75cd21a1975025c6d8614e710161baaJeff Brownimport android.os.CancellationSignal; 57bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Handler; 58bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.HandlerThread; 59bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Message; 60ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringertimport android.os.ParcelFileDescriptor; 61c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoroimport android.os.ParcelFileDescriptor.AutoCloseInputStream; 62bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Process; 63b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.os.RemoteException; 6415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikovimport android.os.StrictMode; 650dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikovimport android.os.SystemClock; 660e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport android.os.SystemProperties; 673d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikovimport android.preference.PreferenceManager; 68508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkeyimport android.provider.BaseColumns; 693de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract; 70b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport android.provider.ContactsContract.AggregationExceptions; 7182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoroimport android.provider.ContactsContract.Authorization; 728f8b122c7556350d94c2e349b3093024b0205d8dYorke Leeimport android.provider.ContactsContract.CommonDataKinds.Contactables; 7397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Email; 7497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.GroupMembership; 750992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onukiimport android.provider.ContactsContract.CommonDataKinds.Identity; 7697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Im; 7797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Nickname; 786d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Note; 7997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Organization; 8097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Phone; 8197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Photo; 824928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawaimport android.provider.ContactsContract.CommonDataKinds.SipAddress; 8397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredName; 8497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal; 85ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikovimport android.provider.ContactsContract.ContactCounts; 863de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Contacts; 875b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikovimport android.provider.ContactsContract.Contacts.AggregationSuggestions; 883de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Data; 8971340347b4862d4b1368a5d69d1667e2245952e4Daisuke Miyakawaimport android.provider.ContactsContract.DataUsageFeedback; 90d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikovimport android.provider.ContactsContract.Directory; 91f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.provider.ContactsContract.DisplayPhoto; 923de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Groups; 933de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.PhoneLookup; 941dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoroimport android.provider.ContactsContract.PhotoFiles; 950c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoroimport android.provider.ContactsContract.Profile; 9609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikovimport android.provider.ContactsContract.ProviderStatus; 973de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.RawContacts; 983711af1a5799a7ae0c8e761e13a67a9fb5878cc8Martijn Coenenimport android.provider.ContactsContract.RawContactsEntity; 99916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikovimport android.provider.ContactsContract.SearchSnippetColumns; 1003de6754a90e3682f2f52b99621d0fded060b99aeDmitri Plotnikovimport android.provider.ContactsContract.Settings; 10182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikovimport android.provider.ContactsContract.StatusUpdates; 1023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmannimport android.provider.ContactsContract.StreamItemPhotos; 103f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.provider.ContactsContract.StreamItems; 10497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.OpenableColumns; 10597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikovimport android.provider.SyncStateContract; 106a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.telephony.PhoneNumberUtils; 1079a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikovimport android.telephony.TelephonyManager; 108a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamiltonimport android.text.TextUtils; 109c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikovimport android.util.Log; 1104f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 11138210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.common.content.ProjectionMap; 11238210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.common.content.SyncStateContentProviderHelper; 113a62622b31107f97be7da9a4b79393e465b64fd36Chiao Chengimport com.android.common.io.MoreCloseables; 11438210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactLookupKey.LookupKeySegment; 11538210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.AccountsColumns; 11638210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.AggregatedPresenceColumns; 11738210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.AggregationExceptionColumns; 11838210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.Clauses; 11938210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.ContactsColumns; 12038210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.ContactsStatusUpdatesColumns; 12138210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.DataColumns; 12238210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.DataUsageStatColumns; 12338210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.DbProperties; 12438210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.GroupsColumns; 12538210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.Joins; 12638210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.NameLookupColumns; 12738210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.NameLookupType; 12838210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.PhoneLookupColumns; 12938210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.PhotoFilesColumns; 13038210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.PresenceColumns; 13138210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.Projections; 13238210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.RawContactsColumns; 13338210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.SearchIndexColumns; 13438210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.SettingsColumns; 13538210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.StatusUpdatesColumns; 13638210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.StreamItemPhotosColumns; 13738210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.StreamItemsColumns; 13838210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.Tables; 13938210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.ViewGroupsColumns; 14038210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.Views; 14138210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.SearchIndexManager.FtsQueryBuilder; 14238210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.aggregation.ContactAggregator; 14338210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.aggregation.ContactAggregator.AggregationSuggestionParameter; 14438210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.aggregation.ProfileAggregator; 14538210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.aggregation.util.CommonNicknameCache; 1468ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Chengimport com.android.providers.contacts.database.ContactsTableUtil; 1478ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Chengimport com.android.providers.contacts.database.DeletedContactsTableUtil; 14838210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.util.Clock; 14938210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.util.DbQueryUtils; 15038210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.util.NeededForTesting; 15138210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.vcard.VCardComposer; 15238210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.vcard.VCardConfig; 15338210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.google.android.collect.Lists; 15438210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.google.android.collect.Maps; 15538210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.google.android.collect.Sets; 15638210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.google.common.annotations.VisibleForTesting; 15738210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.google.common.base.Preconditions; 15838210445730ee04c351c7cc1b3800cfe23e34325Makoto Onuki 159108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawaimport java.io.BufferedWriter; 160d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.ByteArrayOutputStream; 161f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport java.io.File; 16235997f3fdee2984b6d5373326110eda26929001aMakoto Onukiimport java.io.FileDescriptor; 163b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikovimport java.io.FileNotFoundException; 164d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.IOException; 165d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkeyimport java.io.OutputStream; 166108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawaimport java.io.OutputStreamWriter; 16735997f3fdee2984b6d5373326110eda26929001aMakoto Onukiimport java.io.PrintWriter; 168108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawaimport java.io.Writer; 169d0eb93009559d095de0448907527aeb059801dc4Dave Santoroimport java.security.SecureRandom; 17042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmannimport java.text.SimpleDateFormat; 1717e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintanaimport java.util.ArrayList; 1722fe1f4f757a84cb76382c375ba3755a802c5e444Makoto Onukiimport java.util.Arrays; 1735870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport java.util.Collections; 17442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmannimport java.util.Date; 175b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikovimport java.util.HashMap; 1760e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport java.util.HashSet; 1775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikovimport java.util.List; 178622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkeyimport java.util.Locale; 179b5a4add17815167d20a90645779df34cdf45280dFred Quintanaimport java.util.Map; 1800e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriffimport java.util.Set; 181ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikovimport java.util.concurrent.CountDownLatch; 1824f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1834f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton/** 1844f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * Contacts content provider. The contract between this provider and applications 1854f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton * is defined in {@link ContactsContract}. 1864f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton */ 187078f588cef389358adabc579de00747878f3c108Dave Santoropublic class ContactsProvider2 extends AbstractContactsProvider 188078f588cef389358adabc579de00747878f3c108Dave Santoro implements OnAccountsUpdateListener { 189caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 19015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_INITIALIZE = 0; 19115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_OPEN_WRITE_ACCESS = 1; 19215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_ACCOUNTS = 3; 19315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_LOCALE = 4; 19415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private static final int BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM = 5; 19505e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_SEARCH_INDEX = 6; 19605e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_PROVIDER_STATUS = 7; 19705e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_UPDATE_DIRECTORIES = 8; 19805e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov private static final int BACKGROUND_TASK_CHANGE_LOCALE = 9; 199f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int BACKGROUND_TASK_CLEANUP_PHOTOS = 10; 2008ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng private static final int BACKGROUND_TASK_CLEAN_DELETE_LOG = 11; 201619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 2023cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** Default for the maximum number of returned aggregation suggestions. */ 2033cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov private static final int DEFAULT_MAX_SUGGESTIONS = 5; 2043cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 2053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** Limit for the maximum number of social stream items to store under a raw contact. */ 2063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int MAX_STREAM_ITEMS_PER_RAW_CONTACT = 5; 2073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 208f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** Rate limit (in ms) for photo cleanup. Do it at most once per day. */ 209f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int PHOTO_CLEANUP_RATE_LIMIT = 24 * 60 * 60 * 1000; 210f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 2113d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov /** 21282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * Default expiration duration for pre-authorized URIs. May be overridden from a secure 21382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * setting. 21482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro */ 21582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro private static final int DEFAULT_PREAUTHORIZED_URI_EXPIRATION = 5 * 60 * 1000; 21682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 217216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee private static final int USAGE_TYPE_ALL = -1; 218216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee 21982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro /** 22082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * Random URI parameter that will be appended to preauthorized URIs for uniqueness. 22182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro */ 22282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro private static final String PREAUTHORIZED_URI_TOKEN = "perm_token"; 22382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 22451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov private static final String PREF_LOCALE = "locale"; 2253d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 2260992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki private static final int PROPERTY_AGGREGATION_ALGORITHM_VERSION = 3; 2270dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 2280e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff private static final String AGGREGATE_CONTACTS = "sync.contacts.aggregate"; 2290e8520cf7f15576ce4d66202203770086fd26a71Ken Shirriff 230b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki /** 231b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki * If set to "1", we don't remove account data when accounts have been removed. 232b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki * 233b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki * This should be used sparingly; even though there are data still available, the UI 234b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki * don't know anything about them, so they won't show up in the contact filter screen, and 235b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki * the contact card/editor may get confused to see unknown custom mimetypes. 236b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki * 237b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki * We can't spell it out because a property name must be less than 32 chars. 238b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki */ 239b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki private static final String DEBUG_PROPERTY_KEEP_STALE_ACCOUNT_DATA = 240b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki "debug.contacts.ksad"; 241b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki 2425d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private static final ProfileAwareUriMatcher sUriMatcher = 2435d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new ProfileAwareUriMatcher(UriMatcher.NO_MATCH); 2444f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 24545ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa private static final String FREQUENT_ORDER_BY = DataUsageStatColumns.TIMES_USED + " DESC," 24645ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; 24745ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa 2486e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori /* package */ static final String UPDATE_TIMES_CONTACTED_CONTACTS_TABLE = 2499b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori "UPDATE " + Tables.CONTACTS + " SET " + Contacts.TIMES_CONTACTED + "=" + 250dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " ifnull(" + Contacts.TIMES_CONTACTED + ",0)+1" + 251dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " WHERE " + Contacts._ID + "=?"; 2529b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori 2536e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori /* package */ static final String UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE = 2549b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori "UPDATE " + Tables.RAW_CONTACTS + " SET " + RawContacts.TIMES_CONTACTED + "=" + 255dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " ifnull(" + RawContacts.TIMES_CONTACTED + ",0)+1 " + 256dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " WHERE " + RawContacts.CONTACT_ID + "=?"; 2579b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori 258de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa /* package */ static final String PHONEBOOK_COLLATOR_NAME = "PHONEBOOK"; 259de8f19d5cc1ef7d5bd76ede6be888dad37112966Daisuke Miyakawa 2603716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // Regex for splitting query strings - we split on any group of non-alphanumeric characters, 2613716f1447ceb21180d1301790eabd8b9453f486dDave Santoro // excluding the @ symbol. 2623716f1447ceb21180d1301790eabd8b9453f486dDave Santoro /* package */ static final String QUERY_TOKENIZER_REGEX = "[^\\w@]+"; 2633716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 264d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private static final int CONTACTS = 1000; 265d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private static final int CONTACTS_ID = 1001; 2665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_LOOKUP = 1002; 2675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_LOOKUP_ID = 1003; 268a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private static final int CONTACTS_ID_DATA = 1004; 2695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_FILTER = 1005; 2705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_STREQUENT = 1006; 2715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_STREQUENT_FILTER = 1007; 2725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private static final int CONTACTS_GROUP = 1008; 273a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private static final int CONTACTS_ID_PHOTO = 1009; 274bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_PHOTO = 1010; 275bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_ID_PHOTO = 1011; 276bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_ID_DISPLAY_PHOTO = 1012; 277bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_DISPLAY_PHOTO = 1013; 278bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_ID_DISPLAY_PHOTO = 1014; 279bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_AS_VCARD = 1015; 280bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_AS_MULTI_VCARD = 1016; 281bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_DATA = 1017; 282bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_ID_DATA = 1018; 283bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_ID_ENTITIES = 1019; 284bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_ENTITIES = 1020; 285bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_ID_ENTITIES = 1021; 286bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_ID_STREAM_ITEMS = 1022; 287bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_STREAM_ITEMS = 1023; 288bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_LOOKUP_ID_STREAM_ITEMS = 1024; 289bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro private static final int CONTACTS_FREQUENT = 1025; 290b6186821548995dce533ee502e82e9abf4c0aadcMakoto Onuki private static final int CONTACTS_DELETE_USAGE = 1026; 2914f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 2925ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov private static final int RAW_CONTACTS = 2002; 2935ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov private static final int RAW_CONTACTS_ID = 2003; 294193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private static final int RAW_CONTACTS_ID_DATA = 2004; 295193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private static final int RAW_CONTACT_ID_ENTITY = 2005; 296f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int RAW_CONTACTS_ID_DISPLAY_PHOTO = 2006; 297f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int RAW_CONTACTS_ID_STREAM_ITEMS = 2007; 29882780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro private static final int RAW_CONTACTS_ID_STREAM_ITEMS_ID = 2008; 2994f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 3006bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int DATA = 3000; 3016bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int DATA_ID = 3001; 302ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar private static final int PHONES = 3002; 30348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int PHONES_ID = 3003; 30448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int PHONES_FILTER = 3004; 30548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS = 3005; 30648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_ID = 3006; 30748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_LOOKUP = 3007; 30848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int EMAILS_FILTER = 3008; 30948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int POSTALS = 3009; 31048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov private static final int POSTALS_ID = 3010; 311e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa private static final int CALLABLES = 3011; 312e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa private static final int CALLABLES_ID = 3012; 313e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa private static final int CALLABLES_FILTER = 3013; 3148f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee private static final int CONTACTABLES = 3014; 3158f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee private static final int CONTACTABLES_FILTER = 3015; 316a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 3176bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov private static final int PHONE_LOOKUP = 4000; 3186bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 319b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final int AGGREGATION_EXCEPTIONS = 6000; 320b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov private static final int AGGREGATION_EXCEPTION_ID = 6001; 321b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 32282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private static final int STATUS_UPDATES = 7000; 32382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private static final int STATUS_UPDATES_ID = 7001; 3241f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 32531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov private static final int AGGREGATION_SUGGESTIONS = 8000; 32631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 327eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey private static final int SETTINGS = 9000; 328eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 329ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS = 10000; 330ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS_ID = 10001; 331ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey private static final int GROUPS_SUMMARY = 10003; 332ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 33335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana private static final int SYNCSTATE = 11000; 334b5a4add17815167d20a90645779df34cdf45280dFred Quintana private static final int SYNCSTATE_ID = 11001; 3355d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private static final int PROFILE_SYNCSTATE = 11002; 3365d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private static final int PROFILE_SYNCSTATE_ID = 11003; 33735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 338c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov private static final int SEARCH_SUGGESTIONS = 12001; 339c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov private static final int SEARCH_SHORTCUT = 12002; 340c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 34146b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana private static final int RAW_CONTACT_ENTITIES = 15001; 34246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 34309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private static final int PROVIDER_STATUS = 16001; 34409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 345d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final int DIRECTORIES = 17001; 346d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final int DIRECTORIES_ID = 17002; 347d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 3487a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private static final int COMPLETE_NAME = 18000; 3497a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 35024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE = 19000; 35124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_ENTITIES = 19001; 35224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_DATA = 19002; 35324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_DATA_ID = 19003; 35424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_AS_VCARD = 19004; 35524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS = 19005; 35624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID = 19006; 35724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID_DATA = 19007; 35824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro private static final int PROFILE_RAW_CONTACTS_ID_ENTITIES = 19008; 3595d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private static final int PROFILE_STATUS_UPDATES = 19009; 3603202ae2de5c5fec9f5f61003a0e6b608283e1961Dave Santoro private static final int PROFILE_RAW_CONTACT_ENTITIES = 19010; 36185077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro private static final int PROFILE_PHOTO = 19011; 36285077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro private static final int PROFILE_DISPLAY_PHOTO = 19012; 36324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 36446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final int DATA_USAGE_FEEDBACK_ID = 20001; 36546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 3663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS = 21000; 3673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_PHOTOS = 21001; 3683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID = 21002; 3693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID_PHOTOS = 21003; 3703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_ID_PHOTOS_ID = 21004; 3713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final int STREAM_ITEMS_LIMIT = 21005; 3723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 373193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private static final int DISPLAY_PHOTO_ID = 22000; 374f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private static final int PHOTO_DIMENSIONS = 22001; 375f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 3768ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng private static final int DELETED_CONTACTS = 23000; 3778ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng private static final int DELETED_CONTACTS_ID = 23001; 3788ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng 3795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Inserts into URIs in this map will direct to the profile database if the parent record's 3805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // value (looked up from the ContentValues object with the key specified by the value in this 3815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // map) is in the profile ID-space (see {@link ProfileDatabaseHelper#PROFILE_ID_SPACE}). 3825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private static final Map<Integer, String> INSERT_URI_ID_VALUE_MAP = Maps.newHashMap(); 3835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro static { 3845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(DATA, Data.RAW_CONTACT_ID); 385193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki INSERT_URI_ID_VALUE_MAP.put(RAW_CONTACTS_ID_DATA, Data.RAW_CONTACT_ID); 3865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(STATUS_UPDATES, StatusUpdates.DATA_ID); 3875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(STREAM_ITEMS, StreamItems.RAW_CONTACT_ID); 3885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(RAW_CONTACTS_ID_STREAM_ITEMS, StreamItems.RAW_CONTACT_ID); 3895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(STREAM_ITEMS_PHOTOS, StreamItemPhotos.STREAM_ITEM_ID); 3905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro INSERT_URI_ID_VALUE_MAP.put(STREAM_ITEMS_ID_PHOTOS, StreamItemPhotos.STREAM_ITEM_ID); 3915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 3925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 39336612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro // Any interactions that involve these URIs will also require the calling package to have either 39436612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro // android.permission.READ_SOCIAL_STREAM permission or android.permission.WRITE_SOCIAL_STREAM 39536612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro // permission, depending on the type of operation being performed. 39636612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro private static final List<Integer> SOCIAL_STREAM_URIS = Lists.newArrayList( 39736612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro CONTACTS_ID_STREAM_ITEMS, 39836612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro CONTACTS_LOOKUP_STREAM_ITEMS, 39936612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro CONTACTS_LOOKUP_ID_STREAM_ITEMS, 40036612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro RAW_CONTACTS_ID_STREAM_ITEMS, 40136612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro RAW_CONTACTS_ID_STREAM_ITEMS_ID, 40236612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro STREAM_ITEMS, 40336612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro STREAM_ITEMS_PHOTOS, 40436612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro STREAM_ITEMS_ID, 40536612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro STREAM_ITEMS_ID_PHOTOS, 40636612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro STREAM_ITEMS_ID_PHOTOS_ID 40736612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro ); 40836612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 409dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_FAVORITES_GROUPS_BY_RAW_CONTACT_ID = 410dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana RawContactsColumns.CONCRETE_ID + "=? AND " 4119d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + GroupsColumns.CONCRETE_ACCOUNT_ID + "=" + RawContactsColumns.CONCRETE_ACCOUNT_ID 4129d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + " AND " + Groups.FAVORITES + " != 0"; 413dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 414dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_AUTO_ADD_GROUPS_BY_RAW_CONTACT_ID = 415dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana RawContactsColumns.CONCRETE_ID + "=? AND " 4169d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + GroupsColumns.CONCRETE_ACCOUNT_ID + "=" + RawContactsColumns.CONCRETE_ACCOUNT_ID 4179d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + " AND " + Groups.AUTO_ADD + " != 0"; 418dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 419dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String[] PROJECTION_GROUP_ID 420dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana = new String[]{Tables.GROUPS + "." + Groups._ID}; 421dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 422dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_GROUPMEMBERSHIP_DATA = DataColumns.MIMETYPE_ID + "=? " 423dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "AND " + GroupMembership.GROUP_ROW_ID + "=? " 424dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + "AND " + GroupMembership.RAW_CONTACT_ID + "=?"; 425dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 426dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private static final String SELECTION_STARRED_FROM_RAW_CONTACTS = 427dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana "SELECT " + RawContacts.STARRED 428dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " FROM " + Tables.RAW_CONTACTS + " WHERE " + RawContacts._ID + "=?"; 429dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 430d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private interface DataContactsQuery { 431f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov public static final String TABLE = "data " 432f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov + "JOIN raw_contacts ON (data.raw_contact_id = raw_contacts._id) " 4339d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + "JOIN " + Tables.ACCOUNTS + " ON (" 4349d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + AccountsColumns.CONCRETE_ID + "=" + RawContactsColumns.CONCRETE_ACCOUNT_ID 4359d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + ")" 436f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov + "JOIN contacts ON (raw_contacts.contact_id = contacts._id)"; 43767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 43867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey public static final String[] PROJECTION = new String[] { 4396cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov RawContactsColumns.CONCRETE_ID, 4409d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki AccountsColumns.CONCRETE_ACCOUNT_TYPE, 4419d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki AccountsColumns.CONCRETE_ACCOUNT_NAME, 4429d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki AccountsColumns.CONCRETE_DATA_SET, 4433cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DataColumns.CONCRETE_ID, 444f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov ContactsColumns.CONCRETE_ID 445ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey }; 446ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 447d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov public static final int RAW_CONTACT_ID = 0; 4486802030a777c0c3ba1dc029c534cca4784260632Dave Santoro public static final int ACCOUNT_TYPE = 1; 4496802030a777c0c3ba1dc029c534cca4784260632Dave Santoro public static final int ACCOUNT_NAME = 2; 45043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro public static final int DATA_SET = 3; 45143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro public static final int DATA_ID = 4; 45243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro public static final int CONTACT_ID = 5; 453ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 4541f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 455f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov interface RawContactsQuery { 4569d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki String TABLE = Tables.RAW_CONTACTS_JOIN_ACCOUNTS; 45719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 45819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka String[] COLUMNS = new String[] { 459ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov RawContacts.DELETED, 4609d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki RawContactsColumns.ACCOUNT_ID, 4619d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki AccountsColumns.CONCRETE_ACCOUNT_TYPE, 4629d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki AccountsColumns.CONCRETE_ACCOUNT_NAME, 4639d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki AccountsColumns.CONCRETE_DATA_SET, 46419cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka }; 46519cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 46619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka int DELETED = 0; 4679d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki int ACCOUNT_ID = 1; 4689d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki int ACCOUNT_TYPE = 2; 4699d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki int ACCOUNT_NAME = 3; 4709d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki int DATA_SET = 4; 47119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 47219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka 473c76cdd0723b99f478c9ba5329d14a971cd8dfb3dCostin Manolache public static final String DEFAULT_ACCOUNT_TYPE = "com.google"; 474caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 47571e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov /** Sql where statement for filtering on groups. */ 47671e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov private static final String CONTACTS_IN_GROUP_SELECT = 47771e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov Contacts._ID + " IN " 47871e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + RawContacts.CONTACT_ID 47971e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.RAW_CONTACTS 48071e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " WHERE " + RawContactsColumns.CONCRETE_ID + " IN " 48171e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + DataColumns.CONCRETE_RAW_CONTACT_ID 48271e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.DATA_JOIN_MIMETYPES 4837cf50494501938f175d288077145acf49da8f171Daniel Lehmann + " WHERE " + DataColumns.MIMETYPE_ID + "=?" 4847cf50494501938f175d288077145acf49da8f171Daniel Lehmann + " AND " + GroupMembership.GROUP_ROW_ID + "=" 48571e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + "(SELECT " + Tables.GROUPS + "." + Groups._ID 48671e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " FROM " + Tables.GROUPS 48771e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov + " WHERE " + Groups.TITLE + "=?)))"; 48871e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov 489a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** Sql for updating DIRTY flag on multiple raw contacts */ 490a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov private static final String UPDATE_RAW_CONTACT_SET_DIRTY_SQL = 491a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov "UPDATE " + Tables.RAW_CONTACTS + 492a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " SET " + RawContacts.DIRTY + "=1" + 493a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " WHERE " + RawContacts._ID + " IN ("; 494a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 495a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** Sql for updating VERSION on multiple raw contacts */ 496a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov private static final String UPDATE_RAW_CONTACT_SET_VERSION_SQL = 497a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov "UPDATE " + Tables.RAW_CONTACTS + 498a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " SET " + RawContacts.VERSION + " = " + RawContacts.VERSION + " + 1" + 499a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov " WHERE " + RawContacts._ID + " IN ("; 500a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 501c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov // Current contacts - those contacted within the last 3 days (in seconds) 50263630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki private static final long LAST_TIME_USED_CURRENT_SEC = 3 * 24 * 60 * 60; 503c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 504c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov // Recent contacts - those contacted within the last 30 days (in seconds) 50563630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki private static final long LAST_TIME_USED_RECENT_SEC = 30 * 24 * 60 * 60; 506c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 50763630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki private static final String TIME_SINCE_LAST_USED_SEC = 508f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa "(strftime('%s', 'now') - " + DataUsageStatColumns.LAST_TIME_USED + "/1000)"; 509f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa 51063630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki private static final String SORT_BY_DATA_USAGE = 51163630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki "(CASE WHEN " + TIME_SINCE_LAST_USED_SEC + " < " + LAST_TIME_USED_CURRENT_SEC + 51263630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki " THEN 0 " + 51363630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki " WHEN " + TIME_SINCE_LAST_USED_SEC + " < " + LAST_TIME_USED_RECENT_SEC + 51463630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki " THEN 1 " + 51563630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki " ELSE 2 END), " + 51663630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki DataUsageStatColumns.TIMES_USED + " DESC"; 51763630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki 518c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov /* 519c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov * Sorting order for email address suggestions: first starred, then the rest. 5204c4ea154ba08f2c772d645a092c3ffa4497295dfDaisuke Miyakawa * Within the two groups: 5214c4ea154ba08f2c772d645a092c3ffa4497295dfDaisuke Miyakawa * - three buckets: very recently contacted, then fairly recently contacted, then the rest. 5224c4ea154ba08f2c772d645a092c3ffa4497295dfDaisuke Miyakawa * Within each of the bucket - descending count of times contacted (both for data row and for 5234c4ea154ba08f2c772d645a092c3ffa4497295dfDaisuke Miyakawa * contact row). 5244c4ea154ba08f2c772d645a092c3ffa4497295dfDaisuke Miyakawa * If all else fails, in_visible_group, alphabetical. 52546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * (Super)primary email address is returned before other addresses for the same contact. 526c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov */ 527c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov private static final String EMAIL_FILTER_SORT_ORDER = 5282262f0ccc800b93a9d1e63c55654ca3aaf5e7d1cDaisuke Miyakawa Contacts.STARRED + " DESC, " 529dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng + Data.IS_SUPER_PRIMARY + " DESC, " 53063630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki + SORT_BY_DATA_USAGE + ", " 5314c4ea154ba08f2c772d645a092c3ffa4497295dfDaisuke Miyakawa + Contacts.IN_VISIBLE_GROUP + " DESC, " 53246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa + Contacts.DISPLAY_NAME + ", " 533c6e28121e4c522c31c96e0ea97b66012cc571160Chiao Cheng + Data.CONTACT_ID + ", " 534c6e28121e4c522c31c96e0ea97b66012cc571160Chiao Cheng + Data.IS_PRIMARY + " DESC"; 53546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 53646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** Currently same as {@link #EMAIL_FILTER_SORT_ORDER} */ 53746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private static final String PHONE_FILTER_SORT_ORDER = EMAIL_FILTER_SORT_ORDER; 538c918b0d3ab17a45a392748f43956b927c83eb402Dmitri Plotnikov 539916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** Name lookup types used for contact filtering */ 540916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov private static final String CONTACT_LOOKUP_NAME_TYPES = 541916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov NameLookupType.NAME_COLLATION_KEY + "," + 542916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov NameLookupType.EMAIL_BASED_NICKNAME + "," + 54392ddc5cdc4d89ee2c6e861ae7b3a3a913ffa0100Dmitri Plotnikov NameLookupType.NICKNAME; 544916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 545f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov /** 546f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov * If any of these columns are used in a Data projection, there is no point in 547f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov * using the DISTINCT keyword, which can negatively affect performance. 548f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov */ 549f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov private static final String[] DISTINCT_DATA_PROHIBITING_COLUMNS = { 550f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data._ID, 551f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data.RAW_CONTACT_ID, 552f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov Data.NAME_RAW_CONTACT_ID, 553f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.ACCOUNT_NAME, 554f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.ACCOUNT_TYPE, 55543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.DATA_SET, 55643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 557f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.DIRTY, 558f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.NAME_VERIFIED, 559f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.SOURCE_ID, 560f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov RawContacts.VERSION, 561f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov }; 562916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 563f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsColumns = ProjectionMap.builder() 564f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CUSTOM_RINGTONE) 565f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME) 566f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME_ALTERNATIVE) 567f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.DISPLAY_NAME_SOURCE) 568f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.IN_VISIBLE_GROUP) 569f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.LAST_TIME_CONTACTED) 570f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.LOOKUP_KEY) 571f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHONETIC_NAME) 572f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHONETIC_NAME_STYLE) 573f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.PHOTO_ID) 574f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .add(Contacts.PHOTO_FILE_ID) 5753d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(Contacts.PHOTO_URI) 5763d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(Contacts.PHOTO_THUMBNAIL_URI) 577f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SEND_TO_VOICEMAIL) 578f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SORT_KEY_ALTERNATIVE) 579f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.SORT_KEY_PRIMARY) 580a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner .add(ContactsColumns.PHONEBOOK_LABEL_PRIMARY) 581a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner .add(ContactsColumns.PHONEBOOK_BUCKET_PRIMARY) 582a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner .add(ContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE) 583a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner .add(ContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE) 584f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.STARRED) 585f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.TIMES_CONTACTED) 586cf832869bcf91b8037d8b7f510a3a213b30764a3Dmitri Plotnikov .add(Contacts.HAS_PHONE_NUMBER) 5878ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng .add(Contacts.CONTACT_LAST_UPDATED_TIMESTAMP) 588f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 589f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 590f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsPresenceColumns = ProjectionMap.builder() 591f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_PRESENCE, 592f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.PRESENCE) 593f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_CHAT_CAPABILITY, 594f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + "." + StatusUpdates.CHAT_CAPABILITY) 595f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS, 596f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS) 597f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_TIMESTAMP, 598f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 599f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_RES_PACKAGE, 600f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 601f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_LABEL, 602f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_LABEL) 603f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_ICON, 604f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_ICON) 605f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 606f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 607f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sSnippetColumns = ProjectionMap.builder() 60803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov .add(SearchSnippetColumns.SNIPPET) 609f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 610f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 611f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactColumns = ProjectionMap.builder() 612f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.ACCOUNT_NAME) 613f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.ACCOUNT_TYPE) 61443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(RawContacts.DATA_SET) 61543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(RawContacts.ACCOUNT_TYPE_AND_DATA_SET) 616f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DIRTY) 617f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.NAME_VERIFIED) 618f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SOURCE_ID) 619f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.VERSION) 620f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 621f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 622f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactSyncColumns = ProjectionMap.builder() 623f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC1) 624f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC2) 625f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC3) 626f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SYNC4) 627f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 628f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 629f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataColumns = ProjectionMap.builder() 630f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA1) 631f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA2) 632f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA3) 633f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA4) 634f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA5) 635f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA6) 636f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA7) 637f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA8) 638f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA9) 639f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA10) 640f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA11) 641f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA12) 642f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA13) 643f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA14) 644f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA15) 645f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.DATA_VERSION) 646f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.IS_PRIMARY) 647f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.IS_SUPER_PRIMARY) 648f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.MIMETYPE) 649f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.RES_PACKAGE) 650f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC1) 651f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC2) 652f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC3) 653f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.SYNC4) 654f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(GroupMembership.GROUP_SOURCE_ID) 655f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 656f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 657f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactPresenceColumns = ProjectionMap.builder() 658f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_PRESENCE, 659f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + '.' + StatusUpdates.PRESENCE) 660f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_CHAT_CAPABILITY, 661f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov Tables.AGGREGATED_PRESENCE + '.' + StatusUpdates.CHAT_CAPABILITY) 662f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS, 663f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS) 664f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_TIMESTAMP, 665f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 666f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_RES_PACKAGE, 667f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 668f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_LABEL, 669f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_LABEL) 670f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.CONTACT_STATUS_ICON, 671f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov ContactsStatusUpdatesColumns.CONCRETE_STATUS_ICON) 672f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 673f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 674f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataPresenceColumns = ProjectionMap.builder() 675f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.PRESENCE, Tables.PRESENCE + "." + StatusUpdates.PRESENCE) 676f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.CHAT_CAPABILITY, Tables.PRESENCE + "." + StatusUpdates.CHAT_CAPABILITY) 677f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS, StatusUpdatesColumns.CONCRETE_STATUS) 678f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_TIMESTAMP, StatusUpdatesColumns.CONCRETE_STATUS_TIMESTAMP) 679f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_RES_PACKAGE, StatusUpdatesColumns.CONCRETE_STATUS_RES_PACKAGE) 680f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_LABEL, StatusUpdatesColumns.CONCRETE_STATUS_LABEL) 681f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.STATUS_ICON, StatusUpdatesColumns.CONCRETE_STATUS_ICON) 682f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 683f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 684216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee private static final ProjectionMap sDataUsageColumns = ProjectionMap.builder() 685216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee .add(Data.TIMES_USED, Tables.DATA_USAGE_STAT + "." + Data.TIMES_USED) 686216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee .add(Data.LAST_TIME_USED, Tables.DATA_USAGE_STAT + "." + Data.LAST_TIME_USED) 687216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee .build(); 688216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee 689038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana /** Contains just BaseColumns._COUNT */ 690f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sCountProjectionMap = ProjectionMap.builder() 691f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(BaseColumns._COUNT, "COUNT(*)") 692f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 693f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 694e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov /** Contains just the contacts columns */ 695f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsProjectionMap = ProjectionMap.builder() 696f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts._ID) 697f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.HAS_PHONE_NUMBER) 698f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.NAME_RAW_CONTACT_ID) 69924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(Contacts.IS_USER_PROFILE) 700f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 701f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsPresenceColumns) 702f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 703f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 704916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** Contains just the contacts columns */ 705f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsProjectionWithSnippetMap = ProjectionMap.builder() 706f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 707f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sSnippetColumns) 708f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 709916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 7105e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar /** Used for pushing starred contacts to the top of a times contacted list **/ 711f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStrequentStarredProjectionMap = ProjectionMap.builder() 712f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 71363630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki .add(DataUsageStatColumns.TIMES_USED, String.valueOf(Long.MAX_VALUE)) 71463630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki .add(DataUsageStatColumns.LAST_TIME_USED, String.valueOf(Long.MAX_VALUE)) 715f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 716f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 717f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStrequentFrequentProjectionMap = ProjectionMap.builder() 718f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsProjectionMap) 71963630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki .add(DataUsageStatColumns.TIMES_USED, 72063630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki "SUM(" + DataUsageStatColumns.CONCRETE_TIMES_USED + ")") 72163630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki .add(DataUsageStatColumns.LAST_TIME_USED, 72263630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki "MAX(" + DataUsageStatColumns.CONCRETE_LAST_TIME_USED + ")") 723f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 724f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 7254928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa /** 7264928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Used for Strequent Uri with {@link ContactsContract#STREQUENT_PHONE_ONLY}, which allows 7274928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * users to obtain part of Data columns. Right now Starred part just returns NULL for 7284928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * those data columns (frequent part should return real ones in data table). 7294928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa **/ 7304928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa private static final ProjectionMap sStrequentPhoneOnlyStarredProjectionMap 7314928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa = ProjectionMap.builder() 7324928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .addAll(sContactsProjectionMap) 73363630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki .add(DataUsageStatColumns.TIMES_USED, 73463630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki String.valueOf(Long.MAX_VALUE)) 73563630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki .add(DataUsageStatColumns.LAST_TIME_USED, String.valueOf(Long.MAX_VALUE)) 7364928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.NUMBER, "NULL") 7374928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.TYPE, "NULL") 7384928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.LABEL, "NULL") 7394928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .build(); 7404928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 7414928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa /** 7424928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Used for Strequent Uri with {@link ContactsContract#STREQUENT_PHONE_ONLY}, which allows 7434928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * users to obtain part of Data columns. We hard-code {@link Contacts#IS_USER_PROFILE} to NULL, 7444928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * because sContactsProjectionMap specifies a field that doesn't exist in the view behind the 7454928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * query that uses this projection map. 7464928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa **/ 7474928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa private static final ProjectionMap sStrequentPhoneOnlyFrequentProjectionMap 7484928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa = ProjectionMap.builder() 7494928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .addAll(sContactsProjectionMap) 75063630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki .add(DataUsageStatColumns.TIMES_USED, DataUsageStatColumns.CONCRETE_TIMES_USED) 75163630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki .add(DataUsageStatColumns.LAST_TIME_USED, DataUsageStatColumns.CONCRETE_LAST_TIME_USED) 7524928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.NUMBER) 7534928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.TYPE) 7544928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Phone.LABEL) 7554928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .add(Contacts.IS_USER_PROFILE, "NULL") 7564928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa .build(); 7574928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 758f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey /** Contains just the contacts vCard columns */ 759f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sContactsVCardProjectionMap = ProjectionMap.builder() 760fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen .add(Contacts._ID) 761f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(OpenableColumns.DISPLAY_NAME, Contacts.DISPLAY_NAME + " || '.vcf'") 762f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(OpenableColumns.SIZE, "NULL") 763f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 764f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 765ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov /** Contains just the raw contacts columns */ 766f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawContactsProjectionMap = ProjectionMap.builder() 767f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts._ID) 768f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 769f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DELETED) 770f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_PRIMARY) 771f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_ALTERNATIVE) 772f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DISPLAY_NAME_SOURCE) 773f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.PHONETIC_NAME) 774f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.PHONETIC_NAME_STYLE) 775f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SORT_KEY_PRIMARY) 776f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SORT_KEY_ALTERNATIVE) 777a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner .add(RawContactsColumns.PHONEBOOK_LABEL_PRIMARY) 778a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner .add(RawContactsColumns.PHONEBOOK_BUCKET_PRIMARY) 779a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner .add(RawContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE) 780a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner .add(RawContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE) 781f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.TIMES_CONTACTED) 782f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.LAST_TIME_CONTACTED) 783f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CUSTOM_RINGTONE) 784f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.SEND_TO_VOICEMAIL) 785f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.STARRED) 786f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.AGGREGATION_MODE) 78724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 788f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 789f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 790f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 791f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 792a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** Contains the columns from the raw entity view*/ 793f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sRawEntityProjectionMap = ProjectionMap.builder() 794f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts._ID) 795f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 796f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.Entity.DATA_ID) 797f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.DELETED) 798f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.STARRED) 79924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 800f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 801f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 802f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 803f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 804f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 805a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** Contains the columns from the contact entity view*/ 806f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sEntityProjectionMap = ProjectionMap.builder() 807f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity._ID) 808f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.CONTACT_ID) 809f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.RAW_CONTACT_ID) 810f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.DATA_ID) 811f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.NAME_RAW_CONTACT_ID) 812f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Contacts.Entity.DELETED) 81324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(Contacts.IS_USER_PROFILE) 814f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 815f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 816f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 817f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactSyncColumns) 818f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 819f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 820f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 821f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 82258795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda /** Contains columns in PhoneLookup which are not contained in the data view. */ 82358795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda private static final ProjectionMap sSipLookupColumns = ProjectionMap.builder() 82458795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda .add(PhoneLookup.NUMBER, SipAddress.SIP_ADDRESS) 82558795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda .add(PhoneLookup.TYPE, "0") 82658795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda .add(PhoneLookup.LABEL, "NULL") 82758795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda .add(PhoneLookup.NORMALIZED_NUMBER, "NULL") 82858795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda .build(); 82958795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda 8304a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov /** Contains columns from the data view */ 831f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDataProjectionMap = ProjectionMap.builder() 832f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data._ID) 833f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.RAW_CONTACT_ID) 834f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.CONTACT_ID) 835f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data.NAME_RAW_CONTACT_ID) 83624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 837f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 838f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 839f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sRawContactColumns) 840f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 841f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 842216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee .addAll(sDataUsageColumns) 843f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 844f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 84558795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda /** Contains columns from the data view used for SIP address lookup. */ 84658795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda private static final ProjectionMap sDataSipLookupProjectionMap = ProjectionMap.builder() 84758795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda .addAll(sDataProjectionMap) 84858795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda .addAll(sSipLookupColumns) 84958795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda .build(); 85058795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda 8515e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov /** Contains columns from the data view */ 852f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDistinctDataProjectionMap = ProjectionMap.builder() 853f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Data._ID, "MIN(" + Data._ID + ")") 854f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(RawContacts.CONTACT_ID) 85524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro .add(RawContacts.RAW_CONTACT_IS_USER_PROFILE) 856f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataColumns) 857f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sDataPresenceColumns) 858f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactsColumns) 859f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sContactPresenceColumns) 860216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee .addAll(sDataUsageColumns) 861f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 862f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 86358795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda /** Contains columns from the data view used for SIP address lookup. */ 86458795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda private static final ProjectionMap sDistinctDataSipLookupProjectionMap = ProjectionMap.builder() 86558795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda .addAll(sDistinctDataProjectionMap) 86658795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda .addAll(sSipLookupColumns) 86758795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda .build(); 86858795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda 8699261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** Contains the data and contacts columns, for joined tables */ 870f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sPhoneLookupProjectionMap = ProjectionMap.builder() 871f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup._ID, "contacts_view." + Contacts._ID) 872f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LOOKUP_KEY, "contacts_view." + Contacts.LOOKUP_KEY) 873f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.DISPLAY_NAME, "contacts_view." + Contacts.DISPLAY_NAME) 874f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LAST_TIME_CONTACTED, "contacts_view." + Contacts.LAST_TIME_CONTACTED) 875f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.TIMES_CONTACTED, "contacts_view." + Contacts.TIMES_CONTACTED) 876f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.STARRED, "contacts_view." + Contacts.STARRED) 877f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.IN_VISIBLE_GROUP, "contacts_view." + Contacts.IN_VISIBLE_GROUP) 878f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.PHOTO_ID, "contacts_view." + Contacts.PHOTO_ID) 8793d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(PhoneLookup.PHOTO_URI, "contacts_view." + Contacts.PHOTO_URI) 8803d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov .add(PhoneLookup.PHOTO_THUMBNAIL_URI, "contacts_view." + Contacts.PHOTO_THUMBNAIL_URI) 881f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.CUSTOM_RINGTONE, "contacts_view." + Contacts.CUSTOM_RINGTONE) 882f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.HAS_PHONE_NUMBER, "contacts_view." + Contacts.HAS_PHONE_NUMBER) 883f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.SEND_TO_VOICEMAIL, "contacts_view." + Contacts.SEND_TO_VOICEMAIL) 884f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.NUMBER, Phone.NUMBER) 885f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.TYPE, Phone.TYPE) 886f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PhoneLookup.LABEL, Phone.LABEL) 8872530512f639c4979fd7371c7dd25dd67e8118124Bai Tao .add(PhoneLookup.NORMALIZED_NUMBER, Phone.NORMALIZED_NUMBER) 888f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 889f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 890ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** Contains the just the {@link Groups} columns */ 891f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sGroupsProjectionMap = ProjectionMap.builder() 892f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups._ID) 893f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.ACCOUNT_NAME) 894f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.ACCOUNT_TYPE) 89543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(Groups.DATA_SET) 89643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro .add(Groups.ACCOUNT_TYPE_AND_DATA_SET) 897f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SOURCE_ID) 898f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.DIRTY) 899f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.VERSION) 900f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.RES_PACKAGE) 901f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.TITLE) 902f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.TITLE_RES) 903f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.GROUP_VISIBLE) 904f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYSTEM_ID) 905f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.DELETED) 906f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.NOTES) 907f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SHOULD_SYNC) 908f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.FAVORITES) 909f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.AUTO_ADD) 910c039cfb78c40730483fd71178df63ada5826a315Dmitri Plotnikov .add(Groups.GROUP_IS_READ_ONLY) 911f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC1) 912f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC2) 913f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC3) 914f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SYNC4) 915f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 916f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 9178ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng private static final ProjectionMap sDeletedContactsProjectionMap = ProjectionMap.builder() 9188ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng .add(ContactsContract.DeletedContacts.CONTACT_ID) 9198ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng .add(ContactsContract.DeletedContacts.CONTACT_DELETED_TIMESTAMP) 9208ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng .build(); 9218ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng 92223ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki /** 92323ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki * Contains {@link Groups} columns along with summary details. 92423ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki * 92523ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki * Note {@link Groups#SUMMARY_COUNT} doesn't exist in groups/view_groups. 92623ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki * When we detect this column being requested, we join {@link Joins#GROUP_MEMBER_COUNT} to 92723ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki * generate it. 92818b09495f5f37b38ff2e1c965e087dfde68c27fbMakoto Onuki * 92918b09495f5f37b38ff2e1c965e087dfde68c27fbMakoto Onuki * TODO Support SUMMARY_GROUP_COUNT_PER_ACCOUNT too. See also queryLocal(). 93023ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki */ 931f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sGroupsSummaryProjectionMap = ProjectionMap.builder() 932f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .addAll(sGroupsProjectionMap) 93323ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki .add(Groups.SUMMARY_COUNT, "ifnull(group_member_count, 0)") 934f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Groups.SUMMARY_WITH_PHONES, 935f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa "(SELECT COUNT(" + ContactsColumns.CONCRETE_ID + ") FROM " 936f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + Tables.CONTACTS_JOIN_RAW_CONTACTS_DATA_FILTERED_BY_GROUPMEMBERSHIP 937f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa + " WHERE " + Contacts.HAS_PHONE_NUMBER + ")") 93818b09495f5f37b38ff2e1c965e087dfde68c27fbMakoto Onuki .add(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT, "0") // Always returns 0 for now. 939f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 940f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 941373f7d2adc36680c31ff33e9ee12be865af6b5fbDmitri Plotnikov /** Contains the agg_exceptions columns */ 942f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sAggregationExceptionsProjectionMap = ProjectionMap.builder() 943f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptionColumns._ID, Tables.AGGREGATION_EXCEPTIONS + "._id") 944f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.TYPE) 945f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.RAW_CONTACT_ID1) 946f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(AggregationExceptions.RAW_CONTACT_ID2) 947f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 948f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 949eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey /** Contains the agg_exceptions columns */ 950f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sSettingsProjectionMap = ProjectionMap.builder() 951f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ACCOUNT_NAME) 952f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ACCOUNT_TYPE) 953f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro .add(Settings.DATA_SET) 954f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_VISIBLE) 955f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.SHOULD_SYNC) 956f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.ANY_UNSYNCED, 957f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(CASE WHEN MIN(" + Settings.SHOULD_SYNC 958f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + ",(SELECT " 959f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "(CASE WHEN MIN(" + Groups.SHOULD_SYNC + ") IS NULL" 960f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN 1" 961f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE MIN(" + Groups.SHOULD_SYNC + ")" 962f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " END)" 9639d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + " FROM " + Views.GROUPS 9649d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + " WHERE " + ViewGroupsColumns.CONCRETE_ACCOUNT_NAME + "=" 965f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + SettingsColumns.CONCRETE_ACCOUNT_NAME 9669d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + " AND " + ViewGroupsColumns.CONCRETE_ACCOUNT_TYPE + "=" 967f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro + SettingsColumns.CONCRETE_ACCOUNT_TYPE 9689d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + " AND ((" + ViewGroupsColumns.CONCRETE_DATA_SET + " IS NULL AND " 969f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro + SettingsColumns.CONCRETE_DATA_SET + " IS NULL) OR (" 9709d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki + ViewGroupsColumns.CONCRETE_DATA_SET + "=" 971f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro + SettingsColumns.CONCRETE_DATA_SET + "))))=0" 972f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN 1" 973f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE 0" 974f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " END)") 975f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_COUNT, 976f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(SELECT COUNT(*)" 977f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM (SELECT 1" 978f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS 979f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID 980f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " HAVING " + Clauses.HAVING_NO_GROUPS 981f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "))") 982f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Settings.UNGROUPED_WITH_PHONES, 983f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(SELECT COUNT(*)" 984f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM (SELECT 1" 985f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " FROM " + Tables.SETTINGS_JOIN_RAW_CONTACTS_DATA_MIMETYPES_CONTACTS 986f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " WHERE " + Contacts.HAS_PHONE_NUMBER 987f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " GROUP BY " + Clauses.GROUP_BY_ACCOUNT_CONTACT_ID 988f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " HAVING " + Clauses.HAVING_NO_GROUPS 989f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + "))") 990f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 991f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 99282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov /** Contains StatusUpdates columns */ 993f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sStatusUpdatesProjectionMap = ProjectionMap.builder() 994f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(PresenceColumns.RAW_CONTACT_ID) 995f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.DATA_ID, DataColumns.CONCRETE_ID) 996f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.IM_ACCOUNT) 997f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.IM_HANDLE) 998f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.PROTOCOL) 999f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // We cannot allow a null in the custom protocol field, because SQLite3 does not 1000f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov // properly enforce uniqueness of null values 1001f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.CUSTOM_PROTOCOL, 1002f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov "(CASE WHEN " + StatusUpdates.CUSTOM_PROTOCOL + "=''" 1003f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " THEN NULL" 1004f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov + " ELSE " + StatusUpdates.CUSTOM_PROTOCOL + " END)") 1005f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.PRESENCE) 1006f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.CHAT_CAPABILITY) 1007f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS) 1008f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_TIMESTAMP) 1009f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_RES_PACKAGE) 1010f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_ICON) 1011f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(StatusUpdates.STATUS_LABEL) 1012f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 1013f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov 10143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** Contains StreamItems columns */ 10153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final ProjectionMap sStreamItemsProjectionMap = ProjectionMap.builder() 10169b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems._ID) 10179b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems.CONTACT_ID) 1018af10329f85c5d8c4196c495a9f0f9a6c6ecbc231Daniel Lehmann .add(StreamItems.CONTACT_LOOKUP_KEY) 10199b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems.ACCOUNT_NAME) 10209b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems.ACCOUNT_TYPE) 10219b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems.DATA_SET) 10223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RAW_CONTACT_ID) 10239b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann .add(StreamItems.RAW_CONTACT_SOURCE_ID) 10243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_PACKAGE) 10253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_ICON) 10263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RES_LABEL) 10273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.TEXT) 10283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.TIMESTAMP) 10293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.COMMENTS) 10300bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItems.SYNC1) 10310bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItems.SYNC2) 10320bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItems.SYNC3) 10330bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItems.SYNC4) 10343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .build(); 10353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 10363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private static final ProjectionMap sStreamItemPhotosProjectionMap = ProjectionMap.builder() 10373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos._ID, StreamItemPhotosColumns.CONCRETE_ID) 10383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItems.RAW_CONTACT_ID) 10390bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItems.RAW_CONTACT_SOURCE_ID, RawContactsColumns.CONCRETE_SOURCE_ID) 10403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.STREAM_ITEM_ID) 10413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .add(StreamItemPhotos.SORT_INDEX) 10426802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .add(StreamItemPhotos.PHOTO_FILE_ID) 10436802030a777c0c3ba1dc029c534cca4784260632Dave Santoro .add(StreamItemPhotos.PHOTO_URI, 10446802030a777c0c3ba1dc029c534cca4784260632Dave Santoro "'" + DisplayPhoto.CONTENT_URI + "'||'/'||" + StreamItemPhotos.PHOTO_FILE_ID) 10451dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.HEIGHT) 10461dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.WIDTH) 10471dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro .add(PhotoFiles.FILESIZE) 10480bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItemPhotos.SYNC1) 10490bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItemPhotos.SYNC2) 10500bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItemPhotos.SYNC3) 10510bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann .add(StreamItemPhotos.SYNC4) 10523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann .build(); 10533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 1054d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** Contains {@link Directory} columns */ 1055f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov private static final ProjectionMap sDirectoryProjectionMap = ProjectionMap.builder() 1056f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory._ID) 1057f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.PACKAGE_NAME) 1058f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.TYPE_RESOURCE_ID) 1059f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.DISPLAY_NAME) 1060f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.DIRECTORY_AUTHORITY) 1061f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.ACCOUNT_TYPE) 1062f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.ACCOUNT_NAME) 1063f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .add(Directory.EXPORT_SUPPORT) 1064778d92d4dce5f76c649e2aca9d00d3f214cd7643Dmitri Plotnikov .add(Directory.SHORTCUT_SUPPORT) 1065778d92d4dce5f76c649e2aca9d00d3f214cd7643Dmitri Plotnikov .add(Directory.PHOTO_SUPPORT) 1066f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov .build(); 10677e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 10689705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // where clause to update the status_updates table 10699705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private static final String WHERE_CLAUSE_FOR_STATUS_UPDATES_TABLE = 10709705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdatesColumns.DATA_ID + " IN (SELECT Distinct " + StatusUpdates.DATA_ID + 10719705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori " FROM " + Tables.STATUS_UPDATES + " LEFT OUTER JOIN " + Tables.PRESENCE + 10729705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori " ON " + StatusUpdatesColumns.DATA_ID + " = " + StatusUpdates.DATA_ID + " WHERE "; 10739705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 10742526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov private static final String[] EMPTY_STRING_ARRAY = new String[0]; 10752526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov 1076bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov /** 1077bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov * Notification ID for failure to import contacts. 1078bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov */ 1079bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov private static final int LEGACY_IMPORT_FAILED_NOTIFICATION = 1; 108051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 108103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_START_MATCH = "["; 108203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_END_MATCH = "]"; 108303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final String DEFAULT_SNIPPET_ARG_ELLIPSIS = "..."; 108403197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private static final int DEFAULT_SNIPPET_ARG_MAX_TOKENS = -10; 108503197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 1086193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private boolean mIsPhoneInitialized; 1087193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private boolean mIsPhone; 10889a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 1089193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private final StringBuilder mSb = new StringBuilder(); 1090193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private final String[] mSelectionArgs1 = new String[1]; 1091193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private final String[] mSelectionArgs2 = new String[2]; 1092dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki private final String[] mSelectionArgs3 = new String[3]; 1093dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki private final String[] mSelectionArgs4 = new String[4]; 1094193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private final ArrayList<String> mSelectionArgs = Lists.newArrayList(); 10952526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov 1096f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private Account mAccount; 1097f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 10984f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton static { 10994f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton // Contacts URI matching table 1100a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final UriMatcher matcher = sUriMatcher; 1101d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts", CONTACTS); 1102d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID); 1103a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_ID_DATA); 1104a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/entities", CONTACTS_ID_ENTITIES); 11053653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions", 11063653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov AGGREGATION_SUGGESTIONS); 11072d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions/*", 11082d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov AGGREGATION_SUGGESTIONS); 1109a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/photo", CONTACTS_ID_PHOTO); 1110f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/display_photo", 1111f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_ID_DISPLAY_PHOTO); 11123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/stream_items", 11133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_ID_STREAM_ITEMS); 1114c9e6d75562621a3dee26a99c2b082e2fd9b0c8b3Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter", CONTACTS_FILTER); 11155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter/*", CONTACTS_FILTER); 11165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*", CONTACTS_LOOKUP); 11172149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/data", CONTACTS_LOOKUP_DATA); 1118bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/photo", 1119bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro CONTACTS_LOOKUP_PHOTO); 11205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_LOOKUP_ID); 11212149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/data", 11222149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov CONTACTS_LOOKUP_ID_DATA); 1123bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/photo", 1124bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro CONTACTS_LOOKUP_ID_PHOTO); 1125f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/display_photo", 1126f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_LOOKUP_DISPLAY_PHOTO); 1127f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/display_photo", 1128f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro CONTACTS_LOOKUP_ID_DISPLAY_PHOTO); 1129a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/entities", 1130a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov CONTACTS_LOOKUP_ENTITIES); 1131a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/entities", 1132a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov CONTACTS_LOOKUP_ID_ENTITIES); 11333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/stream_items", 11343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_LOOKUP_STREAM_ITEMS); 11353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/stream_items", 11363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann CONTACTS_LOOKUP_ID_STREAM_ITEMS); 1137f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_vcard/*", CONTACTS_AS_VCARD); 113842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "contacts/as_multi_vcard/*", 113942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann CONTACTS_AS_MULTI_VCARD); 11405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/", CONTACTS_STREQUENT); 1141ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/strequent/filter/*", 1142ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov CONTACTS_STREQUENT_FILTER); 11435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "contacts/group/*", CONTACTS_GROUP); 114445ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "contacts/frequent", CONTACTS_FREQUENT); 1145b6186821548995dce533ee502e82e9abf4c0aadcMakoto Onuki matcher.addURI(ContactsContract.AUTHORITY, "contacts/delete_usage", CONTACTS_DELETE_USAGE); 11463653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov 11475ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts", RAW_CONTACTS); 11485ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#", RAW_CONTACTS_ID); 1149193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/data", RAW_CONTACTS_ID_DATA); 1150f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/display_photo", 1151f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro RAW_CONTACTS_ID_DISPLAY_PHOTO); 1152193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/entity", RAW_CONTACT_ID_ENTITY); 11533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/stream_items", 11543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann RAW_CONTACTS_ID_STREAM_ITEMS); 115582780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/stream_items/#", 115682780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro RAW_CONTACTS_ID_STREAM_ITEMS_ID); 115746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 115846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana matcher.addURI(ContactsContract.AUTHORITY, "raw_contact_entities", RAW_CONTACT_ENTITIES); 1159b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 11604f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data", DATA); 11614f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "data/#", DATA_ID); 1162ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones", PHONES); 116348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/phones/#", PHONES_ID); 11645e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter", PHONES_FILTER); 1165ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/phones/filter/*", PHONES_FILTER); 11664a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails", EMAILS); 116748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/#", EMAILS_ID); 11681dac83b8fa58944acfd00f44e717a7dddc659d2dDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup", EMAILS_LOOKUP); 11695e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/lookup/*", EMAILS_LOOKUP); 11705e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter", EMAILS_FILTER); 11714a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/emails/filter/*", EMAILS_FILTER); 1172ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar matcher.addURI(ContactsContract.AUTHORITY, "data/postals", POSTALS); 117348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "data/postals/#", POSTALS_ID); 117446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** "*" is in CSV form with data ids ("123,456,789") */ 117546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "data/usagefeedback/*", DATA_USAGE_FEEDBACK_ID); 1176e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "data/callables/", CALLABLES); 1177e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "data/callables/#", CALLABLES_ID); 1178e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "data/callables/filter", CALLABLES_FILTER); 1179e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa matcher.addURI(ContactsContract.AUTHORITY, "data/callables/filter/*", CALLABLES_FILTER); 11801f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 11818f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee matcher.addURI(ContactsContract.AUTHORITY, "data/contactables/", CONTACTABLES); 11828f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee matcher.addURI(ContactsContract.AUTHORITY, "data/contactables/filter", CONTACTABLES_FILTER); 11838f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee matcher.addURI(ContactsContract.AUTHORITY, "data/contactables/filter/*", 11848f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee CONTACTABLES_FILTER); 11858f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee 1186ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups", GROUPS); 1187ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups/#", GROUPS_ID); 1188ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "groups_summary", GROUPS_SUMMARY); 1189ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 119035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH, SYNCSTATE); 1191b5a4add17815167d20a90645779df34cdf45280dFred Quintana matcher.addURI(ContactsContract.AUTHORITY, SyncStateContentProviderHelper.PATH + "/#", 1192b5a4add17815167d20a90645779df34cdf45280dFred Quintana SYNCSTATE_ID); 11935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/" + SyncStateContentProviderHelper.PATH, 11945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PROFILE_SYNCSTATE); 11955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, 11965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro "profile/" + SyncStateContentProviderHelper.PATH + "/#", 11975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PROFILE_SYNCSTATE_ID); 119835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1199a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton matcher.addURI(ContactsContract.AUTHORITY, "phone_lookup/*", PHONE_LOOKUP); 1200b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions", 1201b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTIONS); 1202b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "aggregation_exceptions/*", 1203b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov AGGREGATION_EXCEPTION_ID); 12044f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1205eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey matcher.addURI(ContactsContract.AUTHORITY, "settings", SETTINGS); 1206eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 120782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "status_updates", STATUS_UPDATES); 120882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "status_updates/#", STATUS_UPDATES_ID); 12091f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 1210c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, 1211c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SUGGESTIONS); 1212c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", 1213c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SUGGESTIONS); 12142d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill matcher.addURI(ContactsContract.AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*", 1215c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov SEARCH_SHORTCUT); 1216c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 121709c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "provider_status", PROVIDER_STATUS); 1218d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 1219d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "directories", DIRECTORIES); 1220d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "directories/#", DIRECTORIES_ID); 12217a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 12227a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov matcher.addURI(ContactsContract.AUTHORITY, "complete_name", COMPLETE_NAME); 122324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 122424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile", PROFILE); 122524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/entities", PROFILE_ENTITIES); 122624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/data", PROFILE_DATA); 122724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/data/#", PROFILE_DATA_ID); 122885077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/photo", PROFILE_PHOTO); 122985077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/display_photo", PROFILE_DISPLAY_PHOTO); 123024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/as_vcard", PROFILE_AS_VCARD); 123124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts", PROFILE_RAW_CONTACTS); 123224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#", 123324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID); 123424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#/data", 123524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID_DATA); 123624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contacts/#/entity", 123724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro PROFILE_RAW_CONTACTS_ID_ENTITIES); 12385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/status_updates", 12395d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PROFILE_STATUS_UPDATES); 12403202ae2de5c5fec9f5f61003a0e6b608283e1961Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "profile/raw_contact_entities", 12413202ae2de5c5fec9f5f61003a0e6b608283e1961Dave Santoro PROFILE_RAW_CONTACT_ENTITIES); 124246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 12433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items", STREAM_ITEMS); 12443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/photo", STREAM_ITEMS_PHOTOS); 12453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#", STREAM_ITEMS_ID); 12463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#/photo", STREAM_ITEMS_ID_PHOTOS); 12473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items/#/photo/#", 12483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann STREAM_ITEMS_ID_PHOTOS_ID); 12493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann matcher.addURI(ContactsContract.AUTHORITY, "stream_items_limit", STREAM_ITEMS_LIMIT); 12503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 1251193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki matcher.addURI(ContactsContract.AUTHORITY, "display_photo/#", DISPLAY_PHOTO_ID); 1252f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro matcher.addURI(ContactsContract.AUTHORITY, "photo_dimensions", PHOTO_DIMENSIONS); 12538ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng 12548ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng matcher.addURI(ContactsContract.AUTHORITY, "deleted_contacts", DELETED_CONTACTS); 12558ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng matcher.addURI(ContactsContract.AUTHORITY, "deleted_contacts/#", DELETED_CONTACTS_ID); 125619a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov } 125719a0962e62c13a5e5f8e5b4eed5e30d3477894b4Dmitri Plotnikov 1258d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static class DirectoryInfo { 1259d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String authority; 1260d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String accountName; 1261d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String accountType; 1262d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 1263d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 1264d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** 1265d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov * Cached information about contact directories. 1266d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov */ 12674458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov private HashMap<String, DirectoryInfo> mDirectoryCache = new HashMap<String, DirectoryInfo>(); 12684458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov private boolean mDirectoryCacheValid = false; 1269d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 12703cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov /** 12719d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * An entry in group id cache. 12729d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * 12739d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * TODO: Move this and {@link #mGroupIdCache} to {@link DataRowHandlerForGroupMembership}. 1274ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov */ 1275e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov public static class GroupIdCacheEntry { 12769d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki long accountId; 1277ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov String sourceId; 1278ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov long groupId; 1279ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov } 1280a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov 12819d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki /** 12829d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * Map from group source IDs to lists of {@link GroupIdCacheEntry}s. 12839d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * 12849d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * We don't need a soft cache for groups - the assumption is that there will only 12859d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * be a small number of contact groups. The cache is keyed off source id. The value 12869d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * is a list of groups with this group id. 12879d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki */ 1288e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov private HashMap<String, ArrayList<GroupIdCacheEntry>> mGroupIdCache = Maps.newHashMap(); 1289e8b3427e88d28a00cdcad7d296544f2459dfc629Dmitri Plotnikov 129024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro /** 12915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Sub-provider for handling profile requests against the profile database. 12925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 12935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private ProfileProvider mProfileProvider; 1294f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 12954097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov private NameSplitter mNameSplitter; 1296f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov private NameLookupBuilder mNameLookupBuilder; 1297315dd702d006aedf2f867d3fe49e31e05e4f9a16Dmitri Plotnikov 1298622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey private PostalSplitter mPostalSplitter; 1299622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey 130072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov private ContactDirectoryManager mContactDirectoryManager; 13015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 1302078f588cef389358adabc579de00747878f3c108Dave Santoro // The database tag to use for representing the contacts DB in contacts transactions. 1303078f588cef389358adabc579de00747878f3c108Dave Santoro /* package */ static final String CONTACTS_DB_TAG = "contacts"; 1304078f588cef389358adabc579de00747878f3c108Dave Santoro 1305078f588cef389358adabc579de00747878f3c108Dave Santoro // The database tag to use for representing the profile DB in contacts transactions. 1306078f588cef389358adabc579de00747878f3c108Dave Santoro /* package */ static final String PROFILE_DB_TAG = "profile"; 1307078f588cef389358adabc579de00747878f3c108Dave Santoro 13085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 13096efb7db26598b105342d02207e0ca1c8725c10daDave Santoro * The thread-local holder of the active transaction. Shared between this and the profile 13106efb7db26598b105342d02207e0ca1c8725c10daDave Santoro * provider, to keep transactions on both databases synchronized. 13116efb7db26598b105342d02207e0ca1c8725c10daDave Santoro */ 13126efb7db26598b105342d02207e0ca1c8725c10daDave Santoro private final ThreadLocal<ContactsTransaction> mTransactionHolder = 13136efb7db26598b105342d02207e0ca1c8725c10daDave Santoro new ThreadLocal<ContactsTransaction>(); 13146efb7db26598b105342d02207e0ca1c8725c10daDave Santoro 13155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // This variable keeps track of whether the current operation is intended for the profile DB. 13165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<Boolean> mInProfileMode = new ThreadLocal<Boolean>(); 13175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 13185d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Separate data row handler instances for contact data and profile data. 13195d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private HashMap<String, DataRowHandler> mDataRowHandlers; 13205d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private HashMap<String, DataRowHandler> mProfileDataRowHandlers; 13215d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 13225d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Depending on whether the action being performed is for the profile, we will use one of two 13235d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // database helper instances. 13245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<ContactsDatabaseHelper> mDbHelper = 13255d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new ThreadLocal<ContactsDatabaseHelper>(); 13265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private ContactsDatabaseHelper mContactsHelper; 13275d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private ProfileDatabaseHelper mProfileHelper; 13285d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 13295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Depending on whether the action being performed is for the profile or not, we will use one of 13305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // two aggregator instances. 13315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<ContactAggregator> mAggregator = new ThreadLocal<ContactAggregator>(); 1332622e0a2f00b3de248926ec9e89b11a6425919819Jeff Sharkey private ContactAggregator mContactAggregator; 13335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private ContactAggregator mProfileAggregator; 13345d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 13355d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Depending on whether the action being performed is for the profile or not, we will use one of 13365d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // two photo store instances (with their files stored in separate subdirectories). 13375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<PhotoStore> mPhotoStore = new ThreadLocal<PhotoStore>(); 13385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private PhotoStore mContactsPhotoStore; 13395d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private PhotoStore mProfilePhotoStore; 13405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 13415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // The active transaction context will switch depending on the operation being performed. 13425d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Both transaction contexts will be cleared out when a batch transaction is started, and 13435d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // each will be processed separately when a batch transaction completes. 1344193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private final TransactionContext mContactTransactionContext = new TransactionContext(false); 1345193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private final TransactionContext mProfileTransactionContext = new TransactionContext(true); 13465d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private final ThreadLocal<TransactionContext> mTransactionContext = 13475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new ThreadLocal<TransactionContext>(); 13485d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 134982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Duration in milliseconds that pre-authorized URIs will remain valid. 135082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro private long mPreAuthorizedUriDuration; 135182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 135282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Map of single-use pre-authorized URIs to expiration times. 1353193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private final Map<Uri, Long> mPreAuthorizedUris = Maps.newHashMap(); 135482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 1355d0eb93009559d095de0448907527aeb059801dc4Dave Santoro // Random number generator. 1356193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private final SecureRandom mRandom = new SecureRandom(); 135782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 1358f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov private LegacyApiSupport mLegacyApiSupport; 1359a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov private GlobalSearchSupport mGlobalSearchSupport; 1360d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov private CommonNicknameCache mCommonNicknameCache; 1361f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov private SearchIndexManager mSearchIndexManager; 1362a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 1363193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private final ContentValues mValues = new ContentValues(); 1364193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki private final HashMap<String, Boolean> mAccountWritability = Maps.newHashMap(); 136520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 136609c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private int mProviderStatus = ProviderStatus.STATUS_NORMAL; 13673826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private boolean mProviderStatusUpdateNeeded; 136809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov private long mEstimatedStorageRequirement = 0; 136915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private volatile CountDownLatch mReadAccessLatch; 137015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private volatile CountDownLatch mWriteAccessLatch; 137115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private boolean mAccountUpdateListenerRegistered; 1372bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private boolean mOkToOpenAccess = true; 137373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 13741a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey private boolean mVisibleTouched = false; 13751a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey 137681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov private boolean mSyncToNetwork; 137781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 13784cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao private Locale mCurrentLocale; 13793826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private int mContactsAccountCount; 1380d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov 1381bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private HandlerThread mBackgroundThread; 1382bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov private Handler mBackgroundHandler; 1383bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1384f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private long mLastPhotoCleanup = 0; 1385f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 138635997f3fdee2984b6d5373326110eda26929001aMakoto Onuki private FastScrollingIndexCache mFastScrollingIndexCache; 138735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 138835997f3fdee2984b6d5373326110eda26929001aMakoto Onuki // Stats about FastScrollingIndex. 138935997f3fdee2984b6d5373326110eda26929001aMakoto Onuki private int mFastScrollingIndexCacheRequestCount; 139035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki private int mFastScrollingIndexCacheMissCount; 139135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki private long mTotalTimeFastScrollingIndexGenerate; 139235997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 13934f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 13944f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public boolean onCreate() { 1395663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) { 1396663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki Log.d(Constants.PERFORMANCE_TAG, "ContactsProvider2.onCreate start"); 1397663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki } 1398de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov super.onCreate(); 1399c9626e7befd591923c6af859ad079abba8a84e41Dianne Hackborn setAppOps(AppOpsManager.OP_READ_CONTACTS, AppOpsManager.OP_WRITE_CONTACTS); 1400ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov try { 1401ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov return initialize(); 1402ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } catch (RuntimeException e) { 1403ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov Log.e(TAG, "Cannot start provider", e); 1404887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki // In production code we don't want to throw here, so that phone will still work 1405887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki // in low storage situations. 1406887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki // See I5c88a3024ff1c5a06b5756b29a2d903f8f6a2531 1407887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki if (shouldThrowExceptionForInitializationError()) { 1408887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki throw e; 1409887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki } 1410ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov return false; 1411663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki } finally { 1412663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) { 1413663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki Log.d(Constants.PERFORMANCE_TAG, "ContactsProvider2.onCreate finish"); 1414663b8b8ce7a29fb2796dc6431f2cd5992934f315Makoto Onuki } 1415ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } 1416ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov } 141735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 1418887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki protected boolean shouldThrowExceptionForInitializationError() { 1419887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki return false; 1420887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki } 1421887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki 1422ea029fd79225640e49be82457b83b6b3a0279fd0Dmitri Plotnikov private boolean initialize() { 142315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov StrictMode.setThreadPolicy( 142415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()); 142515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 14262d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner mFastScrollingIndexCache = FastScrollingIndexCache.getInstance(getContext()); 142735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 1428078f588cef389358adabc579de00747878f3c108Dave Santoro mContactsHelper = getDatabaseHelper(getContext()); 14295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.set(mContactsHelper); 1430078f588cef389358adabc579de00747878f3c108Dave Santoro 1431078f588cef389358adabc579de00747878f3c108Dave Santoro // Set up the DB helper for keeping transactions serialized. 1432ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki setDbHelperToSerializeOn(mContactsHelper, CONTACTS_DB_TAG, this); 1433078f588cef389358adabc579de00747878f3c108Dave Santoro 143472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov mContactDirectoryManager = new ContactDirectoryManager(this); 1435a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov mGlobalSearchSupport = new GlobalSearchSupport(this); 143665ce381c2bb7ddcc3e7d3b8f5f7095831be97603Dmitri Plotnikov 1437bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov // The provider is closed for business until fully initialized 143815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch = new CountDownLatch(1); 143915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch = new CountDownLatch(1); 144072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 1441bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundThread = new HandlerThread("ContactsProviderWorker", 1442bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov Process.THREAD_PRIORITY_BACKGROUND); 1443bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundThread.start(); 1444bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler = new Handler(mBackgroundThread.getLooper()) { 1445bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov @Override 1446bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov public void handleMessage(Message msg) { 1447bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov performBackgroundTask(msg.what, msg.obj); 1448bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1449bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov }; 14502a0d5f9c628e723261bc5198e0fd606076b76b74Dmitri Plotnikov 14515d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Set up the sub-provider for handling profiles. 1452ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki mProfileProvider = newProfileProvider(); 1453ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki mProfileProvider.setDbHelperToSerializeOn(mContactsHelper, CONTACTS_DB_TAG, this); 14545d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro ProviderInfo profileInfo = new ProviderInfo(); 14555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro profileInfo.readPermission = "android.permission.READ_PROFILE"; 14565d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro profileInfo.writePermission = "android.permission.WRITE_PROFILE"; 14575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileProvider.attachInfo(getContext(), profileInfo); 1458078f588cef389358adabc579de00747878f3c108Dave Santoro mProfileHelper = mProfileProvider.getDatabaseHelper(getContext()); 14595d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 146082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Initialize the pre-authorized URI duration. 14617b4a5d522df5282cd7dac655b4c673c06d1f449bJeff Sharkey mPreAuthorizedUriDuration = DEFAULT_PREAUTHORIZED_URI_EXPIRATION; 146282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 146315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_INITIALIZE); 1464bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_ACCOUNTS); 1465bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_LOCALE); 1466bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM); 146705e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_SEARCH_INDEX); 1468bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_PROVIDER_STATUS); 146915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_OPEN_WRITE_ACCESS); 1470f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 14713826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 147249d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov return true; 14734f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 14744f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 1475767e109d6f08749b9ed202c0b71f3459eaae2115Dmitri Plotnikov /** 147651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * (Re)allocates all locale-sensitive structures. 147751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov */ 147804b7ce026c73077d9d982742bc662ea4b3ac74e7Dmitri Plotnikov private void initForDefaultLocale() { 147915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Context context = getContext(); 14805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mLegacyApiSupport = new LegacyApiSupport(context, mContactsHelper, this, 14815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mGlobalSearchSupport); 14824cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mCurrentLocale = getLocale(); 14835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mNameSplitter = mContactsHelper.createNameSplitter(); 14844cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mNameLookupBuilder = new StructuredNameLookupBuilder(mNameSplitter); 14854cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao mPostalSplitter = new PostalSplitter(mCurrentLocale); 14865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mCommonNicknameCache = new CommonNicknameCache(mContactsHelper.getReadableDatabase()); 1487a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner ContactLocaleUtils.setLocale(mCurrentLocale); 14885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactAggregator = new ContactAggregator(this, mContactsHelper, 148915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov createPhotoPriorityResolver(context), mNameSplitter, mCommonNicknameCache); 14905b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov mContactAggregator.setEnabled(SystemProperties.getBoolean(AGGREGATE_CONTACTS, true)); 14915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileAggregator = new ProfileAggregator(this, mProfileHelper, 14925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro createPhotoPriorityResolver(context), mNameSplitter, mCommonNicknameCache); 14935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileAggregator.setEnabled(SystemProperties.getBoolean(AGGREGATE_CONTACTS, true)); 1494f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov mSearchIndexManager = new SearchIndexManager(this); 14955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 14965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsPhotoStore = new PhotoStore(getContext().getFilesDir(), mContactsHelper); 14975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfilePhotoStore = new PhotoStore(new File(getContext().getFilesDir(), "profile"), 14985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileHelper); 14995b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov 1500bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mDataRowHandlers = new HashMap<String, DataRowHandler>(); 15015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro initDataRowHandlers(mDataRowHandlers, mContactsHelper, mContactAggregator, 15025d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsPhotoStore); 15035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileDataRowHandlers = new HashMap<String, DataRowHandler>(); 15045d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro initDataRowHandlers(mProfileDataRowHandlers, mProfileHelper, mProfileAggregator, 15055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfilePhotoStore); 15065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 15075d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Set initial thread-local state variables for the Contacts DB. 15085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 15095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 1510bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 15115d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private void initDataRowHandlers(Map<String, DataRowHandler> handlerMap, 15125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro ContactsDatabaseHelper dbHelper, ContactAggregator contactAggregator, 15135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PhotoStore photoStore) { 15145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Context context = getContext(); 15155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Email.CONTENT_ITEM_TYPE, 15165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForEmail(context, dbHelper, contactAggregator)); 15175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Im.CONTENT_ITEM_TYPE, 15185d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForIm(context, dbHelper, contactAggregator)); 15195d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Organization.CONTENT_ITEM_TYPE, 15205d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForOrganization(context, dbHelper, contactAggregator)); 15215d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Phone.CONTENT_ITEM_TYPE, 15225d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForPhoneNumber(context, dbHelper, contactAggregator)); 15235d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Nickname.CONTENT_ITEM_TYPE, 15245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForNickname(context, dbHelper, contactAggregator)); 15255d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(StructuredName.CONTENT_ITEM_TYPE, 15265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForStructuredName(context, dbHelper, contactAggregator, 1527bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mNameSplitter, mNameLookupBuilder)); 15285d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(StructuredPostal.CONTENT_ITEM_TYPE, 15295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForStructuredPostal(context, dbHelper, contactAggregator, 1530bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mPostalSplitter)); 15315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(GroupMembership.CONTENT_ITEM_TYPE, 15325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForGroupMembership(context, dbHelper, contactAggregator, 1533bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mGroupIdCache)); 15345d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Photo.CONTENT_ITEM_TYPE, 153587426833d4c2c626e032f5d0b84a08b58024daf6Makoto Onuki new DataRowHandlerForPhoto(context, dbHelper, contactAggregator, photoStore, 153687426833d4c2c626e032f5d0b84a08b58024daf6Makoto Onuki getMaxDisplayPhotoDim(), getMaxThumbnailDim())); 15375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handlerMap.put(Note.CONTENT_ITEM_TYPE, 15385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new DataRowHandlerForNote(context, dbHelper, contactAggregator)); 15390992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki handlerMap.put(Identity.CONTENT_ITEM_TYPE, 15400992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki new DataRowHandlerForIdentity(context, dbHelper, contactAggregator)); 1541bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1542bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1543193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki @VisibleForTesting 1544193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki PhotoPriorityResolver createPhotoPriorityResolver(Context context) { 1545bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov return new PhotoPriorityResolver(context); 1546bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1547bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1548bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void scheduleBackgroundTask(int task) { 1549bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler.sendEmptyMessage(task); 1550bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1551bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1552bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void scheduleBackgroundTask(int task, Object arg) { 1553bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mBackgroundHandler.sendMessage(mBackgroundHandler.obtainMessage(task, arg)); 1554bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1555bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1556bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void performBackgroundTask(int task, Object arg) { 1557ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki // Make sure we operate on the contacts db by default. 1558ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki switchToContactMode(); 1559bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov switch (task) { 156015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov case BACKGROUND_TASK_INITIALIZE: { 156115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov initForDefaultLocale(); 156215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch.countDown(); 156315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mReadAccessLatch = null; 156415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov break; 156515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 156615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 156715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov case BACKGROUND_TASK_OPEN_WRITE_ACCESS: { 1568bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (mOkToOpenAccess) { 156915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch.countDown(); 157015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mWriteAccessLatch = null; 1571bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1572bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1573bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1574bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1575bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_ACCOUNTS: { 157615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Context context = getContext(); 157715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (!mAccountUpdateListenerRegistered) { 157815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov AccountManager.get(context).addOnAccountsUpdatedListener(this, null, false); 157915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov mAccountUpdateListenerRegistered = true; 158015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 158115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 15825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Update the accounts for both the contacts and profile DBs. 158315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Account[] accounts = AccountManager.get(context).getAccounts(); 15845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 1585bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov boolean accountsChanged = updateAccountsInBackground(accounts); 15865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToProfileMode(); 15875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro accountsChanged |= updateAccountsInBackground(accounts); 15885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 1589ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki switchToContactMode(); 1590ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 1591bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateContactsAccountCount(accounts); 1592bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateDirectoriesInBackground(accountsChanged); 1593bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1594bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1595bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1596bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_LOCALE: { 1597bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateLocaleInBackground(); 1598bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1599bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1600bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1601fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov case BACKGROUND_TASK_CHANGE_LOCALE: { 1602fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov changeLocaleInBackground(); 1603fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov break; 1604fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1605fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 1606bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM: { 1607bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (isAggregationUpgradeNeeded()) { 1608bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov upgradeAggregationAlgorithmInBackground(); 16099ff2587608416b4378767141ad396f51f23040a7Makoto Onuki invalidateFastScrollingIndexCache(); 1610bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1611bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1612bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1613bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 161405e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_SEARCH_INDEX: { 161505e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov updateSearchIndexInBackground(); 161605e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov break; 161705e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov } 161805e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov 1619bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_PROVIDER_STATUS: { 1620bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov updateProviderStatus(); 1621bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1622bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1623bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov 1624bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov case BACKGROUND_TASK_UPDATE_DIRECTORIES: { 1625bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (arg != null) { 1626bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.onPackageChanged((String) arg); 1627bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1628bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov break; 1629bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 1630f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1631f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case BACKGROUND_TASK_CLEANUP_PHOTOS: { 1632f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Check rate limit. 1633f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long now = System.currentTimeMillis(); 1634f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (now - mLastPhotoCleanup > PHOTO_CLEANUP_RATE_LIMIT) { 1635f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mLastPhotoCleanup = now; 16365d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 16375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Clean up photo stores for both contacts and profiles. 16385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 16395d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro cleanupPhotoStore(); 16405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToProfileMode(); 1641f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cleanupPhotoStore(); 1642ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 1643ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki switchToContactMode(); // Switch to the default, just in case. 1644f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro break; 1645f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1646f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 16478ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng 16488ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng case BACKGROUND_TASK_CLEAN_DELETE_LOG: { 16498ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 16508ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng DeletedContactsTableUtil.deleteOldLogs(db); 16518ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng } 1652bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 16534cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao } 16544cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao 165553fac8f99f3884c372c907a76766d27fa9e1d95fDmitri Plotnikov public void onLocaleChanged() { 16563826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != ProviderStatus.STATUS_NORMAL 16573826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov && mProviderStatus != ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS) { 16584f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov return; 16594f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov } 16604f20a360a2f0a7a83900c28fc7728542b38d8939Dmitri Plotnikov 1661fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_CHANGE_LOCALE); 16624cd13c4266d8e476e1a49c4b6bcd5b18c33d0de3Bai Tao } 166351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 16642d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner private static boolean needsToUpdateLocaleData(SharedPreferences prefs, 16652d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner Locale locale,ContactsDatabaseHelper contactsHelper, 16662d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner ProfileDatabaseHelper profileHelper) { 16672d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner final String providerLocale = prefs.getString(PREF_LOCALE, null); 16682d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner 16692d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner // If locale matches that of the provider, and neither DB needs 16702d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner // updating, there's nothing to do. A DB might require updating 16712d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner // as a result of a system upgrade. 16722d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner if (!locale.toString().equals(providerLocale)) { 16732d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner Log.i(TAG, "Locale has changed from " + providerLocale 16742d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner + " to " + locale.toString()); 16752d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner return true; 16762d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner } 16772d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner if (contactsHelper.needsToUpdateLocaleData(locale) || 16782d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner profileHelper.needsToUpdateLocaleData(locale)) { 16792d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner return true; 16802d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner } 16812d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner return false; 16822d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner } 16832d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner 168451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov /** 168551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * Verifies that the contacts database is properly configured for the current locale. 168651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * If not, changes the database locale to the current locale using an asynchronous task. 168751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * This needs to be done asynchronously because the process involves rebuilding 168851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * large data structures (name lookup, sort keys), which can take minutes on 168951f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov * a large set of contacts. 169051f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov */ 1691bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void updateLocaleInBackground() { 1692f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov 1693f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov // The process is already running - postpone the change 1694f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov if (mProviderStatus == ProviderStatus.STATUS_CHANGING_LOCALE) { 1695f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov return; 1696f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov } 1697f0da835940ab6ae1aa37e0ba2ddd29c3117eb212Dmitri Plotnikov 169851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov final Locale currentLocale = mCurrentLocale; 16992d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner final SharedPreferences prefs = 17002d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner PreferenceManager.getDefaultSharedPreferences(getContext()); 17012d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner if (!needsToUpdateLocaleData(prefs, currentLocale, 17022d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner mContactsHelper, mProfileHelper)) { 170351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov return; 170451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 170551f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 170651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov int providerStatus = mProviderStatus; 170751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_CHANGING_LOCALE); 17082d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner mContactsHelper.setLocale(currentLocale); 17092d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner mProfileHelper.setLocale(currentLocale); 1710d2f6ad6d50b5570327f8cca3b2d2bdcaec36ea90Makoto Onuki mSearchIndexManager.updateIndex(true); 17112d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner prefs.edit().putString(PREF_LOCALE, currentLocale.toString()).commit(); 1712bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov setProviderStatus(providerStatus); 1713bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov } 171451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 17152d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner // Static update routine for use by ContactsUpgradeReceiver during startup. 17162d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner // This clears the search index and marks it to be rebuilt, but doesn't 17172d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner // actually rebuild it. That is done later by 17182d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner // BACKGROUND_TASK_UPDATE_SEARCH_INDEX. 17192d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner protected static void updateLocaleOffline(Context context, 17202d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner ContactsDatabaseHelper contactsHelper, 17212d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner ProfileDatabaseHelper profileHelper) { 17222d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner final Locale currentLocale = Locale.getDefault(); 17232d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner final SharedPreferences prefs = 17242d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner PreferenceManager.getDefaultSharedPreferences(context); 17252d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner if (!needsToUpdateLocaleData(prefs, currentLocale, 17262d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner contactsHelper, profileHelper)) { 17272d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner return; 17282d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner } 17292d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner 17302d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner contactsHelper.setLocale(currentLocale); 17312d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner profileHelper.setLocale(currentLocale); 17322d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner contactsHelper.rebuildSearchIndex(); 17332d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner prefs.edit().putString(PREF_LOCALE, currentLocale.toString()).commit(); 17342d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner } 17352d2e22626b698b2484026ae18eca3c2c6340f2d1Jay Shrauner 1736fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov /** 1737fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov * Reinitializes the provider for a new locale. 1738fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov */ 1739fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov private void changeLocaleInBackground() { 1740fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // Re-initializing the provider without stopping it. 1741fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // Locking the database will prevent inserts/updates/deletes from 1742fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // running at the same time, but queries may still be running 1743fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov // on other threads. Those queries may return inconsistent results. 17445d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro SQLiteDatabase db = mContactsHelper.getWritableDatabase(); 17455d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro SQLiteDatabase profileDb = mProfileHelper.getWritableDatabase(); 1746fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.beginTransaction(); 17475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro profileDb.beginTransaction(); 1748fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov try { 1749fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov initForDefaultLocale(); 1750fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.setTransactionSuccessful(); 17515d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro profileDb.setTransactionSuccessful(); 1752fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } finally { 1753fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov db.endTransaction(); 17545d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro profileDb.endTransaction(); 1755fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1756fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 1757fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov updateLocaleInBackground(); 1758fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov } 1759fd2a6a5b7ecbbec6298182daee3b252896f82ea4Dmitri Plotnikov 176005e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov protected void updateSearchIndexInBackground() { 1761d2f6ad6d50b5570327f8cca3b2d2bdcaec36ea90Makoto Onuki mSearchIndexManager.updateIndex(false); 176205e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov } 176305e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov 1764bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void updateDirectoriesInBackground(boolean rescan) { 1765bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.scanAllPackages(rescan); 176651f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 176751f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 17683826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private void updateProviderStatus() { 17693826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != ProviderStatus.STATUS_NORMAL 17703826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov && mProviderStatus != ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS) { 17713826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return; 17723826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 17733826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 17743e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson // No accounts/no contacts status is true if there are no account and 17755d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // there are no contacts or one profile contact 17763e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson if (mContactsAccountCount == 0) { 17775d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long contactsNum = DatabaseUtils.queryNumEntries(mContactsHelper.getReadableDatabase(), 17783e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson Tables.CONTACTS, null); 17795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long profileNum = DatabaseUtils.queryNumEntries(mProfileHelper.getReadableDatabase(), 17805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Tables.CONTACTS, null); 17815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 17825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // TODO: Different status if there is a profile but no contacts? 17835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (contactsNum == 0 && profileNum <= 1) { 17843e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson setProviderStatus(ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS); 17853e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson } else { 17863e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson setProviderStatus(ProviderStatus.STATUS_NORMAL); 17873e6cd1fbafd09bf9b6ec35a19a55b48a271727dfIsaac Katzenelson } 17883826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } else { 17893826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov setProviderStatus(ProviderStatus.STATUS_NORMAL); 17903826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 17913826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 17923826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 1793193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki @VisibleForTesting 1794f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro protected void cleanupPhotoStore() { 1795ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 17966802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 17976802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Assemble the set of photo store file IDs that are in use, and send those to the photo 1798f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // store. Any photos that aren't in that set will be deleted, and any photos that no 1799f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // longer exist in the photo store will be returned for us to clear out in the DB. 18007cf50494501938f175d288077145acf49da8f171Daniel Lehmann long photoMimeTypeId = mDbHelper.get().getMimeTypeId(Photo.CONTENT_ITEM_TYPE); 18016802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Cursor c = db.query(Views.DATA, new String[]{Data._ID, Photo.PHOTO_FILE_ID}, 18027cf50494501938f175d288077145acf49da8f171Daniel Lehmann DataColumns.MIMETYPE_ID + "=" + photoMimeTypeId + " AND " 1803f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro + Photo.PHOTO_FILE_ID + " IS NOT NULL", null, null, null, null); 18046802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Set<Long> usedPhotoFileIds = Sets.newHashSet(); 18056802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> photoFileIdToDataId = Maps.newHashMap(); 1806f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 1807f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro while (c.moveToNext()) { 18086802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long dataId = c.getLong(0); 18096802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = c.getLong(1); 18106802030a777c0c3ba1dc029c534cca4784260632Dave Santoro usedPhotoFileIds.add(photoFileId); 18116802030a777c0c3ba1dc029c534cca4784260632Dave Santoro photoFileIdToDataId.put(photoFileId, dataId); 18126802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 18136802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } finally { 18146802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.close(); 18156802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 18166802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 18176802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Also query for all social stream item photos. 1818c2714bbd397b09a20da476c89560e1caecdcce58Dave Santoro c = db.query(Tables.STREAM_ITEM_PHOTOS + " JOIN " + Tables.STREAM_ITEMS 1819887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki + " ON " + StreamItemPhotos.STREAM_ITEM_ID + "=" + StreamItemsColumns.CONCRETE_ID, 18206802030a777c0c3ba1dc029c534cca4784260632Dave Santoro new String[]{ 1821c2714bbd397b09a20da476c89560e1caecdcce58Dave Santoro StreamItemPhotosColumns.CONCRETE_ID, 1822c2714bbd397b09a20da476c89560e1caecdcce58Dave Santoro StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID, 1823887a804b03fcb37be1fde000945dcfd799b3c012Makoto Onuki StreamItemPhotos.PHOTO_FILE_ID 18246802030a777c0c3ba1dc029c534cca4784260632Dave Santoro }, 18256802030a777c0c3ba1dc029c534cca4784260632Dave Santoro null, null, null, null, null); 18266802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> photoFileIdToStreamItemPhotoId = Maps.newHashMap(); 18276802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Map<Long, Long> streamItemPhotoIdToStreamItemId = Maps.newHashMap(); 18286802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 18296802030a777c0c3ba1dc029c534cca4784260632Dave Santoro while (c.moveToNext()) { 18306802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemPhotoId = c.getLong(0); 18316802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long streamItemId = c.getLong(1); 18326802030a777c0c3ba1dc029c534cca4784260632Dave Santoro long photoFileId = c.getLong(2); 18336802030a777c0c3ba1dc029c534cca4784260632Dave Santoro usedPhotoFileIds.add(photoFileId); 18346802030a777c0c3ba1dc029c534cca4784260632Dave Santoro photoFileIdToStreamItemPhotoId.put(photoFileId, streamItemPhotoId); 18356802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemPhotoIdToStreamItemId.put(streamItemPhotoId, streamItemId); 1836f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1837f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 1838f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 1839f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1840f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1841f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Run the photo store cleanup. 18425d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Set<Long> missingPhotoIds = mPhotoStore.get().cleanup(usedPhotoFileIds); 1843f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1844d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro // If any of the keys we're using no longer exist, clean them up. We need to do these 1845d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro // using internal APIs or direct DB access to avoid permission errors. 18466802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (!missingPhotoIds.isEmpty()) { 1847f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 1848ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki // Need to set the db listener because we need to run onCommit afterwards. 1849ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki // Make sure to use the proper listener depending on the current mode. 1850ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki db.beginTransactionWithListener(inProfileMode() ? mProfileProvider : this); 1851d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro for (long missingPhotoId : missingPhotoIds) { 1852d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro if (photoFileIdToDataId.containsKey(missingPhotoId)) { 1853d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro long dataId = photoFileIdToDataId.get(missingPhotoId); 1854d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro ContentValues updateValues = new ContentValues(); 1855d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro updateValues.putNull(Photo.PHOTO_FILE_ID); 1856d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro updateData(ContentUris.withAppendedId(Data.CONTENT_URI, dataId), 1857d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro updateValues, null, null, false); 1858d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } 1859d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro if (photoFileIdToStreamItemPhotoId.containsKey(missingPhotoId)) { 1860d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro // For missing photos that were in stream item photos, just delete the 1861d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro // stream item photo. 1862d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro long streamItemPhotoId = photoFileIdToStreamItemPhotoId.get(missingPhotoId); 1863d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro db.delete(Tables.STREAM_ITEM_PHOTOS, StreamItemPhotos._ID + "=?", 1864d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro new String[]{String.valueOf(streamItemPhotoId)}); 1865d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } 1866d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } 1867d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro db.setTransactionSuccessful(); 1868d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } catch (Exception e) { 1869d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro // Cleanup failure is not a fatal problem. We'll try again later. 1870d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro Log.e(TAG, "Failed to clean up outdated photo references", e); 1871d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } finally { 1872d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro db.endTransaction(); 1873f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1874f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1875f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1876f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 18776efb7db26598b105342d02207e0ca1c8725c10daDave Santoro @Override 1878b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov protected ContactsDatabaseHelper getDatabaseHelper(final Context context) { 1879b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov return ContactsDatabaseHelper.getInstance(context); 188031b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 188131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 18826efb7db26598b105342d02207e0ca1c8725c10daDave Santoro @Override 18836efb7db26598b105342d02207e0ca1c8725c10daDave Santoro protected ThreadLocal<ContactsTransaction> getTransactionHolder() { 18846efb7db26598b105342d02207e0ca1c8725c10daDave Santoro return mTransactionHolder; 18856efb7db26598b105342d02207e0ca1c8725c10daDave Santoro } 18866efb7db26598b105342d02207e0ca1c8725c10daDave Santoro 1887ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki public ProfileProvider newProfileProvider() { 18885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return new ProfileProvider(this); 18895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 18905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 1891524913c66ce75ca8dec127ac88e3bc2249c246d9Dave Santoro @VisibleForTesting 1892f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /* package */ PhotoStore getPhotoStore() { 18935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mContactsPhotoStore; 1894f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 1895f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 1896d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro @VisibleForTesting 1897d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro /* package */ PhotoStore getProfilePhotoStore() { 1898d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro return mProfilePhotoStore; 1899d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } 1900d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro 1901c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki /** 1902c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki * Maximum dimension (height or width) of photo thumbnails. 1903c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki */ 1904c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki public int getMaxThumbnailDim() { 1905c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki return PhotoProcessor.getMaxThumbnailSize(); 190687614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro } 190787614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro 1908c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki /** 1909c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki * Maximum dimension (height or width) of display photos. Larger images will be scaled 1910c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki * to fit. 1911c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki */ 1912c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki public int getMaxDisplayPhotoDim() { 1913c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki return PhotoProcessor.getMaxDisplayPhotoSize(); 191487614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro } 191587614d7d293b1519dc1f0f403fd59c8bf4d8a347Dave Santoro 1916193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki @VisibleForTesting 1917ed78fd6df5e9f3a2d572162e5d374d1f4a625bddDmitri Plotnikov public ContactDirectoryManager getContactDirectoryManagerForTest() { 191872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov return mContactDirectoryManager; 191972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov } 192072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 1921193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki @VisibleForTesting 19225dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov protected Locale getLocale() { 19235dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov return Locale.getDefault(); 19245dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov } 19255dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov 1926ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki @VisibleForTesting 1927ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final boolean inProfileMode() { 19285d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Boolean profileMode = mInProfileMode.get(); 19295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return profileMode != null && profileMode; 19305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 19315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 1932a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov /** 1933a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov * Wipes all data from the contacts database. 1934a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov */ 193510178e5e0b9de566e04508b624a89860c61787d6Makoto Onuki @NeededForTesting 193610178e5e0b9de566e04508b624a89860c61787d6Makoto Onuki void wipeData() { 193735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 19385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsHelper.wipeData(); 19395d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileHelper.wipeData(); 19405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactsPhotoStore.clear(); 19415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfilePhotoStore.clear(); 19423826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatus = ProviderStatus.STATUS_NO_ACCOUNTS_NO_CONTACTS; 1943a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov } 1944a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 1945568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov /** 194615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov * During intialization, this content provider will 1947568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * block all attempts to change contacts data. In particular, it will hold 1948568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * up all contact syncs. As soon as the import process is complete, all 1949568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * processes waiting to write to the provider are unblocked and can proceed 1950568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov * to compete for the database transaction monitor. 1951568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov */ 195215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov private void waitForAccess(CountDownLatch latch) { 195315c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (latch == null) { 195415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov return; 195515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } 195615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 195715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov while (true) { 195815c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov try { 195915c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov latch.await(); 196015c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov return; 196115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov } catch (InterruptedException e) { 196215c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov Thread.currentThread().interrupt(); 1963ff065d085b794a0bf4be4cf6e87a67bf060e0319Dmitri Plotnikov } 1964568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1965568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 1966568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 19675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 19685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Determines whether the given URI should be directed to the profile 19695d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * database rather than the contacts database. This is true under either 19705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * of three conditions: 19715d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * 1. The URI itself is specifically for the profile. 19725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * 2. The URI contains ID references that are in the profile ID-space. 19735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * 3. The URI contains lookup key references that match the special profile lookup key. 19745d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @param uri The URI to examine. 19755d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @return Whether to direct the DB operation to the profile database. 19765d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 19775d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private boolean mapsToProfileDb(Uri uri) { 19785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return sUriMatcher.mapsToProfile(uri); 19795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 19805d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 19815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 19825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Determines whether the given URI with the given values being inserted 19835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * should be directed to the profile database rather than the contacts 19845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * database. This is true if the URI already maps to the profile DB from 19855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * a call to {@link #mapsToProfileDb} or if the URI matches a URI that 19865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * specifies parent IDs via the ContentValues, and the given ContentValues 19875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * contains an ID in the profile ID-space. 19885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @param uri The URI to examine. 19895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @param values The values being inserted. 19905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * @return Whether to direct the DB insert to the profile database. 19915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 19925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private boolean mapsToProfileDbWithInsertedValues(Uri uri, ContentValues values) { 19935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mapsToProfileDb(uri)) { 19945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return true; 19955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 19965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro int match = sUriMatcher.match(uri); 19975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (INSERT_URI_ID_VALUE_MAP.containsKey(match)) { 19985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String idField = INSERT_URI_ID_VALUE_MAP.get(match); 19995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (values.containsKey(idField)) { 20005d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long id = values.getAsLong(idField); 20015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (ContactsContract.isProfileId(id)) { 20025d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return true; 20035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20045d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return false; 20075d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 20095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 20105d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Switches the provider's thread-local context variables to prepare for performing 20115d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * a profile operation. 20125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 2013ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki private void switchToProfileMode() { 2014ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki if (ENABLE_TRANSACTION_LOG) { 2015ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Log.i(TAG, "switchToProfileMode", new RuntimeException("switchToProfileMode")); 2016ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki } 20175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.set(mProfileHelper); 20185d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.set(mProfileTransactionContext); 20195d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.set(mProfileAggregator); 20205d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mPhotoStore.set(mProfilePhotoStore); 20215d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mInProfileMode.set(true); 20225d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20235d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 20245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro /** 20255d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * Switches the provider's thread-local context variables to prepare for performing 20265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro * a contacts operation. 20275d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro */ 2028ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki private void switchToContactMode() { 2029ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki if (ENABLE_TRANSACTION_LOG) { 2030ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Log.i(TAG, "switchToContactMode", new RuntimeException("switchToContactMode")); 2031ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki } 20325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.set(mContactsHelper); 20335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.set(mContactTransactionContext); 20345d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.set(mContactAggregator); 20355d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mPhotoStore.set(mContactsPhotoStore); 20365d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mInProfileMode.set(false); 20375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 2039568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 2040568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public Uri insert(Uri uri, ContentValues values) { 204115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 204236612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 204336612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro // Enforce stream items access check if applicable. 204436612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro enforceSocialStreamWritePermission(uri); 204536612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 20465d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mapsToProfileDbWithInsertedValues(uri, values)) { 2047078f588cef389358adabc579de00747878f3c108Dave Santoro switchToProfileMode(); 2048078f588cef389358adabc579de00747878f3c108Dave Santoro return mProfileProvider.insert(uri, values); 20495d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 20505d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 20515d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return super.insert(uri, values); 20525d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 2053568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 2054568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 2055568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 2056568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 205715c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov if (mWriteAccessLatch != null) { 205810178e5e0b9de566e04508b624a89860c61787d6Makoto Onuki // Update on PROVIDER_STATUS used to be used as a trigger to re-start legacy contact 205910178e5e0b9de566e04508b624a89860c61787d6Makoto Onuki // import. Now that we no longer support it, we just ignore it. 2060bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov int match = sUriMatcher.match(uri); 2061bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov if (match == PROVIDER_STATUS) { 206210178e5e0b9de566e04508b624a89860c61787d6Makoto Onuki return 0; 2063bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 2064bd578a748ab5bd74aa63511cce8769d5882f4651Dmitri Plotnikov } 206515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 206636612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 206736612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro // Enforce stream items access check if applicable. 206836612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro enforceSocialStreamWritePermission(uri); 206936612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 20705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mapsToProfileDb(uri)) { 2071078f588cef389358adabc579de00747878f3c108Dave Santoro switchToProfileMode(); 2072078f588cef389358adabc579de00747878f3c108Dave Santoro return mProfileProvider.update(uri, values, selection, selectionArgs); 20735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 20745d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 20755d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return super.update(uri, values, selection, selectionArgs); 20765d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 2077568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 2078568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 2079568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 2080568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public int delete(Uri uri, String selection, String[] selectionArgs) { 208115c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 208236612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 208336612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro // Enforce stream items access check if applicable. 208436612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro enforceSocialStreamWritePermission(uri); 208536612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 20865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mapsToProfileDb(uri)) { 2087078f588cef389358adabc579de00747878f3c108Dave Santoro switchToProfileMode(); 2088078f588cef389358adabc579de00747878f3c108Dave Santoro return mProfileProvider.delete(uri, selection, selectionArgs); 20895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 20905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 20915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return super.delete(uri, selection, selectionArgs); 20925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 20945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 2095568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov @Override 209682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro public Bundle call(String method, String arg, Bundle extras) { 209782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro waitForAccess(mReadAccessLatch); 2098ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki switchToContactMode(); 209982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro if (method.equals(Authorization.AUTHORIZATION_METHOD)) { 210082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro Uri uri = (Uri) extras.getParcelable(Authorization.KEY_URI_TO_AUTHORIZE); 210182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 210282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Check permissions on the caller. The URI can only be pre-authorized if the caller 210382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // already has the necessary permissions. 210482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro enforceSocialStreamReadPermission(uri); 210582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro if (mapsToProfileDb(uri)) { 210682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro mProfileProvider.enforceReadPermission(uri); 210782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 210882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 210982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // If there hasn't been a security violation yet, we're clear to pre-authorize the URI. 211082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro Uri authUri = preAuthorizeUri(uri); 211182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro Bundle response = new Bundle(); 211282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro response.putParcelable(Authorization.KEY_AUTHORIZED_URI, authUri); 211382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro return response; 211482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 211582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro return null; 211682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 211782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 211882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro /** 211982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * Pre-authorizes the given URI, adding an expiring permission token to it and placing that 212082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * in our map of pre-authorized URIs. 212182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * @param uri The URI to pre-authorize. 212282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * @return A pre-authorized URI that will not require special permissions to use. 212382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro */ 212482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro private Uri preAuthorizeUri(Uri uri) { 212582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro String token = String.valueOf(mRandom.nextLong()); 212682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro Uri authUri = uri.buildUpon() 212782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro .appendQueryParameter(PREAUTHORIZED_URI_TOKEN, token) 212882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro .build(); 212982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro long expiration = SystemClock.elapsedRealtime() + mPreAuthorizedUriDuration; 213082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro mPreAuthorizedUris.put(authUri, expiration); 213182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 213282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro return authUri; 213382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 213482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 213582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro /** 213682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * Checks whether the given URI has an unexpired permission token that would grant access to 213782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * query the content. If it does, the regular permission check should be skipped. 213882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * @param uri The URI being accessed. 213982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro * @return Whether the URI is a pre-authorized URI that is still valid. 214082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro */ 214182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro public boolean isValidPreAuthorizedUri(Uri uri) { 214282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Only proceed if the URI has a permission token parameter. 214382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro if (uri.getQueryParameter(PREAUTHORIZED_URI_TOKEN) != null) { 214482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // First expire any pre-authorization URIs that are no longer valid. 214582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro long now = SystemClock.elapsedRealtime(); 214682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro Set<Uri> expiredUris = Sets.newHashSet(); 214782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro for (Uri preAuthUri : mPreAuthorizedUris.keySet()) { 214882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro if (mPreAuthorizedUris.get(preAuthUri) < now) { 214982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro expiredUris.add(preAuthUri); 215082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 215182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 215282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro for (Uri expiredUri : expiredUris) { 215382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro mPreAuthorizedUris.remove(expiredUri); 215482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 215582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 215682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Now check to see if the pre-authorized URI map contains the URI. 215782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro if (mPreAuthorizedUris.containsKey(uri)) { 215882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Unexpired token - skip the permission check. 215982792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro return true; 216082792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 216182792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 216282792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro return false; 216382792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro } 216482792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro 216582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro @Override 2166078f588cef389358adabc579de00747878f3c108Dave Santoro protected boolean yield(ContactsTransaction transaction) { 2167078f588cef389358adabc579de00747878f3c108Dave Santoro // If there's a profile transaction in progress, and we're yielding, we need to 2168078f588cef389358adabc579de00747878f3c108Dave Santoro // end it. Unlike the Contacts DB yield (which re-starts a transaction at its 2169078f588cef389358adabc579de00747878f3c108Dave Santoro // conclusion), we can just go back into a state in which we have no active 2170078f588cef389358adabc579de00747878f3c108Dave Santoro // profile transaction, and let it be re-created as needed. We can't hold onto 2171078f588cef389358adabc579de00747878f3c108Dave Santoro // the transaction without risking a deadlock. 2172078f588cef389358adabc579de00747878f3c108Dave Santoro SQLiteDatabase profileDb = transaction.removeDbForTag(PROFILE_DB_TAG); 2173078f588cef389358adabc579de00747878f3c108Dave Santoro if (profileDb != null) { 2174078f588cef389358adabc579de00747878f3c108Dave Santoro profileDb.setTransactionSuccessful(); 2175078f588cef389358adabc579de00747878f3c108Dave Santoro profileDb.endTransaction(); 2176078f588cef389358adabc579de00747878f3c108Dave Santoro } 2177078f588cef389358adabc579de00747878f3c108Dave Santoro 2178078f588cef389358adabc579de00747878f3c108Dave Santoro // Now proceed with the Contacts DB yield. 2179078f588cef389358adabc579de00747878f3c108Dave Santoro SQLiteDatabase contactsDb = transaction.getDbForTag(CONTACTS_DB_TAG); 2180078f588cef389358adabc579de00747878f3c108Dave Santoro return contactsDb != null && contactsDb.yieldIfContendedSafely(SLEEP_AFTER_YIELD_DELAY); 2181078f588cef389358adabc579de00747878f3c108Dave Santoro } 2182078f588cef389358adabc579de00747878f3c108Dave Santoro 2183078f588cef389358adabc579de00747878f3c108Dave Santoro @Override 2184568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 2185568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov throws OperationApplicationException { 218615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mWriteAccessLatch); 2187078f588cef389358adabc579de00747878f3c108Dave Santoro return super.applyBatch(operations); 2188568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov } 2189568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 21904f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 21917b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov public int bulkInsert(Uri uri, ContentValues[] values) { 21927b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov waitForAccess(mWriteAccessLatch); 2193078f588cef389358adabc579de00747878f3c108Dave Santoro return super.bulkInsert(uri, values); 21947b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov } 21957b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov 21967b330a64cdf77ddb1c3e7259a7f069e99b025b51Dmitri Plotnikov @Override 2197078f588cef389358adabc579de00747878f3c108Dave Santoro public void onBegin() { 2198ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki onBeginTransactionInternal(false); 2199ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki } 2200ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 2201ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki protected void onBeginTransactionInternal(boolean forProfile) { 2202ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki if (ENABLE_TRANSACTION_LOG) { 2203ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Log.i(TAG, "onBeginTransaction: " + (forProfile ? "profile" : "contacts"), 2204ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki new RuntimeException("onBeginTransactionInternal")); 2205b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2206ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki if (forProfile) { 2207ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki switchToProfileMode(); 22085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileAggregator.clearPendingAggregations(); 22090992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki mProfileTransactionContext.clearExceptSearchIndexUpdates(); 22105d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 2211ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki switchToContactMode(); 22125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mContactAggregator.clearPendingAggregations(); 22130992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki mContactTransactionContext.clearExceptSearchIndexUpdates(); 22145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 2215b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2216b5a4add17815167d20a90645779df34cdf45280dFred Quintana 2217285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov @Override 2218078f588cef389358adabc579de00747878f3c108Dave Santoro public void onCommit() { 2219ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki onCommitTransactionInternal(false); 2220ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki } 2221ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 2222ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki protected void onCommitTransactionInternal(boolean forProfile) { 2223ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki if (ENABLE_TRANSACTION_LOG) { 2224ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Log.i(TAG, "onCommitTransactionInternal: " + (forProfile ? "profile" : "contacts"), 2225ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki new RuntimeException("onCommitTransactionInternal")); 2226b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2227ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki if (forProfile) { 2228ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki switchToProfileMode(); 2229ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki } else { 2230ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki switchToContactMode(); 2231ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki } 2232ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 2233b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 2234ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 2235ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki mAggregator.get().aggregateInTransaction(mTransactionContext.get(), db); 22361a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (mVisibleTouched) { 22371a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = false; 22385d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().updateAllVisible(); 223935997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 224035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki // Need to rebuild the fast-indxer bundle. 224135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 22421a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey } 22433826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 2244bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov updateSearchIndexInTransaction(); 2245bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov 22463826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatusUpdateNeeded) { 22473826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov updateProviderStatus(); 22483826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = false; 22493826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 2250b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2251b5a4add17815167d20a90645779df34cdf45280dFred Quintana 2252078f588cef389358adabc579de00747878f3c108Dave Santoro @Override 2253078f588cef389358adabc579de00747878f3c108Dave Santoro public void onRollback() { 2254ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki onRollbackTransactionInternal(false); 2255ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki } 2256ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 2257ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki protected void onRollbackTransactionInternal(boolean forProfile) { 2258ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki if (ENABLE_TRANSACTION_LOG) { 2259ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Log.i(TAG, "onRollbackTransactionInternal: " + (forProfile ? "profile" : "contacts"), 2260ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki new RuntimeException("onRollbackTransactionInternal")); 2261ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki } 2262ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki if (forProfile) { 2263ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki switchToProfileMode(); 2264ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki } else { 2265ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki switchToContactMode(); 2266fb25f3a5a86ca15de8507baf02a357a63032af62Makoto Onuki } 2267ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 2268ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki mDbHelper.get().invalidateAllCache(); 2269078f588cef389358adabc579de00747878f3c108Dave Santoro } 2270078f588cef389358adabc579de00747878f3c108Dave Santoro 2271bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov private void updateSearchIndexInTransaction() { 22725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Set<Long> staleContacts = mTransactionContext.get().getStaleSearchIndexContactIds(); 22735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Set<Long> staleRawContacts = mTransactionContext.get().getStaleSearchIndexRawContactIds(); 2274bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov if (!staleContacts.isEmpty() || !staleRawContacts.isEmpty()) { 2275bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov mSearchIndexManager.updateIndexForRawContacts(staleContacts, staleRawContacts); 22765d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().clearSearchIndexUpdates(); 2277bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov } 2278bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov } 2279bd9abbb6b03b4ec1e28ad3fa2fcba5d1eb8609eaDmitri Plotnikov 2280b5a4add17815167d20a90645779df34cdf45280dFred Quintana private void flushTransactionalChanges() { 2281bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 2282ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Log.v(TAG, "flushTransactionalChanges: " + (inProfileMode() ? "profile" : "contacts")); 2283b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 22841129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov 2285ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 22865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro for (long rawContactId : mTransactionContext.get().getInsertedRawContactIds()) { 2287ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki mDbHelper.get().updateRawContactDisplayName(db, rawContactId); 2288ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki mAggregator.get().onRawContactInsert(mTransactionContext.get(), db, 22895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro rawContactId); 229024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 229124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 22925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Set<Long> dirtyRawContacts = mTransactionContext.get().getDirtyRawContactIds(); 2293d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov if (!dirtyRawContacts.isEmpty()) { 2294a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.setLength(0); 2295a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(UPDATE_RAW_CONTACT_SET_DIRTY_SQL); 2296d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov appendIds(mSb, dirtyRawContacts); 2297a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(")"); 2298ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki db.execSQL(mSb.toString()); 2299a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov } 2300a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 23015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Set<Long> updatedRawContacts = mTransactionContext.get().getUpdatedRawContactIds(); 2302d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov if (!updatedRawContacts.isEmpty()) { 2303a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.setLength(0); 2304a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(UPDATE_RAW_CONTACT_SET_VERSION_SQL); 2305d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov appendIds(mSb, updatedRawContacts); 2306a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov mSb.append(")"); 2307ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki db.execSQL(mSb.toString()); 2308b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2309b5a4add17815167d20a90645779df34cdf45280dFred Quintana 23108ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng final Set<Long> changedRawContacts = mTransactionContext.get().getChangedRawContactIds(); 2311da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng ContactsTableUtil.updateContactLastUpdateByRawContactId(db, changedRawContacts); 23128ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng 23135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Update sync states. 23145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro for (Map.Entry<Long, Object> entry : mTransactionContext.get().getUpdatedSyncStates()) { 2315b5a4add17815167d20a90645779df34cdf45280dFred Quintana long id = entry.getKey(); 2316ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki if (mDbHelper.get().getSyncState().update(db, id, entry.getValue()) <= 0) { 23179d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana throw new IllegalStateException( 23189d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana "unable to update sync state, does it still exist?"); 23199d9673d6a93926c337e23b7e2dcfb9aebc43e9abFred Quintana } 2320b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2321b5a4add17815167d20a90645779df34cdf45280dFred Quintana 23220992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki mTransactionContext.get().clearExceptSearchIndexUpdates(); 2323b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2324b5a4add17815167d20a90645779df34cdf45280dFred Quintana 2325a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov /** 2326a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov * Appends comma separated ids. 2327a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov * @param ids Should not be empty 2328a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov */ 2329d364d74ce9cc677c10362b8686d7c33fafe78bebDmitri Plotnikov private void appendIds(StringBuilder sb, Set<Long> ids) { 2330b5a4add17815167d20a90645779df34cdf45280dFred Quintana for (long id : ids) { 2331a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.append(id).append(','); 2332b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2333a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov 2334a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.setLength(sb.length() - 1); // Yank the last comma 2335285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 2336285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 2337285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov @Override 2338cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov protected void notifyChange() { 233981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov notifyChange(mSyncToNetwork); 234081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = false; 234181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 234281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 234381d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov protected void notifyChange(boolean syncToNetwork) { 234481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov getContext().getContentResolver().notifyChange(ContactsContract.AUTHORITY_URI, null, 234581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov syncToNetwork); 2346cdbd854decda3f493b395c8867f2cd131d95d09fDmitri Plotnikov } 2347568904d1cc9acfabac78b6fcbf8a7d5115688174Dmitri Plotnikov 234851f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov protected void setProviderStatus(int status) { 23493826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (mProviderStatus != status) { 23503826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatus = status; 23513826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov getContext().getContentResolver().notifyChange(ProviderStatus.CONTENT_URI, null, false); 23523826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 235351f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov } 235451f41be3b905c63ccffcdc82ec58cf5f7ded2c34Dmitri Plotnikov 2355f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov public DataRowHandler getDataRowHandler(final String mimeType) { 23565d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (inProfileMode()) { 23575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return getDataRowHandlerForProfile(mimeType); 23585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 23593cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov DataRowHandler handler = mDataRowHandlers.get(mimeType); 23603cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov if (handler == null) { 23616d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov handler = new DataRowHandlerForCustomMimetype( 23625d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro getContext(), mContactsHelper, mContactAggregator, mimeType); 23633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov mDataRowHandlers.put(mimeType, handler); 23643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 23653cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return handler; 23663cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov } 23673cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov 23685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro public DataRowHandler getDataRowHandlerForProfile(final String mimeType) { 23695d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro DataRowHandler handler = mProfileDataRowHandlers.get(mimeType); 23705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (handler == null) { 23715d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro handler = new DataRowHandlerForCustomMimetype( 23725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro getContext(), mProfileHelper, mProfileAggregator, mimeType); 23735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mProfileDataRowHandlers.put(mimeType, handler); 23745d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 23755d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return handler; 23765d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 23775d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 23784f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 2379de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected Uri insertInTransaction(Uri uri, ContentValues values) { 2380bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 23812fe1f4f757a84cb76382c375ba3755a802c5e444Makoto Onuki Log.v(TAG, "insertInTransaction: uri=" + uri + " values=[" + values + "]"); 2382b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 2383f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana 2384ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 23855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 2386f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 2387f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 2388f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana 2389a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 2390a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 239135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 2392a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton switch (match) { 239335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 23945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE: 2395ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki id = mDbHelper.get().getSyncState().insert(db, values); 239635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana break; 239735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 2398d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 239935997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 2400d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov insertContact(values); 24016bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 24026bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 24036bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 240424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 240524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro throw new UnsupportedOperationException( 240624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro "The profile contact is created automatically"); 240724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 240824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 2409d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case RAW_CONTACTS: 2410d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS: { 241135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 24125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro id = insertRawContact(uri, values, callerIsSyncAdapter); 2413f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2414a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2415a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2416a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2417193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki case RAW_CONTACTS_ID_DATA: 2418d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS_ID_DATA: { 241935997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 2420193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki int segment = match == RAW_CONTACTS_ID_DATA ? 1 : 2; 2421d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro values.put(Data.RAW_CONTACT_ID, uri.getPathSegments().get(segment)); 2422f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana id = insertData(values, callerIsSyncAdapter); 2423f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2424a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2425a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2426a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 24273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case RAW_CONTACTS_ID_STREAM_ITEMS: { 24283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.put(StreamItems.RAW_CONTACT_ID, uri.getPathSegments().get(1)); 24293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItem(uri, values); 24303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 24313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 24323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 24333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24340c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro case DATA: 24350c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro case PROFILE_DATA: { 243635997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 2437f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana id = insertData(values, callerIsSyncAdapter); 2438f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2439a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 2440a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2441a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2442ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 2443f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov id = insertGroup(uri, values, callerIsSyncAdapter); 2444f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 2445ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 2446ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 2447ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 2448eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 24495aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey id = insertSettings(uri, values); 245043880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 2451eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 2452eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 2453eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 24545d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case STATUS_UPDATES: 24555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_STATUS_UPDATES: { 245682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov id = insertStatusUpdate(values); 24571f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey break; 24581f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 24591f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 24603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 24613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItem(uri, values); 24623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 24633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 24643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 24653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 24673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItemPhoto(uri, values); 24683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 24693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 24703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 24713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 24723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 24733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.put(StreamItemPhotos.STREAM_ITEM_ID, uri.getPathSegments().get(1)); 24743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = insertStreamItemPhoto(uri, values); 24753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 24763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 24773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 24783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 2479a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton default: 248081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 2481f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.insert(uri, values); 2482a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2483a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 24847e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana if (id < 0) { 24857e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana return null; 24867e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 24877e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 2488de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov return ContentUris.withAppendedId(uri, id); 2489a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2490a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2491a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 2492e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * If account is non-null then store it in the values. If the account is 2493e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * already specified in the values then it must be consistent with the 2494e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * account, if it is non-null. 2495e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * 2496e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @param uri Current {@link Uri} being operated on. 2497e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @param values {@link ContentValues} to read and possibly update. 2498e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @throws IllegalArgumentException when only one of 2499e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * {@link RawContacts#ACCOUNT_NAME} or 2500e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * {@link RawContacts#ACCOUNT_TYPE} is specified, leaving the 2501e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * other undefined. 2502e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * @throws IllegalArgumentException when {@link RawContacts#ACCOUNT_NAME} 2503e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * and {@link RawContacts#ACCOUNT_TYPE} are inconsistent between 2504e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey * the given {@link Uri} and {@link ContentValues}. 25057e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana */ 2506e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey private Account resolveAccount(Uri uri, ContentValues values) throws IllegalArgumentException { 2507f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 2508f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 2509e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 2510f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2511f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String valueAccountName = values.getAsString(RawContacts.ACCOUNT_NAME); 2512f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String valueAccountType = values.getAsString(RawContacts.ACCOUNT_TYPE); 2513e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialValues = TextUtils.isEmpty(valueAccountName) 2514e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey ^ TextUtils.isEmpty(valueAccountType); 2515e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2516e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri || partialValues) { 2517e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 25185d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 2519fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 2520e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 2521e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2522e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 2523e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 2524e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validUri = !TextUtils.isEmpty(accountName); 2525e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean validValues = !TextUtils.isEmpty(valueAccountName); 2526e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 2527e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validValues && validUri) { 2528e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Check that accounts match when both present 2529e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean accountMatch = TextUtils.equals(accountName, valueAccountName) 2530e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey && TextUtils.equals(accountType, valueAccountType); 2531e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (!accountMatch) { 25325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 2533fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "When both specified, ACCOUNT_NAME and ACCOUNT_TYPE must match", uri)); 2534e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 2535e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else if (validUri) { 2536e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Fill values from Uri when not present 2537f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov values.put(RawContacts.ACCOUNT_NAME, accountName); 2538f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov values.put(RawContacts.ACCOUNT_TYPE, accountType); 2539e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else if (validValues) { 2540f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov accountName = valueAccountName; 2541f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov accountType = valueAccountType; 2542e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } else { 2543e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return null; 2544f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 2545f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2546e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Use cached Account object when matches, otherwise create 2547f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (mAccount == null 2548f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov || !mAccount.name.equals(accountName) 2549f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov || !mAccount.type.equals(accountType)) { 2550f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mAccount = new Account(accountName, accountType); 2551035b4cc204be2641079a0b04e9ee9791a8f8248bFred Quintana } 2552f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2553e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return mAccount; 25547e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 25557e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 25567e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 255743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * Resolves the account and builds an {@link AccountWithDataSet} based on the data set specified 255843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * in the URI or values (if any). 255943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * @param uri Current {@link Uri} being operated on. 256043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * @param values {@link ContentValues} to read and possibly update. 256143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro */ 256243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro private AccountWithDataSet resolveAccountWithDataSet(Uri uri, ContentValues values) { 25633593682b8d9213fde576a0cff54458ad50563980Dave Santoro final Account account = resolveAccount(uri, values); 256443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro AccountWithDataSet accountWithDataSet = null; 256543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (account != null) { 256643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String dataSet = getQueryParameter(uri, RawContacts.DATA_SET); 256743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (dataSet == null) { 25683593682b8d9213fde576a0cff54458ad50563980Dave Santoro dataSet = values.getAsString(RawContacts.DATA_SET); 2569a71dc460ca951c7aca591f3f470c160cde70a1e3Dave Santoro } else { 25703593682b8d9213fde576a0cff54458ad50563980Dave Santoro values.put(RawContacts.DATA_SET, dataSet); 257143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 25729ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki accountWithDataSet = AccountWithDataSet.get(account.name, account.type, dataSet); 257343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 257443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro return accountWithDataSet; 257543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 257643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 257743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro /** 25789d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * Same as {@link #resolveAccountWithDataSet}, but returns the account id for the 25799d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * {@link AccountWithDataSet}. Used for insert. 25809d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * 25819d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki * May update the account cache; must be used only in a transaction. 25829d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki */ 25839d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki private long resolveAccountIdInTransaction(Uri uri, ContentValues values) { 25849d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki return mDbHelper.get().getOrCreateAccountIdInTransaction( 25859d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki resolveAccountWithDataSet(uri, mValues)); 25869d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 25879d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 25889d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki /** 2589d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov * Inserts an item in the contacts table 25906bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * 25916bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @param values the values for the new row 25926bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov * @return the row ID of the newly created row 25936bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov */ 2594d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov private long insertContact(ContentValues values) { 2595de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov throw new UnsupportedOperationException("Aggregate contacts are created automatically"); 25966bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 25976bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 25986bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov /** 259924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro * Inserts an item in the raw contacts table 2600a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 2601f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * @param uri the values for the new row 2602f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * @param values the account this contact should be associated with. may be null. 2603dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana * @param callerIsSyncAdapter 2604a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 2605a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 26065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private long insertRawContact(Uri uri, ContentValues values, boolean callerIsSyncAdapter) { 2607f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.clear(); 2608f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putAll(values); 2609f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putNull(RawContacts.CONTACT_ID); 2610f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 26119d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final long accountId = resolveAccountIdInTransaction(uri, mValues); 26129d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mValues.remove(RawContacts.ACCOUNT_NAME); 26139d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mValues.remove(RawContacts.ACCOUNT_TYPE); 26149d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mValues.remove(RawContacts.DATA_SET); 26159d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mValues.put(RawContactsColumns.ACCOUNT_ID, accountId); 26167e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 26173d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov if (values.containsKey(RawContacts.DELETED) 26183d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov && values.getAsInteger(RawContacts.DELETED) != 0) { 2619f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED); 26203d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov } 26213d8b043c3341a5b6c2e781b7eba9767d5cd13267Dmitri Plotnikov 2622ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 2623ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 2624ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki long rawContactId = db.insert(Tables.RAW_CONTACTS, 26255d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro RawContacts.CONTACT_ID, mValues); 2626f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov int aggregationMode = RawContacts.AGGREGATION_MODE_DEFAULT; 26275d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mValues.containsKey(RawContacts.AGGREGATION_MODE)) { 2628f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov aggregationMode = mValues.getAsInteger(RawContacts.AGGREGATION_MODE); 2629f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 26305d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().markNewForAggregation(rawContactId, aggregationMode); 2631285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov 26325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Trigger creation of a Contact based on this RawContact at the end of transaction 26339d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mTransactionContext.get().rawContactInserted(rawContactId, accountId); 2634f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 2635dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter) { 2636dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana addAutoAddMembership(rawContactId); 2637dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long starred = values.getAsLong(RawContacts.STARRED); 2638dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (starred != null && starred != 0) { 2639dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, starred != 0); 2640dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2641dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2642dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 26433826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 2644023b9437a3644e59309b8cfd12c6d84b98433f95Dmitri Plotnikov return rawContactId; 2645a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 2646a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 2647dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void addAutoAddMembership(long rawContactId) { 2648dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long groupId = findGroupByRawContactId(SELECTION_AUTO_ADD_GROUPS_BY_RAW_CONTACT_ID, 2649dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana rawContactId); 2650dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (groupId != null) { 2651dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana insertDataGroupMembership(rawContactId, groupId); 2652dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2653dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2654dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2655dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private Long findGroupByRawContactId(String selection, long rawContactId) { 2656ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getReadableDatabase(); 2657ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor c = db.query(Tables.GROUPS + "," + Tables.RAW_CONTACTS, 26585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PROJECTION_GROUP_ID, selection, 2659dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{Long.toString(rawContactId)}, 2660dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana null /* groupBy */, null /* having */, null /* orderBy */); 2661dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana try { 2662dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana while (c.moveToNext()) { 2663dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return c.getLong(0); 2664dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2665dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return null; 2666dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } finally { 2667dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana c.close(); 2668dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2669dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2670dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2671dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void updateFavoritesMembership(long rawContactId, boolean isStarred) { 2672dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final Long groupId = findGroupByRawContactId(SELECTION_FAVORITES_GROUPS_BY_RAW_CONTACT_ID, 2673dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana rawContactId); 2674dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (groupId != null) { 2675dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (isStarred) { 2676dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana insertDataGroupMembership(rawContactId, groupId); 2677dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } else { 2678dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana deleteDataGroupMembership(rawContactId, groupId); 2679dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2680dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2681dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2682dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2683dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void insertDataGroupMembership(long rawContactId, long groupId) { 2684dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana ContentValues groupMembershipValues = new ContentValues(); 2685dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(GroupMembership.GROUP_ROW_ID, groupId); 2686dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(GroupMembership.RAW_CONTACT_ID, rawContactId); 2687dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana groupMembershipValues.put(DataColumns.MIMETYPE_ID, 26885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)); 2689ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 2690ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki db.insert(Tables.DATA, null, groupMembershipValues); 2691dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2692dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2693dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private void deleteDataGroupMembership(long rawContactId, long groupId) { 2694dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final String[] selectionArgs = { 26955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Long.toString(mDbHelper.get().getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)), 2696dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(groupId), 2697dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana Long.toString(rawContactId)}; 2698ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 2699ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki db.delete(Tables.DATA, SELECTION_GROUPMEMBERSHIP_DATA, selectionArgs); 2700dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 2701dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 2702a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton /** 2703a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * Inserts an item in the data table 2704a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * 2705a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @param values the values for the new row 2706a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton * @return the row ID of the newly created row 2707a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton */ 2708f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private long insertData(ContentValues values, boolean callerIsSyncAdapter) { 2709a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton long id = 0; 2710de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.clear(); 2711de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.putAll(values); 271267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey 2713de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov long rawContactId = mValues.getAsLong(Data.RAW_CONTACT_ID); 271420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 2715de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Replace package with internal mapping 2716de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov final String packageName = mValues.getAsString(Data.RES_PACKAGE); 2717de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov if (packageName != null) { 27185d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mValues.put(DataColumns.PACKAGE_ID, mDbHelper.get().getPackageId(packageName)); 2719de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov } 2720de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.remove(Data.RES_PACKAGE); 2721508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 2722de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Replace mimetype with internal mapping 2723de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov final String mimeType = mValues.getAsString(Data.MIMETYPE); 2724de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov if (TextUtils.isEmpty(mimeType)) { 2725de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov throw new IllegalArgumentException(Data.MIMETYPE + " is required"); 2726de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov } 27274097855e2d672b3f8e1c5c8a169efb80203bf53eDmitri Plotnikov 27285d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mValues.put(DataColumns.MIMETYPE_ID, mDbHelper.get().getMimeTypeId(mimeType)); 2729de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov mValues.remove(Data.MIMETYPE); 2730a8dc456684a104c7e5547ba17d44f952022cd8c5Dmitri Plotnikov 2731a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 2732ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 2733ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki id = rowHandler.insert(db, mTransactionContext.get(), rawContactId, mValues); 27348ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng mTransactionContext.get().markRawContactDirtyAndChanged(rawContactId, callerIsSyncAdapter); 27355d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().rawContactUpdated(rawContactId); 2736a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton return id; 27374f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 27384f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 27393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 27403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Inserts an item in the stream_items table. The account is checked against the 27413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * account in the raw contact for which the stream item is being inserted. If the 27423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * new stream item results in more stream items under this raw contact than the limit, 27433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the oldest one will be deleted (note that if the stream item inserted was the 27443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * oldest, it will be immediately deleted, and this will return 0). 27453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 27463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param uri the insertion URI 27473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param values the values for the new row 27483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return the stream item _ID of the newly created row, or 0 if it was not created 27493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 27503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long insertStreamItem(Uri uri, ContentValues values) { 27513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long id = 0; 27523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.clear(); 27533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.putAll(values); 27543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 27553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = mValues.getAsLong(StreamItems.RAW_CONTACT_ID); 27563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 27576802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to insert accounts params - they don't exist in the stream items table. 27586802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_NAME); 27596802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_TYPE); 27606802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 27613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Insert the new stream item. 2762ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 2763ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki id = db.insert(Tables.STREAM_ITEMS, null, mValues); 27646802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (id == -1) { 27656802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Insertion failed. 27666802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return 0; 27676802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 27683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 27693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Check to see if we're over the limit for stream items under this raw contact. 27703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // It's possible that the inserted stream item is older than the the existing 27713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // ones, in which case it may be deleted immediately (resetting the ID to 0). 27723b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann id = cleanUpOldStreamItems(rawContactId, id); 27733b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 27743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return id; 27753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 27763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 27773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 27783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Inserts an item in the stream_item_photos table. The account is checked against 27793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the account in the raw contact that owns the stream item being modified. 27803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 27813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param uri the insertion URI 27823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param values the values for the new row 27836802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @return the stream item photo _ID of the newly created row, or 0 if there was an issue 27846802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * with processing the photo or creating the row 27853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 27863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long insertStreamItemPhoto(Uri uri, ContentValues values) { 27873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long id = 0; 27883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.clear(); 27893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mValues.putAll(values); 27903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 27913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long streamItemId = mValues.getAsLong(StreamItemPhotos.STREAM_ITEM_ID); 27923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (streamItemId != 0) { 27933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = lookupRawContactIdForStreamId(streamItemId); 27943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 27956802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to insert accounts params - they don't exist in the stream item 27966802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // photos table. 27976802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_NAME); 27986802030a777c0c3ba1dc029c534cca4784260632Dave Santoro mValues.remove(RawContacts.ACCOUNT_TYPE); 27993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 28006802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo and store it. 28016802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (processStreamItemPhoto(mValues, false)) { 28026802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Insert the stream item photo. 2803ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 2804ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki id = db.insert(Tables.STREAM_ITEM_PHOTOS, null, mValues); 28056802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 28063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return id; 28083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 28103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 28116802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * Processes the photo contained in the {@link ContactsContract.StreamItemPhotos#PHOTO} 28126802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * field of the given values, attempting to store it in the photo store. If successful, 28136802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * the resulting photo file ID will be added to the values for insert/update in the table. 28146802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * <p> 28156802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * If updating, it is valid for the picture to be empty or unspecified (the function will 28166802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * still return true). If inserting, a valid picture must be specified. 28176802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @param values The content values provided by the caller. 28186802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @param forUpdate Whether this photo is being processed for update (vs. insert). 28196802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @return Whether the insert or update should proceed. 28206802030a777c0c3ba1dc029c534cca4784260632Dave Santoro */ 28216802030a777c0c3ba1dc029c534cca4784260632Dave Santoro private boolean processStreamItemPhoto(ContentValues values, boolean forUpdate) { 28226802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (!values.containsKey(StreamItemPhotos.PHOTO)) { 28236802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return forUpdate; 28246802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 28256802030a777c0c3ba1dc029c534cca4784260632Dave Santoro byte[] photoBytes = values.getAsByteArray(StreamItemPhotos.PHOTO); 28266802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoBytes == null) { 28276802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return forUpdate; 28286802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 28296802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 28306802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo and store it. 28316802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 28325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long photoFileId = mPhotoStore.get().insert(new PhotoProcessor(photoBytes, 2833c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki getMaxDisplayPhotoDim(), getMaxThumbnailDim(), true), true); 28346802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (photoFileId != 0) { 28356802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.put(StreamItemPhotos.PHOTO_FILE_ID, photoFileId); 28366802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(StreamItemPhotos.PHOTO); 28376802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return true; 28386802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 28396802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Couldn't store the photo, return 0. 28406802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Log.e(TAG, "Could not process stream item photo for insert"); 28416802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return false; 28426802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 28436802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } catch (IOException ioe) { 28446802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Log.e(TAG, "Could not process stream item photo for insert", ioe); 28456802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return false; 28466802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 28476802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 28486802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 28496802030a777c0c3ba1dc029c534cca4784260632Dave Santoro /** 28503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Looks up the raw contact ID that owns the specified stream item. 28513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param streamItemId The ID of the stream item. 28523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The associated raw contact ID, or -1 if no such stream item exists. 28533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 28543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long lookupRawContactIdForStreamId(long streamItemId) { 28553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = -1; 2856ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getReadableDatabase(); 2857ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor c = db.query(Tables.STREAM_ITEMS, 28585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new String[]{StreamItems.RAW_CONTACT_ID}, 28593b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItems._ID + "=?", new String[]{String.valueOf(streamItemId)}, 28603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, null); 28613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 28623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (c.moveToFirst()) { 28633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann rawContactId = c.getLong(0); 28643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 28663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 28673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return rawContactId; 28693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 28703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 28713b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann /** 287236612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro * If the given URI is reading stream items or stream photos, this will run a permission check 287336612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro * for the android.permission.READ_SOCIAL_STREAM permission - otherwise it will do nothing. 287436612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro * @param uri The URI to check. 287536612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro */ 287636612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro private void enforceSocialStreamReadPermission(Uri uri) { 287782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro if (SOCIAL_STREAM_URIS.contains(sUriMatcher.match(uri)) 287882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro && !isValidPreAuthorizedUri(uri)) { 287936612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro getContext().enforceCallingOrSelfPermission( 288036612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro "android.permission.READ_SOCIAL_STREAM", null); 288136612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro } 288236612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro } 288336612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 288436612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro /** 288536612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro * If the given URI is modifying stream items or stream photos, this will run a permission check 288636612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro * for the android.permission.WRITE_SOCIAL_STREAM permission - otherwise it will do nothing. 288736612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro * @param uri The URI to check. 288836612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro */ 288936612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro private void enforceSocialStreamWritePermission(Uri uri) { 289036612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro if (SOCIAL_STREAM_URIS.contains(sUriMatcher.match(uri))) { 289136612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro getContext().enforceCallingOrSelfPermission( 289236612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro "android.permission.WRITE_SOCIAL_STREAM", null); 289336612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro } 289436612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro } 289536612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 289636612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro /** 28973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * Queries the database for stream items under the given raw contact. If there are 28983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * more entries than {@link ContactsProvider2#MAX_STREAM_ITEMS_PER_RAW_CONTACT}, 28993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * the oldest entries (as determined by timestamp) will be deleted. 29003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param rawContactId The raw contact ID to examine for stream items. 29013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @param insertedStreamItemId The ID of the stream item that was just inserted, 29023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * prompting this cleanup. Callers may pass 0 if no insertion prompted the 29033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * cleanup. 29043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * @return The ID of the inserted stream item if it still exists after cleanup; 29053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann * 0 otherwise. 29063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann */ 29073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private long cleanUpOldStreamItems(long rawContactId, long insertedStreamItemId) { 29083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long postCleanupInsertedStreamId = insertedStreamItemId; 2909ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 2910ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor c = db.query(Tables.STREAM_ITEMS, new String[]{StreamItems._ID}, 29113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItems.RAW_CONTACT_ID + "=?", new String[]{String.valueOf(rawContactId)}, 29123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann null, null, StreamItems.TIMESTAMP + " DESC, " + StreamItems._ID + " DESC"); 29133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann try { 29143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann int streamItemCount = c.getCount(); 29153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (streamItemCount <= MAX_STREAM_ITEMS_PER_RAW_CONTACT) { 29163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Still under the limit - nothing to clean up! 29173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return insertedStreamItemId; 29183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } else { 29193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.moveToLast(); 29203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann while (c.getPosition() >= MAX_STREAM_ITEMS_PER_RAW_CONTACT) { 29213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long streamItemId = c.getLong(0); 29223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (insertedStreamItemId == streamItemId) { 29233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // The stream item just inserted is being deleted. 29243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann postCleanupInsertedStreamId = 0; 29253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 2926ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki deleteStreamItem(db, c.getLong(0)); 29273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.moveToPrevious(); 29283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 29293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 29303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } finally { 29313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann c.close(); 29323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 29333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return postCleanupInsertedStreamId; 29343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 29353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 29369261b2141aa90a4fed632fd6da03026d4c216280Fred Quintana /** 293720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov * Delete data row by row so that fixing of primaries etc work correctly. 293820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov */ 2939f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private int deleteData(String selection, String[] selectionArgs, boolean callerIsSyncAdapter) { 294020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov int count = 0; 294120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 2942ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 2943ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 2944de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 2945de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov // so we don't need to worry about deleting data we don't have permission to read. 29460c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro Uri dataUri = inProfileMode() 29470c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro ? Uri.withAppendedPath(Profile.CONTENT_URI, RawContacts.Data.CONTENT_DIRECTORY) 29480c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro : Data.CONTENT_URI; 29490c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro Cursor c = query(dataUri, DataRowHandler.DataDeleteQuery.COLUMNS, 2950f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov selection, selectionArgs, null); 2951de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov try { 2952de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov while(c.moveToNext()) { 2953f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov long rawContactId = c.getLong(DataRowHandler.DataDeleteQuery.RAW_CONTACT_ID); 2954f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov String mimeType = c.getString(DataRowHandler.DataDeleteQuery.MIMETYPE); 2955a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 2956ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki count += rowHandler.delete(db, mTransactionContext.get(), c); 29578ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng mTransactionContext.get().markRawContactDirtyAndChanged(rawContactId, 29588ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng callerIsSyncAdapter); 295920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 296020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 2961de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov c.close(); 296220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 296320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 296420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return count; 296520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 296620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 296788e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov /** 296888e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov * Delete a data row provided that it is one of the allowed mime types. 296988e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov */ 297020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov public int deleteData(long dataId, String[] allowedMimeTypes) { 2971f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov 2972ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 2973ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 297488e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 297588e5f4d32aa9cd3af0ac9654de479f1b8113f712Dmitri Plotnikov // so we don't need to worry about deleting data we don't have permission to read. 29764da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(dataId); 2977f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov Cursor c = query(Data.CONTENT_URI, DataRowHandler.DataDeleteQuery.COLUMNS, Data._ID + "=?", 29784da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1, null); 2979f992bfab334b760d36a053fc0b439382dcfb51adDmitri Plotnikov 298020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov try { 298120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (!c.moveToFirst()) { 298220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov return 0; 298320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 298420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 2985f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov String mimeType = c.getString(DataRowHandler.DataDeleteQuery.MIMETYPE); 298620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov boolean valid = false; 298720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov for (int i = 0; i < allowedMimeTypes.length; i++) { 298820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (TextUtils.equals(mimeType, allowedMimeTypes[i])) { 298920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov valid = true; 299020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov break; 299120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 299220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 299320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 299420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (!valid) { 29957a4550f2afb24b2112b6c937f416c6f46ece35f4Fred Quintana throw new IllegalArgumentException("Data type mismatch: expected " 299620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov + Lists.newArrayList(allowedMimeTypes)); 299720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 2998a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 2999ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return rowHandler.delete(db, mTransactionContext.get(), c); 300020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } finally { 300120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov c.close(); 300220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 300320a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 300420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 300520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov /** 3006ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * Inserts an item in the groups table 3007ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey */ 3008f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private long insertGroup(Uri uri, ContentValues values, boolean callerIsSyncAdapter) { 3009f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.clear(); 3010f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.putAll(values); 3011f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 30129d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final long accountId = mDbHelper.get().getOrCreateAccountIdInTransaction( 30139d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki resolveAccountWithDataSet(uri, mValues)); 30149d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mValues.remove(Groups.ACCOUNT_NAME); 30159d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mValues.remove(Groups.ACCOUNT_TYPE); 30169d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mValues.remove(Groups.DATA_SET); 30179d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mValues.put(GroupsColumns.ACCOUNT_ID, accountId); 3018ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3019ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey // Replace package with internal mapping 3020f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String packageName = mValues.getAsString(Groups.RES_PACKAGE); 302167dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey if (packageName != null) { 30225d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mValues.put(GroupsColumns.PACKAGE_ID, mDbHelper.get().getPackageId(packageName)); 302367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey } 3024f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.remove(Groups.RES_PACKAGE); 3025ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3026dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana final boolean isFavoritesGroup = mValues.getAsLong(Groups.FAVORITES) != null 3027dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana ? mValues.getAsLong(Groups.FAVORITES) != 0 3028dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana : false; 3029dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 3030f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (!callerIsSyncAdapter) { 3031f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov mValues.put(Groups.DIRTY, 1); 303273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } 303373776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 3034ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 3035ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 3036ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki long result = db.insert(Tables.GROUPS, Groups.TITLE, mValues); 3037ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey 3038dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter && isFavoritesGroup) { 30399d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // If the inserted group is a favorite group, add all starred raw contacts to it. 30409d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mSelectionArgs1[0] = Long.toString(accountId); 3041ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor c = db.query(Tables.RAW_CONTACTS, 3042dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{RawContacts._ID, RawContacts.STARRED}, 30439d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki RawContactsColumns.CONCRETE_ACCOUNT_ID + "=?", mSelectionArgs1, 30449d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki null, null, null); 3045892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov try { 3046892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov while (c.moveToNext()) { 3047892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov if (c.getLong(1) != 0) { 3048892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov final long rawContactId = c.getLong(0); 3049892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov insertDataGroupMembership(rawContactId, result); 30508ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng mTransactionContext.get().markRawContactDirtyAndChanged(rawContactId, 30518ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng callerIsSyncAdapter); 3052892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov } 3053dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3054892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov } finally { 3055892a3d9ded5c64a63ae3d5d5c52c59528b466c93Dmitri Plotnikov c.close(); 3056dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3057dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 3058dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 3059f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (mValues.containsKey(Groups.GROUP_VISIBLE)) { 30601a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 3061ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey } 3062ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey 3063ac004680e3cc127b6ebf32b78d2813654b9c56fbJeff Sharkey return result; 3064ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3065ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 30665aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private long insertSettings(Uri uri, ContentValues values) { 3067f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro // Before inserting, ensure that no settings record already exists for the 3068f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro // values being inserted (this used to be enforced by a primary key, but that no 3069f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro // longer works with the nullable data_set field added). 3070f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro String accountName = values.getAsString(Settings.ACCOUNT_NAME); 3071f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro String accountType = values.getAsString(Settings.ACCOUNT_TYPE); 3072f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro String dataSet = values.getAsString(Settings.DATA_SET); 3073f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro Uri.Builder settingsUri = Settings.CONTENT_URI.buildUpon(); 3074f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro if (accountName != null) { 3075f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro settingsUri.appendQueryParameter(Settings.ACCOUNT_NAME, accountName); 3076f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } 3077f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro if (accountType != null) { 3078f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro settingsUri.appendQueryParameter(Settings.ACCOUNT_TYPE, accountType); 3079f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } 3080f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro if (dataSet != null) { 3081f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro settingsUri.appendQueryParameter(Settings.DATA_SET, dataSet); 3082f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } 308315826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann Cursor c = queryLocal(settingsUri.build(), null, null, null, null, 0, null); 3084f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro try { 3085f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro if (c.getCount() > 0) { 30860e21a867a572679d64d79041eb574d13665178d4Dave Santoro // If a record was found, replace it with the new values. 30870e21a867a572679d64d79041eb574d13665178d4Dave Santoro String selection = null; 30880e21a867a572679d64d79041eb574d13665178d4Dave Santoro String[] selectionArgs = null; 30890e21a867a572679d64d79041eb574d13665178d4Dave Santoro if (accountName != null && accountType != null) { 30900e21a867a572679d64d79041eb574d13665178d4Dave Santoro selection = Settings.ACCOUNT_NAME + "=? AND " + Settings.ACCOUNT_TYPE + "=?"; 30910e21a867a572679d64d79041eb574d13665178d4Dave Santoro if (dataSet == null) { 30920e21a867a572679d64d79041eb574d13665178d4Dave Santoro selection += " AND " + Settings.DATA_SET + " IS NULL"; 30930e21a867a572679d64d79041eb574d13665178d4Dave Santoro selectionArgs = new String[] {accountName, accountType}; 30940e21a867a572679d64d79041eb574d13665178d4Dave Santoro } else { 30950e21a867a572679d64d79041eb574d13665178d4Dave Santoro selection += " AND " + Settings.DATA_SET + "=?"; 30960e21a867a572679d64d79041eb574d13665178d4Dave Santoro selectionArgs = new String[] {accountName, accountType, dataSet}; 30970e21a867a572679d64d79041eb574d13665178d4Dave Santoro } 30980e21a867a572679d64d79041eb574d13665178d4Dave Santoro } 30990e21a867a572679d64d79041eb574d13665178d4Dave Santoro return updateSettings(uri, values, selection, selectionArgs); 3100f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } 3101f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } finally { 3102f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro c.close(); 3103f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } 3104f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro 3105ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 3106ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 3107f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro // If we didn't find a duplicate, we're fine to insert. 3108ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final long id = db.insert(Tables.SETTINGS, null, values); 31095aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey 31101a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (values.containsKey(Settings.UNGROUPED_VISIBLE)) { 31111a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 3112e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 31131a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey 3114e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return id; 3115e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3116e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 3117ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey /** 311882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov * Inserts a status update. 31191f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey */ 312082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov public long insertStatusUpdate(ContentValues values) { 312182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov final String handle = values.getAsString(StatusUpdates.IM_HANDLE); 31220a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov final Integer protocol = values.getAsInteger(StatusUpdates.PROTOCOL); 31234dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov String customProtocol = null; 31244dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov 3125ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 3126ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 31270a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (protocol != null && protocol == Im.PROTOCOL_CUSTOM) { 312882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov customProtocol = values.getAsString(StatusUpdates.CUSTOM_PROTOCOL); 31294dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov if (TextUtils.isEmpty(customProtocol)) { 31304dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov throw new IllegalArgumentException( 31314dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov "CUSTOM_PROTOCOL is required when PROTOCOL=PROTOCOL_CUSTOM"); 31324dcd106ccc27dbbfaae86baf0cd57beb42c27cccDmitri Plotnikov } 31331f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 31341f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 3135dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton long rawContactId = -1; 3136dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton long contactId = -1; 313782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov Long dataId = values.getAsLong(StatusUpdates.DATA_ID); 31386802030a777c0c3ba1dc029c534cca4784260632Dave Santoro String accountType = null; 31396802030a777c0c3ba1dc029c534cca4784260632Dave Santoro String accountName = null; 3140f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov mSb.setLength(0); 31412526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.clear(); 3142dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (dataId != null) { 3143dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // Lookup the contact info for the given data row. 3144dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 31452526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(Tables.DATA + "." + Data._ID + "=?"); 31462526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(dataId)); 31471f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 3148dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // Lookup the data row to attach this presence update to 3149dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 31500a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov if (TextUtils.isEmpty(handle) || protocol == null) { 31510a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov throw new IllegalArgumentException("PROTOCOL and IM_HANDLE are required"); 31520a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 31530a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 3154dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton // TODO: generalize to allow other providers to match against email 3155dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton boolean matchEmail = Im.PROTOCOL_GOOGLE_TALK == protocol; 3156dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton 31575d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String mimeTypeIdIm = String.valueOf(mDbHelper.get().getMimeTypeIdForIm()); 3158dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (matchEmail) { 31595d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String mimeTypeIdEmail = String.valueOf(mDbHelper.get().getMimeTypeIdForEmail()); 3160f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 3161f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // The following hack forces SQLite to use the (mimetype_id,data1) index, otherwise 3162f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // the "OR" conjunction confuses it and it switches to a full scan of 3163f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // the raw_contacts table. 3164f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov 3165f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // This code relies on the fact that Im.DATA and Email.DATA are in fact the same 3166f8b937f62fb80445bf59b2e504d765bcab746557Dmitri Plotnikov // column - Data.DATA1 31672526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(DataColumns.MIMETYPE_ID + " IN (?,?)" + 31682526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Data.DATA1 + "=?" + 31692526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND ((" + DataColumns.MIMETYPE_ID + "=? AND " + Im.PROTOCOL + "=?"); 31702526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdEmail); 31712526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 31722526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(handle); 31732526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 31742526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(protocol)); 3175dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (customProtocol != null) { 31762526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + Im.CUSTOM_PROTOCOL + "=?"); 31772526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(customProtocol); 3178dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 31792526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(") OR (" + DataColumns.MIMETYPE_ID + "=?))"); 31802526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdEmail); 3181dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } else { 31822526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(DataColumns.MIMETYPE_ID + "=?" + 31832526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Im.PROTOCOL + "=?" + 31842526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov " AND " + Im.DATA + "=?"); 31852526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(mimeTypeIdIm); 31862526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(String.valueOf(protocol)); 31872526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(handle); 3188dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton if (customProtocol != null) { 31892526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + Im.CUSTOM_PROTOCOL + "=?"); 31902526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(customProtocol); 3191dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 3192dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 31931f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 319482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.DATA_ID)) { 31952526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.append(" AND " + DataColumns.CONCRETE_ID + "=?"); 31962526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSelectionArgs.add(values.getAsString(StatusUpdates.DATA_ID)); 3197dea2b6389abf1ae0448ae047b4b0a9e423381d77Jeff Hamilton } 319870b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov } 319970b5ee6864cb3368d24a9e876fb93008997b12dfDmitri Plotnikov 32001f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey Cursor cursor = null; 32011f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey try { 3202ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki cursor = db.query(DataContactsQuery.TABLE, DataContactsQuery.PROJECTION, 32032526f94e532ac973c846db0099f94b375a23be93Dmitri Plotnikov mSb.toString(), mSelectionArgs.toArray(EMPTY_STRING_ARRAY), null, null, 32044394086494fe7909aaca70f56fb4bb08beebf303Dmitri Plotnikov Clauses.CONTACT_VISIBLE + " DESC, " + Data.RAW_CONTACT_ID); 32051f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey if (cursor.moveToFirst()) { 320667dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey dataId = cursor.getLong(DataContactsQuery.DATA_ID); 32075ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov rawContactId = cursor.getLong(DataContactsQuery.RAW_CONTACT_ID); 32086802030a777c0c3ba1dc029c534cca4784260632Dave Santoro accountType = cursor.getString(DataContactsQuery.ACCOUNT_TYPE); 32096802030a777c0c3ba1dc029c534cca4784260632Dave Santoro accountName = cursor.getString(DataContactsQuery.ACCOUNT_NAME); 3210e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov contactId = cursor.getLong(DataContactsQuery.CONTACT_ID); 32111f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } else { 32121f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey // No contact found, return a null URI 32131f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey return -1; 32141f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 32151f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } finally { 321631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov if (cursor != null) { 321731b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov cursor.close(); 321831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 32191f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 32201f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 322182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.PRESENCE)) { 3222a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (customProtocol == null) { 3223a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // We cannot allow a null in the custom protocol field, because SQLite3 does not 3224a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // properly enforce uniqueness of null values 3225a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov customProtocol = ""; 3226a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 3227a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov 3228a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.clear(); 322982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.DATA_ID, dataId); 3230a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.put(PresenceColumns.RAW_CONTACT_ID, rawContactId); 3231a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov mValues.put(PresenceColumns.CONTACT_ID, contactId); 323282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.PROTOCOL, protocol); 323382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.CUSTOM_PROTOCOL, customProtocol); 323482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.IM_HANDLE, handle); 323582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.IM_ACCOUNT)) { 323682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.IM_ACCOUNT, values.getAsString(StatusUpdates.IM_ACCOUNT)); 3237a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 323882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov mValues.put(StatusUpdates.PRESENCE, 323982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov values.getAsString(StatusUpdates.PRESENCE)); 3240aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori mValues.put(StatusUpdates.CHAT_CAPABILITY, 3241aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori values.getAsString(StatusUpdates.CHAT_CAPABILITY)); 32421f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 3243a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov // Insert the presence update 3244ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki db.replace(Tables.PRESENCE, null, mValues); 3245a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 3246e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov 32470a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 324882bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (values.containsKey(StatusUpdates.STATUS)) { 324982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov String status = values.getAsString(StatusUpdates.STATUS); 32500a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov String resPackage = values.getAsString(StatusUpdates.STATUS_RES_PACKAGE); 32510bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann Resources resources = getContext().getResources(); 32520bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann if (!TextUtils.isEmpty(resPackage)) { 32530bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann PackageManager pm = getContext().getPackageManager(); 32540bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann try { 32550bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann resources = pm.getResourcesForApplication(resPackage); 32560bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } catch (NameNotFoundException e) { 32570bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann Log.w(TAG, "Contact status update resource package not found: " 32580bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann + resPackage); 32590bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } 32600bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } 32610bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann Integer labelResourceId = values.getAsInteger(StatusUpdates.STATUS_LABEL); 32620a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 32630bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann if ((labelResourceId == null || labelResourceId == 0) && protocol != null) { 32640bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann labelResourceId = Im.getProtocolLabelResource(protocol); 32650a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 32660bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann String labelResource = getResourceName(resources, "string", labelResourceId); 32670a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 32680bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann Integer iconResourceId = values.getAsInteger(StatusUpdates.STATUS_ICON); 32690a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov // TODO compute the default icon based on the protocol 32700a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 32710bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann String iconResource = getResourceName(resources, "drawable", iconResourceId); 32720bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann 3273a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (TextUtils.isEmpty(status)) { 32745d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().deleteStatusUpdate(dataId); 3275a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } else { 32766802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Long timestamp = values.getAsLong(StatusUpdates.STATUS_TIMESTAMP); 32776802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (timestamp != null) { 32785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().replaceStatusUpdate(dataId, timestamp, status, resPackage, 32790bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann iconResourceId, labelResourceId); 32806802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 32815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().insertStatusUpdate(dataId, status, resPackage, iconResourceId, 32820bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann labelResourceId); 32836802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 32846802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 32856802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // For forward compatibility with the new stream item API, insert this status update 32866802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // there as well. If we already have a stream item from this source, update that 32876802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // one instead of inserting a new one (since the semantics of the old status update 32886802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // API is to only have a single record). 32896802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (rawContactId != -1 && !TextUtils.isEmpty(status)) { 32906802030a777c0c3ba1dc029c534cca4784260632Dave Santoro ContentValues streamItemValues = new ContentValues(); 32916802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RAW_CONTACT_ID, rawContactId); 3292d5ef5903570e533a501abe6a8e3d533fdb5318fcFlavio Lerda // Status updates are text only but stream items are HTML. 3293e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda streamItemValues.put(StreamItems.TEXT, statusUpdateToHtml(status)); 32946802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.COMMENTS, ""); 32956802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_PACKAGE, resPackage); 32966802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_ICON, iconResource); 32976802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.RES_LABEL, labelResource); 32986802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(StreamItems.TIMESTAMP, 32996802030a777c0c3ba1dc029c534cca4784260632Dave Santoro timestamp == null ? System.currentTimeMillis() : timestamp); 33006802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 33016802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Note: The following is basically a workaround for the fact that status 33026802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // updates didn't do any sort of account enforcement, while social stream item 33036802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // updates do. We can't expect callers of the old API to start passing account 33046802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // information along, so we just populate the account params appropriately for 330543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // the raw contact. Data set is not relevant here, as we only check account 330643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // name and type. 33076802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (accountName != null && accountType != null) { 33086802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(RawContacts.ACCOUNT_NAME, accountName); 33096802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues.put(RawContacts.ACCOUNT_TYPE, accountType); 33106802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 33116802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 33126802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Check for an existing stream item from this source, and insert or update. 33136802030a777c0c3ba1dc029c534cca4784260632Dave Santoro Uri streamUri = StreamItems.CONTENT_URI; 331436612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro Cursor c = queryLocal(streamUri, new String[]{StreamItems._ID}, 33156802030a777c0c3ba1dc029c534cca4784260632Dave Santoro StreamItems.RAW_CONTACT_ID + "=?", 331636612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro new String[]{String.valueOf(rawContactId)}, 331715826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann null, -1 /* directory ID */, null); 33186802030a777c0c3ba1dc029c534cca4784260632Dave Santoro try { 33196802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (c.getCount() > 0) { 33206802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.moveToFirst(); 332136612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro updateInTransaction(ContentUris.withAppendedId(streamUri, c.getLong(0)), 33226802030a777c0c3ba1dc029c534cca4784260632Dave Santoro streamItemValues, null, null); 33236802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } else { 332436612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro insertInTransaction(streamUri, streamItemValues); 33256802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 33266802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } finally { 33276802030a777c0c3ba1dc029c534cca4784260632Dave Santoro c.close(); 33286802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 33296802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 3330e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 3331e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 3332bffeabdf3dcf58f963ad1bb4d3e6e51f3ac16cfdDmitri Plotnikov 3333a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov if (contactId != -1) { 33345d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().updateLastStatusUpdateId(contactId); 3335a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov } 3336a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov 3337a23cd5b6f478f6c9dda54173e84bd0098b9f3364Dmitri Plotnikov return dataId; 33381f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 33391f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 3340e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda /** Converts a status update to HTML. */ 3341e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda private String statusUpdateToHtml(String status) { 33424747809486541f7a3d342d3e1dd48fb5ea255ad6Flavio Lerda return TextUtils.htmlEncode(status); 3343e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda } 3344e3a10e4fcdb8b5e619f02a26fd1a26cef3b149a3Flavio Lerda 33450bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann private String getResourceName(Resources resources, String expectedType, Integer resourceId) { 33460bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann try { 33470bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann if (resourceId == null || resourceId == 0) return null; 33480bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann 33490bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann // Resource has an invalid type (e.g. a string as icon)? ignore 33500bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann final String resourceEntryName = resources.getResourceEntryName(resourceId); 33510bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann final String resourceTypeName = resources.getResourceTypeName(resourceId); 33520bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann if (!expectedType.equals(resourceTypeName)) { 33530bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann Log.w(TAG, "Resource " + resourceId + " (" + resourceEntryName + ") is of type " + 33540bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann resourceTypeName + " but " + expectedType + " is required."); 33550bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann return null; 33560bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } 33570bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann 33580bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann return resourceEntryName; 33590bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } catch (NotFoundException e) { 33600bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann return null; 33610bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } 33620bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann } 33630bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann 33644f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 3365de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) { 3366bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 33672fe1f4f757a84cb76382c375ba3755a802c5e444Makoto Onuki Log.v(TAG, "deleteInTransaction: uri=" + uri + 33682fe1f4f757a84cb76382c375ba3755a802c5e444Makoto Onuki " selection=[" + selection + "] args=" + Arrays.toString(selectionArgs)); 3369b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 33705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 3371ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 33725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 3373b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 3374f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 3375f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 3376508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey final int match = sUriMatcher.match(uri); 3377508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey switch (match) { 337835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 33795d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE: 3380ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return mDbHelper.get().getSyncState().delete(db, selection, 33815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs); 33825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 33835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case SYNCSTATE_ID: { 33845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String selectionWithId = 33855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 33865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro + (selection == null ? "" : " AND (" + selection + ")"); 3387ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return mDbHelper.get().getSyncState().delete(db, selectionWithId, 33885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs); 33895d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 339035ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 33915d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE_ID: { 3392b5a4add17815167d20a90645779df34cdf45280dFred Quintana String selectionWithId = 3393b5a4add17815167d20a90645779df34cdf45280dFred Quintana (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 3394b5a4add17815167d20a90645779df34cdf45280dFred Quintana + (selection == null ? "" : " AND (" + selection + ")"); 3395ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return mProfileHelper.getSyncState().delete(db, selectionWithId, 33965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs); 33975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 3398b5a4add17815167d20a90645779df34cdf45280dFred Quintana 3399cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov case CONTACTS: { 340035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 3401cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov // TODO 3402cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov return 0; 3403cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3404cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 3405d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 340635997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 3407d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 3408dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 34096bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 34106bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 34119fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann case CONTACTS_LOOKUP: { 341235997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 34132e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final List<String> pathSegments = uri.getPathSegments(); 34142e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final int segmentCount = pathSegments.size(); 34152e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey if (segmentCount < 3) { 34165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 3417fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 34182e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 34192e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final String lookupKey = pathSegments.get(2); 3420ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final long contactId = lookupContactIdByLookupKey(db, lookupKey); 3421dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 34222e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 34232e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey 34249fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann case CONTACTS_LOOKUP_ID: { 342535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 34269fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // lookup contact by id and lookup key to see if they still match the actual record 34279fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final List<String> pathSegments = uri.getPathSegments(); 34289fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann final String lookupKey = pathSegments.get(2); 34299fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 34309fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann setTablesAndProjectionMapForContacts(lookupQb, uri, null); 3431a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 34329fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann String[] args; 34339fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann if (selectionArgs == null) { 34349fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args = new String[2]; 34359fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } else { 34369fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args = new String[selectionArgs.length + 2]; 34379fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann System.arraycopy(selectionArgs, 0, args, 2, selectionArgs.length); 34389fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 34399fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann args[0] = String.valueOf(contactId); 344060de6f6c3c70e53b603a47b0efc80993353a8368Daniel Lehmann args[1] = Uri.encode(lookupKey); 34419fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann lookupQb.appendWhere(Contacts._ID + "=? AND " + Contacts.LOOKUP_KEY + "=?"); 3442ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor c = query(db, lookupQb, null, selection, args, null, null, 344380628945e7e41bb9363c2fbbd2938890b9217792Makoto Onuki null, null, null); 34449fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann try { 34459fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann if (c.getCount() == 1) { 34469fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // contact was unmodified so go ahead and delete it 3447dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana return deleteContact(contactId, callerIsSyncAdapter); 34489fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } else { 34499fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // row was changed (e.g. the merging might have changed), we got multiple 34509fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann // rows or the supplied selection filtered the record out 34519fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann return 0; 34529fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 34539fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } finally { 34549fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann c.close(); 34559fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 34569fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann } 34579fcf109b56cec0aad05322a3b4594228ea06d859Daniel Lehmann 3458b6186821548995dce533ee502e82e9abf4c0aadcMakoto Onuki case CONTACTS_DELETE_USAGE: { 3459b6186821548995dce533ee502e82e9abf4c0aadcMakoto Onuki return deleteDataUsage(); 3460b6186821548995dce533ee502e82e9abf4c0aadcMakoto Onuki } 3461b6186821548995dce533ee502e82e9abf4c0aadcMakoto Onuki 3462d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case RAW_CONTACTS: 3463d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS: { 346435997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 34652971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana int numDeletes = 0; 3466ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor c = db.query(Views.RAW_CONTACTS, 3467fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov new String[]{RawContacts._ID, RawContacts.CONTACT_ID}, 34689d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki appendAccountIdToSelection(uri, selection), selectionArgs, 34699d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki null, null, null); 34702971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana try { 34712971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana while (c.moveToNext()) { 34722971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana final long rawContactId = c.getLong(0); 3473fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov long contactId = c.getLong(1); 3474fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov numDeletes += deleteRawContact(rawContactId, contactId, 3475fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov callerIsSyncAdapter); 34762971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 34772971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } finally { 34782971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana c.close(); 34792971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 34802971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana return numDeletes; 34812971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 34822971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana 3483d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case RAW_CONTACTS_ID: 3484d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS_ID: { 348535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 34862971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana final long rawContactId = ContentUris.parseId(uri); 34875d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return deleteRawContact(rawContactId, mDbHelper.get().getContactId(rawContactId), 3488fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov callerIsSyncAdapter); 3489508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 3490508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 34910c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro case DATA: 34920c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro case PROFILE_DATA: { 349335997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 3494f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 3495944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong return deleteData(appendAccountToSelection(uri, selection), selectionArgs, 3496f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana callerIsSyncAdapter); 349720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 349820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 349948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case DATA_ID: 350048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 350148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 3502e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa case CALLABLES_ID: 3503d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case POSTALS_ID: 3504d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_DATA_ID: { 350535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 3506508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey long dataId = ContentUris.parseId(uri); 3507f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 35084da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(dataId); 35094da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov return deleteData(Data._ID + "=?", mSelectionArgs1, callerIsSyncAdapter); 3510ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3511ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3512ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 3513f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 35145aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey return deleteGroup(uri, ContentUris.parseId(uri), callerIsSyncAdapter); 35152971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 35162971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana 35172971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana case GROUPS: { 35182971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana int numDeletes = 0; 3519ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor c = db.query(Views.GROUPS, Projections.ID, 35209d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki appendAccountIdToSelection(uri, selection), selectionArgs, 35219d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki null, null, null); 35222971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana try { 35232971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana while (c.moveToNext()) { 35245aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey numDeletes += deleteGroup(uri, c.getLong(0), callerIsSyncAdapter); 35252971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 35262971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } finally { 35272971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana c.close(); 35282971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana } 352981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (numDeletes > 0) { 3530f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 353181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 35322971716e6a68660721d45be97bf3bd2dfad1c5efFred Quintana return numDeletes; 3533508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 3534508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey 3535eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 353643880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 3537e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey return deleteSettings(uri, appendAccountToSelection(uri, selection), selectionArgs); 3538eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 3539eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 35405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case STATUS_UPDATES: 35415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_STATUS_UPDATES: { 35420a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov return deleteStatusUpdates(selection, selectionArgs); 35431f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey } 35441f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey 35453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 35463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 35473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItems(uri, new ContentValues(), selection, selectionArgs); 35483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35493b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35503b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 35513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 35523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItems(uri, new ContentValues(), 35539b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann StreamItems._ID + "=?", 35543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{uri.getLastPathSegment()}); 35553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35563b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 355782780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro case RAW_CONTACTS_ID_STREAM_ITEMS_ID: { 355882780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro mSyncToNetwork |= !callerIsSyncAdapter; 355982780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro String rawContactId = uri.getPathSegments().get(1); 356082780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro String streamItemId = uri.getLastPathSegment(); 356182780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro return deleteStreamItems(uri, new ContentValues(), 356282780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro StreamItems.RAW_CONTACT_ID + "=? AND " + StreamItems._ID + "=?", 356382780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro new String[]{rawContactId, streamItemId}); 356482780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro 356582780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro } 356682780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro 35673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 35683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 35695d9fcbaaa0007134564d63272470296f5d23b62aDave Santoro String streamItemId = uri.getPathSegments().get(1); 35705d9fcbaaa0007134564d63272470296f5d23b62aDave Santoro String selectionWithId = 35715d9fcbaaa0007134564d63272470296f5d23b62aDave Santoro (StreamItemPhotos.STREAM_ITEM_ID + "=" + streamItemId + " ") 35725d9fcbaaa0007134564d63272470296f5d23b62aDave Santoro + (selection == null ? "" : " AND (" + selection + ")"); 35735d9fcbaaa0007134564d63272470296f5d23b62aDave Santoro return deleteStreamItemPhotos(uri, new ContentValues(), 35745d9fcbaaa0007134564d63272470296f5d23b62aDave Santoro selectionWithId, selectionArgs); 35753b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 35773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 35783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann mSyncToNetwork |= !callerIsSyncAdapter; 35793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 35803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 35813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return deleteStreamItemPhotos(uri, new ContentValues(), 35823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=? AND " 35833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann + StreamItemPhotos.STREAM_ITEM_ID + "=?", 35843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{streamItemPhotoId, streamItemId}); 35853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 35863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 358781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov default: { 358881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 35893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov return mLegacyApiSupport.delete(uri, selection, selectionArgs); 359081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3591508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey } 35924f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 35934f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 35941c8e40c18f92722b9bec6e8ce2e345a9828efa16Dmitri Plotnikov public int deleteGroup(Uri uri, long groupId, boolean callerIsSyncAdapter) { 3595ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 3596ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov mGroupIdCache.clear(); 35975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final long groupMembershipMimetypeId = mDbHelper.get() 359894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE); 3599ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki db.delete(Tables.DATA, DataColumns.MIMETYPE_ID + "=" 360094021b213e4db367f60b30fcbfe9019e28571784Fred Quintana + groupMembershipMimetypeId + " AND " + GroupMembership.GROUP_ROW_ID + "=" 360194021b213e4db367f60b30fcbfe9019e28571784Fred Quintana + groupId, null); 360294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 360394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana try { 3604f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana if (callerIsSyncAdapter) { 3605ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return db.delete(Tables.GROUPS, Groups._ID + "=" + groupId, null); 360694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } else { 360794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana mValues.clear(); 360894021b213e4db367f60b30fcbfe9019e28571784Fred Quintana mValues.put(Groups.DELETED, 1); 3609f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mValues.put(Groups.DIRTY, 1); 3610ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return db.update(Tables.GROUPS, mValues, Groups._ID + "=" + groupId, 36115d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro null); 361294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 361394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } finally { 36141a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 361594021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 361694021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 361794021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 36185aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey private int deleteSettings(Uri uri, String selection, String[] selectionArgs) { 3619ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 3620ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final int count = db.delete(Tables.SETTINGS, selection, selectionArgs); 36211a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 3622e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return count; 3623e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 3624e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 3625dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int deleteContact(long contactId, boolean callerIsSyncAdapter) { 3626ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 362796b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1[0] = Long.toString(contactId); 3628ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor c = db.query(Tables.RAW_CONTACTS, new String[]{RawContacts._ID}, 362996b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker RawContacts.CONTACT_ID + "=?", mSelectionArgs1, 363096b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker null, null, null); 3631cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov try { 3632cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov while (c.moveToNext()) { 3633cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov long rawContactId = c.getLong(0); 3634ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki markRawContactAsDeleted(db, rawContactId, callerIsSyncAdapter); 3635cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3636cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } finally { 3637cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov c.close(); 3638cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3639cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 36403826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 36413826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 36428ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng int result = ContactsTableUtil.deleteContact(db, contactId); 36438ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng scheduleBackgroundTask(BACKGROUND_TASK_CLEAN_DELETE_LOG); 36448ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng return result; 3645cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3646cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 3647fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov public int deleteRawContact(long rawContactId, long contactId, boolean callerIsSyncAdapter) { 36485d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().invalidateAggregationExceptionCache(); 36493826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mProviderStatusUpdateNeeded = true; 36503826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 3651ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 3652ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 365382780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro // Find and delete stream items associated with the raw contact. 3654ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor c = db.query(Tables.STREAM_ITEMS, 365582780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro new String[]{StreamItems._ID}, 365682780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro StreamItems.RAW_CONTACT_ID + "=?", new String[]{String.valueOf(rawContactId)}, 365782780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro null, null, null); 365882780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro try { 365982780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro while (c.moveToNext()) { 3660ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki deleteStreamItem(db, c.getLong(0)); 366182780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro } 366282780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro } finally { 366382780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro c.close(); 366482780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro } 366582780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro 3666d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro if (callerIsSyncAdapter || rawContactIsLocal(rawContactId)) { 36678ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng 36688ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng // When a raw contact is deleted, a sqlite trigger deletes the parent contact. 36698ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng // TODO: all contact deletes was consolidated into ContactTableUtil but this one can't 36708ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng // because it's in a trigger. Consider removing trigger and replacing with java code. 36718ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng // This has to happen before the raw contact is deleted since it relies on the number 36728ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng // of raw contacts. 36738ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng ContactsTableUtil.deleteContactIfSingleton(db, rawContactId); 36748ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng 3675ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki db.delete(Tables.PRESENCE, 36765d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null); 3677ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki int count = db.delete(Tables.RAW_CONTACTS, 36785d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro RawContacts._ID + "=" + rawContactId, null); 36798ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng 368041f76a59a31946f6d784dacf9f13d9a4c0bbe203Dave Santoro mAggregator.get().updateAggregateData(mTransactionContext.get(), contactId); 36818ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng mTransactionContext.get().markRawContactChangedOrDeletedOrInserted(rawContactId); 3682fada1f08e7ffc8012bf2175f61f3ef3270eba9ecDmitri Plotnikov return count; 368333b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } else { 36848ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng ContactsTableUtil.deleteContactIfSingleton(db, rawContactId); 3685ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return markRawContactAsDeleted(db, rawContactId, callerIsSyncAdapter); 368633b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 368733b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 368833b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov 3689d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro /** 3690d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro * Returns whether the given raw contact ID is local (i.e. has no account associated with it). 3691d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro */ 3692d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro private boolean rawContactIsLocal(long rawContactId) { 3693ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getReadableDatabase(); 3694ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor c = db.query(Tables.RAW_CONTACTS, Projections.LITERAL_ONE, 36959d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki RawContactsColumns.CONCRETE_ID + "=? AND " + 36969d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki RawContactsColumns.ACCOUNT_ID + "=" + Clauses.LOCAL_ACCOUNT_ID, 3697d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro new String[] {String.valueOf(rawContactId)}, null, null, null); 3698d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro try { 36999d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki return c.getCount() > 0; 3700d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro } finally { 3701d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro c.close(); 3702d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro } 3703d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro } 3704d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro 37050a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov private int deleteStatusUpdates(String selection, String[] selectionArgs) { 37069705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // delete from both tables: presence and status_updates 37079705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO should account type/name be appended to the where clause? 37089705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (VERBOSE_LOGGING) { 37099705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori Log.v(TAG, "deleting data from status_updates for " + selection); 37109705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 3711ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 3712ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki db.delete(Tables.STATUS_UPDATES, getWhereClauseForStatusUpdatesTable(selection), 37139705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selectionArgs); 3714ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return db.delete(Tables.PRESENCE, selection, selectionArgs); 37150a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 37160a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 37173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItems(Uri uri, ContentValues values, String selection, 37183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 3719ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 37209d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki int count = 0; 3721ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final Cursor c = db.query(Views.STREAM_ITEMS, Projections.ID, 37229d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki selection, selectionArgs, null, null, null); 37239d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki try { 37249d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki c.moveToPosition(-1); 37259d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki while (c.moveToNext()) { 3726ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki count += deleteStreamItem(db, c.getLong(0)); 37279d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 37289d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } finally { 37299d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki c.close(); 37303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 37319d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki return count; 37323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 37333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 3734ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki private int deleteStreamItem(SQLiteDatabase db, long streamItemId) { 37353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann deleteStreamItemPhotos(streamItemId); 3736ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return db.delete(Tables.STREAM_ITEMS, StreamItems._ID + "=?", 37373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(streamItemId)}); 37383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 37393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 37403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItemPhotos(Uri uri, ContentValues values, String selection, 37413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 3742ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 3743ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return db.delete(Tables.STREAM_ITEM_PHOTOS, selection, selectionArgs); 37443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 37453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 37463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int deleteStreamItemPhotos(long streamItemId) { 3747ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 37483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Note that this does not enforce the modifying account. 3749ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return db.delete(Tables.STREAM_ITEM_PHOTOS, 37505d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro StreamItemPhotos.STREAM_ITEM_ID + "=?", 37513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{String.valueOf(streamItemId)}); 37523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 37533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 3754ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki private int markRawContactAsDeleted(SQLiteDatabase db, long rawContactId, 3755ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki boolean callerIsSyncAdapter) { 375681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 375781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov 3758cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.clear(); 3759cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.DELETED, 1); 3760cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED); 3761cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContactsColumns.AGGREGATION_NEEDED, 1); 3762cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.putNull(RawContacts.CONTACT_ID); 3763cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov mValues.put(RawContacts.DIRTY, 1); 3764ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return updateRawContact(db, rawContactId, mValues, callerIsSyncAdapter); 3765cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov } 3766cb144e1429596701603c016f4a078f6331e6481dDmitri Plotnikov 3767b6186821548995dce533ee502e82e9abf4c0aadcMakoto Onuki private int deleteDataUsage() { 3768ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 3769a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki db.execSQL("UPDATE " + Tables.RAW_CONTACTS + " SET " + 3770a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki Contacts.TIMES_CONTACTED + "=0," + 3771a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki Contacts.LAST_TIME_CONTACTED + "=NULL" 3772a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki ); 3773a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki db.execSQL("UPDATE " + Tables.CONTACTS + " SET " + 3774a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki Contacts.TIMES_CONTACTED + "=0," + 3775a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki Contacts.LAST_TIME_CONTACTED + "=NULL" 3776a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki ); 3777a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki db.delete(Tables.DATA_USAGE_STAT, null, null); 3778a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki 3779a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki return 1; 3780a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki } 3781a780048d2caafbd922444b0c08adb81790db4635Makoto Onuki 37824f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 3783de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov protected int updateInTransaction(Uri uri, ContentValues values, String selection, 3784de955f25491cdc0e826ea5c7d4cd0e93cb970fb7Dmitri Plotnikov String[] selectionArgs) { 3785bce6ee29f2d971ceae2bfce85a06bb3ecec6537aDmitri Plotnikov if (VERBOSE_LOGGING) { 37862fe1f4f757a84cb76382c375ba3755a802c5e444Makoto Onuki Log.v(TAG, "updateInTransaction: uri=" + uri + 37872fe1f4f757a84cb76382c375ba3755a802c5e444Makoto Onuki " selection=[" + selection + "] args=" + Arrays.toString(selectionArgs) + 37882fe1f4f757a84cb76382c375ba3755a802c5e444Makoto Onuki " values=[" + values + "]"); 3789b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3790b5a4add17815167d20a90645779df34cdf45280dFred Quintana 3791ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 37925d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 379335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana int count = 0; 379400d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 379500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar final int match = sUriMatcher.match(uri); 3796b5a4add17815167d20a90645779df34cdf45280dFred Quintana if (match == SYNCSTATE_ID && selection == null) { 3797b5a4add17815167d20a90645779df34cdf45280dFred Quintana long rowId = ContentUris.parseId(uri); 37981129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov Object data = values.get(ContactsContract.SyncState.DATA); 37995d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mTransactionContext.get().syncStateUpdated(rowId, data); 3800b5a4add17815167d20a90645779df34cdf45280dFred Quintana return 1; 3801b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 3802b5a4add17815167d20a90645779df34cdf45280dFred Quintana flushTransactionalChanges(); 3803f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana final boolean callerIsSyncAdapter = 3804f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana readBooleanQueryParameter(uri, ContactsContract.CALLER_IS_SYNCADAPTER, false); 380500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar switch(match) { 380635ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 38075d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE: 3808ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return mDbHelper.get().getSyncState().update(db, values, 3809b5a4add17815167d20a90645779df34cdf45280dFred Quintana appendAccountToSelection(uri, selection), selectionArgs); 3810b5a4add17815167d20a90645779df34cdf45280dFred Quintana 3811b5a4add17815167d20a90645779df34cdf45280dFred Quintana case SYNCSTATE_ID: { 3812b5a4add17815167d20a90645779df34cdf45280dFred Quintana selection = appendAccountToSelection(uri, selection); 3813b5a4add17815167d20a90645779df34cdf45280dFred Quintana String selectionWithId = 3814b5a4add17815167d20a90645779df34cdf45280dFred Quintana (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 3815b5a4add17815167d20a90645779df34cdf45280dFred Quintana + (selection == null ? "" : " AND (" + selection + ")"); 3816ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return mDbHelper.get().getSyncState().update(db, values, 38175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionWithId, selectionArgs); 38185d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 38195d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 38205d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE_ID: { 38215d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selection = appendAccountToSelection(uri, selection); 38225d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String selectionWithId = 38235d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro (SyncStateContract.Columns._ID + "=" + ContentUris.parseId(uri) + " ") 38245d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro + (selection == null ? "" : " AND (" + selection + ")"); 3825ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return mProfileHelper.getSyncState().update(db, values, 3826b5a4add17815167d20a90645779df34cdf45280dFred Quintana selectionWithId, selectionArgs); 3827b5a4add17815167d20a90645779df34cdf45280dFred Quintana } 382835ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 3829d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case CONTACTS: 3830d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE: { 383135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 3832dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateContactOptions(values, selection, selectionArgs, callerIsSyncAdapter); 383300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 383400d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 383500d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 3836d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 383735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 3838ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki count = updateContactOptions(db, ContentUris.parseId(uri), values, 3839ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki callerIsSyncAdapter); 3840c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar break; 3841c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar } 3842c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 38432e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey case CONTACTS_LOOKUP: 38442e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey case CONTACTS_LOOKUP_ID: { 384535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 38462e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final List<String> pathSegments = uri.getPathSegments(); 38472e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final int segmentCount = pathSegments.size(); 38482e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey if (segmentCount < 3) { 38495d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 3850fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 38512e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 38522e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey final String lookupKey = pathSegments.get(2); 3853ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final long contactId = lookupContactIdByLookupKey(db, lookupKey); 3854ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki count = updateContactOptions(db, contactId, values, callerIsSyncAdapter); 38552e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey break; 38562e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey } 38572e990cc352353b2e4d83f1eeecff137b94b84266Jeff Sharkey 3858193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki case RAW_CONTACTS_ID_DATA: 3859d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS_ID_DATA: { 386035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 3861193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki int segment = match == RAW_CONTACTS_ID_DATA ? 1 : 2; 3862d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro final String rawContactId = uri.getPathSegments().get(segment); 38637d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh String selectionWithId = (Data.RAW_CONTACT_ID + "=" + rawContactId + " ") 38647d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh + (selection == null ? "" : " AND " + selection); 38657d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 38667d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh count = updateData(uri, values, selectionWithId, selectionArgs, callerIsSyncAdapter); 38677d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 38687d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh break; 38697d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh } 38707d9fdcf8346f789436148eff1f00e8f49b370ef0Neel Parekh 38710c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro case DATA: 38720c5812a467378c57c2d2715ee4f0a9f541c64809Dave Santoro case PROFILE_DATA: { 387335997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 3874944abb09aa47fc08db668be8909fc4045a681117Cynthia Wong count = updateData(uri, values, appendAccountToSelection(uri, selection), 3875f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana selectionArgs, callerIsSyncAdapter); 387681d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3877f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 387881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 387920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov break; 388020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 3881c0834a81ef469e6ee7e72ce34a8a02855a162858Evan Millar 388248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case DATA_ID: 388348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 388448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 3885e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa case CALLABLES_ID: 388648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 388735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 3888f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana count = updateData(uri, values, selection, selectionArgs, callerIsSyncAdapter); 388981d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3890f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 389181d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 389200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar break; 389300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 38947e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 38955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case RAW_CONTACTS: 38965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_RAW_CONTACTS: { 389735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 38989d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki selection = appendAccountIdToSelection(uri, selection); 3899dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateRawContacts(values, selection, selectionArgs, callerIsSyncAdapter); 39007e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 39017e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 39027e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 39035ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov case RAW_CONTACTS_ID: { 390435997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 390533b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov long rawContactId = ContentUris.parseId(uri); 39064529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov if (selection != null) { 39074da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 39084da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov count = updateRawContacts(values, RawContacts._ID + "=?" 3909dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana + " AND(" + selection + ")", selectionArgs, 3910dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana callerIsSyncAdapter); 39114529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } else { 39124da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(rawContactId); 3913dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana count = updateRawContacts(values, RawContacts._ID + "=?", mSelectionArgs1, 3914dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana callerIsSyncAdapter); 39154529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 39167e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana break; 39177e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana } 39187e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 3919ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 39209d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki count = updateGroups(uri, values, appendAccountIdToSelection(uri, selection), 3921f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana selectionArgs, callerIsSyncAdapter); 392281d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3923f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 392481d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3925ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 3926ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3927ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3928ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 3929ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey long groupId = ContentUris.parseId(uri); 39304da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(groupId)); 39314da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov String selectionWithId = Groups._ID + "=? " 393273776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov + (selection == null ? "" : " AND " + selection); 39335aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey count = updateGroups(uri, values, selectionWithId, selectionArgs, 39345aec18c7ba70a011ffff949cfa3faaffce0a79c7Jeff Sharkey callerIsSyncAdapter); 393581d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov if (count > 0) { 3936f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana mSyncToNetwork |= !callerIsSyncAdapter; 393781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 3938ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 3939ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 3940ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 3941127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 3942ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki count = updateAggregationException(db, values); 39439ff2587608416b4378767141ad396f51f23040a7Makoto Onuki invalidateFastScrollingIndexCache(); 3944b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 3945b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 3946b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 3947eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 3948e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey count = updateSettings(uri, values, appendAccountToSelection(uri, selection), 3949e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey selectionArgs); 395043880c9228332d0ea1426341fcf712d302b2c55bDmitri Plotnikov mSyncToNetwork |= !callerIsSyncAdapter; 3951eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 3952eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 3953eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 39545d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case STATUS_UPDATES: 39555d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_STATUS_UPDATES: { 39569705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori count = updateStatusUpdate(uri, values, selection, selectionArgs); 39579705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori break; 39589705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 39599705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 39603b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 39613b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItems(uri, values, selection, selectionArgs); 39623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 39633b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 39643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 39653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 39669b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann count = updateStreamItems(uri, values, StreamItems._ID + "=?", 39673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{uri.getLastPathSegment()}); 39683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 39693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 39703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 397182780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro case RAW_CONTACTS_ID_STREAM_ITEMS_ID: { 397282780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro String rawContactId = uri.getPathSegments().get(1); 397382780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro String streamItemId = uri.getLastPathSegment(); 397482780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro count = updateStreamItems(uri, values, 397582780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro StreamItems.RAW_CONTACT_ID + "=? AND " + StreamItems._ID + "=?", 397682780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro new String[]{rawContactId, streamItemId}); 397782780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro break; 397882780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro } 397982780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro 39803b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 39813b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, selection, selectionArgs); 39823b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 39833b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 39843b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 39853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 39863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 39873b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, 39883b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotos.STREAM_ITEM_ID + "=?", new String[]{streamItemId}); 39893b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 39903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 39913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 39923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 39933b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 39943b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 39953b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann count = updateStreamItemPhotos(uri, values, 39963b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=? AND " + 39973b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=?", 39983b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann new String[]{streamItemPhotoId, streamItemId}); 39993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 40003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 40013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 400272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov case DIRECTORIES: { 4003bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov mContactDirectoryManager.scanPackagesByUid(Binder.getCallingUid()); 400472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov count = 1; 4005d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 4006d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4007d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 400846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa case DATA_USAGE_FEEDBACK_ID: { 400946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (handleDataUsageFeedback(uri)) { 401046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa count = 1; 401146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 401246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa count = 0; 401346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 401446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa break; 401546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 401646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 401781d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov default: { 401881d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov mSyncToNetwork = true; 4019f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.update(uri, values, selection, selectionArgs); 402081d6a78dffd57f24f9aaecb6cd54e4084c3c9846Dmitri Plotnikov } 402100d71133c63c882fb41729ddc3a52f66fb155374Evan Millar } 402200d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 402300d71133c63c882fb41729ddc3a52f66fb155374Evan Millar return count; 40244f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 40254f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 40269705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private int updateStatusUpdate(Uri uri, ContentValues values, String selection, 40279705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori String[] selectionArgs) { 4028ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 40299705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // update status_updates table, if status is provided 40309705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO should account type/name be appended to the where clause? 40319705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori int updateCount = 0; 40329705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContentValues settableValues = getSettableColumnsForStatusUpdatesTable(values); 40339705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (settableValues.size() > 0) { 4034ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki updateCount = db.update(Tables.STATUS_UPDATES, 40359705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori settableValues, 40369705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori getWhereClauseForStatusUpdatesTable(selection), 40379705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selectionArgs); 40389705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 40399705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 40409705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // now update the Presence table 40419705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori settableValues = getSettableColumnsForPresenceTable(values); 40429705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori if (settableValues.size() > 0) { 4043ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki updateCount = db.update(Tables.PRESENCE, settableValues, 40449705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori selection, selectionArgs); 40459705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 40469705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // TODO updateCount is not entirely a valid count of updated rows because 2 tables could 40479705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori // potentially get updated in this method. 40489705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return updateCount; 40499705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 40509705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 40513b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int updateStreamItems(Uri uri, ContentValues values, String selection, 40523b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 40533b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Stream items can't be moved to a new raw contact. 40543b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.remove(StreamItems.RAW_CONTACT_ID); 40553b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 40566802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to update accounts params - they don't exist in the stream items table. 40576802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_NAME); 40586802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_TYPE); 40596802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 4060ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 4061ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 40623b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // If there's been no exception, the update should be fine. 4063ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return db.update(Tables.STREAM_ITEMS, values, selection, selectionArgs); 40643b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 40653b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 40663b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private int updateStreamItemPhotos(Uri uri, ContentValues values, String selection, 40673b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String[] selectionArgs) { 40683b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann // Stream item photos can't be moved to a new stream item. 40693b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann values.remove(StreamItemPhotos.STREAM_ITEM_ID); 40703b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 40716802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Don't attempt to update accounts params - they don't exist in the stream item 40726802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // photos table. 40736802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_NAME); 40746802030a777c0c3ba1dc029c534cca4784260632Dave Santoro values.remove(RawContacts.ACCOUNT_TYPE); 40756802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 4076ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 4077ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 40786802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Process the photo (since we're updating, it's valid for the photo to not be present). 40796802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (processStreamItemPhoto(values, true)) { 40806802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // If there's been no exception, the update should be fine. 4081ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return db.update(Tables.STREAM_ITEM_PHOTOS, values, selection, 40825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs); 40836802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 40846802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return 0; 40853b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 40863b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 40879705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori /** 40889705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori * Build a where clause to select the rows to be updated in status_updates table. 40899705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori */ 40909705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private String getWhereClauseForStatusUpdatesTable(String selection) { 40919705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.setLength(0); 40929705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(WHERE_CLAUSE_FOR_STATUS_UPDATES_TABLE); 40939705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(selection); 40949705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mSb.append(")"); 40959705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mSb.toString(); 40969705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 40979705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 40989705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private ContentValues getSettableColumnsForStatusUpdatesTable(ContentValues values) { 40999705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mValues.clear(); 41009705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS, values, 41019705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS); 41029705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_TIMESTAMP, values, 41039705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_TIMESTAMP); 41049705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_RES_PACKAGE, values, 41059705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_RES_PACKAGE); 41069705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_LABEL, values, 41079705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_LABEL); 41089705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.STATUS_ICON, values, 41099705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.STATUS_ICON); 41109705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mValues; 41119705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 41129705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 41139705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori private ContentValues getSettableColumnsForPresenceTable(ContentValues values) { 41149705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori mValues.clear(); 41159705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.PRESENCE, values, 41169705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori StatusUpdates.PRESENCE); 4117aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori ContactsDatabaseHelper.copyStringValue(mValues, StatusUpdates.CHAT_CAPABILITY, values, 4118aabcd1d34a71ad06ee0a9395331540484f1ceb17Vasu Nori StatusUpdates.CHAT_CAPABILITY); 41199705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori return mValues; 41209705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori } 41219705f5bcb04c4b3012a762fb3ba8620b518587ccVasu Nori 41229d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki private interface GroupAccountQuery { 41239d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki String TABLE = Views.GROUPS; 41249d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 41259d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki String[] COLUMNS = new String[] { 41269d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki Groups._ID, 41279d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki Groups.ACCOUNT_TYPE, 41289d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki Groups.ACCOUNT_NAME, 41299d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki Groups.DATA_SET, 41309d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki }; 41319d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki int ID = 0; 41329d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki int ACCOUNT_TYPE = 1; 41339d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki int ACCOUNT_NAME = 2; 41349d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki int DATA_SET = 3; 41359d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 413673776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 41379d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki private int updateGroups(Uri uri, ContentValues originalValues, String selectionWithId, 41389d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki String[] selectionArgs, boolean callerIsSyncAdapter) { 4139ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov mGroupIdCache.clear(); 4140ab91a8babdbda516d4e5088fedf3fdebf9cf88adDmitri Plotnikov 4141ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 41429d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final ContactsDatabaseHelper dbHelper = mDbHelper.get(); 41439d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 41449d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final ContentValues updatedValues = new ContentValues(); 41459d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki updatedValues.putAll(originalValues); 41469d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 41479d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (!callerIsSyncAdapter && !updatedValues.containsKey(Groups.DIRTY)) { 414873776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov updatedValues.put(Groups.DIRTY, 1); 414973776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov } 41501a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (updatedValues.containsKey(Groups.GROUP_VISIBLE)) { 41511a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 415294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 415343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 41549d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // Prepare for account change 41559d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final boolean isAccountNameChanging = updatedValues.containsKey(Groups.ACCOUNT_NAME); 41569d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final boolean isAccountTypeChanging = updatedValues.containsKey(Groups.ACCOUNT_TYPE); 41579d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final boolean isDataSetChanging = updatedValues.containsKey(Groups.DATA_SET); 41589d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final boolean isAccountChanging = isAccountNameChanging || isAccountTypeChanging 41599d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki || isDataSetChanging; 41609d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final String updatedAccountName = updatedValues.getAsString(Groups.ACCOUNT_NAME); 41619d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final String updatedAccountType = updatedValues.getAsString(Groups.ACCOUNT_TYPE); 41629d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final String updatedDataSet = updatedValues.getAsString(Groups.DATA_SET); 41639d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 41649d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki updatedValues.remove(Groups.ACCOUNT_NAME); 41659d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki updatedValues.remove(Groups.ACCOUNT_TYPE); 41669d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki updatedValues.remove(Groups.DATA_SET); 41679d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 41689d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // We later call requestSync() on all affected accounts. 41699d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final Set<Account> affectedAccounts = Sets.newHashSet(); 41709d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 41719d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // Look for all affected rows, and change them row by row. 41729d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final Cursor c = db.query(GroupAccountQuery.TABLE, GroupAccountQuery.COLUMNS, 41739d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki selectionWithId, selectionArgs, null, null, null); 41749d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki int returnCount = 0; 41759d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki try { 41769d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki c.moveToPosition(-1); 41779d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki while (c.moveToNext()) { 41789d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final long groupId = c.getLong(GroupAccountQuery.ID); 41799d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 41809d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mSelectionArgs1[0] = Long.toString(groupId); 41819d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 41829d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final String accountName = isAccountNameChanging 41839d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki ? updatedAccountName : c.getString(GroupAccountQuery.ACCOUNT_NAME); 41849d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final String accountType = isAccountTypeChanging 41859d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki ? updatedAccountType : c.getString(GroupAccountQuery.ACCOUNT_TYPE); 41869d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final String dataSet = isDataSetChanging 41879d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki ? updatedDataSet : c.getString(GroupAccountQuery.DATA_SET); 41889d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 41899d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (isAccountChanging) { 41909d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final long accountId = dbHelper.getOrCreateAccountIdInTransaction( 41919d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki AccountWithDataSet.get(accountName, accountType, dataSet)); 41929d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki updatedValues.put(GroupsColumns.ACCOUNT_ID, accountId); 41939d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 41949d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 41959d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // Finally do the actual update. 41969d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final int count = db.update(Tables.GROUPS, updatedValues, 41979d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki GroupsColumns.CONCRETE_ID + "=?", mSelectionArgs1); 41989d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 41999d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if ((count > 0) 42009d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki && !TextUtils.isEmpty(accountName) 42019d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki && !TextUtils.isEmpty(accountType)) { 42029d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki affectedAccounts.add(new Account(accountName, accountType)); 42039d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 42049d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 42059d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki returnCount += count; 42069d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 42079d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } finally { 42089d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki c.close(); 42099d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 42109d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 421143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // TODO: This will not work for groups that have a data set specified, since the content 421243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // resolver will not be able to request a sync for the right source (unless it is updated 421343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // to key off account with data set). 42149d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // i.e. requestSync only takes Account, not AccountWithDataSet. 42156ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi if (updatedValues.containsKey(Groups.SHOULD_SYNC) 42161129311abb3db9bf6eb5731da054276164e0b8d1Dmitri Plotnikov && updatedValues.getAsInteger(Groups.SHOULD_SYNC) != 0) { 42179d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki for (Account account : affectedAccounts) { 42189d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki ContentResolver.requestSync(account, ContactsContract.AUTHORITY, new Bundle()); 42196ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 42206ce24dc1d53f1ed2760a06cd60c705ebdf666f43Megha Joshi } 42219d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki return returnCount; 422294021b213e4db367f60b30fcbfe9019e28571784Fred Quintana } 422394021b213e4db367f60b30fcbfe9019e28571784Fred Quintana 4224b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov private int updateSettings(Uri uri, ContentValues values, String selection, 4225b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov String[] selectionArgs) { 4226ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 4227ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final int count = db.update(Tables.SETTINGS, values, selection, selectionArgs); 42281a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey if (values.containsKey(Settings.UNGROUPED_VISIBLE)) { 42291a21fa6383449df4bf0d46138a23aa02dfa235a0Jeff Sharkey mVisibleTouched = true; 4230e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 4231e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey return count; 4232e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 4233e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 4234dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana private int updateRawContacts(ContentValues values, String selection, String[] selectionArgs, 4235dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 42364529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov if (values.containsKey(RawContacts.CONTACT_ID)) { 42374529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov throw new IllegalArgumentException(RawContacts.CONTACT_ID + " should not be included " + 42384529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov "in content values. Contact IDs are assigned automatically"); 42394529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 424073776ffd5c00e94db987ee30864e9c7a8396d22dDmitri Plotnikov 424197fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov if (!callerIsSyncAdapter) { 424297fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov selection = DatabaseUtils.concatenateWhere(selection, 424397fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov RawContacts.RAW_CONTACT_IS_READ_ONLY + "=0"); 424497fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov } 424597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 42464529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov int count = 0; 4247ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 4248ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor cursor = db.query(Views.RAW_CONTACTS, 42499d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki Projections.ID, selection, 42504529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov selectionArgs, null, null, null); 42514529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov try { 42524529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov while (cursor.moveToNext()) { 42534529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov long rawContactId = cursor.getLong(0); 4254ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki updateRawContact(db, rawContactId, values, callerIsSyncAdapter); 42554529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov count++; 42564529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 42574529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } finally { 42584529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov cursor.close(); 42594529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 42604529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov 42614529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov return count; 42624529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov } 42634529f06d48c8ad3cc573a9b7b8f2f952b1e20dcdDmitri Plotnikov 4264ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki private int updateRawContact(SQLiteDatabase db, long rawContactId, ContentValues values, 4265dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 42669d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final String selection = RawContactsColumns.CONCRETE_ID + " = ?"; 426796b7618a3996f2f356cb33553e76877d23a996f2Doug Zongker mSelectionArgs1[0] = Long.toString(rawContactId); 42689d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 42699d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final ContactsDatabaseHelper dbHelper = mDbHelper.get(); 42709d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 427119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka final boolean requestUndoDelete = (values.containsKey(RawContacts.DELETED) 427219cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka && values.getAsInteger(RawContacts.DELETED) == 0); 42739d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 42749d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final boolean isAccountNameChanging = values.containsKey(RawContacts.ACCOUNT_NAME); 42759d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final boolean isAccountTypeChanging = values.containsKey(RawContacts.ACCOUNT_TYPE); 42769d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final boolean isDataSetChanging = values.containsKey(RawContacts.DATA_SET); 42779d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final boolean isAccountChanging = isAccountNameChanging || isAccountTypeChanging 42789d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki || isDataSetChanging; 42799d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 428019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka int previousDeleted = 0; 42819d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki long accountId = 0; 42829d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki String oldAccountType = null; 42839d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki String oldAccountName = null; 42849d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki String oldDataSet = null; 42859d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 42869d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (requestUndoDelete || isAccountChanging) { 4287ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor cursor = db.query(RawContactsQuery.TABLE, RawContactsQuery.COLUMNS, 42885d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selection, mSelectionArgs1, null, null, null); 428919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka try { 429019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (cursor.moveToFirst()) { 429119cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka previousDeleted = cursor.getInt(RawContactsQuery.DELETED); 42929d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki accountId = cursor.getLong(RawContactsQuery.ACCOUNT_ID); 42939d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki oldAccountType = cursor.getString(RawContactsQuery.ACCOUNT_TYPE); 42949d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki oldAccountName = cursor.getString(RawContactsQuery.ACCOUNT_NAME); 42959d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki oldDataSet = cursor.getString(RawContactsQuery.DATA_SET); 429619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 429719cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } finally { 429819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka cursor.close(); 429919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 43009d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (isAccountChanging) { 43019d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // We can't change the original ContentValues, as it'll be re-used over all 43029d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // updateRawContact invocations in a transaction, so we need to create a new one. 43039d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // (However we don't want to use mValues here, because mValues may be used in some 43049d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // other methods that are called by this method.) 43059d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final ContentValues originalValues = values; 43069d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki values = new ContentValues(); 43079d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki values.clear(); 43089d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki values.putAll(originalValues); 43099d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 43109d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final AccountWithDataSet newAccountWithDataSet = AccountWithDataSet.get( 43119d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki isAccountNameChanging 43129d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki ? values.getAsString(RawContacts.ACCOUNT_NAME) : oldAccountName, 43139d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki isAccountTypeChanging 43149d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki ? values.getAsString(RawContacts.ACCOUNT_TYPE) : oldAccountType, 43159d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki isDataSetChanging 43169d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki ? values.getAsString(RawContacts.DATA_SET) : oldDataSet 43179d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki ); 43189d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki accountId = dbHelper.getOrCreateAccountIdInTransaction(newAccountWithDataSet); 43199d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 43209d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki values.put(RawContactsColumns.ACCOUNT_ID, accountId); 43219d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 43229d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki values.remove(RawContacts.ACCOUNT_NAME); 43239d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki values.remove(RawContacts.ACCOUNT_TYPE); 43249d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki values.remove(RawContacts.DATA_SET); 43259d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 43269d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 43279d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (requestUndoDelete) { 432819cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka values.put(ContactsContract.RawContacts.AGGREGATION_MODE, 432919cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT); 433019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 4331f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov 4332ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki int count = db.update(Tables.RAW_CONTACTS, values, selection, mSelectionArgs1); 43335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count != 0) { 4334f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov if (values.containsKey(RawContacts.AGGREGATION_MODE)) { 4335f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov int aggregationMode = values.getAsInteger(RawContacts.AGGREGATION_MODE); 4336f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov 4337f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov // As per ContactsContract documentation, changing aggregation mode 4338f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov // to DEFAULT should not trigger aggregation 4339f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov if (aggregationMode != RawContacts.AGGREGATION_MODE_DEFAULT) { 43405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().markForAggregation(rawContactId, aggregationMode, false); 4341f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 4342f5a847e8c93db02f3334dbc276debd90bdea5658Dmitri Plotnikov } 4343433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey if (values.containsKey(RawContacts.STARRED)) { 4344dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (!callerIsSyncAdapter) { 4345dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, 4346dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana values.getAsLong(RawContacts.STARRED) != 0); 4347dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 43485d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().updateStarred(rawContactId); 4349dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } else { 4350dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // if this raw contact is being associated with an account, then update the 4351dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // favorites group membership based on whether or not this contact is starred. 4352dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // If it is starred, add a group membership, if one doesn't already exist 4353dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // otherwise delete any matching group memberships. 43549d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (!callerIsSyncAdapter && isAccountChanging) { 4355ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki boolean starred = 0 != DatabaseUtils.longForQuery(db, 4356dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana SELECTION_STARRED_FROM_RAW_CONTACTS, 4357dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[]{Long.toString(rawContactId)}); 4358dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, starred); 4359dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4360dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4361dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 4362dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // if this raw contact is being associated with an account, then add a 4363dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana // group membership to the group marked as AutoAdd, if any. 43649d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (!callerIsSyncAdapter && isAccountChanging) { 4365dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana addAutoAddMembership(rawContactId); 4366433a3a08a4726952c080e22e3969ac6c4f28e8dfJeff Sharkey } 4367dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 4368285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov if (values.containsKey(RawContacts.SOURCE_ID)) { 4369ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki mAggregator.get().updateLookupKeyForRawContact(db, rawContactId); 4370285b771bc955305fa6d49ca23f808cecc8a13d5eDmitri Plotnikov } 4371f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov if (values.containsKey(RawContacts.NAME_VERIFIED)) { 4372f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov 4373f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov // If setting NAME_VERIFIED for this raw contact, reset it for all 4374f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov // other raw contacts in the same aggregate 4375f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov if (values.getAsInteger(RawContacts.NAME_VERIFIED) != 0) { 43765d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().resetNameVerifiedForOtherRawContacts(rawContactId); 4377f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov } 4378ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki mAggregator.get().updateDisplayNameForRawContact(db, rawContactId); 4379f01c876a92b9c950a0450ed8b706ac5eb2c9b660Dmitri Plotnikov } 438019cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka if (requestUndoDelete && previousDeleted == 1) { 43819d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // Note before the accounts refactoring, we used to use the *old* account here, 43829d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // which doesn't make sense, so now we pass the *new* account. 43839d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // (In practice it doesn't matter because there's probably no apps that undo-delete 43849d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // and change accounts at the same time.) 43859d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki mTransactionContext.get().rawContactInserted(rawContactId, accountId); 438619cf97e1f8a569ad782756183419b7ba45ce15a0Tadashi G. Takaoka } 43878ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng mTransactionContext.get().markRawContactChangedOrDeletedOrInserted(rawContactId); 43885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 43895870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return count; 439033b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov } 439133b41fdb8d7c3c654cb070799c9d6e2b4ab16078Dmitri Plotnikov 4392321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana private int updateData(Uri uri, ContentValues values, String selection, 4393f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 439420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.clear(); 439520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.putAll(values); 439620a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data._ID); 43975ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov mValues.remove(Data.RAW_CONTACT_ID); 439820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.MIMETYPE); 439920a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 440020a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov String packageName = values.getAsString(Data.RES_PACKAGE); 440120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov if (packageName != null) { 440220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov mValues.remove(Data.RES_PACKAGE); 44035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mValues.put(DataColumns.PACKAGE_ID, mDbHelper.get().getPackageId(packageName)); 440420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 440520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 440697fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov if (!callerIsSyncAdapter) { 440797fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov selection = DatabaseUtils.concatenateWhere(selection, 440897fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov Data.IS_READ_ONLY + "=0"); 440997fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov } 441097fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov 4411653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov int count = 0; 441220a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 4413653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov // Note that the query will return data according to the access restrictions, 4414653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov // so we don't need to worry about updating data we don't have permission to read. 44155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = queryLocal(uri, 4416f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro DataRowHandler.DataUpdateQuery.COLUMNS, 441715826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann selection, selectionArgs, null, -1 /* directory ID */, null); 4418653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov try { 4419653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov while(c.moveToNext()) { 4420f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana count += updateData(mValues, c, callerIsSyncAdapter); 442120a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 4422653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov } finally { 4423653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov c.close(); 442420a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 442520a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 4426653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov return count; 442720a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov } 442820a94c86ede7380c8dd8df2f6a72b3c00ac1bed8Dmitri Plotnikov 4429f6be85f72615168c836b05c03ab5fc80d4794a82Fred Quintana private int updateData(ContentValues values, Cursor c, boolean callerIsSyncAdapter) { 4430653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov if (values.size() == 0) { 4431653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov return 0; 4432321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana } 4433653f73c9417ee0d2cf90e9aacd32848016747cf7Dmitri Plotnikov 4434ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 4435ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 4436f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov final String mimeType = c.getString(DataRowHandler.DataUpdateQuery.MIMETYPE); 4437a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov DataRowHandler rowHandler = getDataRowHandler(mimeType); 4438f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro boolean updated = 4439ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki rowHandler.update(db, mTransactionContext.get(), values, c, 44405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro callerIsSyncAdapter); 4441f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) { 4442f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 4443a6733943584294492aa0118fc32bf4e58dabb028Dmitri Plotnikov } 4444f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return updated ? 1 : 0; 4445321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana } 4446321afd997c985f150a13e0a5538e2a12b755b217Fred Quintana 44478c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov private int updateContactOptions(ContentValues values, String selection, 4448dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana String[] selectionArgs, boolean callerIsSyncAdapter) { 44498c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov int count = 0; 4450ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 4451ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 4452ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor cursor = db.query(Views.CONTACTS, 44535d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro new String[] { Contacts._ID }, selection, selectionArgs, null, null, null); 44548c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov try { 44558c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov while (cursor.moveToNext()) { 44568c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov long contactId = cursor.getLong(0); 445724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 4458ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki updateContactOptions(db, contactId, values, callerIsSyncAdapter); 44598c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov count++; 44608c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 44618c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } finally { 44628c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov cursor.close(); 44638c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 44648c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 44658c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov return count; 44668c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov } 44678c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 4468ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki private int updateContactOptions(SQLiteDatabase db, long contactId, ContentValues values, 4469dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana boolean callerIsSyncAdapter) { 4470d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 44718c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.clear(); 4472b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE, 4473d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.CUSTOM_RINGTONE); 4474b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL, 4475d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.SEND_TO_VOICEMAIL); 4476b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED, 4477d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.LAST_TIME_CONTACTED); 4478b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED, 4479d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.TIMES_CONTACTED); 4480b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED, 4481d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov values, Contacts.STARRED); 4482d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 4483d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov // Nothing to update - just return 44848c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov if (mValues.size() == 0) { 4485d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov return 0; 4486d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov } 4487d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 44888c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov if (mValues.containsKey(RawContacts.STARRED)) { 4489c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey // Mark dirty when changing starred to trigger sync 44908c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.put(RawContacts.DIRTY, 1); 4491c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey } 4492c76d0a78fe2d3471195cfa555bab016eec154f07Jeff Sharkey 44934da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs1[0] = String.valueOf(contactId); 4494ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki db.update(Tables.RAW_CONTACTS, mValues, RawContacts.CONTACT_ID + "=?" 449597fd30388bd6530f86679510cd7b43b9c518bcefDmitri Plotnikov + " AND " + RawContacts.RAW_CONTACT_IS_READ_ONLY + "=0", mSelectionArgs1); 44968c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 4497dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana if (mValues.containsKey(RawContacts.STARRED) && !callerIsSyncAdapter) { 4498ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor cursor = db.query(Views.RAW_CONTACTS, 4499dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana new String[] { RawContacts._ID }, RawContacts.CONTACT_ID + "=?", 4500dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mSelectionArgs1, null, null, null); 4501dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana try { 4502dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana while (cursor.moveToNext()) { 4503dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana long rawContactId = cursor.getLong(0); 4504dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana updateFavoritesMembership(rawContactId, 4505dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana mValues.getAsLong(RawContacts.STARRED) != 0); 4506dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4507dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } finally { 4508dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana cursor.close(); 4509dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4510dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana } 4511dd5c25c65f09ada246c826fb6d04f0b6d4cf4388Fred Quintana 45128c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov // Copy changeable values to prevent automatically managed fields from 45138c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov // being explicitly updated by clients. 45148c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov mValues.clear(); 4515b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyStringValue(mValues, RawContacts.CUSTOM_RINGTONE, 45168c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.CUSTOM_RINGTONE); 4517b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.SEND_TO_VOICEMAIL, 45188c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.SEND_TO_VOICEMAIL); 4519b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.LAST_TIME_CONTACTED, 45208c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.LAST_TIME_CONTACTED); 4521b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.TIMES_CONTACTED, 45228c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.TIMES_CONTACTED); 4523b38ed2c5ffeb20efc677b4a9229db4a00603aa8dDmitri Plotnikov ContactsDatabaseHelper.copyLongValue(mValues, RawContacts.STARRED, 45248c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov values, Contacts.STARRED); 45258ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng mValues.put(Contacts.CONTACT_LAST_UPDATED_TIMESTAMP, 45268ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng Clock.getInstance().currentTimeMillis()); 45278c4f838f899daadb6f46f8c27ab7636023e39c38Dmitri Plotnikov 4528ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki int rslt = db.update(Tables.CONTACTS, mValues, Contacts._ID + "=?", 45295d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mSelectionArgs1); 45306e38acbd1e72c62a6f8917297aed97e35c0c4697Vasu Nori 45319b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori if (values.containsKey(Contacts.LAST_TIME_CONTACTED) && 45329b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori !values.containsKey(Contacts.TIMES_CONTACTED)) { 4533ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki db.execSQL(UPDATE_TIMES_CONTACTED_CONTACTS_TABLE, mSelectionArgs1); 4534ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki db.execSQL(UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE, mSelectionArgs1); 45359b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori } 45369b1bd62417ef1764829398a61c3d5df93a924106Vasu Nori return rslt; 4537f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov } 4538d35d9c748af4c3182679c4c546137acfc11eb7a8Dmitri Plotnikov 4539127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov private int updateAggregationException(SQLiteDatabase db, ContentValues values) { 4540127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov int exceptionType = values.getAsInteger(AggregationExceptions.TYPE); 45410c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov long rcId1 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID1); 45420c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov long rcId2 = values.getAsInteger(AggregationExceptions.RAW_CONTACT_ID2); 454380c457131bd22afe34828d1a5d15e90bb5f43375Dmitri Plotnikov 4544ed089fd34d7b3baf29709eb4f2bc14fa35117660Dmitri Plotnikov long rawContactId1; 4545ed089fd34d7b3baf29709eb4f2bc14fa35117660Dmitri Plotnikov long rawContactId2; 45460c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov if (rcId1 < rcId2) { 45470c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId1 = rcId1; 45480c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId2 = rcId2; 45490c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov } else { 45500c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId2 = rcId1; 45510c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov rawContactId1 = rcId2; 4552b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 4553127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 45540c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov if (exceptionType == AggregationExceptions.TYPE_AUTOMATIC) { 45554da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs2[0] = String.valueOf(rawContactId1); 45564da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov mSelectionArgs2[1] = String.valueOf(rawContactId2); 45570c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov db.delete(Tables.AGGREGATION_EXCEPTIONS, 45584da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov AggregationExceptions.RAW_CONTACT_ID1 + "=? AND " 45594da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov + AggregationExceptions.RAW_CONTACT_ID2 + "=?", mSelectionArgs2); 45600c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov } else { 45616bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov ContentValues exceptionValues = new ContentValues(3); 45626bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov exceptionValues.put(AggregationExceptions.TYPE, exceptionType); 45630c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1); 45640c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues.put(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2); 45650c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov db.replace(Tables.AGGREGATION_EXCEPTIONS, AggregationExceptions._ID, 45660c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov exceptionValues); 4567127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov } 4568127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 45695d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().invalidateAggregationExceptionCache(); 45705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().markForAggregation(rawContactId1, 457169cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 45725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().markForAggregation(rawContactId2, 457369cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov RawContacts.AGGREGATION_MODE_DEFAULT, true); 4574dea3ee5e7f84be2abfe35837a460cbe779d319dbDmitri Plotnikov 45755d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().aggregateContact(mTransactionContext.get(), db, rawContactId1); 45765d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().aggregateContact(mTransactionContext.get(), db, rawContactId2); 4577127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov 4578127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // The return value is fake - we just confirm that we made a change, not count actual 4579127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov // rows changed. 4580127071b6305023a79b7d8f473ef6887843389f6eDmitri Plotnikov return 1; 4581b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 4582b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 4583ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki @Override 458470d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong public void onAccountsUpdated(Account[] accounts) { 4585bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_ACCOUNTS); 45863826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 45873826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 45889ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki private static final String ACCOUNT_STRING_SEPARATOR_OUTER = "\u0001"; 45899ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki private static final String ACCOUNT_STRING_SEPARATOR_INNER = "\u0002"; 45909d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 45919ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki /** return serialized version of {@code accounts} */ 45929ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki @VisibleForTesting 45939ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki static String accountsToString(Set<Account> accounts) { 45949ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final StringBuilder sb = new StringBuilder(); 45959ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki for (Account account : accounts) { 45969ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki if (sb.length() > 0) { 45979ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki sb.append(ACCOUNT_STRING_SEPARATOR_OUTER); 45989ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 45999ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki sb.append(account.name); 46009ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki sb.append(ACCOUNT_STRING_SEPARATOR_INNER); 46019ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki sb.append(account.type); 46029ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 46039ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki return sb.toString(); 46049ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 46059d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 46069ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki /** 46079ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki * de-serialize string returned by {@link #accountsToString} and return it. 46089ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki * If {@code accountsString} is malformed it'll throw {@link IllegalArgumentException}. 46099ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki */ 46109ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki @VisibleForTesting 46119ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki static Set<Account> stringToAccounts(String accountsString) { 46129ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final Set<Account> ret = Sets.newHashSet(); 46139ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki if (accountsString.length() == 0) return ret; // no accounts 46149ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki try { 46159ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki for (String accountString : accountsString.split(ACCOUNT_STRING_SEPARATOR_OUTER)) { 46169ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki String[] nameAndType = accountString.split(ACCOUNT_STRING_SEPARATOR_INNER); 46179ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki ret.add(new Account(nameAndType[0], nameAndType[1])); 46189ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 46199ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki return ret; 46209ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } catch (RuntimeException ex) { 46219ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki throw new IllegalArgumentException("Malformed string", ex); 46229ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 46239ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 46249ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki 46259ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki /** 46269ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki * @return {@code true} if the given {@code currentSystemAccounts} are different from the 46279ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki * accounts we know, which are stored in the {@link DbProperties#KNOWN_ACCOUNTS} property. 46289ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki */ 46299ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki @VisibleForTesting 46309ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki boolean haveAccountsChanged(Account[] currentSystemAccounts) { 46319ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final ContactsDatabaseHelper dbHelper = mDbHelper.get(); 46329ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final Set<Account> knownAccountSet; 46339ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki try { 46349ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki knownAccountSet = stringToAccounts( 46359ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki dbHelper.getProperty(DbProperties.KNOWN_ACCOUNTS, "")); 46369ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } catch (IllegalArgumentException e) { 46379ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // Failed to get the last known accounts for an unknown reason. Let's just 46389ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // treat as if accounts have changed. 46399ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki return true; 46409ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 46419ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final Set<Account> currentAccounts = Sets.newHashSet(currentSystemAccounts); 46429ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki return !knownAccountSet.equals(currentAccounts); 46439ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 46449ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki 46459ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki @VisibleForTesting 46469ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki void saveAccounts(Account[] systemAccounts) { 46479ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final ContactsDatabaseHelper dbHelper = mDbHelper.get(); 46489ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki dbHelper.setProperty(DbProperties.KNOWN_ACCOUNTS, 46499ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki accountsToString(Sets.newHashSet(systemAccounts))); 46509ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 46519ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki 46529ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki private boolean updateAccountsInBackground(Account[] systemAccounts) { 46539ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki if (!haveAccountsChanged(systemAccounts)) { 46549ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki return false; 46559ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 4656b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki if ("1".equals(SystemProperties.get(DEBUG_PROPERTY_KEEP_STALE_ACCOUNT_DATA))) { 4657b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki Log.w(TAG, "Accounts changed, but not removing stale data for " + 4658b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki DEBUG_PROPERTY_KEEP_STALE_ACCOUNT_DATA); 4659b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki return true; 4660b7e305c1ad38f1e2058453f7412e51477adf8a24Makoto Onuki } 46619ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki Log.i(TAG, "Accounts changed"); 466235997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 466335997f3fdee2984b6d5373326110eda26929001aMakoto Onuki invalidateFastScrollingIndexCache(); 466435997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 46659d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final ContactsDatabaseHelper dbHelper = mDbHelper.get(); 46669d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final SQLiteDatabase db = dbHelper.getWritableDatabase(); 46675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.beginTransaction(); 46685dccfb059f5df0e9fdba026bcfbed677f44922cdDave Santoro 46695dccfb059f5df0e9fdba026bcfbed677f44922cdDave Santoro // WARNING: This method can be run in either contacts mode or profile mode. It is 46705dccfb059f5df0e9fdba026bcfbed677f44922cdDave Santoro // absolutely imperative that no calls be made inside the following try block that can 4671a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng // interact with a specific contacts or profile DB. Otherwise it is quite possible for a 4672a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng // deadlock to occur. i.e. always use the current database in mDbHelper and do not access 4673a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng // mContactsHelper or mProfileHelper directly. 4674a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng // 4675a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng // The problem may be a bit more subtle if you also access something that stores the current 4676a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng // db instance in it's constructor. updateSearchIndexInTransaction relies on the 4677a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng // SearchIndexManager which upon construction, stores the current db. In this case, 4678a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng // SearchIndexManager always contains the contact DB. This is why the 4679a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng // updateSearchIndexInTransaction is protected with !isInProfileMode now. 468070d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong try { 46819d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // First, remove stale rows from raw_contacts, groups, and related tables. 46829d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 46839d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // All accounts that are used in raw_contacts and/or groups. 46849d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final Set<AccountWithDataSet> knownAccountsWithDataSets 46859d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki = dbHelper.getAllAccountsWithDataSets(); 468648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 46879d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // Find the accounts that have been removed. 46889d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final List<AccountWithDataSet> accountsWithDataSetsToDelete = Lists.newArrayList(); 46899d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki for (AccountWithDataSet knownAccountWithDataSet : knownAccountsWithDataSets) { 46909d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (knownAccountWithDataSet.isLocalAccount() 46919d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki || knownAccountWithDataSet.inSystemAccounts(systemAccounts)) { 46929d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki continue; 469343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 46949d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki accountsWithDataSetsToDelete.add(knownAccountWithDataSet); 469570d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 469670d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong 469743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (!accountsWithDataSetsToDelete.isEmpty()) { 469843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro for (AccountWithDataSet accountWithDataSet : accountsWithDataSetsToDelete) { 469943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Log.d(TAG, "removing data for removed account " + accountWithDataSet); 47009d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final Long accountIdOrNull = dbHelper.getAccountIdOrNull(accountWithDataSet); 47019d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 47029d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // getAccountIdOrNull() really shouldn't return null here, but just in case... 47039d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (accountIdOrNull != null) { 4704da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng final String accountId = Long.toString(accountIdOrNull); 47059d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final String[] accountIdParams = 4706da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng new String[] {accountId}; 47079d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki db.execSQL( 47089d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "DELETE FROM " + Tables.GROUPS + 47099d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " WHERE " + GroupsColumns.ACCOUNT_ID + " = ?", 47109d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki accountIdParams); 47119d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki db.execSQL( 47129d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "DELETE FROM " + Tables.PRESENCE + 47139d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " WHERE " + PresenceColumns.RAW_CONTACT_ID + " IN (" + 47149d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "SELECT " + RawContacts._ID + 47159d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " FROM " + Tables.RAW_CONTACTS + 47169d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " WHERE " + RawContactsColumns.ACCOUNT_ID + " = ?)", 47179d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki accountIdParams); 47189d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki db.execSQL( 47199d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "DELETE FROM " + Tables.STREAM_ITEM_PHOTOS + 47209d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " WHERE " + StreamItemPhotos.STREAM_ITEM_ID + " IN (" + 47219d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "SELECT " + StreamItems._ID + 47229d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " FROM " + Tables.STREAM_ITEMS + 47239d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " WHERE " + StreamItems.RAW_CONTACT_ID + " IN (" + 47249d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "SELECT " + RawContacts._ID + 47259d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " FROM " + Tables.RAW_CONTACTS + 47269d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " WHERE " + RawContactsColumns.ACCOUNT_ID + "=?))", 47279d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki accountIdParams); 47289d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki db.execSQL( 47299d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "DELETE FROM " + Tables.STREAM_ITEMS + 47309d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " WHERE " + StreamItems.RAW_CONTACT_ID + " IN (" + 47319d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "SELECT " + RawContacts._ID + 47329d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " FROM " + Tables.RAW_CONTACTS + 47339d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " WHERE " + RawContactsColumns.ACCOUNT_ID + " = ?)", 47349d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki accountIdParams); 4735a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng 4736a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng // Delta api is only needed for regular contacts. 4737a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng if (!inProfileMode()) { 4738a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng // Contacts are deleted by a trigger on the raw_contacts table. 4739a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng // But we also need to insert the contact into the delete log. 4740a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng // This logic is being consolidated into the ContactsTableUtil. 4741da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng 4742da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng // deleteContactIfSingleton() does not work in this case because raw 4743da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng // contacts will be deleted in a single batch below. Contacts with 4744da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng // multiple raw contacts in the same account will be missed. 4745da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng 4746da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng // Find all contacts that do not have raw contacts in other accounts. 4747da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng // These should be deleted. 4748da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng Cursor cursor = db.rawQuery( 4749da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng "SELECT " + RawContactsColumns.CONCRETE_CONTACT_ID + 4750a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng " FROM " + Tables.RAW_CONTACTS + 4751da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng " WHERE " + RawContactsColumns.ACCOUNT_ID + " = ?1" + 4752da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng " AND " + RawContactsColumns.CONCRETE_CONTACT_ID + 4753da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng " NOT IN (" + 4754da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng " SELECT " + RawContactsColumns.CONCRETE_CONTACT_ID + 4755da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng " FROM " + Tables.RAW_CONTACTS + 4756da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng " WHERE " + RawContactsColumns.ACCOUNT_ID + " != ?1" 4757da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng + ")", accountIdParams); 4758a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng try { 4759a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng while (cursor.moveToNext()) { 4760da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng final long contactId = cursor.getLong(0); 4761da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng ContactsTableUtil.deleteContact(db, contactId); 4762a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng } 4763a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng } finally { 4764a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng MoreCloseables.closeQuietly(cursor); 4765a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng } 4766a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng 4767a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng // If the contact was not deleted, it's last updated timestamp needs to 4768a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng // be refreshed since one of it's raw contacts got removed. 4769da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng // Find all contacts that will not be deleted (i.e. contacts with 4770da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng // raw contacts in other accounts) 4771da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng cursor = db.rawQuery( 4772da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng "SELECT DISTINCT " + RawContactsColumns.CONCRETE_CONTACT_ID + 4773da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng " FROM " + Tables.RAW_CONTACTS + 4774da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng " WHERE " + RawContactsColumns.ACCOUNT_ID + " = ?1" + 4775da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng " AND " + RawContactsColumns.CONCRETE_CONTACT_ID + 4776da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng " IN (" + 4777da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng " SELECT " + RawContactsColumns.CONCRETE_CONTACT_ID + 4778da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng " FROM " + Tables.RAW_CONTACTS + 4779da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng " WHERE " + RawContactsColumns.ACCOUNT_ID + " != ?1" 4780da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng + ")", accountIdParams); 4781da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng try { 4782da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng while (cursor.moveToNext()) { 4783da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng final long contactId = cursor.getLong(0); 4784da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng ContactsTableUtil.updateContactLastUpdateByContactId(db, 4785da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng contactId); 4786da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng } 4787da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng } finally { 4788da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng MoreCloseables.closeQuietly(cursor); 4789da51adb4b99894666e7ea91fed0e8afc94162333Chiao Cheng } 4790a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng } 4791a62622b31107f97be7da9a4b79393e465b64fd36Chiao Cheng 47929d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki db.execSQL( 47939d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "DELETE FROM " + Tables.RAW_CONTACTS + 47949d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " WHERE " + RawContactsColumns.ACCOUNT_ID + " = ?", 47959d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki accountIdParams); 47969d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki db.execSQL( 47979d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "DELETE FROM " + Tables.ACCOUNTS + 47989d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " WHERE " + AccountsColumns._ID + "=?", 47999d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki accountIdParams); 48009d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 4801e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov } 4802e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov 480333fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov // Find all aggregated contacts that used to contain the raw contacts 480433fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov // we have just deleted and see if they are still referencing the deleted 4805e3e79030101447da07547647bad225686eb9b8dfDmitri Plotnikov // names or photos. If so, fix up those contacts. 480633fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov HashSet<Long> orphanContactIds = Sets.newHashSet(); 48075d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor cursor = db.rawQuery("SELECT " + Contacts._ID + 480833fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " FROM " + Tables.CONTACTS + 480933fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " WHERE (" + Contacts.NAME_RAW_CONTACT_ID + " NOT NULL AND " + 481069cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov Contacts.NAME_RAW_CONTACT_ID + " NOT IN " + 481169cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov "(SELECT " + RawContacts._ID + 481269cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + "))" + 481333fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov " OR (" + Contacts.PHOTO_ID + " NOT NULL AND " + 481433fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov Contacts.PHOTO_ID + " NOT IN " + 481569cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov "(SELECT " + Data._ID + 481669cc3a2b09e2ffb606c6e52a71b604bba526d225Dmitri Plotnikov " FROM " + Tables.DATA + "))", null); 481733fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov try { 481833fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov while (cursor.moveToNext()) { 481933fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov orphanContactIds.add(cursor.getLong(0)); 482033fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 482133fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } finally { 482233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov cursor.close(); 482333fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 482433fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov 482533fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov for (Long contactId : orphanContactIds) { 48265d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mAggregator.get().updateAggregateData(mTransactionContext.get(), contactId); 482733fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 48289d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki dbHelper.updateAllVisible(); 48295dccfb059f5df0e9fdba026bcfbed677f44922cdDave Santoro 48305dccfb059f5df0e9fdba026bcfbed677f44922cdDave Santoro // Don't bother updating the search index if we're in profile mode - there is no 48315dccfb059f5df0e9fdba026bcfbed677f44922cdDave Santoro // search index for the profile DB, and updating it for the contacts DB in this case 48325dccfb059f5df0e9fdba026bcfbed677f44922cdDave Santoro // makes no sense and risks a deadlock. 48335dccfb059f5df0e9fdba026bcfbed677f44922cdDave Santoro if (!inProfileMode()) { 48349ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // TODO Fix it. It only updates index for contacts/raw_contacts that the 48359ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // current transaction context knows updated, but here in this method we don't 48369ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // update that information, so effectively it's no-op. 48379ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // We can probably just schedule BACKGROUND_TASK_UPDATE_SEARCH_INDEX. 48389ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // (But make sure it's not scheduled yet. We schedule this task in initialize() 48399ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // too.) 48405dccfb059f5df0e9fdba026bcfbed677f44922cdDave Santoro updateSearchIndexInTransaction(); 48415dccfb059f5df0e9fdba026bcfbed677f44922cdDave Santoro } 484233fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov } 484333fd566fb6eebdd40a900c0c8a2f6dca894d7829Dmitri Plotnikov 48449d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // Second, remove stale rows from Tables.SETTINGS and Tables.DIRECTORIES 48459d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki removeStaleAccountRows(Tables.SETTINGS, Settings.ACCOUNT_NAME, Settings.ACCOUNT_TYPE, 48469d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki systemAccounts); 48479d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki removeStaleAccountRows(Tables.DIRECTORIES, Directory.ACCOUNT_NAME, 48489d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki Directory.ACCOUNT_TYPE, systemAccounts); 484943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 48509d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // Third, remaining tasks that must be done in a transaction. 48519d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // TODO: Should sync state take data set into consideration? 48529d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki dbHelper.getSyncState().onAccountsChanged(db, systemAccounts); 48539ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki 48549ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki saveAccounts(systemAccounts); 485543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro 48565d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.setTransactionSuccessful(); 485770d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } finally { 48585d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro db.endTransaction(); 485970d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 486073f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov mAccountWritability.clear(); 48613826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 48629d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki updateContactsAccountCount(systemAccounts); 48639d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki updateProviderStatus(); 48649d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki return true; 486570d2ff8c87961703351b223ce8b15342fe795a0bCynthia Wong } 4866619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 48673826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov private void updateContactsAccountCount(Account[] accounts) { 48683826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov int count = 0; 48693826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov for (Account account : accounts) { 48703826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov if (isContactsAccount(account)) { 48713826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov count++; 48723826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 48733826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 48743826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov mContactsAccountCount = count; 48753826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 48763826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 48773826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov protected boolean isContactsAccount(Account account) { 48783826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov final IContentService cs = ContentResolver.getContentService(); 48793826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov try { 48803826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return cs.getIsSyncable(account, ContactsContract.AUTHORITY) > 0; 48813826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } catch (RemoteException e) { 48823826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov Log.e(TAG, "Cannot obtain sync flag for account: " + account, e); 48833826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov return false; 48843826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 48853826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov } 48863826a44d8de41e9c148dd6a967392ea5af478085Dmitri Plotnikov 488772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov public void onPackageChanged(String packageName) { 4888bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_DIRECTORIES, packageName); 4889d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4890d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 48919d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki public void removeStaleAccountRows(String table, String accountNameColumn, 48929d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki String accountTypeColumn, Account[] systemAccounts) { 48939d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 48949d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final Cursor c = db.rawQuery( 48959d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "SELECT DISTINCT " + accountNameColumn + 48969d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki "," + accountTypeColumn + 489743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro " FROM " + table, null); 4898627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov try { 48999d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki c.moveToPosition(-1); 4900627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov while (c.moveToNext()) { 49019d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final AccountWithDataSet accountWithDataSet = AccountWithDataSet.get( 49029d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki c.getString(0), c.getString(1), null); 49039d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (accountWithDataSet.isLocalAccount() 49049d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki || accountWithDataSet.inSystemAccounts(systemAccounts)) { 49059d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // Account still exists. 49069d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki continue; 4907627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 49089d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 49099d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki db.execSQL("DELETE FROM " + table + 49109d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki " WHERE " + accountNameColumn + "=? AND " + 49119d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki accountTypeColumn + "=?", 49129d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki new String[] {accountWithDataSet.getAccountName(), 49139d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki accountWithDataSet.getAccountType()}); 4914627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4915627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } finally { 4916627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov c.close(); 4917627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4918627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 4919627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov 49204f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 49214f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 49224f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton String sortOrder) { 492315826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann return query(uri, projection, selection, selectionArgs, sortOrder, null); 492415826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann } 492515826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann 492615826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann @Override 492715826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 49287898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown String sortOrder, CancellationSignal cancellationSignal) { 492947ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki if (VERBOSE_LOGGING) { 49302fe1f4f757a84cb76382c375ba3755a802c5e444Makoto Onuki Log.v(TAG, "query: uri=" + uri + " projection=" + Arrays.toString(projection) + 49312fe1f4f757a84cb76382c375ba3755a802c5e444Makoto Onuki " selection=[" + selection + "] args=" + Arrays.toString(selectionArgs) + 49322fe1f4f757a84cb76382c375ba3755a802c5e444Makoto Onuki " order=[" + sortOrder + "]"); 493347ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki } 493415c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 493515c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov waitForAccess(mReadAccessLatch); 493615c6e903b6d66e20e7cb1ebe7ff8c713e0a3386bDmitri Plotnikov 493736612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro // Enforce stream items access check if applicable. 493836612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro enforceSocialStreamReadPermission(uri); 493936612112760df799ef89f7e324e5dfabd5ca0d2bDave Santoro 49405d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Query the profile DB if appropriate. 49415d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (mapsToProfileDb(uri)) { 49425d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToProfileMode(); 494315826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann return mProfileProvider.query(uri, projection, selection, selectionArgs, sortOrder, 49447898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown cancellationSignal); 49455d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 49465d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 49475d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // Otherwise proceed with a normal query against the contacts DB. 49485d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro switchToContactMode(); 4949d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov String directory = getQueryParameter(uri, ContactsContract.DIRECTORY_PARAM_KEY); 4950385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov if (directory == null) { 4951b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return addSnippetExtrasToCursor(uri, 495215826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann queryLocal(uri, projection, selection, selectionArgs, sortOrder, -1, 49537898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown cancellationSignal)); 4954385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } else if (directory.equals("0")) { 4955b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return addSnippetExtrasToCursor(uri, 49563716f1447ceb21180d1301790eabd8b9453f486dDave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, 49577898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown Directory.DEFAULT, cancellationSignal)); 4958d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } else if (directory.equals("1")) { 4959b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return addSnippetExtrasToCursor(uri, 49603716f1447ceb21180d1301790eabd8b9453f486dDave Santoro queryLocal(uri, projection, selection, selectionArgs, sortOrder, 49617898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown Directory.LOCAL_INVISIBLE, cancellationSignal)); 4962d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4963d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4964d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov DirectoryInfo directoryInfo = getDirectoryAuthority(directory); 4965d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo == null) { 4966a85745ab25f9ab8fd6fd29e174bf2fac5492e448Dmitri Plotnikov Log.e(TAG, "Invalid directory ID: " + uri); 4967a85745ab25f9ab8fd6fd29e174bf2fac5492e448Dmitri Plotnikov return null; 4968d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4969d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 4970d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Builder builder = new Uri.Builder(); 4971d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.scheme(ContentResolver.SCHEME_CONTENT); 4972d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.authority(directoryInfo.authority); 4973d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.encodedPath(uri.getEncodedPath()); 4974d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo.accountName != null) { 4975d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, directoryInfo.accountName); 4976d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 4977d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov if (directoryInfo.accountType != null) { 4978d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, directoryInfo.accountType); 4979d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 49802e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov 49812e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov String limit = getLimit(uri); 49822e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov if (limit != null) { 49832e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, limit); 49842e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov } 49852e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov 4986d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Uri directoryUri = builder.build(); 498709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 498809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov if (projection == null) { 498909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov projection = getDefaultProjection(uri); 499009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 499109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 4992332321f2832d52f50b9f8fc1f4006459000a4b21Dmitri Plotnikov Cursor cursor = getContext().getContentResolver().query(directoryUri, projection, selection, 4993d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov selectionArgs, sortOrder); 49946ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 49956ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov if (cursor == null) { 49966ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov return null; 49976ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 49986ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 4999b6b22df3a64a80531d58f9cd60f2872fc2af92d1Dave Santoro // Load the cursor contents into a memory cursor (backed by a cursor window) and close the 5000b6b22df3a64a80531d58f9cd60f2872fc2af92d1Dave Santoro // underlying cursor. 5001b6b22df3a64a80531d58f9cd60f2872fc2af92d1Dave Santoro try { 5002b6b22df3a64a80531d58f9cd60f2872fc2af92d1Dave Santoro MemoryCursor memCursor = new MemoryCursor(null, cursor.getColumnNames()); 5003b6b22df3a64a80531d58f9cd60f2872fc2af92d1Dave Santoro memCursor.fillFromCursor(cursor); 5004b6b22df3a64a80531d58f9cd60f2872fc2af92d1Dave Santoro return memCursor; 5005b6b22df3a64a80531d58f9cd60f2872fc2af92d1Dave Santoro } finally { 5006b6b22df3a64a80531d58f9cd60f2872fc2af92d1Dave Santoro cursor.close(); 5007547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } 50083716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 50093716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 5010b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson private Cursor addSnippetExtrasToCursor(Uri uri, Cursor cursor) { 5011547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro 5012547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro // If the cursor doesn't contain a snippet column, don't bother wrapping it. 5013547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro if (cursor.getColumnIndex(SearchSnippetColumns.SNIPPET) < 0) { 5014b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return cursor; 5015547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro } 5016547c5eddcc79f680dc128b3851bf6cc03b0d0ebfDave Santoro 50173716f1447ceb21180d1301790eabd8b9453f486dDave Santoro String query = uri.getLastPathSegment(); 50183716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 5019b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson // Snippet data is needed for the snippeting on the client side, so store it in the cursor 5020b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson if (cursor instanceof AbstractCursor && deferredSnippetingRequested(uri)){ 5021b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson Bundle oldExtras = cursor.getExtras(); 5022b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson Bundle extras = new Bundle(); 5023b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson if (oldExtras != null) { 5024b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson extras.putAll(oldExtras); 5025b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 5026b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson extras.putString(ContactsContract.DEFERRED_SNIPPETING_QUERY, query); 5027b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson 5028b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson ((AbstractCursor) cursor).setExtras(extras); 50295517770250b3afa4fd88b6869c3244680821d222Dave Santoro } 5030b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return cursor; 5031b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 5032b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson 5033b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson private Cursor addDeferredSnippetingExtra(Cursor cursor) { 5034b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson if (cursor instanceof AbstractCursor){ 5035b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson Bundle oldExtras = cursor.getExtras(); 5036b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson Bundle extras = new Bundle(); 5037b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson if (oldExtras != null) { 5038b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson extras.putAll(oldExtras); 5039b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 5040b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson extras.putBoolean(ContactsContract.DEFERRED_SNIPPETING, true); 5041b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson ((AbstractCursor) cursor).setExtras(extras); 5042b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 5043b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return cursor; 50446ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov } 50456ca827312e6c69bdd88b48e485debee9fe5d16baDmitri Plotnikov 5046d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private static final class DirectoryQuery { 5047d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final String[] COLUMNS = new String[] { 5048d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory._ID, 5049d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.DIRECTORY_AUTHORITY, 5050d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.ACCOUNT_NAME, 5051d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov Directory.ACCOUNT_TYPE 5052d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov }; 5053d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 5054d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int DIRECTORY_ID = 0; 5055d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int AUTHORITY = 1; 5056d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int ACCOUNT_NAME = 2; 5057d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov public static final int ACCOUNT_TYPE = 3; 5058d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 5059d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 5060d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov /** 5061d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov * Reads and caches directory information for the database. 5062d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov */ 5063d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov private DirectoryInfo getDirectoryAuthority(String directoryId) { 50644458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov synchronized (mDirectoryCache) { 50654458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov if (!mDirectoryCacheValid) { 50664458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCache.clear(); 50675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro SQLiteDatabase db = mDbHelper.get().getReadableDatabase(); 506849d48c0a709c1efa8593acadadd31350bfc75d9aDmitri Plotnikov Cursor cursor = db.query(Tables.DIRECTORIES, 50694458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov DirectoryQuery.COLUMNS, 50704458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov null, null, null, null, null); 50714458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov try { 50724458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov while (cursor.moveToNext()) { 50734458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov DirectoryInfo info = new DirectoryInfo(); 50744458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov String id = cursor.getString(DirectoryQuery.DIRECTORY_ID); 50754458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.authority = cursor.getString(DirectoryQuery.AUTHORITY); 50764458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.accountName = cursor.getString(DirectoryQuery.ACCOUNT_NAME); 50774458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov info.accountType = cursor.getString(DirectoryQuery.ACCOUNT_TYPE); 50784458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCache.put(id, info); 50794458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 50804458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } finally { 50814458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov cursor.close(); 5082d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 50834458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCacheValid = true; 5084d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 5085d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 50864458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov return mDirectoryCache.get(directoryId); 50874458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 5088d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 5089d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 509072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov public void resetDirectoryCache() { 50914458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov synchronized(mDirectoryCache) { 50924458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov mDirectoryCacheValid = false; 50934458d63ef3384832fd2ad82130d4ad042cce2de6Dmitri Plotnikov } 509472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov } 509572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov 509635997f3fdee2984b6d5373326110eda26929001aMakoto Onuki protected Cursor queryLocal(final Uri uri, final String[] projection, String selection, 509735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki String[] selectionArgs, String sortOrder, final long directoryId, 509835997f3fdee2984b6d5373326110eda26929001aMakoto Onuki final CancellationSignal cancellationSignal) { 50990b30cac29514b3978896731ba1df6a54fc94e9e4Dmitri Plotnikov 5100ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getReadableDatabase(); 510135ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 5102d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 51031f42f1958113b2dadc6cf26b51192b42f883f3b0Jeff Sharkey String groupBy = null; 510480628945e7e41bb9363c2fbbd2938890b9217792Makoto Onuki String having = null; 5105c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov String limit = getLimit(uri); 5106b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson boolean snippetDeferred = false; 5107c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 51082ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki // The expression used in bundleLetterCountExtras() to get count. 51092ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki String addressBookIndexerCountExpression = null; 51102ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki 5111a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 51124f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 511335ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana case SYNCSTATE: 51145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_SYNCSTATE: 5115ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return mDbHelper.get().getSyncState().query(db, projection, selection, 51165d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selectionArgs, sortOrder); 511735ed95769096bb5dd406ad7d1fcaa49a0e35a307Fred Quintana 5118d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS: { 5119763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 51209ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki appendLocalDirectoryAndAccountSelectionIfNeeded(qb, directoryId, uri); 5121619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey break; 5122619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey } 5123619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey 5124d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov case CONTACTS_ID: { 51254a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov long contactId = ContentUris.parseId(uri); 5126763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 51274da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 51284da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 51296bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 51306bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 51316bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov 51325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov case CONTACTS_LOOKUP: 51335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov case CONTACTS_LOOKUP_ID: { 51345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 51355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int segmentCount = pathSegments.size(); 51365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segmentCount < 3) { 51375d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 5138fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Missing a lookup key", uri)); 51395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 5140a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 51415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String lookupKey = pathSegments.get(2); 51425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segmentCount == 4) { 51435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 51445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 5145763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(lookupQb, uri, projection); 5146a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 5147ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 5148a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 514915826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann Contacts._ID, contactId, Contacts.LOOKUP_KEY, lookupKey, 51507898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown cancellationSignal); 5151a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 51525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return c; 51535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 51545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 51555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 5156763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 51574da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 5158ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki String.valueOf(lookupContactIdByLookupKey(db, lookupKey))); 51594da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 51605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 51615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 51625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 51632149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov case CONTACTS_LOOKUP_DATA: 5164bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro case CONTACTS_LOOKUP_ID_DATA: 5165bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro case CONTACTS_LOOKUP_PHOTO: 5166bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro case CONTACTS_LOOKUP_ID_PHOTO: { 51672149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 51682149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov int segmentCount = pathSegments.size(); 51692149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov if (segmentCount < 4) { 51705d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 51712149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov "Missing a lookup key", uri)); 51722149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 51732149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov String lookupKey = pathSegments.get(2); 51742149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov if (segmentCount == 5) { 51752149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 51762149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 51772149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov setTablesAndProjectionMapForData(lookupQb, uri, projection, false); 5178bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro if (match == CONTACTS_LOOKUP_PHOTO || match == CONTACTS_LOOKUP_ID_PHOTO) { 5179cde9e5e83f7c3a6bf341f9f2fa2359a1ed127f95Daniel Lehmann lookupQb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID); 5180bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro } 5181a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(" AND "); 5182ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 5183a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 518415826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann Data.CONTACT_ID, contactId, Data.LOOKUP_KEY, lookupKey, 51857898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown cancellationSignal); 5186a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 51872149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov return c; 51882149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 51892149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 51902149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov // TODO see if the contact exists but has no data rows (rare) 51912149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 51922149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 51932149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 5194ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki long contactId = lookupContactIdByLookupKey(db, lookupKey); 51952149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 519624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String.valueOf(contactId)); 5197bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro if (match == CONTACTS_LOOKUP_PHOTO || match == CONTACTS_LOOKUP_ID_PHOTO) { 5198bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro qb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID); 5199bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro } 52002149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov qb.appendWhere(" AND " + Data.CONTACT_ID + "=?"); 52012149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov break; 52022149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov } 52032149ab82f021c204618d0d3644e261fd7a8d8490Dmitri Plotnikov 52043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_ID_STREAM_ITEMS: { 52053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = Long.parseLong(uri.getPathSegments().get(1)); 52063b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 52073b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 5208af10329f85c5d8c4196c495a9f0f9a6c6ecbc231Daniel Lehmann qb.appendWhere(StreamItems.CONTACT_ID + "=?"); 52093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 52103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 52113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 52123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_LOOKUP_STREAM_ITEMS: 52133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case CONTACTS_LOOKUP_ID_STREAM_ITEMS: { 52143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann List<String> pathSegments = uri.getPathSegments(); 52153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann int segmentCount = pathSegments.size(); 52163b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (segmentCount < 4) { 52175d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 52183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann "Missing a lookup key", uri)); 52193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 52203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String lookupKey = pathSegments.get(2); 52213b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (segmentCount == 5) { 52223b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long contactId = Long.parseLong(pathSegments.get(3)); 52233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 52243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(lookupQb); 5225ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 52263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann projection, selection, selectionArgs, sortOrder, groupBy, limit, 5227af10329f85c5d8c4196c495a9f0f9a6c6ecbc231Daniel Lehmann StreamItems.CONTACT_ID, contactId, 522815826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann StreamItems.CONTACT_LOOKUP_KEY, lookupKey, 52297898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown cancellationSignal); 52303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann if (c != null) { 52313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann return c; 52323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 52333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 52343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 52353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 5236ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki long contactId = lookupContactIdByLookupKey(db, lookupKey); 52373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 52383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(RawContacts.CONTACT_ID + "=?"); 52393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 52403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 52413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 5242f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey case CONTACTS_AS_VCARD: { 524342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String lookupKey = Uri.encode(uri.getPathSegments().get(2)); 5244ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki long contactId = lookupContactIdByLookupKey(db, lookupKey); 5245ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 5246f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey qb.setProjectionMap(sContactsVCardProjectionMap); 52474da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 524824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro String.valueOf(contactId)); 52494da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Contacts._ID + "=?"); 5250f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey break; 5251f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey } 5252f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey 525342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: { 52540788053f47eb6bc66b99a8747351ece2db7c3871Johan Redestig SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US); 525542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann String currentDateString = dateFormat.format(new Date()).toString(); 5256ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return db.rawQuery( 525742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann "SELECT" + 525842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann " 'vcards_' || ? || '.vcf' AS " + OpenableColumns.DISPLAY_NAME + "," + 525942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann " NULL AS " + OpenableColumns.SIZE, 526042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann new String[] { currentDateString }); 526142aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 526242aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 5263ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_FILTER: { 5264916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov String filterParam = ""; 5265b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson boolean deferredSnipRequested = deferredSnippetingRequested(uri); 5266ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 5267916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov filterParam = uri.getLastPathSegment(); 5268ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5269fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki 5270fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki // If the query consists of a single word, we can do snippetizing after-the-fact for 5271fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki // a performance boost. Otherwise, we can't defer. 5272fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki snippetDeferred = isSingleWordQuery(filterParam) 5273fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki && deferredSnipRequested && snippetNeeded(projection); 52747ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov setTablesAndProjectionMapForContactsWithSnippet( 5275b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson qb, uri, projection, filterParam, directoryId, 5276fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki snippetDeferred); 5277ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 5278ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5279ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 5280ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_STREQUENT_FILTER: 5281ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_STREQUENT: { 52822f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Basically the resultant SQL should look like this: 52832f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // (SQL for listing starred items) 52842f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // UNION ALL 52852f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // (SQL for listing frequently contacted items) 52862f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // ORDER BY ... 52872f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 52882f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final boolean phoneOnly = readBooleanQueryParameter( 52892f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa uri, ContactsContract.STREQUENT_PHONE_ONLY, false); 52902f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (match == CONTACTS_STREQUENT_FILTER && uri.getPathSegments().size() > 3) { 52914a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov String filterParam = uri.getLastPathSegment(); 52924a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 5293e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov sb.append(Contacts._ID + " IN "); 52945e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov appendContactFilterAsNestedQuery(sb, filterParam); 52952f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa selection = DbQueryUtils.concatenateClauses(selection, sb.toString()); 52964a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 52974a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 52982f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa String[] subProjection = null; 52995e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar if (projection != null) { 530063630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki subProjection = new String[projection.length + 2]; 530163630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki System.arraycopy(projection, 0, subProjection, 0, projection.length); 530263630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki subProjection[projection.length + 0] = DataUsageStatColumns.TIMES_USED; 530363630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki subProjection[projection.length + 1] = DataUsageStatColumns.LAST_TIME_USED; 53045e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar } 53055e28b3a5e44bf4f2c0980c50a2ab35350fc5f230Evan Millar 53064a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov // Build the first query for starred 53074928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, false); 53084928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(phoneOnly ? 53094928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa sStrequentPhoneOnlyStarredProjectionMap 53104928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa : sStrequentStarredProjectionMap); 53119dbfd650ccf93714f3266e80f9fbdbcb526ae7b3Daisuke Miyakawa if (phoneOnly) { 53125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro qb.appendWhere(DbQueryUtils.concatenateClauses( 53135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro selection, Contacts.HAS_PHONE_NUMBER + "=1")); 53149dbfd650ccf93714f3266e80f9fbdbcb526ae7b3Daisuke Miyakawa } 53152f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.setStrict(true); 531672c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann final String starredInnerQuery = qb.buildQuery(subProjection, 531772c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann Contacts.STARRED + "=1", Contacts._ID, null, 531872c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC", null); 5319d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 53202f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Reset the builder. 5321d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar qb = new SQLiteQueryBuilder(); 53222f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa qb.setStrict(true); 53234928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 532472c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann // Build the second query for frequent part. These JOINS can be very slow 532572c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann // if assembled in the wrong order. Be sure to test changes against huge databases. 532672c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann final String frequentInnerQuery; 53274928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa if (phoneOnly) { 53284928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa final StringBuilder tableBuilder = new StringBuilder(); 53294928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // In phone only mode, we need to look at view_data instead of 53304928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // contacts/raw_contacts to obtain actual phone numbers. One problem is that 53314928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // view_data is much larger than view_contacts, so our query might become much 53324928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // slower. 53334928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // 53344928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // To avoid the possible slow down, we start from data usage table and join 53354928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // view_data to the table, assuming data usage table is quite smaller than 53364928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // data rows (almost always it should be), and we don't want any phone 53374928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // numbers not used by the user. This way sqlite is able to drop a number of 53384928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa // rows in view_data in the early stage of data lookup. 53394928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa tableBuilder.append(Tables.DATA_USAGE_STAT 53404928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + " INNER JOIN " + Views.DATA + " " + Tables.DATA 53414928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + " ON (" + DataUsageStatColumns.CONCRETE_DATA_ID + "=" 53424928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataColumns.CONCRETE_ID + " AND " 53434928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataUsageStatColumns.CONCRETE_USAGE_TYPE + "=" 53444928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa + DataUsageStatColumns.USAGE_TYPE_INT_CALL + ")"); 53454928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa appendContactPresenceJoin(tableBuilder, projection, RawContacts.CONTACT_ID); 53464928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa appendContactStatusUpdateJoin(tableBuilder, projection, 53474928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa ContactsColumns.LAST_STATUS_UPDATE_ID); 53484928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa 53494928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setTables(tableBuilder.toString()); 53504928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(sStrequentPhoneOnlyFrequentProjectionMap); 535172c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann final long phoneMimeTypeId = 535272c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann mDbHelper.get().getMimeTypeId(Phone.CONTENT_ITEM_TYPE); 535372c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann final long sipMimeTypeId = 535472c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann mDbHelper.get().getMimeTypeId(SipAddress.CONTENT_ITEM_TYPE); 53554928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 53564928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa selection, 5357db0e85645ffe5a79500b31390149507ac432a2d9Makoto Onuki "(" + Contacts.STARRED + "=0 OR " + Contacts.STARRED + " IS NULL", 535872c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann DataColumns.MIMETYPE_ID + " IN (" + 5359db0e85645ffe5a79500b31390149507ac432a2d9Makoto Onuki phoneMimeTypeId + ", " + sipMimeTypeId + ")) AND (" + 5360db0e85645ffe5a79500b31390149507ac432a2d9Makoto Onuki RawContacts.CONTACT_ID + " IN " + Tables.DEFAULT_DIRECTORY + ")")); 536163630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki frequentInnerQuery = qb.buildQuery(subProjection, null, null, null, 536263630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki SORT_BY_DATA_USAGE, "25"); 53634928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa } else { 53644928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, true); 53654928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.setProjectionMap(sStrequentFrequentProjectionMap); 53664928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa qb.appendWhere(DbQueryUtils.concatenateClauses( 53674928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa selection, 53685d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro "(" + Contacts.STARRED + " =0 OR " + Contacts.STARRED + " IS NULL)")); 5369db0e85645ffe5a79500b31390149507ac432a2d9Makoto Onuki // Note frequentInnerQuery is a grouping query, so the "IN default_directory" 5370db0e85645ffe5a79500b31390149507ac432a2d9Makoto Onuki // selection needs to be in HAVING, not in WHERE. 5371db0e85645ffe5a79500b31390149507ac432a2d9Makoto Onuki final String HAVING = 5372db0e85645ffe5a79500b31390149507ac432a2d9Makoto Onuki RawContacts.CONTACT_ID + " IN " + Tables.DEFAULT_DIRECTORY; 537372c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann frequentInnerQuery = qb.buildQuery(subProjection, 537463630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki null, Contacts._ID, HAVING, SORT_BY_DATA_USAGE, "25"); 53754928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa } 5376d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 537772c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann // We need to wrap the inner queries in an extra select, because they contain 537872c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann // their own SORT and LIMIT 537972c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann final String frequentQuery = "SELECT * FROM (" + frequentInnerQuery + ")"; 538072c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann final String starredQuery = "SELECT * FROM (" + starredInnerQuery + ")"; 538172c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann 5382d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar // Put them together 53832f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final String unionQuery = 538472c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann qb.buildUnionQuery(new String[] {starredQuery, frequentQuery}, null, null); 53852f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 53862f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Here, we need to use selection / selectionArgs (supplied from users) "twice", 53872f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // as we want them both for starred items and for frequently contacted items. 53882f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // 53892f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // e.g. if the user specify selection = "starred =?" and selectionArgs = "0", 53902f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // the resultant SQL should be like: 53912f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // SELECT ... WHERE starred =? AND ... 53922f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // UNION ALL 53932f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // SELECT ... WHERE starred =? AND ... 53942f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa String[] doubledSelectionArgs = null; 53952f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (selectionArgs != null) { 53962f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa final int length = selectionArgs.length; 53972f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa doubledSelectionArgs = new String[length * 2]; 53987d7d0e95636344c01eb4e4d034791c199bee98e9Daisuke Miyakawa System.arraycopy(selectionArgs, 0, doubledSelectionArgs, 0, length); 53997d7d0e95636344c01eb4e4d034791c199bee98e9Daisuke Miyakawa System.arraycopy(selectionArgs, 0, doubledSelectionArgs, length, length); 54002f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 54012f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 5402ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor cursor = db.rawQuery(unionQuery, doubledSelectionArgs); 54032f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa if (cursor != null) { 54042f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa cursor.setNotificationUri(getContext().getContentResolver(), 5405d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar ContactsContract.AUTHORITY_URI); 5406d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 54072f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa return cursor; 5408d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar } 5409d3b76e00699679c519adc1c1770cd28ee6ae7aa3Evan Millar 541045ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa case CONTACTS_FREQUENT: { 541145ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, true); 541245ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa qb.setProjectionMap(sStrequentFrequentProjectionMap); 541345ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa groupBy = Contacts._ID; 541480628945e7e41bb9363c2fbbd2938890b9217792Makoto Onuki having = Contacts._ID + " IN " + Tables.DEFAULT_DIRECTORY; 541545ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa if (!TextUtils.isEmpty(sortOrder)) { 541645ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa sortOrder = FREQUENT_ORDER_BY + ", " + sortOrder; 541745ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } else { 541845ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa sortOrder = FREQUENT_ORDER_BY; 541945ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } 542045ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa break; 542145ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa } 542245ae7eaf0e2c9459ccbeeb5eb5977f055c4ed8ecDaisuke Miyakawa 5423ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov case CONTACTS_GROUP: { 5424763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 5425b67163a1088f09c59f324350662eb18772fac6b6Evan Millar if (uri.getPathSegments().size() > 2) { 542671e051c79a57af70ec7b095074c3e7faf9507b52Dmitri Plotnikov qb.appendWhere(CONTACTS_IN_GROUP_SELECT); 54277cf50494501938f175d288077145acf49da8f171Daniel Lehmann String groupMimeTypeId = String.valueOf( 54287cf50494501938f175d288077145acf49da8f171Daniel Lehmann mDbHelper.get().getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)); 54294a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 54307cf50494501938f175d288077145acf49da8f171Daniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, groupMimeTypeId); 5431b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 5432b67163a1088f09c59f324350662eb18772fac6b6Evan Millar break; 5433b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 5434b67163a1088f09c59f324350662eb18772fac6b6Evan Millar 543524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: { 543624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForContacts(qb, uri, projection); 543724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 543824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 543924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 544024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_ENTITIES: { 544124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForEntities(qb, uri, projection); 544224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 544324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 544424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 544524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: { 5446ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.CONTACTS); 544724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro qb.setProjectionMap(sContactsVCardProjectionMap); 544824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 544924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 545024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 5451a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_DATA: { 54524a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 545382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 54544da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 54554da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 54566bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov break; 54576bc8c0d15f4eacd2e92e9064c88cdf0659524a0eDmitri Plotnikov } 545800d71133c63c882fb41729ddc3a52f66fb155374Evan Millar 5459a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_PHOTO: { 54603653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 546182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 54624da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 54634da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 54643653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID); 54653653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov break; 54663653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov } 54673653cf1fa8fb36a96a7e4a6ebd615438877c3183Dmitri Plotnikov 5468a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_ENTITIES: { 5469a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 5470a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(qb, uri, projection); 5471a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(contactId)); 5472a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.appendWhere(" AND " + RawContacts.CONTACT_ID + "=?"); 5473a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov break; 5474a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5475a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 5476a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_LOOKUP_ENTITIES: 5477a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_LOOKUP_ID_ENTITIES: { 5478a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 5479a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov int segmentCount = pathSegments.size(); 5480a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (segmentCount < 4) { 54815d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 5482a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov "Missing a lookup key", uri)); 5483a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5484a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String lookupKey = pathSegments.get(2); 5485a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (segmentCount == 5) { 5486a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov long contactId = Long.parseLong(pathSegments.get(3)); 5487a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 5488a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(lookupQb, uri, projection); 5489a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(" AND "); 5490a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 5491ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 5492a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov projection, selection, selectionArgs, sortOrder, groupBy, limit, 5493a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.Entity.CONTACT_ID, contactId, 549415826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann Contacts.Entity.LOOKUP_KEY, lookupKey, 54957898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown cancellationSignal); 5496a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c != null) { 5497a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return c; 5498a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5499a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5500a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 5501a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForEntities(qb, uri, projection); 5502a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, 5503ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki String.valueOf(lookupContactIdByLookupKey(db, lookupKey))); 5504a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.appendWhere(" AND " + Contacts.Entity.CONTACT_ID + "=?"); 5505a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov break; 5506a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 5507a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 55083b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS: { 55093b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 55103b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 55113b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 55123b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 55133b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID: { 55143b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 55153b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 55169b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann qb.appendWhere(StreamItems._ID + "=?"); 55173b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 55183b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 55193b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 55203b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_LIMIT: { 5521084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki return buildSingleRowResult(projection, new String[] {StreamItems.MAX_ITEMS}, 5522084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki new Object[] {MAX_STREAM_ITEMS_PER_RAW_CONTACT}); 55233b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 55243b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 55253b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_PHOTOS: { 55263b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 55273b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 55283b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 55293b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 55303b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS: { 55313b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 55323b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 55333b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemId); 55343b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=?"); 55353b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 55363b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 55373b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 55383b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case STREAM_ITEMS_ID_PHOTOS_ID: { 55393b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItemPhotos(qb); 55403b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemId = uri.getPathSegments().get(1); 55413b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann String streamItemPhotoId = uri.getPathSegments().get(3); 55423b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemPhotoId); 55433b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, streamItemId); 55443b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=? AND " + 55453b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann StreamItemPhotosColumns.CONCRETE_ID + "=?"); 55463b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 55473b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 55483b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 5549f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case PHOTO_DIMENSIONS: { 5550084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki return buildSingleRowResult(projection, 5551084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki new String[] {DisplayPhoto.DISPLAY_MAX_DIM, DisplayPhoto.THUMBNAIL_MAX_DIM}, 5552c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki new Object[] {getMaxDisplayPhotoDim(), getMaxThumbnailDim()}); 5553f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 5554f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 5555e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa case PHONES: 5556e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa case CALLABLES: { 5557e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa final String mimeTypeIsPhoneExpression = 5558e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa DataColumns.MIMETYPE_ID + "=" + mDbHelper.get().getMimeTypeIdForPhone(); 5559e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa final String mimeTypeIsSipExpression = 5560e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa DataColumns.MIMETYPE_ID + "=" + mDbHelper.get().getMimeTypeIdForSip(); 556182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 5562e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa if (match == CALLABLES) { 5563e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa qb.appendWhere(" AND ((" + mimeTypeIsPhoneExpression + 5564e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa ") OR (" + mimeTypeIsSipExpression + "))"); 5565e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa } else { 5566e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa qb.appendWhere(" AND " + mimeTypeIsPhoneExpression); 5567e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa } 55682ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki 55698ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa final boolean removeDuplicates = readBooleanQueryParameter( 55708ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa uri, ContactsContract.REMOVE_DUPLICATE_ENTRIES, false); 55718ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa if (removeDuplicates) { 55728ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa groupBy = RawContacts.CONTACT_ID + ", " + Data.DATA1; 55738ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa 55748ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa // In this case, because we dedupe phone numbers, the address book indexer needs 55758ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa // to take it into account too. (Otherwise headers will appear in wrong 55768ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa // positions.) 55778ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa // So use count(distinct pair(CONTACT_ID, PHONE NUMBER)) instead of count(*). 55788ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa // But because there's no such thing as pair() on sqlite, we use 55798ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa // CONTACT_ID || ',' || PHONE NUMBER instead. 55808ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa // This only slows down the query by 14% with 10,000 contacts. 55818ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa addressBookIndexerCountExpression = "DISTINCT " 55828ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa + RawContacts.CONTACT_ID + "||','||" + Data.DATA1; 55838ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa } 55842815f58f72f109790585931f601a63ddc02536a5Evan Millar break; 55852815f58f72f109790585931f601a63ddc02536a5Evan Millar } 55862815f58f72f109790585931f601a63ddc02536a5Evan Millar 5587e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa case PHONES_ID: 5588e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa case CALLABLES_ID: { 5589e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa final String mimeTypeIsPhoneExpression = 5590e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa DataColumns.MIMETYPE_ID + "=" + mDbHelper.get().getMimeTypeIdForPhone(); 5591e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa final String mimeTypeIsSipExpression = 5592e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa DataColumns.MIMETYPE_ID + "=" + mDbHelper.get().getMimeTypeIdForSip(); 559382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 55944da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 5595e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa if (match == CALLABLES_ID) { 5596e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa qb.appendWhere(" AND ((" + mimeTypeIsPhoneExpression + 5597e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa ") OR (" + mimeTypeIsSipExpression + "))"); 5598e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa } else { 5599e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa qb.appendWhere(" AND " + mimeTypeIsPhoneExpression); 5600e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa } 56014da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 560248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 560348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 560448828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 5605e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa case PHONES_FILTER: 5606e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa case CALLABLES_FILTER: { 5607e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa final String mimeTypeIsPhoneExpression = 5608e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa DataColumns.MIMETYPE_ID + "=" + mDbHelper.get().getMimeTypeIdForPhone(); 5609e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa final String mimeTypeIsSipExpression = 5610e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa DataColumns.MIMETYPE_ID + "=" + mDbHelper.get().getMimeTypeIdForSip(); 5611e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa 561246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String typeParam = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 5613dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki final int typeInt = getDataUsageFeedbackType(typeParam, 5614dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki DataUsageStatColumns.USAGE_TYPE_INT_CALL); 561546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, true, typeInt); 5616e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa if (match == CALLABLES_FILTER) { 5617e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa qb.appendWhere(" AND ((" + mimeTypeIsPhoneExpression + 5618e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa ") OR (" + mimeTypeIsSipExpression + "))"); 5619e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa } else { 5620e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa qb.appendWhere(" AND " + mimeTypeIsPhoneExpression); 5621e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa } 5622e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa 5623ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar if (uri.getPathSegments().size() > 2) { 56244c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki final String filterParam = uri.getLastPathSegment(); 56254c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki final boolean searchDisplayName = uri.getBooleanQueryParameter( 56264c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki Phone.SEARCH_DISPLAY_NAME_KEY, true); 56274c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki final boolean searchPhoneNumber = uri.getBooleanQueryParameter( 56284c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki Phone.SEARCH_PHONE_NUMBER_KEY, true); 56294c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki 56304c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki final StringBuilder sb = new StringBuilder(); 5631a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov sb.append(" AND ("); 56325e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 563345d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov boolean hasCondition = false; 56344c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki // TODO This only searches the name field. Search other fields, such as 56354c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki // note, nickname, as well. (Which should be disabled by default.) 56364c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki // Fix EMAILS_FILTER too. 56374c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki final String ftsMatchQuery = 56384c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki searchDisplayName 56394c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki ? SearchIndexManager.getFtsMatchQuery(filterParam, 5640fda4395adc9266d0f8e0be8637d0effa7fd1e057Yorke Lee FtsQueryBuilder.SCOPED_NAME_NORMALIZING) 56414c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki : null; 56424c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki if (!TextUtils.isEmpty(ftsMatchQuery)) { 5643155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(Data.RAW_CONTACT_ID + " IN " + 5644155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov "(SELECT " + RawContactsColumns.CONCRETE_ID + 5645155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.SEARCH_INDEX + 5646155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " JOIN " + Tables.RAW_CONTACTS + 5647155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " ON (" + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID 5648155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov + "=" + RawContactsColumns.CONCRETE_CONTACT_ID + ")" + 5649fda4395adc9266d0f8e0be8637d0effa7fd1e057Yorke Lee " WHERE " + Tables.SEARCH_INDEX + " MATCH '"); 5650d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann sb.append(ftsMatchQuery); 5651d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann sb.append("')"); 565245d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov hasCondition = true; 56535e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 56545e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 56554c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki if (searchPhoneNumber) { 56564c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki final String number = PhoneNumberUtils.normalizeNumber(filterParam); 56574c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki if (!TextUtils.isEmpty(number)) { 56584c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki if (hasCondition) { 56594c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki sb.append(" OR "); 56604c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki } 56614c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki sb.append(Data._ID + 56624c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki " IN (SELECT DISTINCT " + PhoneLookupColumns.DATA_ID 56634c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki + " FROM " + Tables.PHONE_LOOKUP 56644c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki + " WHERE " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 56654c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki sb.append(number); 56664c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki sb.append("%')"); 56674c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki hasCondition = true; 56685e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 566945d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov 56704c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki if (!TextUtils.isEmpty(filterParam) && match == CALLABLES_FILTER) { 56714c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki // If the request is via Callable uri, Sip addresses matching the filter 56724c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki // parameter should be returned. 56734c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki if (hasCondition) { 56744c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki sb.append(" OR "); 56754c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki } 56764c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki sb.append("("); 56774c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki sb.append(mimeTypeIsSipExpression); 56784c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki sb.append(" AND ((" + Data.DATA1 + " LIKE "); 56794c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki DatabaseUtils.appendEscapedSQLString(sb, filterParam + '%'); 56804c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki sb.append(") OR (" + Data.DATA1 + " LIKE "); 56814c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki // Users may want SIP URIs starting from "sip:" 56824c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki DatabaseUtils.appendEscapedSQLString(sb, "sip:"+ filterParam + '%'); 56834c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki sb.append(")))"); 56844c3a04572ead6ad9f0cfc20a34db3252fdb31201Makoto Onuki hasCondition = true; 5685e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa } 5686e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa } 5687e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa 568845d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov if (!hasCondition) { 568945d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov // If it is neither a phone number nor a name, the query should return 569045d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov // an empty cursor. Let's ensure that. 569145d8626bf586b5c7111fa86324a7201ae8073607Dmitri Plotnikov sb.append("0"); 56925e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 56935e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(")"); 5694a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov qb.appendWhere(sb); 5695ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5696e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa if (match == CALLABLES_FILTER) { 5697e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa // If the row is for a phone number that has a normalized form, we should use 5698e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa // the normalized one as PHONES_FILTER does, while we shouldn't do that 5699e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa // if the row is for a sip address. 5700e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa String isPhoneAndHasNormalized = "(" 5701e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa + mimeTypeIsPhoneExpression + " AND " 5702fc42772538fc6f7e2e444cbe6b24e06a3fbf933dMakoto Onuki + Phone.NORMALIZED_NUMBER + " IS NOT NULL)"; 5703e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa groupBy = "(CASE WHEN " + isPhoneAndHasNormalized 5704fc42772538fc6f7e2e444cbe6b24e06a3fbf933dMakoto Onuki + " THEN " + Phone.NORMALIZED_NUMBER 5705fc42772538fc6f7e2e444cbe6b24e06a3fbf933dMakoto Onuki + " ELSE " + Phone.NUMBER + " END), " + RawContacts.CONTACT_ID; 5706e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa } else { 5707fc42772538fc6f7e2e444cbe6b24e06a3fbf933dMakoto Onuki groupBy = "(CASE WHEN " + Phone.NORMALIZED_NUMBER 5708fc42772538fc6f7e2e444cbe6b24e06a3fbf933dMakoto Onuki + " IS NOT NULL THEN " + Phone.NORMALIZED_NUMBER 570958567abca253f1efa2db5c39e17e42dca589e916Daisuke Miyakawa + " ELSE " + Phone.NUMBER + " END), " + RawContacts.CONTACT_ID; 5710e432023d408c461295e53c0593fabb2b4c17aeb3Daisuke Miyakawa } 5711a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov if (sortOrder == null) { 571246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String accountPromotionSortOrder = getAccountPromotionSortOrder(uri); 571346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(accountPromotionSortOrder)) { 571446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = accountPromotionSortOrder + ", " + PHONE_FILTER_SORT_ORDER; 571546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 571646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = PHONE_FILTER_SORT_ORDER; 571746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 5718a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov } 5719ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 5720ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5721ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 57224a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov case EMAILS: { 572382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 57247cf50494501938f175d288077145acf49da8f171Daniel Lehmann qb.appendWhere(" AND " + DataColumns.MIMETYPE_ID + " = " 57257cf50494501938f175d288077145acf49da8f171Daniel Lehmann + mDbHelper.get().getMimeTypeIdForEmail()); 57268ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa 57278ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa final boolean removeDuplicates = readBooleanQueryParameter( 57288ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa uri, ContactsContract.REMOVE_DUPLICATE_ENTRIES, false); 57298ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa if (removeDuplicates) { 57308ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa groupBy = RawContacts.CONTACT_ID + ", " + Data.DATA1; 57318ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa 57328ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa // See PHONES for more detail. 57338ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa addressBookIndexerCountExpression = "DISTINCT " 57348ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa + RawContacts.CONTACT_ID + "||','||" + Data.DATA1; 57358ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa } 57364a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov break; 57374a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 57384a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 573948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: { 574082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 57414da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 57427cf50494501938f175d288077145acf49da8f171Daniel Lehmann qb.appendWhere(" AND " + DataColumns.MIMETYPE_ID + " = " 57437cf50494501938f175d288077145acf49da8f171Daniel Lehmann + mDbHelper.get().getMimeTypeIdForEmail() 57444da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov + " AND " + Data._ID + "=?"); 574548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 574648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 574748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 57485e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov case EMAILS_LOOKUP: { 574982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 57507cf50494501938f175d288077145acf49da8f171Daniel Lehmann qb.appendWhere(" AND " + DataColumns.MIMETYPE_ID + " = " 57517cf50494501938f175d288077145acf49da8f171Daniel Lehmann + mDbHelper.get().getMimeTypeIdForEmail()); 57524a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov if (uri.getPathSegments().size() > 2) { 575308768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov String email = uri.getLastPathSegment(); 57545d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro String address = mDbHelper.get().extractAddressFromEmailAddress(email); 575508768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, address); 575608768a0f3434130fa46379c1bbfec93a19094939Dmitri Plotnikov qb.appendWhere(" AND UPPER(" + Email.DATA + ")=UPPER(?)"); 57574a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 5758071d0e7bd3b2f3c9628dd655b09d147e668c3931Daniel Lehmann // unless told otherwise, we'll return visible before invisible contacts 5759071d0e7bd3b2f3c9628dd655b09d147e668c3931Daniel Lehmann if (sortOrder == null) { 5760071d0e7bd3b2f3c9628dd655b09d147e668c3931Daniel Lehmann sortOrder = "(" + RawContacts.CONTACT_ID + " IN " + 5761071d0e7bd3b2f3c9628dd655b09d147e668c3931Daniel Lehmann Tables.DEFAULT_DIRECTORY + ") DESC"; 5762071d0e7bd3b2f3c9628dd655b09d147e668c3931Daniel Lehmann } 5763ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 5764ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5765ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 57665e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov case EMAILS_FILTER: { 576746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String typeParam = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 5768dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki final int typeInt = getDataUsageFeedbackType(typeParam, 5769dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki DataUsageStatColumns.USAGE_TYPE_INT_LONG_TEXT); 577046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa setTablesAndProjectionMapForData(qb, uri, projection, true, typeInt); 577107ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov String filterParam = null; 57727d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa 577307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (uri.getPathSegments().size() > 3) { 577407ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov filterParam = uri.getLastPathSegment(); 577507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (TextUtils.isEmpty(filterParam)) { 577607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov filterParam = null; 577707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } 577807ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } 57795e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 578007ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov if (filterParam == null) { 578107ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov // If the filter is unspecified, return nothing 578207ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov qb.appendWhere(" AND 0"); 578307ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov } else { 578407ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov StringBuilder sb = new StringBuilder(); 578507ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov sb.append(" AND " + Data._ID + " IN ("); 578607ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov sb.append( 578707ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov "SELECT " + Data._ID + 578807ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov " FROM " + Tables.DATA + 57892a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov " WHERE " + DataColumns.MIMETYPE_ID + "="); 57905d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro sb.append(mDbHelper.get().getMimeTypeIdForEmail()); 57912a8fefb86282c06a7669f80e1b2b86d87619dfc2Dmitri Plotnikov sb.append(" AND " + Data.DATA1 + " LIKE "); 579207ce1624de652aa8494630a071b051a1670c4e3dDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, filterParam + '%'); 579320938cd6df602bf08c232b32fc047592c1561347Dmitri Plotnikov if (!filterParam.contains("@")) { 5794155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append( 5795155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " UNION SELECT " + Data._ID + 5796155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.DATA + 5797155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " WHERE +" + DataColumns.MIMETYPE_ID + "="); 57985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro sb.append(mDbHelper.get().getMimeTypeIdForEmail()); 5799155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov sb.append(" AND " + Data.RAW_CONTACT_ID + " IN " + 5800155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov "(SELECT " + RawContactsColumns.CONCRETE_ID + 5801155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " FROM " + Tables.SEARCH_INDEX + 5802155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " JOIN " + Tables.RAW_CONTACTS + 5803155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov " ON (" + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID 5804155accbcb95fc13b984cf0ea8e5498a9c619cbf5Dmitri Plotnikov + "=" + RawContactsColumns.CONCRETE_CONTACT_ID + ")" + 5805d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann " WHERE " + SearchIndexColumns.NAME + " MATCH '"); 5806d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann final String ftsMatchQuery = SearchIndexManager.getFtsMatchQuery( 5807d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann filterParam, FtsQueryBuilder.UNSCOPED_NORMALIZING); 5808d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann sb.append(ftsMatchQuery); 5809d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann sb.append("')"); 58105e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 58115e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov sb.append(")"); 5812a8d8b1cb48a6e94645dbce836193b40c7481356cDmitri Plotnikov qb.appendWhere(sb); 58135e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 58145e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov groupBy = Email.DATA + "," + RawContacts.CONTACT_ID; 5815a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov if (sortOrder == null) { 581646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String accountPromotionSortOrder = getAccountPromotionSortOrder(uri); 581746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(accountPromotionSortOrder)) { 581846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sortOrder = accountPromotionSortOrder + ", " + EMAIL_FILTER_SORT_ORDER; 58197d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa } else { 58207d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa sortOrder = EMAIL_FILTER_SORT_ORDER; 58217d82ae92714f2132e3a0971d844ae8cdf10d76e7Daisuke Miyakawa } 5822dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng 5823dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng final String primaryAccountName = 5824dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng uri.getQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME); 5825dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng if (!TextUtils.isEmpty(primaryAccountName)) { 5826dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng final int index = primaryAccountName.indexOf('@'); 5827dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng if (index != -1) { 5828dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng // Purposely include '@' in matching. 5829dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng final String domain = primaryAccountName.substring(index); 5830dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng final char escapeChar = '\\'; 5831dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng 5832dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng final StringBuilder likeValue = new StringBuilder(); 5833dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng likeValue.append('%'); 5834dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng DbQueryUtils.escapeLikeValue(likeValue, domain, escapeChar); 5835dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng selectionArgs = appendSelectionArg(selectionArgs, likeValue.toString()); 5836dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng 5837dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng // similar email domains is the last sort preference. 5838dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng sortOrder += ", (CASE WHEN " + Data.DATA1 + " like ? ESCAPE '" + 5839dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng escapeChar + "' THEN 0 ELSE 1 END)"; 5840dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng } 5841dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng } 5842a0e72d9b20207ec244f92ace2917932990f2bc8bDmitri Plotnikov } 58435e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov break; 58445e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov } 58455e99505757457d11d9388f6d04960e97fc776a59Dmitri Plotnikov 58468f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee case CONTACTABLES: 58478f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee case CONTACTABLES_FILTER: { 58488f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee setTablesAndProjectionMapForData(qb, uri, projection, false); 58498f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee 58508f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee String filterParam = null; 58518f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee 58528f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee final int uriPathSize = uri.getPathSegments().size(); 58538f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee if (uriPathSize > 3) { 58548f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee filterParam = uri.getLastPathSegment(); 58558f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee if (TextUtils.isEmpty(filterParam)) { 58568f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee filterParam = null; 58578f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee } 58588f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee } 58598f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee 58608f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee // CONTACTABLES_FILTER but no query provided, return an empty cursor 58618f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee if (uriPathSize > 2 && filterParam == null) { 58628f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee qb.appendWhere(" AND 0"); 58638f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee break; 58648f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee } 58658f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee 58668f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee if (uri.getBooleanQueryParameter(Contactables.VISIBLE_CONTACTS_ONLY, false)) { 58678f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee qb.appendWhere(" AND " + Data.CONTACT_ID + " in " + 58688f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee Tables.DEFAULT_DIRECTORY); 58698f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee } 58708f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee 58718f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee final StringBuilder sb = new StringBuilder(); 58728f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee 58738f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee // we only want data items that are either email addresses or phone numbers 58748f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee sb.append(" AND ("); 58758f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee sb.append(DataColumns.MIMETYPE_ID + " IN ("); 58768f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee sb.append(mDbHelper.get().getMimeTypeIdForEmail()); 58778f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee sb.append(","); 58788f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee sb.append(mDbHelper.get().getMimeTypeIdForPhone()); 58798f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee sb.append("))"); 58808f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee 58818f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee // Rest of the query is only relevant if we are handling CONTACTABLES_FILTER 58828f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee if (uriPathSize < 3) { 58838f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee qb.appendWhere(sb); 58848f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee break; 58858f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee } 58868f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee 58878f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee // but we want all the email addresses and phone numbers that belong to 58888f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee // all contacts that have any data items (or name) that match the query 58898f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee sb.append(" AND "); 58908f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee sb.append("(" + Data.CONTACT_ID + " IN ("); 58918f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee 58928f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee // All contacts where the email address data1 column matches the query 58938f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee sb.append( 58948f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee "SELECT " + RawContacts.CONTACT_ID + 58958f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee " FROM " + Tables.DATA + " JOIN " + Tables.RAW_CONTACTS + 58968f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee " ON " + Tables.DATA + "." + Data.RAW_CONTACT_ID + "=" + 58978f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee Tables.RAW_CONTACTS + "." + RawContacts._ID + 58988f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee " WHERE (" + DataColumns.MIMETYPE_ID + "="); 58998f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee sb.append(mDbHelper.get().getMimeTypeIdForEmail()); 59008f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee 59018f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee sb.append(" AND " + Data.DATA1 + " LIKE "); 59028f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee DatabaseUtils.appendEscapedSQLString(sb, filterParam + '%'); 59038f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee sb.append(")"); 59048f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee 59058f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee // All contacts where the phone number matches the query (determined by checking 59068f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee // Tables.PHONE_LOOKUP 59078f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee final String number = PhoneNumberUtils.normalizeNumber(filterParam); 59088f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee if (!TextUtils.isEmpty(number)) { 59098f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee sb.append("UNION SELECT DISTINCT " + RawContacts.CONTACT_ID + 59108f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee " FROM " + Tables.PHONE_LOOKUP + " JOIN " + Tables.RAW_CONTACTS + 59118f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee " ON (" + Tables.PHONE_LOOKUP + "." + 59128f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee PhoneLookupColumns.RAW_CONTACT_ID + "=" + 59138f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee Tables.RAW_CONTACTS + "." + RawContacts._ID + ")" + 59148f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee " WHERE " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 59158f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee sb.append(number); 59168f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee sb.append("%'"); 59178f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee } 59188f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee 59198f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee // All contacts where the name matches the query (determined by checking 59208f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee // Tables.SEARCH_INDEX 59218f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee sb.append( 59228f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee " UNION SELECT " + Data.CONTACT_ID + 59238f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee " FROM " + Tables.DATA + " JOIN " + Tables.RAW_CONTACTS + 59248f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee " ON " + Tables.DATA + "." + Data.RAW_CONTACT_ID + "=" + 59258f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee Tables.RAW_CONTACTS + "." + RawContacts._ID + 59268f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee 59278f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee " WHERE " + Data.RAW_CONTACT_ID + " IN " + 59288f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee 59298f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee "(SELECT " + RawContactsColumns.CONCRETE_ID + 59308f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee " FROM " + Tables.SEARCH_INDEX + 59318f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee " JOIN " + Tables.RAW_CONTACTS + 59328f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee " ON (" + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID 59338f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee + "=" + RawContactsColumns.CONCRETE_CONTACT_ID + ")" + 59348f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee 59358f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee " WHERE " + SearchIndexColumns.NAME + " MATCH '"); 59368f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee 59378f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee final String ftsMatchQuery = SearchIndexManager.getFtsMatchQuery( 59388f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee filterParam, FtsQueryBuilder.UNSCOPED_NORMALIZING); 59398f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee sb.append(ftsMatchQuery); 59408f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee sb.append("')"); 59418f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee 59428f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee sb.append("))"); 59438f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee qb.appendWhere(sb); 59448f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee 59458f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee break; 59468f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee } 59478f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee 5948ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar case POSTALS: { 594982bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 59507cf50494501938f175d288077145acf49da8f171Daniel Lehmann qb.appendWhere(" AND " + DataColumns.MIMETYPE_ID + " = " 59517cf50494501938f175d288077145acf49da8f171Daniel Lehmann + mDbHelper.get().getMimeTypeIdForStructuredPostal()); 59528ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa 59538ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa final boolean removeDuplicates = readBooleanQueryParameter( 59548ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa uri, ContactsContract.REMOVE_DUPLICATE_ENTRIES, false); 59558ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa if (removeDuplicates) { 59568ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa groupBy = RawContacts.CONTACT_ID + ", " + Data.DATA1; 59578ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa 59588ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa // See PHONES for more detail. 59598ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa addressBookIndexerCountExpression = "DISTINCT " 59608ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa + RawContacts.CONTACT_ID + "||','||" + Data.DATA1; 59618ead0dc62d0031a22af0d14c7ed05893507893c9Daisuke Miyakawa } 5962ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar break; 5963ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar } 5964ea0ec7120315589eaafb45d88ff872abbde35e38Evan Millar 596548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: { 596682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 59674da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 59687cf50494501938f175d288077145acf49da8f171Daniel Lehmann qb.appendWhere(" AND " + DataColumns.MIMETYPE_ID + " = " 59697cf50494501938f175d288077145acf49da8f171Daniel Lehmann + mDbHelper.get().getMimeTypeIdForStructuredPostal()); 59704da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 597148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov break; 597248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov } 597348828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov 5974d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case RAW_CONTACTS: 5975d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS: { 5976763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForRawContacts(qb, uri); 59774f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 59784f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 59794f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 5980d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case RAW_CONTACTS_ID: 5981d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS_ID: { 59825ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov long rawContactId = ContentUris.parseId(uri); 5983763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForRawContacts(qb, uri); 59844da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 59854da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts._ID + "=?"); 59864f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton break; 59874f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 59884f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 5989193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki case RAW_CONTACTS_ID_DATA: 5990d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_RAW_CONTACTS_ID_DATA: { 5991193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki int segment = match == RAW_CONTACTS_ID_DATA ? 1 : 2; 5992d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(segment)); 599382bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 59944da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 59954da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data.RAW_CONTACT_ID + "=?"); 599624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro break; 599724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 599824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 59993b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann case RAW_CONTACTS_ID_STREAM_ITEMS: { 60003b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 60013b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann setTablesAndProjectionMapForStreamItems(qb); 60023b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 60033b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.appendWhere(StreamItems.RAW_CONTACT_ID + "=?"); 60043b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann break; 60053b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 600624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 600782780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro case RAW_CONTACTS_ID_STREAM_ITEMS_ID: { 600882780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 600982780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro long streamItemId = Long.parseLong(uri.getPathSegments().get(3)); 601082780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro setTablesAndProjectionMapForStreamItems(qb); 601182780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(streamItemId)); 6012c88cc79e0e19b8299a2a356c7d70b48f70b4a93eDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 601382780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro qb.appendWhere(StreamItems.RAW_CONTACT_ID + "=? AND " + 601482780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro StreamItems._ID + "=?"); 601582780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro break; 601682780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro } 601782780691f1a3b4d8784e29a961b1140cd07bc9a8Dave Santoro 601824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID_ENTITIES: { 601924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(2)); 602024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 602124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro setTablesAndProjectionMapForRawEntities(qb, uri); 60225d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro qb.appendWhere(" AND " + RawContacts._ID + "=?"); 6023e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 6024e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 6025e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 6026d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case DATA: 6027d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_DATA: { 6028216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee final String usageType = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 6029216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee final int typeInt = getDataUsageFeedbackType(usageType, USAGE_TYPE_ALL); 6030216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee setTablesAndProjectionMapForData(qb, uri, projection, false, typeInt); 60318f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee if (uri.getBooleanQueryParameter(Data.VISIBLE_CONTACTS_ONLY, false)) { 60328f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee qb.appendWhere(" AND " + Data.CONTACT_ID + " in " + 60338f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee Tables.DEFAULT_DIRECTORY); 60348f8b122c7556350d94c2e349b3093024b0205d8dYorke Lee } 6035e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey break; 6036e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey } 6037e17c303827c5be8107dcd4a8b64333f349b688f5Jeff Sharkey 6038d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case DATA_ID: 6039d9e353f4a13154dace037c99eb1054d85cce2521Dave Santoro case PROFILE_DATA_ID: { 604082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov setTablesAndProjectionMapForData(qb, uri, projection, false); 60414da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 60424da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + Data._ID + "=?"); 6043a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov break; 6044a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov } 6045a6def2055f5d12cb6ee5cc3dc1adaf39f2b7c97cDmitri Plotnikov 604685077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro case PROFILE_PHOTO: { 604785077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 604885077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro qb.appendWhere(" AND " + Data._ID + "=" + Contacts.PHOTO_ID); 604985077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro break; 605085077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } 605185077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro 6052a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton case PHONE_LOOKUP: { 6053e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov // Phone lookup cannot be combined with a selection 6054e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov selection = null; 6055e3eb7ef438010c893c429f3031dcc7298171865dDmitri Plotnikov selectionArgs = null; 605658795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda if (uri.getBooleanQueryParameter(PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS, false)) { 605758795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda if (TextUtils.isEmpty(sortOrder)) { 605858795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda // Default the sort order to something reasonable so we get consistent 605958795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda // results when callers don't request an ordering 606058795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda sortOrder = Contacts.DISPLAY_NAME + " ASC"; 606158795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda } 606258795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda 606358795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda String sipAddress = uri.getPathSegments().size() > 1 606458795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda ? Uri.decode(uri.getLastPathSegment()) : ""; 606558795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda setTablesAndProjectionMapForData(qb, uri, null, false, true); 606658795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda StringBuilder sb = new StringBuilder(); 606758795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda selectionArgs = mDbHelper.get().buildSipContactQuery(sb, sipAddress); 606858795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda selection = sb.toString(); 606958795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda } else { 60706db6c6d74da066cbbe3e3b5b89caf1ba5626d240Yorke Lee // Use this flag to track whether sortOrder was originally empty 60716db6c6d74da066cbbe3e3b5b89caf1ba5626d240Yorke Lee boolean sortOrderIsEmpty = false; 607258795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda if (TextUtils.isEmpty(sortOrder)) { 607358795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda // Default the sort order to something reasonable so we get consistent 607458795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda // results when callers don't request an ordering 607558795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda sortOrder = " length(lookup.normalized_number) DESC"; 60766db6c6d74da066cbbe3e3b5b89caf1ba5626d240Yorke Lee sortOrderIsEmpty = true; 607758795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda } 607858795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda 607958795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda String number = uri.getPathSegments().size() > 1 608058795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda ? uri.getLastPathSegment() : ""; 608158795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda String numberE164 = PhoneNumberUtils.formatNumberToE164(number, 608258795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda mDbHelper.get().getCurrentCountryIso()); 608358795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda String normalizedNumber = 608458795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda PhoneNumberUtils.normalizeNumber(number); 608558795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda mDbHelper.get().buildPhoneLookupAndContactQuery( 608658795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda qb, normalizedNumber, numberE164); 608758795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda qb.setProjectionMap(sPhoneLookupProjectionMap); 608856abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro 608956abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro // Peek at the results of the first query (which attempts to use fully 609056abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro // normalized and internationalized numbers for comparison). If no results 60916db6c6d74da066cbbe3e3b5b89caf1ba5626d240Yorke Lee // were returned, fall back to using the SQLite function 60926db6c6d74da066cbbe3e3b5b89caf1ba5626d240Yorke Lee // phone_number_compare_loose. 609356abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro qb.setStrict(true); 609456abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro boolean foundResult = false; 6095ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor cursor = query(db, qb, projection, selection, selectionArgs, 609680628945e7e41bb9363c2fbbd2938890b9217792Makoto Onuki sortOrder, groupBy, null, limit, cancellationSignal); 609756abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro try { 609856abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro if (cursor.getCount() > 0) { 609956abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro foundResult = true; 610056abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro return cursor; 610156abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro } else { 61026db6c6d74da066cbbe3e3b5b89caf1ba5626d240Yorke Lee // Use fallback lookup method 61036db6c6d74da066cbbe3e3b5b89caf1ba5626d240Yorke Lee 610456abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro qb = new SQLiteQueryBuilder(); 61056db6c6d74da066cbbe3e3b5b89caf1ba5626d240Yorke Lee 61066db6c6d74da066cbbe3e3b5b89caf1ba5626d240Yorke Lee // use the raw number instead of the normalized number because 61076db6c6d74da066cbbe3e3b5b89caf1ba5626d240Yorke Lee // phone_number_compare_loose in SQLite works only with non-normalized 61086db6c6d74da066cbbe3e3b5b89caf1ba5626d240Yorke Lee // numbers 61096db6c6d74da066cbbe3e3b5b89caf1ba5626d240Yorke Lee mDbHelper.get().buildFallbackPhoneLookupAndContactQuery(qb, number); 61106db6c6d74da066cbbe3e3b5b89caf1ba5626d240Yorke Lee 611156abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro qb.setProjectionMap(sPhoneLookupProjectionMap); 611256abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro } 611356abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro } finally { 611456abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro if (!foundResult) { 611556abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro // We'll be returning a different cursor, so close this one. 611656abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro cursor.close(); 611756abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro } 611856abe81ced08c7af625b3eb8dd543f9030da9badDave Santoro } 611958795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda } 6120a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton break; 6121a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton } 6122a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton 6123ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS: { 6124ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.GROUPS); 6125ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 61269ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki appendAccountIdFromParameter(qb, uri); 6127ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 6128ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 6129ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 6130ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_ID: { 6131ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.GROUPS); 6132ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey qb.setProjectionMap(sGroupsProjectionMap); 61334da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 61344da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(Groups._ID + "=?"); 6135ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 6136ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 6137ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 6138ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey case GROUPS_SUMMARY: { 613923ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki String tables = Views.GROUPS + " AS " + Tables.GROUPS; 6140ac2a6e814edb3d5e5bcca28d7d3f3977a489c2edMakoto Onuki if (ContactsDatabaseHelper.isInProjection(projection, Groups.SUMMARY_COUNT)) { 614123ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki tables = tables + Joins.GROUP_MEMBER_COUNT; 614223ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki } 614318b09495f5f37b38ff2e1c965e087dfde68c27fbMakoto Onuki if (ContactsDatabaseHelper.isInProjection(projection, 614418b09495f5f37b38ff2e1c965e087dfde68c27fbMakoto Onuki Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT)) { 614518b09495f5f37b38ff2e1c965e087dfde68c27fbMakoto Onuki // TODO Add join for this column too (and update the projection map) 614618b09495f5f37b38ff2e1c965e087dfde68c27fbMakoto Onuki // TODO Also remove Groups.PARAM_RETURN_GROUP_COUNT_PER_ACCOUNT when it works. 614718b09495f5f37b38ff2e1c965e087dfde68c27fbMakoto Onuki Log.w(TAG, Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT + " is not supported yet"); 614818b09495f5f37b38ff2e1c965e087dfde68c27fbMakoto Onuki } 614923ba865a6d204ba4aa29d2fad9989e9c44351e81Makoto Onuki qb.setTables(tables); 615018b09495f5f37b38ff2e1c965e087dfde68c27fbMakoto Onuki qb.setProjectionMap(sGroupsSummaryProjectionMap); 61519ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki appendAccountIdFromParameter(qb, uri); 6152f1efadb1255fd75305b59802f736905b9d66e449Daisuke Miyakawa groupBy = GroupsColumns.CONCRETE_ID; 6153ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey break; 6154ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey } 6155ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey 6156b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov case AGGREGATION_EXCEPTIONS: { 61570c0adda32be5de3acf392ab715cff468b6b340f8Dmitri Plotnikov qb.setTables(Tables.AGGREGATION_EXCEPTIONS); 6158b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov qb.setProjectionMap(sAggregationExceptionsProjectionMap); 6159b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov break; 6160b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov } 6161b174c7ccd337a7bea6269139c9b09acc69ae40c1Dmitri Plotnikov 616231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov case AGGREGATION_SUGGESTIONS: { 6163d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov long contactId = Long.parseLong(uri.getPathSegments().get(1)); 61642d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov String filter = null; 61652d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov if (uri.getPathSegments().size() > 3) { 61662d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov filter = uri.getPathSegments().get(3); 61672d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov } 616831b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov final int maxSuggestions; 6169d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov if (limit != null) { 6170d659078547c329b58f90d8809910a845d913dbc6Dmitri Plotnikov maxSuggestions = Integer.parseInt(limit); 617131b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } else { 617231b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov maxSuggestions = DEFAULT_MAX_SUGGESTIONS; 617331b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 617431b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 61755b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov ArrayList<AggregationSuggestionParameter> parameters = null; 61765b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov List<String> query = uri.getQueryParameters("query"); 61775b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov if (query != null && !query.isEmpty()) { 61785b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameters = new ArrayList<AggregationSuggestionParameter>(query.size()); 61795b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov for (String parameter : query) { 61805b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov int offset = parameter.indexOf(':'); 61815b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameters.add(offset == -1 61825b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov ? new AggregationSuggestionParameter( 618376dfa406e2cde19c824983c37fc92c1c5bf63eecDaniel Lehmann AggregationSuggestions.PARAMETER_MATCH_NAME, 61845b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter) 61855b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov : new AggregationSuggestionParameter( 61865b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter.substring(0, offset), 61875b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov parameter.substring(offset + 1))); 61885b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov } 61895b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov } 61905b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov 6191763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar setTablesAndProjectionMapForContacts(qb, uri, projection); 61927581213e160c460671aebdb054b8afd2f138d99eDmitri Plotnikov 61935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mAggregator.get().queryAggregationSuggestions(qb, projection, contactId, 61945b3634b24d3c21618f96860e969fd5c9ba7d9ca8Dmitri Plotnikov maxSuggestions, filter, parameters); 619531b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov } 619631b86315536573a72dc7fff1baac3b314e5a04c3Dmitri Plotnikov 6197eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey case SETTINGS: { 6198eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey qb.setTables(Tables.SETTINGS); 6199eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey qb.setProjectionMap(sSettingsProjectionMap); 6200f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro appendAccountFromParameter(qb, uri); 6201e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 6202e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey // When requesting specific columns, this query requires 6203e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey // late-binding of the GroupMembership MIME-type. 62045d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro final String groupMembershipMimetypeId = Long.toString(mDbHelper.get() 6205e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey .getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE)); 620682bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (projection != null && projection.length != 0 && 62075d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().isInProjection(projection, Settings.UNGROUPED_COUNT)) { 6208e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId); 6209e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 621082bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov if (projection != null && projection.length != 0 && 62115d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().isInProjection( 62125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro projection, Settings.UNGROUPED_WITH_PHONES)) { 6213e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey selectionArgs = insertSelectionArg(selectionArgs, groupMembershipMimetypeId); 6214e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey } 6215e07913c61c320b0cc2036db3b714e39534d8cd7aJeff Sharkey 6216eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey break; 6217eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey } 6218eb9ffdccfa19f5b2f22e688f733fd77e39605f9eJeff Sharkey 62195d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case STATUS_UPDATES: 62205d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro case PROFILE_STATUS_UPDATES: { 62210a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov setTableAndProjectionMapForStatusUpdates(qb, projection); 62225ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov break; 62235ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov } 62245ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov 622582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov case STATUS_UPDATES_ID: { 62260a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov setTableAndProjectionMapForStatusUpdates(qb, projection); 62274da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment()); 62284da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(DataColumns.CONCRETE_ID + "=?"); 62295ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov break; 62305ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov } 62315ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov 6232c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SUGGESTIONS: { 6233174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov return mGlobalSearchSupport.handleSearchSuggestionsQuery( 6234bdf112f12eafe116bbf931a0c4158a6fb5713b3fPiotr Jastrzebski db, uri, projection, limit, cancellationSignal); 6235c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6236c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 6237c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SHORTCUT: { 62382d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill String lookupKey = uri.getLastPathSegment(); 6239174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String filter = getQueryParameter( 6240174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov uri, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA); 6241174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov return mGlobalSearchSupport.handleSearchShortcutRefresh( 6242bdf112f12eafe116bbf931a0c4158a6fb5713b3fPiotr Jastrzebski db, projection, lookupKey, filter, cancellationSignal); 6243c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 6244c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 62453202ae2de5c5fec9f5f61003a0e6b608283e1961Dave Santoro case RAW_CONTACT_ENTITIES: 62463202ae2de5c5fec9f5f61003a0e6b608283e1961Dave Santoro case PROFILE_RAW_CONTACT_ENTITIES: { 6247a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForRawEntities(qb, uri); 624846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana break; 624946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 625046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 6251193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki case RAW_CONTACT_ID_ENTITY: { 625246b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 6253a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov setTablesAndProjectionMapForRawEntities(qb, uri); 62544da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(rawContactId)); 62554da1b8ded4435a3392bac3511c67182015e0953fDmitri Plotnikov qb.appendWhere(" AND " + RawContacts._ID + "=?"); 625646b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana break; 625746b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 625846b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 625909c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov case PROVIDER_STATUS: { 6260084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki return buildSingleRowResult(projection, 6261084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki new String[] {ProviderStatus.STATUS, ProviderStatus.DATA1}, 6262084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki new Object[] {mProviderStatus, mEstimatedStorageRequirement}); 626309c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov } 626409c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 6265d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES : { 6266d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setTables(Tables.DIRECTORIES); 6267d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setProjectionMap(sDirectoryProjectionMap); 6268d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 6269d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 6270d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 6271d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES_ID : { 6272385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov long id = ContentUris.parseId(uri); 6273d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setTables(Tables.DIRECTORIES); 6274d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.setProjectionMap(sDirectoryProjectionMap); 6275385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov selectionArgs = insertSelectionArg(selectionArgs, String.valueOf(id)); 6276d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov qb.appendWhere(Directory._ID + "=?"); 6277d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov break; 6278d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov } 6279d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 62807a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov case COMPLETE_NAME: { 62817a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov return completeName(uri, projection); 62827a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 62837a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 62848ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng case DELETED_CONTACTS: { 62858ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng qb.setTables(Tables.DELETED_CONTACTS); 62868ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng qb.setProjectionMap(sDeletedContactsProjectionMap); 62878ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng break; 62888ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng } 62898ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng 62908ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng case DELETED_CONTACTS_ID: { 62918ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng String id = uri.getLastPathSegment(); 62928ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng qb.setTables(Tables.DELETED_CONTACTS); 62938ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng qb.setProjectionMap(sDeletedContactsProjectionMap); 62948ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng qb.appendWhere(ContactsContract.DeletedContacts.CONTACT_ID + "=?"); 62958ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng selectionArgs = insertSelectionArg(selectionArgs, id); 62968ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng break; 62978ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng } 62988ed367fdc0b086d54c489f68d555e2f0a4035f63Chiao Cheng 62994f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton default: 6300f4e1358f1c8f5fe5e9e7689e36e04c57c2385169Dmitri Plotnikov return mLegacyApiSupport.query(uri, projection, selection, selectionArgs, 6301c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov sortOrder, limit); 63024f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 63034f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 630409e69522745551522c55dff27424496f255def46Daniel Lehmann qb.setStrict(true); 63057f786e5cbde9975b9632beb9b6d19eeef8a64cf1Dmitri Plotnikov 6306a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner // Auto-rewrite SORT_KEY_{PRIMARY, ALTERNATIVE} sort orders. 6307a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner String localizedSortOrder = getLocalizedSortOrder(sortOrder); 6308ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov Cursor cursor = 6309a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner query(db, qb, projection, selection, selectionArgs, localizedSortOrder, groupBy, 631080628945e7e41bb9363c2fbbd2938890b9217792Makoto Onuki having, limit, cancellationSignal); 6311b6b22df3a64a80531d58f9cd60f2872fc2af92d1Dave Santoro 6312ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (readBooleanQueryParameter(uri, ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, false)) { 6313ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki bundleFastScrollingIndexExtras(cursor, uri, db, qb, selection, 631435997f3fdee2984b6d5373326110eda26929001aMakoto Onuki selectionArgs, sortOrder, addressBookIndexerCountExpression, 631535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki cancellationSignal); 6316ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 6317b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson if (snippetDeferred) { 6318b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson cursor = addDeferredSnippetingExtra(cursor); 6319b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 6320b6b22df3a64a80531d58f9cd60f2872fc2af92d1Dave Santoro 6321ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov return cursor; 63225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 63235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 632480628945e7e41bb9363c2fbbd2938890b9217792Makoto Onuki 6325a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner // Rewrites query sort orders using SORT_KEY_{PRIMARY, ALTERNATIVE} 6326a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner // to use PHONEBOOK_BUCKET_{PRIMARY, ALTERNATIVE} as primary key; all 6327a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner // other sort orders are returned unchanged. Preserves ordering 6328a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner // (eg 'DESC') if present. 6329a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner protected static String getLocalizedSortOrder(String sortOrder) { 6330a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner String localizedSortOrder = sortOrder; 6331a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner if (sortOrder != null) { 6332a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner String sortKey; 6333a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner String sortOrderSuffix = ""; 6334a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner int spaceIndex = sortOrder.indexOf(' '); 6335a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner if (spaceIndex != -1) { 6336a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner sortKey = sortOrder.substring(0, spaceIndex); 6337a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner sortOrderSuffix = sortOrder.substring(spaceIndex); 6338a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner } else { 6339a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner sortKey = sortOrder; 6340a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner } 6341a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner if (TextUtils.equals(sortKey, Contacts.SORT_KEY_PRIMARY)) { 6342a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner localizedSortOrder = ContactsColumns.PHONEBOOK_BUCKET_PRIMARY 6343a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner + sortOrderSuffix + ", " + sortOrder; 6344a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner } else if (TextUtils.equals(sortKey, Contacts.SORT_KEY_ALTERNATIVE)) { 6345a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner localizedSortOrder = ContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE 6346a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner + sortOrderSuffix + ", " + sortOrder; 6347a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner } 6348a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner } 6349a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner return localizedSortOrder; 6350a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner } 6351a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner 6352a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner 63535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private Cursor query(final SQLiteDatabase db, SQLiteQueryBuilder qb, String[] projection, 63545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String selection, String[] selectionArgs, String sortOrder, String groupBy, 635580628945e7e41bb9363c2fbbd2938890b9217792Makoto Onuki String having, String limit, CancellationSignal cancellationSignal) { 6356038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana if (projection != null && projection.length == 1 6357038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana && BaseColumns._COUNT.equals(projection[0])) { 6358038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana qb.setProjectionMap(sCountProjectionMap); 6359038c3db1b54dd9313c10c212025d37ca8a9e660fFred Quintana } 636080628945e7e41bb9363c2fbbd2938890b9217792Makoto Onuki final Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, having, 63617898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown sortOrder, limit, cancellationSignal); 63624f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton if (c != null) { 63634f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton c.setNotificationUri(getContext().getContentResolver(), ContactsContract.AUTHORITY_URI); 63644f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 63654f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton return c; 63664f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 63674f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton 636809c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 6369a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov /** 6370a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * Runs the query with the supplied contact ID and lookup ID. If the query succeeds, 6371a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * it returns the resulting cursor, otherwise it returns null and the calling 6372a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov * method needs to resolve the lookup key and rerun the query. 63737898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown * @param cancellationSignal 6374a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov */ 6375a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private Cursor queryWithContactIdAndLookupKey(SQLiteQueryBuilder lookupQb, 6376a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov SQLiteDatabase db, Uri uri, 6377a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] projection, String selection, String[] selectionArgs, 6378a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String sortOrder, String groupBy, String limit, 637915826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann String contactIdColumn, long contactId, String lookupKeyColumn, String lookupKey, 63807898a8e97722d5bf0db3c04107b2957b998c0332Jeff Brown CancellationSignal cancellationSignal) { 6381a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] args; 6382a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (selectionArgs == null) { 6383a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args = new String[2]; 6384a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } else { 6385a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args = new String[selectionArgs.length + 2]; 6386a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov System.arraycopy(selectionArgs, 0, args, 2, selectionArgs.length); 6387a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6388a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args[0] = String.valueOf(contactId); 6389a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov args[1] = Uri.encode(lookupKey); 6390a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov lookupQb.appendWhere(contactIdColumn + "=? AND " + lookupKeyColumn + "=?"); 6391a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Cursor c = query(db, lookupQb, projection, selection, args, sortOrder, 639280628945e7e41bb9363c2fbbd2938890b9217792Makoto Onuki groupBy, null, limit, cancellationSignal); 6393a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov if (c.getCount() != 0) { 6394a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return c; 6395a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 6396a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 6397a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov c.close(); 6398a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov return null; 6399a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 640009c6613dd14cb1911da5d62e39a4e54eb8f4666fDmitri Plotnikov 640135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki private void invalidateFastScrollingIndexCache() { 64025acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // FastScrollingIndexCache is thread-safe, no need to synchronize here. 64035acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki mFastScrollingIndexCache.invalidate(); 640435997f3fdee2984b6d5373326110eda26929001aMakoto Onuki } 640535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 640635997f3fdee2984b6d5373326110eda26929001aMakoto Onuki /** 640735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki * Add the "fast scrolling index" bundle, generated by {@link #getFastScrollingIndexExtras}, 640835997f3fdee2984b6d5373326110eda26929001aMakoto Onuki * to a cursor as extras. It first checks {@link FastScrollingIndexCache} to see if we 640935997f3fdee2984b6d5373326110eda26929001aMakoto Onuki * already have a cached result. 641035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki */ 641135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki private void bundleFastScrollingIndexExtras(Cursor cursor, Uri queryUri, 641235997f3fdee2984b6d5373326110eda26929001aMakoto Onuki final SQLiteDatabase db, SQLiteQueryBuilder qb, String selection, 641335997f3fdee2984b6d5373326110eda26929001aMakoto Onuki String[] selectionArgs, String sortOrder, String countExpression, 641435997f3fdee2984b6d5373326110eda26929001aMakoto Onuki CancellationSignal cancellationSignal) { 641535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki if (!(cursor instanceof AbstractCursor)) { 641635997f3fdee2984b6d5373326110eda26929001aMakoto Onuki Log.w(TAG, "Unable to bundle extras. Cursor is not AbstractCursor."); 641735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki return; 641835997f3fdee2984b6d5373326110eda26929001aMakoto Onuki } 641935997f3fdee2984b6d5373326110eda26929001aMakoto Onuki Bundle b; 64205acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // Note even though FastScrollingIndexCache is thread-safe, we really need to put the 64215acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // put-get pair in a single synchronized block, so that even if multiple-threads request the 64225acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // same index at the same time (which actually happens on the phone app) we only execute 64235acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // the query once. 64245acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // 64255acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // This doesn't cause deadlock, because only reader threads get here but not writer 64265acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // threads. (Writer threads may call invalidateFastScrollingIndexCache(), but it doesn't 64275acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // synchronize on mFastScrollingIndexCache) 64285acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // 64295acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // All reader and writer threads share the single lock object internally in 64305acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // FastScrollingIndexCache, but the lock scope is limited within each put(), get() and 64315acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // invalidate() call, so it won't deadlock. 64325acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki 64335acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // Synchronizing on a non-static field is generally not a good idea, but nobody should 64345acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki // modify mFastScrollingIndexCache once initialized, and it shouldn't be null at this point. 64355acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki synchronized (mFastScrollingIndexCache) { 643635997f3fdee2984b6d5373326110eda26929001aMakoto Onuki // First, try the cache. 643735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki mFastScrollingIndexCacheRequestCount++; 643835997f3fdee2984b6d5373326110eda26929001aMakoto Onuki b = mFastScrollingIndexCache.get(queryUri, selection, selectionArgs, sortOrder, 643935997f3fdee2984b6d5373326110eda26929001aMakoto Onuki countExpression); 644035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 644135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki if (b == null) { 644235997f3fdee2984b6d5373326110eda26929001aMakoto Onuki mFastScrollingIndexCacheMissCount++; 644335997f3fdee2984b6d5373326110eda26929001aMakoto Onuki // Not in the cache. Generate and put. 644435997f3fdee2984b6d5373326110eda26929001aMakoto Onuki final long start = System.currentTimeMillis(); 644535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 644635997f3fdee2984b6d5373326110eda26929001aMakoto Onuki b = getFastScrollingIndexExtras(queryUri, db, qb, selection, selectionArgs, 6447a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner sortOrder, countExpression, cancellationSignal); 644835997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 644935997f3fdee2984b6d5373326110eda26929001aMakoto Onuki final long end = System.currentTimeMillis(); 645035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki final int time = (int) (end - start); 645135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki mTotalTimeFastScrollingIndexGenerate += time; 645235997f3fdee2984b6d5373326110eda26929001aMakoto Onuki if (VERBOSE_LOGGING) { 645335997f3fdee2984b6d5373326110eda26929001aMakoto Onuki Log.v(TAG, "getLetterCountExtraBundle took " + time + "ms"); 645435997f3fdee2984b6d5373326110eda26929001aMakoto Onuki } 64555acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki mFastScrollingIndexCache.put(queryUri, selection, selectionArgs, sortOrder, 64565acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki countExpression, b); 645735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki } 645835997f3fdee2984b6d5373326110eda26929001aMakoto Onuki } 645935997f3fdee2984b6d5373326110eda26929001aMakoto Onuki ((AbstractCursor) cursor).setExtras(b); 646035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki } 646135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 6462bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov private static final class AddressBookIndexQuery { 6463255e7f1b8eebd0df68030289a22e9c3c4d6efa3dJay Shrauner public static final String NAME = "name"; 6464a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner public static final String BUCKET = "bucket"; 6465255e7f1b8eebd0df68030289a22e9c3c4d6efa3dJay Shrauner public static final String LABEL = "label"; 6466bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String COUNT = "count"; 6467ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 6468bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov public static final String[] COLUMNS = new String[] { 6469a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner NAME, BUCKET, LABEL, COUNT 6470ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov }; 6471ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 6472255e7f1b8eebd0df68030289a22e9c3c4d6efa3dJay Shrauner public static final int COLUMN_NAME = 0; 6473a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner public static final int COLUMN_BUCKET = 1; 6474a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner public static final int COLUMN_LABEL = 2; 6475a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner public static final int COLUMN_COUNT = 3; 6476bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 6477a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner public static final String GROUP_BY = BUCKET + ", " + LABEL; 6478a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner public static final String ORDER_BY = 6479a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner BUCKET + ", " + NAME + " COLLATE " + PHONEBOOK_COLLATOR_NAME; 6480ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 6481ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 6482ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov /** 6483255e7f1b8eebd0df68030289a22e9c3c4d6efa3dJay Shrauner * Computes counts by the address book index labels and returns it as {@link Bundle} which 64845acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki * will be appended to a {@link Cursor} as extras. 6485ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov */ 648635997f3fdee2984b6d5373326110eda26929001aMakoto Onuki private static Bundle getFastScrollingIndexExtras(final Uri queryUri, final SQLiteDatabase db, 648735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki final SQLiteQueryBuilder qb, final String selection, final String[] selectionArgs, 64885acb3e091bc334d4e0f367a36f8d62a0add02b39Makoto Onuki final String sortOrder, String countExpression, 6489a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner final CancellationSignal cancellationSignal) { 6490ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String sortKey; 6491ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 6492ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // The sort order suffix could be something like "DESC". 6493ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // We want to preserve it in the query even though we will change 6494ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov // the sort column itself. 6495ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov String sortOrderSuffix = ""; 6496ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (sortOrder != null) { 6497ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov int spaceIndex = sortOrder.indexOf(' '); 6498ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov if (spaceIndex != -1) { 6499ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = sortOrder.substring(0, spaceIndex); 6500ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortOrderSuffix = sortOrder.substring(spaceIndex); 6501ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } else { 6502ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = sortOrder; 6503ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 6504ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } else { 6505ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov sortKey = Contacts.SORT_KEY_PRIMARY; 6506ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 6507ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 6508a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner String bucketKey; 6509a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner String labelKey; 6510a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner if (TextUtils.equals(sortKey, Contacts.SORT_KEY_PRIMARY)) { 6511a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner bucketKey = ContactsColumns.PHONEBOOK_BUCKET_PRIMARY; 6512a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner labelKey = ContactsColumns.PHONEBOOK_LABEL_PRIMARY; 6513a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner } else if (TextUtils.equals(sortKey, Contacts.SORT_KEY_ALTERNATIVE)) { 6514a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner bucketKey = ContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE; 6515a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner labelKey = ContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE; 6516a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner } else { 6517a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner return null; 6518a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner } 6519a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner 6520ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov HashMap<String, String> projectionMap = Maps.newHashMap(); 6521255e7f1b8eebd0df68030289a22e9c3c4d6efa3dJay Shrauner projectionMap.put(AddressBookIndexQuery.NAME, 6522255e7f1b8eebd0df68030289a22e9c3c4d6efa3dJay Shrauner sortKey + " AS " + AddressBookIndexQuery.NAME); 6523a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner projectionMap.put(AddressBookIndexQuery.BUCKET, 6524a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner bucketKey + " AS " + AddressBookIndexQuery.BUCKET); 6525a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner projectionMap.put(AddressBookIndexQuery.LABEL, 6526a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner labelKey + " AS " + AddressBookIndexQuery.LABEL); 6527bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 65282ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki // If "what to count" is not specified, we just count all records. 65292ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki if (TextUtils.isEmpty(countExpression)) { 65302ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki countExpression = "*"; 65312ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki } 65322ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki 6533ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov projectionMap.put(AddressBookIndexQuery.COUNT, 65342ebc62b692be3aaaeafa01d658ae3cdfb25b728aMakoto Onuki "COUNT(" + countExpression + ") AS " + AddressBookIndexQuery.COUNT); 6535ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov qb.setProjectionMap(projectionMap); 6536a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner String orderBy = AddressBookIndexQuery.BUCKET + sortOrderSuffix 6537a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner + ", " + AddressBookIndexQuery.NAME + " COLLATE " 6538a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner + PHONEBOOK_COLLATOR_NAME + sortOrderSuffix; 6539ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 6540f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov Cursor indexCursor = qb.query(db, AddressBookIndexQuery.COLUMNS, selection, selectionArgs, 6541a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner AddressBookIndexQuery.GROUP_BY, null /* having */, 6542a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner orderBy, null, cancellationSignal); 6543ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 6544ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov try { 6545a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner int numLabels = indexCursor.getCount(); 6546a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner String labels[] = new String[numLabels]; 6547a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner int counts[] = new int[numLabels]; 6548a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner 6549a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner for (int i = 0; i < numLabels; i++) { 6550f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov indexCursor.moveToNext(); 6551a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner labels[i] = indexCursor.getString(AddressBookIndexQuery.COLUMN_LABEL); 6552a6a9fa802d1b56c206c670ca1d313bc64effcb5dJay Shrauner counts[i] = indexCursor.getInt(AddressBookIndexQuery.COLUMN_COUNT); 6553bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov } 6554bfd59cb11248659d12a379394774da8ff6f36cefDmitri Plotnikov 6555255e7f1b8eebd0df68030289a22e9c3c4d6efa3dJay Shrauner return FastScrollingIndexCache.buildExtraBundle(labels, counts); 6556ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } finally { 6557f3f4a385d8d1d6788ba79ca353d02235de1d9b33Dmitri Plotnikov indexCursor.close(); 6558ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 6559ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov } 6560ba2c85b4700fbb3ecaf75e1101735f60b5483527Dmitri Plotnikov 65612d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill /** 656292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * Returns the contact Id for the contact identified by the lookupKey. 656392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * Robust against changes in the lookup key: if the key has changed, will 656492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * look up the contact by the raw contact IDs or name encoded in the lookup 656592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov * key. 65662d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill */ 65672d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill public long lookupContactIdByLookupKey(SQLiteDatabase db, String lookupKey) { 65685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ContactLookupKey key = new ContactLookupKey(); 65695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ArrayList<LookupKeySegment> segments = key.parse(lookupKey); 65705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 657192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov long contactId = -1; 65725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_PROFILE)) { 65735d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // We should already be in a profile database context, so just look up a single contact. 65745d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro contactId = lookupSingleContactId(db); 65755d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 65765d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 657792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_SOURCE_ID)) { 657892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov contactId = lookupContactIdBySourceIds(db, segments); 657992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (contactId != -1) { 658092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return contactId; 658192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 658292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 658392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 658492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov boolean hasRawContactIds = 658592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID); 658692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (hasRawContactIds) { 658792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov contactId = lookupContactIdByRawContactIds(db, segments); 658892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (contactId != -1) { 658992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return contactId; 659092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 659192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 659292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 659392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (hasRawContactIds 659492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || lookupKeyContainsType(segments, ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME)) { 65955870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov contactId = lookupContactIdByDisplayNames(db, segments); 65965870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 65975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 65985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return contactId; 65995870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 66005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 66015d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro private long lookupSingleContactId(SQLiteDatabase db) { 66025d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro Cursor c = db.query(Tables.CONTACTS, new String[] {Contacts._ID}, 66035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro null, null, null, null, null, "1"); 66045d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro try { 66055d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (c.moveToFirst()) { 66065d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return c.getLong(0); 66075d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 66085d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return -1; 66095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 66105d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } finally { 66115d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro c.close(); 66125d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 66135d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 66145d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 66155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private interface LookupBySourceIdQuery { 661643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String TABLE = Views.RAW_CONTACTS; 66175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 66185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String COLUMNS[] = { 66195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.CONTACT_ID, 662043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 66215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_NAME, 66225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.SOURCE_ID 66235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov }; 66245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 66255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int CONTACT_ID = 0; 662643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int ACCOUNT_TYPE_AND_DATA_SET = 1; 66275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_NAME = 2; 66285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int SOURCE_ID = 3; 66295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 66305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 66315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private long lookupContactIdBySourceIds(SQLiteDatabase db, 66325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov ArrayList<LookupKeySegment> segments) { 66335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 66345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(RawContacts.SOURCE_ID + " IN ("); 66355870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 66365870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 663792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_SOURCE_ID) { 66385870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, segment.key); 66395870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(","); 66405870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 66415870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 66425870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 66435870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL"); 66445870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 66455870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Cursor c = db.query(LookupBySourceIdQuery.TABLE, LookupBySourceIdQuery.COLUMNS, 66465870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.toString(), null, null, null, null); 66475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov try { 66485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov while (c.moveToNext()) { 664943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String accountTypeAndDataSet = 665043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro c.getString(LookupBySourceIdQuery.ACCOUNT_TYPE_AND_DATA_SET); 66515870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountName = c.getString(LookupBySourceIdQuery.ACCOUNT_NAME); 66525870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int accountHashCode = 665343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro ContactLookupKey.getAccountHashCode(accountTypeAndDataSet, accountName); 66545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String sourceId = c.getString(LookupBySourceIdQuery.SOURCE_ID); 66555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 66565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 665792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_SOURCE_ID 665892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 66595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov && segment.key.equals(sourceId)) { 66605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov segment.contactId = c.getLong(LookupBySourceIdQuery.CONTACT_ID); 66615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 66625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 66635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 66645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 66655870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } finally { 66665870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov c.close(); 66675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 66685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 66695870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return getMostReferencedContactId(segments); 66705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 66715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 667292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private interface LookupByRawContactIdQuery { 667343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String TABLE = Views.RAW_CONTACTS; 66745870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 66755870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String COLUMNS[] = { 66765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.CONTACT_ID, 667743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 66785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov RawContacts.ACCOUNT_NAME, 667992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts._ID, 66805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov }; 66815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 66825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int CONTACT_ID = 0; 668343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int ACCOUNT_TYPE_AND_DATA_SET = 1; 66845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int ACCOUNT_NAME = 2; 668592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int ID = 3; 66865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 66875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 668892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private long lookupContactIdByRawContactIds(SQLiteDatabase db, 668992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov ArrayList<LookupKeySegment> segments) { 669092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 669192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(RawContacts._ID + " IN ("); 66925870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 66935870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 669492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) { 669592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(segment.rawContactId); 669692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(","); 66975870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 66985870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 669992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 670092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.append(") AND " + RawContacts.CONTACT_ID + " NOT NULL"); 67015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 670292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov Cursor c = db.query(LookupByRawContactIdQuery.TABLE, LookupByRawContactIdQuery.COLUMNS, 670392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov sb.toString(), null, null, null, null); 670492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov try { 670592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov while (c.moveToNext()) { 670643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String accountTypeAndDataSet = c.getString( 670743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro LookupByRawContactIdQuery.ACCOUNT_TYPE_AND_DATA_SET); 670892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String accountName = c.getString(LookupByRawContactIdQuery.ACCOUNT_NAME); 670992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int accountHashCode = 671043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro ContactLookupKey.getAccountHashCode(accountTypeAndDataSet, accountName); 671192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String rawContactId = c.getString(LookupByRawContactIdQuery.ID); 671292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 671392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov LookupKeySegment segment = segments.get(i); 671492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID 671592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 671692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && segment.rawContactId.equals(rawContactId)) { 671792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov segment.contactId = c.getLong(LookupByRawContactIdQuery.CONTACT_ID); 671892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov break; 671992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 672092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 672192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 672292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } finally { 672392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov c.close(); 67245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 67255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 672692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return getMostReferencedContactId(segments); 672792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 672892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 672992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private interface LookupByDisplayNameQuery { 673092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String TABLE = Tables.NAME_LOOKUP_JOIN_RAW_CONTACTS; 673192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 673292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov String COLUMNS[] = { 673392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts.CONTACT_ID, 673443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro RawContacts.ACCOUNT_TYPE_AND_DATA_SET, 673592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov RawContacts.ACCOUNT_NAME, 673692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov NameLookupColumns.NORMALIZED_NAME 673792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov }; 673892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 673992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int CONTACT_ID = 0; 674043368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro int ACCOUNT_TYPE_AND_DATA_SET = 1; 674192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int ACCOUNT_NAME = 2; 674292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov int NORMALIZED_NAME = 3; 674392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 674492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 674592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private long lookupContactIdByDisplayNames(SQLiteDatabase db, 674692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov ArrayList<LookupKeySegment> segments) { 67475870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 67485870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(NameLookupColumns.NORMALIZED_NAME + " IN ("); 67495870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 67505870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 675192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME 675292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) { 67535870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, segment.key); 67545870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(","); 67555870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 67565870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 67575870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.setLength(sb.length() - 1); // Last comma 67585870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.append(") AND " + NameLookupColumns.NAME_TYPE + "=" + NameLookupType.NAME_COLLATION_KEY 67595870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov + " AND " + RawContacts.CONTACT_ID + " NOT NULL"); 67605870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 67615870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Cursor c = db.query(LookupByDisplayNameQuery.TABLE, LookupByDisplayNameQuery.COLUMNS, 67625870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov sb.toString(), null, null, null, null); 67635870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov try { 67645870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov while (c.moveToNext()) { 676543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro String accountTypeAndDataSet = 676643368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro c.getString(LookupByDisplayNameQuery.ACCOUNT_TYPE_AND_DATA_SET); 67675870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String accountName = c.getString(LookupByDisplayNameQuery.ACCOUNT_NAME); 67685870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int accountHashCode = 676943368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro ContactLookupKey.getAccountHashCode(accountTypeAndDataSet, accountName); 67705870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov String name = c.getString(LookupByDisplayNameQuery.NORMALIZED_NAME); 67715870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 67725870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 677392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if ((segment.lookupType == ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME 677492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov || segment.lookupType == ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID) 677592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov && accountHashCode == segment.accountHashCode 67765870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov && segment.key.equals(name)) { 67775870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov segment.contactId = c.getLong(LookupByDisplayNameQuery.CONTACT_ID); 67785870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov break; 67795870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 67805870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 67815870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 67825870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } finally { 67835870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov c.close(); 67845870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 67855870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 67865870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return getMostReferencedContactId(segments); 67875870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 67885870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 678992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov private boolean lookupKeyContainsType(ArrayList<LookupKeySegment> segments, int lookupType) { 679092fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov for (int i = 0; i < segments.size(); i++) { 679192fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov LookupKeySegment segment = segments.get(i); 679292fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov if (segment.lookupType == lookupType) { 679392fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return true; 679492fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 679592fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 679692fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 679792fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov return false; 679892fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov } 679992fcdfb24194e8527ef59c0af0731825ee46fa45Dmitri Plotnikov 68005870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov /** 68015870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov * Returns the contact ID that is mentioned the highest number of times. 68025870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov */ 68035870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov private long getMostReferencedContactId(ArrayList<LookupKeySegment> segments) { 68045870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov Collections.sort(segments); 68055870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 68065870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long bestContactId = -1; 68075870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int bestRefCount = 0; 68085870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 68095870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov long contactId = -1; 68105870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int count = 0; 68115870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 68125870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov int segmentCount = segments.size(); 68135870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov for (int i = 0; i < segmentCount; i++) { 68145870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov LookupKeySegment segment = segments.get(i); 68155870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segment.contactId != -1) { 68165870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (segment.contactId == contactId) { 68175870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov count++; 68185870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } else { 68195870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count > bestRefCount) { 68205870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov bestContactId = contactId; 68215870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov bestRefCount = count; 68225870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 68235870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov contactId = segment.contactId; 68245870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov count = 1; 68255870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 68265870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 68275870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 68285870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov if (count > bestRefCount) { 68295870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return contactId; 68305870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } else { 68315870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov return bestContactId; 68325870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 68335870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov } 68345870f2dcc2ac7715b2c078a886ee346622e7887eDmitri Plotnikov 6835763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, Uri uri, 6836763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar String[] projection) { 68374928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa setTablesAndProjectionMapForContacts(qb, uri, projection, false); 68382f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 68392f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 68402f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa /** 68414928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * @param includeDataUsageStat true when the table should include DataUsageStat table. 68424928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * Note that this uses INNER JOIN instead of LEFT OUTER JOIN, so some of data in Contacts 68434928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa * may be dropped. 68442f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa */ 68452f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, Uri uri, 68464928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa String[] projection, boolean includeDataUsageStat) { 684782bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 684872c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann if (includeDataUsageStat) { 684972c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann sb.append(Views.DATA_USAGE_STAT + " AS " + Tables.DATA_USAGE_STAT); 685072c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann sb.append(" INNER JOIN "); 685172c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann } 685272c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann 6853ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.CONTACTS); 68542f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 68552f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa // Just for frequently contacted contacts in Strequent Uri handling. 68564928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa if (includeDataUsageStat) { 685772c4b2612a06636343e2803c0c84fdfbd5ba2f63Daniel Lehmann sb.append(" ON (" + 68582f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa DbQueryUtils.concatenateClauses( 68592f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa DataUsageStatColumns.CONCRETE_TIMES_USED + " > 0", 68604928b8c8c7a49ec088884cd9d330eeecc811dca9Daisuke Miyakawa RawContacts.CONTACT_ID + "=" + Views.CONTACTS + "." + Contacts._ID) + 68612f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa ")"); 68622f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa } 68632f830d3bb66f780937203e9738e046841a070e73Daisuke Miyakawa 68647ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts._ID); 68657ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 6866916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov qb.setTables(sb.toString()); 6867916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov qb.setProjectionMap(sContactsProjectionMap); 6868916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov } 6869916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 6870916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov /** 6871916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov * Finds name lookup records matching the supplied filter, picks one arbitrary match per 6872916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov * contact and joins that with other contacts tables. 6873916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov */ 6874916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov private void setTablesAndProjectionMapForContactsWithSnippet(SQLiteQueryBuilder qb, Uri uri, 6875fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki String[] projection, String filter, long directoryId, boolean deferSnippeting) { 68767ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov 68777ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 6878ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.CONTACTS); 6879916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 688003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov if (filter != null) { 688103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov filter = filter.trim(); 688203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 688303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 688430cc766756461da8d53933f88ea01dd2272a90ebDmitri Plotnikov if (TextUtils.isEmpty(filter) || (directoryId != -1 && directoryId != Directory.DEFAULT)) { 688530cc766756461da8d53933f88ea01dd2272a90ebDmitri Plotnikov sb.append(" JOIN (SELECT NULL AS " + SearchSnippetColumns.SNIPPET + " WHERE 0)"); 68865e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } else { 6887fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki appendSearchIndexJoin(sb, uri, projection, filter, deferSnippeting); 68885e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 68897ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts._ID); 68907ba290f5de7f116ec0eaac30980ffef2878d2b64Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 689103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov qb.setTables(sb.toString()); 689203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov qb.setProjectionMap(sContactsProjectionWithSnippetMap); 689303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 6894916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 689503197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov private void appendSearchIndexJoin( 6896b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson StringBuilder sb, Uri uri, String[] projection, String filter, 6897fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki boolean deferSnippeting) { 6898916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov 6899b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson if (snippetNeeded(projection)) { 690003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov String[] args = null; 690103197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov String snippetArgs = 690203197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov getQueryParameter(uri, SearchSnippetColumns.SNIPPET_ARGS_PARAM_KEY); 690303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov if (snippetArgs != null) { 690403197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov args = snippetArgs.split(","); 690503197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 690603197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 69075e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String startMatch = args != null && args.length > 0 ? args[0] 69085e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_START_MATCH; 69095e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String endMatch = args != null && args.length > 1 ? args[1] 69105e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_END_MATCH; 69115e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov String ellipsis = args != null && args.length > 2 ? args[2] 69125e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_ELLIPSIS; 69135e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov int maxTokens = args != null && args.length > 3 ? Integer.parseInt(args[3]) 69145e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov : DEFAULT_SNIPPET_ARG_MAX_TOKENS; 69155e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 6916174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov appendSearchIndexJoin( 6917b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson sb, filter, true, startMatch, endMatch, ellipsis, maxTokens, 6918fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki deferSnippeting); 6919174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } else { 6920b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson appendSearchIndexJoin(sb, filter, false, null, null, null, 0, false); 6921174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 6922174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 6923174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 6924174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov public void appendSearchIndexJoin(StringBuilder sb, String filter, 6925174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean snippetNeeded, String startMatch, String endMatch, String ellipsis, 6926fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki int maxTokens, boolean deferSnippeting) { 6927174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean isEmailAddress = false; 6928174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String emailAddress = null; 6929174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov boolean isPhoneNumber = false; 6930174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String phoneNumber = null; 6931174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String numberE164 = null; 6932174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 69333716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 6934174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (filter.indexOf('@') != -1) { 69355d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro emailAddress = mDbHelper.get().extractAddressFromEmailAddress(filter); 6936174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov isEmailAddress = !TextUtils.isEmpty(emailAddress); 6937174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } else { 6938174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov isPhoneNumber = isPhoneNumber(filter); 693904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (isPhoneNumber) { 694004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann phoneNumber = PhoneNumberUtils.normalizeNumber(filter); 694104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann numberE164 = PhoneNumberUtils.formatNumberToE164(phoneNumber, 69425d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().getCountryIso()); 694304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 6944174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 6945174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 6946d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann final String SNIPPET_CONTACT_ID = "snippet_contact_id"; 6947d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann sb.append(" JOIN (SELECT " + SearchIndexColumns.CONTACT_ID + " AS " + SNIPPET_CONTACT_ID); 6948174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (snippetNeeded) { 69495e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(", "); 69505e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov if (isEmailAddress) { 69513d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append("ifnull("); 6952fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki if (!deferSnippeting) { 6953fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki // Add the snippet marker only when we're really creating snippet. 6954fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki DatabaseUtils.appendEscapedSQLString(sb, startMatch); 6955fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki sb.append("||"); 6956fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki } 6957fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki sb.append("(SELECT MIN(" + Email.ADDRESS + ")"); 695804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" FROM " + Tables.DATA_JOIN_RAW_CONTACTS); 695904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" WHERE " + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 696004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + RawContacts.CONTACT_ID + " AND " + Email.ADDRESS + " LIKE "); 696104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann DatabaseUtils.appendEscapedSQLString(sb, filter + "%"); 6962fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki sb.append(")"); 6963fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki if (!deferSnippeting) { 6964fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki sb.append("||"); 6965fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki DatabaseUtils.appendEscapedSQLString(sb, endMatch); 6966fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki } 69673d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append(","); 69683716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 6969fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki if (deferSnippeting) { 69703716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 69713716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 69723716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 69733716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 69743d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append(")"); 69753d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov } else if (isPhoneNumber) { 69763d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov sb.append("ifnull("); 6977fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki if (!deferSnippeting) { 6978fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki // Add the snippet marker only when we're really creating snippet. 6979fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki DatabaseUtils.appendEscapedSQLString(sb, startMatch); 6980fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki sb.append("||"); 6981fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki } 6982fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki sb.append("(SELECT MIN(" + Phone.NUMBER + ")"); 698304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" FROM " + 698404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann Tables.DATA_JOIN_RAW_CONTACTS + " JOIN " + Tables.PHONE_LOOKUP); 698504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" ON " + DataColumns.CONCRETE_ID); 698604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + Tables.PHONE_LOOKUP + "." + PhoneLookupColumns.DATA_ID); 698704f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" WHERE " + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 698804f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("=" + RawContacts.CONTACT_ID); 698904f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" AND " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 699004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(phoneNumber); 699104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("%'"); 699204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (!TextUtils.isEmpty(numberE164)) { 699304f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(" OR " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '"); 699404f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append(numberE164); 699504f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("%'"); 699604f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 6997fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki sb.append(")"); 6998fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki if (! deferSnippeting) { 6999fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki sb.append("||"); 7000fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki DatabaseUtils.appendEscapedSQLString(sb, endMatch); 7001fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki } 70025e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 70033716f1447ceb21180d1301790eabd8b9453f486dDave Santoro 7004fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki if (deferSnippeting) { 70053716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 70063716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 70073716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 70083716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 70095e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(")"); 701003197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } else { 701104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann final String normalizedFilter = NameNormalizer.normalize(filter); 701204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann if (!TextUtils.isEmpty(normalizedFilter)) { 7013fba89ea92f519d77ec1d762724ed11bf4ebb7d20Makoto Onuki if (deferSnippeting) { 70143716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(SearchIndexColumns.CONTENT); 70153716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } else { 70163716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("(CASE WHEN EXISTS (SELECT 1 FROM "); 70173716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.RAW_CONTACTS + " AS rc INNER JOIN "); 70183716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.NAME_LOOKUP + " AS nl ON (rc." + RawContacts._ID); 70193716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("=nl." + NameLookupColumns.RAW_CONTACT_ID); 70203716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(") WHERE nl." + NameLookupColumns.NORMALIZED_NAME); 70213716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(" GLOB '" + normalizedFilter + "*' AND "); 70223716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("nl." + NameLookupColumns.NAME_TYPE + "="); 70233716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(NameLookupType.NAME_COLLATION_KEY + " AND "); 70243716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID); 70253716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append("=rc." + RawContacts.CONTACT_ID); 70263716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(") THEN NULL ELSE "); 70273716f1447ceb21180d1301790eabd8b9453f486dDave Santoro appendSnippetFunction(sb, startMatch, endMatch, ellipsis, maxTokens); 70283716f1447ceb21180d1301790eabd8b9453f486dDave Santoro sb.append(" END)"); 70293716f1447ceb21180d1301790eabd8b9453f486dDave Santoro } 703004f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } else { 703104f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann sb.append("NULL"); 703204f7fc0bddad198108d2f45cb730b9506e81dedbDaniel Lehmann } 703303197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } 70345e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" AS " + SearchSnippetColumns.SNIPPET); 70355e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 703603197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov 70375e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" FROM " + Tables.SEARCH_INDEX); 70385e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(" WHERE "); 7039d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann sb.append(Tables.SEARCH_INDEX + " MATCH '"); 70405e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov if (isEmailAddress) { 7041d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann // we know that the emailAddress contains a @. This phrase search should be 7042d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann // scoped against "content:" only, but unfortunately SQLite doesn't support 7043d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann // phrases and scoped columns at once. This is fine in this case however, because: 7044d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann // - We can't erronously match against name, as name is all-hex (so the @ can't match) 7045d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann // - We can't match against tokens, because phone-numbers can't contain @ 7046d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann final String sanitizedEmailAddress = 7047d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann emailAddress == null ? "" : sanitizeMatch(emailAddress); 7048d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann sb.append("\""); 7049d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann sb.append(sanitizedEmailAddress); 7050d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann sb.append("*\""); 70513d0f0e0a1325ae306842b3ad1487d3507df0821dDmitri Plotnikov } else if (isPhoneNumber) { 7052d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann // normalized version of the phone number (phoneNumber can only have + and digits) 7053d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann final String phoneNumberCriteria = " OR tokens:" + phoneNumber + "*"; 7054d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann 7055d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann // international version of this number (numberE164 can only have + and digits) 7056d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann final String numberE164Criteria = 7057d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann (numberE164 != null && !TextUtils.equals(numberE164, phoneNumber)) 7058d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann ? " OR tokens:" + numberE164 + "*" 7059d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann : ""; 7060d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann 7061d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann // combine all criteria 7062d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann final String commonCriteria = 7063d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann phoneNumberCriteria + numberE164Criteria; 7064d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann 7065d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann // search in content 7066d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann sb.append(SearchIndexManager.getFtsMatchQuery(filter, 7067d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann FtsQueryBuilder.getDigitsQueryBuilder(commonCriteria))); 706803197a00e17386aa9b1971bde3cda034bc17e0c3Dmitri Plotnikov } else { 7069d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann // general case: not a phone number, not an email-address 7070d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann sb.append(SearchIndexManager.getFtsMatchQuery(filter, 7071d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann FtsQueryBuilder.SCOPED_NAME_NORMALIZING)); 70729c6ef008d92017108e3d10dcd8e2146eded9e148Dmitri Plotnikov } 70731322df8f90d80587748ad10539516635326c01e8Daniel Lehmann // Omit results in "Other Contacts". 70741322df8f90d80587748ad10539516635326c01e8Daniel Lehmann sb.append("' AND " + SNIPPET_CONTACT_ID + " IN " + Tables.DEFAULT_DIRECTORY + ")"); 70751322df8f90d80587748ad10539516635326c01e8Daniel Lehmann sb.append(" ON (" + Contacts._ID + "=" + SNIPPET_CONTACT_ID + ")"); 7076a1e177389debb74a51587720464a527a193bffc1Dmitri Plotnikov } 7077a1e177389debb74a51587720464a527a193bffc1Dmitri Plotnikov 7078d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann private static String sanitizeMatch(String filter) { 7079d1746e09bc7739f3d1449cececc66d5045ada498Daniel Lehmann return filter.replace("'", "").replace("*", "").replace("-", "").replace("\"", ""); 70802352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov } 70812352cf62c46e1caaad64c7b3dbcc601951018eb3Dmitri Plotnikov 70825e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov private void appendSnippetFunction( 70835e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov StringBuilder sb, String startMatch, String endMatch, String ellipsis, int maxTokens) { 70845e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append("snippet(" + Tables.SEARCH_INDEX + ","); 70855e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, startMatch); 70865e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 70875e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, endMatch); 70885e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(","); 70895e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov DatabaseUtils.appendEscapedSQLString(sb, ellipsis); 70905e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 70915e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov // The index of the column used for the snippet, "content" 70925e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(",1,"); 70935e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(maxTokens); 70945e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov sb.append(")"); 70955e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov } 70965e70c0772ef2b975c95787112ac0f15047a4ff0cDmitri Plotnikov 7097763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar private void setTablesAndProjectionMapForRawContacts(SQLiteQueryBuilder qb, Uri uri) { 7098763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar StringBuilder sb = new StringBuilder(); 7099ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.RAW_CONTACTS); 7100763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar qb.setTables(sb.toString()); 7101763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar qb.setProjectionMap(sRawContactsProjectionMap); 71029ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki appendAccountIdFromParameter(qb, uri); 7103763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar } 7104763100dcfabb368e72f25d24fe181c352bdb66d6Evan Millar 7105a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void setTablesAndProjectionMapForRawEntities(SQLiteQueryBuilder qb, Uri uri) { 7106ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann qb.setTables(Views.RAW_ENTITIES); 7107a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sRawEntityProjectionMap); 71089ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki appendAccountIdFromParameter(qb, uri); 710946b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana } 711046b7bfa3728bf878d1a9dac9fea35fa629975e1bFred Quintana 711182bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri, 711282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov String[] projection, boolean distinct) { 711358795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda setTablesAndProjectionMapForData(qb, uri, projection, distinct, false, null); 711458795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda } 711558795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda 711658795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri, 711758795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda String[] projection, boolean distinct, boolean addSipLookupColumns) { 711858795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda setTablesAndProjectionMapForData(qb, uri, projection, distinct, addSipLookupColumns, null); 711946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 712046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 712146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 712246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * @param usageType when non-null {@link Tables#DATA_USAGE_STAT} is joined with the specified 712346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * type. 712446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 712546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri, 712646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa String[] projection, boolean distinct, Integer usageType) { 712758795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda setTablesAndProjectionMapForData(qb, uri, projection, distinct, false, usageType); 712858795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda } 712958795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda 713058795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri, 713158795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda String[] projection, boolean distinct, boolean addSipLookupColumns, Integer usageType) { 713282bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov StringBuilder sb = new StringBuilder(); 7133ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.DATA); 713482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov sb.append(" data"); 713582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov 7136a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactPresenceJoin(sb, projection, RawContacts.CONTACT_ID); 7137a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 7138a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, DataColumns.CONCRETE_ID); 7139a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, DataColumns.CONCRETE_ID); 71403296d3469bce0041a6cefc44d0486a2a7d0c9f82Jeff Sharkey 7141216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee appendDataUsageStatJoin(sb, usageType == null ? USAGE_TYPE_ALL : usageType, 7142216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee DataColumns.CONCRETE_ID); 714346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 714482bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov qb.setTables(sb.toString()); 7145f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov 714663630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki boolean useDistinct = distinct || !ContactsDatabaseHelper.isInProjection( 714763630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki projection, DISTINCT_DATA_PROHIBITING_COLUMNS); 7148f4e7ae68ba58d82b16bc2101db8d0f358c1d9297Dmitri Plotnikov qb.setDistinct(useDistinct); 714958795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda 715058795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda final ProjectionMap projectionMap; 715158795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda if (addSipLookupColumns) { 715258795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda projectionMap = useDistinct 715358795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda ? sDistinctDataSipLookupProjectionMap : sDataSipLookupProjectionMap; 715458795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda } else { 715558795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda projectionMap = useDistinct ? sDistinctDataProjectionMap : sDataProjectionMap; 715658795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda } 715758795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda 715858795e447fada97b9594bd7ba2e3dca241487d01Flavio Lerda qb.setProjectionMap(projectionMap); 71599ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki appendAccountIdFromParameter(qb, uri); 7160ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov } 7161ff2de103f7e3eeeff4665ef63f07460fef053d6dDmitri Plotnikov 71620a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov private void setTableAndProjectionMapForStatusUpdates(SQLiteQueryBuilder qb, 71630a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov String[] projection) { 71640a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StringBuilder sb = new StringBuilder(); 7165ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.DATA); 71660a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov sb.append(" data"); 7167a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, DataColumns.CONCRETE_ID); 7168a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, DataColumns.CONCRETE_ID); 71690a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 7170a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setTables(sb.toString()); 7171a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sStatusUpdatesProjectionMap); 7172a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 7173a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 71743b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void setTablesAndProjectionMapForStreamItems(SQLiteQueryBuilder qb) { 71759b002837367674b7403769f52dc50ab4dbecef71Daniel Lehmann qb.setTables(Views.STREAM_ITEMS); 71763b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.setProjectionMap(sStreamItemsProjectionMap); 71773b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 71783b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 71793b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann private void setTablesAndProjectionMapForStreamItemPhotos(SQLiteQueryBuilder qb) { 71801dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro qb.setTables(Tables.PHOTO_FILES 71811dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + " JOIN " + Tables.STREAM_ITEM_PHOTOS + " ON (" 71821dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemPhotosColumns.CONCRETE_PHOTO_FILE_ID + "=" 71831dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + PhotoFilesColumns.CONCRETE_ID 71841dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + ") JOIN " + Tables.STREAM_ITEMS + " ON (" 71851dfa964f2e1756e27b36f99421bd403c84ea0a5fDave Santoro + StreamItemPhotosColumns.CONCRETE_STREAM_ITEM_ID + "=" 71860bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann + StreamItemsColumns.CONCRETE_ID + ")" 71870bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann + " JOIN " + Tables.RAW_CONTACTS + " ON (" 71880bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann + StreamItemsColumns.CONCRETE_RAW_CONTACT_ID + "=" + RawContactsColumns.CONCRETE_ID 71890bf6b318e3c994294d4a885f57906debd4a0e64eDaniel Lehmann + ")"); 71903b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann qb.setProjectionMap(sStreamItemPhotosProjectionMap); 71913b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann } 71923b505de6c622d20d40b85b361c1437a89aef82deDaniel Lehmann 7193a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void setTablesAndProjectionMapForEntities(SQLiteQueryBuilder qb, Uri uri, 7194a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String[] projection) { 7195a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 7196ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.ENTITIES); 7197a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" data"); 7198a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 7199a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactPresenceJoin(sb, projection, Contacts.Entity.CONTACT_ID); 7200a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID); 7201a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataPresenceJoin(sb, projection, Contacts.Entity.DATA_ID); 7202a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov appendDataStatusUpdateJoin(sb, projection, Contacts.Entity.DATA_ID); 7203a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 7204a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setTables(sb.toString()); 7205a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov qb.setProjectionMap(sEntityProjectionMap); 72069ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki appendAccountIdFromParameter(qb, uri); 7207a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 7208a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 7209a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendContactStatusUpdateJoin(StringBuilder sb, String[] projection, 7210a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String lastStatusUpdateIdColumn) { 721163630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki if (ContactsDatabaseHelper.isInProjection(projection, 7212a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS, 7213a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_RES_PACKAGE, 7214a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_ICON, 7215a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_LABEL, 7216a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_STATUS_TIMESTAMP)) { 7217a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES + " " 7218a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + ContactsStatusUpdatesColumns.ALIAS + 7219a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + lastStatusUpdateIdColumn + "=" 7220a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + ContactsStatusUpdatesColumns.CONCRETE_DATA_ID + ")"); 72210a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 7222a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 72230a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov 7224a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendDataStatusUpdateJoin(StringBuilder sb, String[] projection, 7225a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String dataIdColumn) { 722663630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki if (ContactsDatabaseHelper.isInProjection(projection, 72270a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS, 72280a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_RES_PACKAGE, 72290a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_ICON, 72300a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_LABEL, 72310a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov StatusUpdates.STATUS_TIMESTAMP)) { 72320a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES + 7233a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + StatusUpdatesColumns.CONCRETE_DATA_ID + "=" 7234a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + dataIdColumn + ")"); 72350a185cdcb65d1beb2a295fffbe2ae11a6a2c097fDmitri Plotnikov } 7236a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 7237a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 723846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private void appendDataUsageStatJoin(StringBuilder sb, int usageType, String dataIdColumn) { 7239216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee if (usageType != USAGE_TYPE_ALL) { 7240216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee sb.append(" LEFT OUTER JOIN " + Tables.DATA_USAGE_STAT + 7241216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee " ON (" + DataUsageStatColumns.CONCRETE_DATA_ID + "="); 7242216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee sb.append(dataIdColumn); 7243216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee sb.append(" AND " + DataUsageStatColumns.CONCRETE_USAGE_TYPE + "="); 7244216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee sb.append(usageType); 7245216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee sb.append(")"); 7246216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee } else { 7247216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee sb.append( 7248216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee " LEFT OUTER JOIN " + 7249216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee "(SELECT " + 7250216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee DataUsageStatColumns.CONCRETE_DATA_ID + ", " + 7251216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee "SUM(" + DataUsageStatColumns.CONCRETE_TIMES_USED + 7252216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee ") as " + DataUsageStatColumns.TIMES_USED + ", " + 7253216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee "MAX(" + DataUsageStatColumns.CONCRETE_LAST_TIME_USED + 7254216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee ") as " + DataUsageStatColumns.LAST_TIME_USED + 7255216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee " FROM " + Tables.DATA_USAGE_STAT + " GROUP BY " + 7256216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee DataUsageStatColumns.DATA_ID + ") as " + Tables.DATA_USAGE_STAT 7257216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee ); 7258216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee sb.append(" ON (" + DataUsageStatColumns.CONCRETE_DATA_ID + "="); 7259216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee sb.append(dataIdColumn); 7260216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee sb.append(")"); 7261216c434537d05a691add4e22ba3a9d958c976c1eYorke Lee } 726246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 726346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 7264a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendContactPresenceJoin(StringBuilder sb, String[] projection, 7265a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String contactIdColumn) { 726663630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki if (ContactsDatabaseHelper.isInProjection(projection, 7267a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov Contacts.CONTACT_PRESENCE, Contacts.CONTACT_CHAT_CAPABILITY)) { 7268a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.AGGREGATED_PRESENCE + 7269a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + contactIdColumn + " = " 7270a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov + AggregatedPresenceColumns.CONCRETE_CONTACT_ID + ")"); 7271a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 7272a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 7273a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 7274a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov private void appendDataPresenceJoin(StringBuilder sb, String[] projection, 7275a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov String dataIdColumn) { 727663630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki if (ContactsDatabaseHelper.isInProjection( 727763630bc7f962fd2b6f2c1bc41cbed45a8bc354baMakoto Onuki projection, Data.PRESENCE, Data.CHAT_CAPABILITY)) { 7278a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov sb.append(" LEFT OUTER JOIN " + Tables.PRESENCE + 7279a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov " ON (" + StatusUpdates.DATA_ID + "=" + dataIdColumn + ")"); 7280a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 7281a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov } 7282a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov 72839ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki private void appendLocalDirectoryAndAccountSelectionIfNeeded(SQLiteQueryBuilder qb, 72849ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki long directoryId, Uri uri) { 72859ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final StringBuilder sb = new StringBuilder(); 7286385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov if (directoryId == Directory.DEFAULT) { 72879ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki sb.append("(" + Contacts._ID + " IN " + Tables.DEFAULT_DIRECTORY + ")"); 7288385182830ff0ed84edce9aba2424d2afe99453ceDmitri Plotnikov } else if (directoryId == Directory.LOCAL_INVISIBLE){ 72899ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki sb.append("(" + Contacts._ID + " NOT IN " + Tables.DEFAULT_DIRECTORY + ")"); 72909ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } else { 72919ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki sb.append("(1)"); 729224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 72939ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki 72949ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final AccountWithDataSet accountWithDataSet = getAccountWithDataSetFromUri(uri); 72959ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // Accounts are valid by only checking one parameter, since we've 72969ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // already ruled out partial accounts. 72979ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final boolean validAccount = !TextUtils.isEmpty(accountWithDataSet.getAccountName()); 72989ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki if (validAccount) { 72999ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final Long accountId = mDbHelper.get().getAccountIdOrNull(accountWithDataSet); 73009ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki if (accountId == null) { 73019ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // No such account. 73029ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki sb.setLength(0); 73039ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki sb.append("(1=2)"); 73049ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } else { 73059ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki sb.append( 73069ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki " AND (" + Contacts._ID + " IN (" + 73079ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki "SELECT " + RawContacts.CONTACT_ID + " FROM " + Tables.RAW_CONTACTS + 73089ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki " WHERE " + RawContactsColumns.ACCOUNT_ID + "=" + accountId.toString() + 73099ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki "))"); 73109ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 73119ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 73129ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki qb.appendWhere(sb.toString()); 731324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro } 731424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro 7315f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro private void appendAccountFromParameter(SQLiteQueryBuilder qb, Uri uri) { 73169ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final AccountWithDataSet accountWithDataSet = getAccountWithDataSetFromUri(uri); 7317e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 7318e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 7319e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 73209ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final boolean validAccount = !TextUtils.isEmpty(accountWithDataSet.getAccountName()); 7321e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validAccount) { 73229ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki String toAppend = "(" + RawContacts.ACCOUNT_NAME + "=" 73239ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki + DatabaseUtils.sqlEscapeString(accountWithDataSet.getAccountName()) + " AND " 73244a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov + RawContacts.ACCOUNT_TYPE + "=" 73259ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki + DatabaseUtils.sqlEscapeString(accountWithDataSet.getAccountType()); 73269ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki if (accountWithDataSet.getDataSet() == null) { 7327f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro toAppend += " AND " + RawContacts.DATA_SET + " IS NULL"; 7328f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } else { 7329f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro toAppend += " AND " + RawContacts.DATA_SET + "=" + 73309ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki DatabaseUtils.sqlEscapeString(accountWithDataSet.getDataSet()); 733143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 73329ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki toAppend += ")"; 733343368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro qb.appendWhere(toAppend); 73344a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } else { 73354a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov qb.appendWhere("1"); 73364a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 73374a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov } 73384a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov 73399ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki private void appendAccountIdFromParameter(SQLiteQueryBuilder qb, Uri uri) { 73409ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final AccountWithDataSet accountWithDataSet = getAccountWithDataSetFromUri(uri); 73419ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki 73429ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // Accounts are valid by only checking one parameter, since we've 73439ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // already ruled out partial accounts. 73449ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final boolean validAccount = !TextUtils.isEmpty(accountWithDataSet.getAccountName()); 73459ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki if (validAccount) { 73469ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki final Long accountId = mDbHelper.get().getAccountIdOrNull(accountWithDataSet); 73479ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki if (accountId == null) { 73489ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki // No such account. 73499ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki qb.appendWhere("(1=2)"); 73509ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } else { 73519ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki qb.appendWhere( 73529ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki "(" + RawContactsColumns.ACCOUNT_ID + "=" + accountId.toString() + ")"); 73539ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 73549ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } else { 73559ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki qb.appendWhere("1"); 73569ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 73579ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 73589ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki 73599d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki private AccountWithDataSet getAccountWithDataSetFromUri(Uri uri) { 7360f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountName = getQueryParameter(uri, RawContacts.ACCOUNT_NAME); 7361f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov final String accountType = getQueryParameter(uri, RawContacts.ACCOUNT_TYPE); 736243368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro final String dataSet = getQueryParameter(uri, RawContacts.DATA_SET); 7363e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 7364e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey final boolean partialUri = TextUtils.isEmpty(accountName) ^ TextUtils.isEmpty(accountType); 7365e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (partialUri) { 7366e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Throw when either account is incomplete 73675d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 7368fa4a38c9d54f3e3aad4674867bb1250f450c0b95Dmitri Plotnikov "Must specify both or neither of ACCOUNT_NAME and ACCOUNT_TYPE", uri)); 7369e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey } 73709d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki return AccountWithDataSet.get(accountName, accountType, dataSet); 73719d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 73729d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 73739d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki private String appendAccountToSelection(Uri uri, String selection) { 73749d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final AccountWithDataSet accountWithDataSet = getAccountWithDataSetFromUri(uri); 7375e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey 7376e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // Accounts are valid by only checking one parameter, since we've 7377e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey // already ruled out partial accounts. 73789d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final boolean validAccount = !TextUtils.isEmpty(accountWithDataSet.getAccountName()); 7379e246689441b2ff39cb97de277d6caeec95358863Jeff Sharkey if (validAccount) { 73809d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki StringBuilder selectionSb = new StringBuilder(RawContacts.ACCOUNT_NAME + "="); 73819d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki selectionSb.append(DatabaseUtils.sqlEscapeString(accountWithDataSet.getAccountName())); 73829d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki selectionSb.append(" AND " + RawContacts.ACCOUNT_TYPE + "="); 73839d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki selectionSb.append(DatabaseUtils.sqlEscapeString(accountWithDataSet.getAccountType())); 73849d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (accountWithDataSet.getDataSet() == null) { 7385f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro selectionSb.append(" AND " + RawContacts.DATA_SET + " IS NULL"); 7386f9b77edaf5855bf6932fbc4b4b4342273669efefDave Santoro } else { 738743368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro selectionSb.append(" AND " + RawContacts.DATA_SET + "=") 73889d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki .append(DatabaseUtils.sqlEscapeString(accountWithDataSet.getDataSet())); 73899d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 73909d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (!TextUtils.isEmpty(selection)) { 73919d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki selectionSb.append(" AND ("); 73929d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki selectionSb.append(selection); 73939d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki selectionSb.append(')'); 73949d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 73959d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki return selectionSb.toString(); 73969d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } else { 73979d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki return selection; 73989d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 73999d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki } 74009d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 74019d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki private String appendAccountIdToSelection(Uri uri, String selection) { 74029d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final AccountWithDataSet accountWithDataSet = getAccountWithDataSetFromUri(uri); 74039d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 74049d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // Accounts are valid by only checking one parameter, since we've 74059d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // already ruled out partial accounts. 74069d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final boolean validAccount = !TextUtils.isEmpty(accountWithDataSet.getAccountName()); 74079d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (validAccount) { 7408321b8325f2adc4b017237b4fe010a7f0f2b017adMakoto Onuki final StringBuilder selectionSb = new StringBuilder(); 7409321b8325f2adc4b017237b4fe010a7f0f2b017adMakoto Onuki 74109d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki final Long accountId = mDbHelper.get().getAccountIdOrNull(accountWithDataSet); 74119d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki if (accountId == null) { 74129d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // No such account in the accounts table. This means, there's no rows to be 74139d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki // selected. 7414321b8325f2adc4b017237b4fe010a7f0f2b017adMakoto Onuki // Note even in this case, we still need to append the original selection, because 7415321b8325f2adc4b017237b4fe010a7f0f2b017adMakoto Onuki // it may have query parameters. If we remove these we'll get the # of parameters 7416321b8325f2adc4b017237b4fe010a7f0f2b017adMakoto Onuki // mismatch exception. 7417321b8325f2adc4b017237b4fe010a7f0f2b017adMakoto Onuki selectionSb.append("(1=2)"); 7418321b8325f2adc4b017237b4fe010a7f0f2b017adMakoto Onuki } else { 7419321b8325f2adc4b017237b4fe010a7f0f2b017adMakoto Onuki selectionSb.append(RawContactsColumns.ACCOUNT_ID + "="); 7420321b8325f2adc4b017237b4fe010a7f0f2b017adMakoto Onuki selectionSb.append(Long.toString(accountId)); 742143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro } 74229d990d339c9e3a9e03f6fe13c260d36665f00e61Makoto Onuki 7423e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong if (!TextUtils.isEmpty(selection)) { 7424e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(" AND ("); 7425e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(selection); 7426e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong selectionSb.append(')'); 7427e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 7428e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong return selectionSb.toString(); 7429e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } else { 7430e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong return selection; 7431e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 7432e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong } 7433e2579e029472f76b2dfda141444d775c67da0ec8Cynthia Wong 74347e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana /** 7435c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * Gets the value of the "limit" URI query parameter. 7436c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * 7437c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * @return A string containing a non-negative integer, or <code>null</code> if 7438c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov * the parameter is not set, or is set to an invalid value. 7439c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov */ 7440f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private String getLimit(Uri uri) { 74412e40e351a80ff608045bc9f55b48bd1a3d16926bDmitri Plotnikov String limitParam = getQueryParameter(uri, ContactsContract.LIMIT_PARAM_KEY); 7442c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov if (limitParam == null) { 7443c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 7444c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 7445c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov // make sure that the limit is a non-negative integer 7446c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov try { 7447c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov int l = Integer.parseInt(limitParam); 7448c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov if (l < 0) { 7449c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov Log.w(TAG, "Invalid limit parameter: " + limitParam); 7450c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 7451c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 7452c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return String.valueOf(l); 7453c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } catch (NumberFormatException ex) { 7454c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov Log.w(TAG, "Invalid limit parameter: " + limitParam); 7455c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return null; 7456c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 7457c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov } 7458c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov 7459b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov @Override 7460f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException { 746147ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki boolean success = false; 746247ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki try { 746347ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki if (mode.equals("r")) { 746447ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki waitForAccess(mReadAccessLatch); 746547ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki } else { 746647ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki waitForAccess(mWriteAccessLatch); 746747ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki } 746847ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki final AssetFileDescriptor ret; 746947ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki if (mapsToProfileDb(uri)) { 747047ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki switchToProfileMode(); 747147ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki ret = mProfileProvider.openAssetFile(uri, mode); 747247ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki } else { 747347ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki switchToContactMode(); 747447ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki ret = openAssetFileLocal(uri, mode); 747547ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki } 747647ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki success = true; 747747ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki return ret; 747847ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki } finally { 747947ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki if (VERBOSE_LOGGING) { 748047ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki Log.v(TAG, "openAssetFile uri=" + uri + " mode=" + mode + " success=" + success); 748147ad37083874664d5983627c3ecd8e1c9e86a6f8Makoto Onuki } 74825d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 74835d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 74845d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 74855d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro public AssetFileDescriptor openAssetFileLocal(Uri uri, String mode) 74865d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throws FileNotFoundException { 748749fb8375e9d3f7385d41b352d164a4e3e98c1528Dianne Hackborn // In some cases to implement this, we will need to do further queries 748849fb8375e9d3f7385d41b352d164a4e3e98c1528Dianne Hackborn // on the content provider. We have already done the permission check for 748949fb8375e9d3f7385d41b352d164a4e3e98c1528Dianne Hackborn // access to the uri given here, so we don't need to do further checks on 749049fb8375e9d3f7385d41b352d164a4e3e98c1528Dianne Hackborn // the queries we will do to populate it. Also this makes sure that when 749149fb8375e9d3f7385d41b352d164a4e3e98c1528Dianne Hackborn // we go through any app ops checks for those queries that the calling uid 749249fb8375e9d3f7385d41b352d164a4e3e98c1528Dianne Hackborn // and package names match at that point. 749349fb8375e9d3f7385d41b352d164a4e3e98c1528Dianne Hackborn final long ident = Binder.clearCallingIdentity(); 749449fb8375e9d3f7385d41b352d164a4e3e98c1528Dianne Hackborn try { 749549fb8375e9d3f7385d41b352d164a4e3e98c1528Dianne Hackborn return openAssetFileInner(uri, mode); 749649fb8375e9d3f7385d41b352d164a4e3e98c1528Dianne Hackborn } finally { 749749fb8375e9d3f7385d41b352d164a4e3e98c1528Dianne Hackborn Binder.restoreCallingIdentity(ident); 749849fb8375e9d3f7385d41b352d164a4e3e98c1528Dianne Hackborn } 749949fb8375e9d3f7385d41b352d164a4e3e98c1528Dianne Hackborn } 750049fb8375e9d3f7385d41b352d164a4e3e98c1528Dianne Hackborn 750149fb8375e9d3f7385d41b352d164a4e3e98c1528Dianne Hackborn private AssetFileDescriptor openAssetFileInner(Uri uri, String mode) 750249fb8375e9d3f7385d41b352d164a4e3e98c1528Dianne Hackborn throws FileNotFoundException { 75035d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro 7504ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final boolean writing = mode.contains("w"); 7505ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 7506ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getDatabase(writing); 7507415ba9ec45dc1be35d3921b28e1dae23e150fb25Dmitri Plotnikov 7508b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov int match = sUriMatcher.match(uri); 7509b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov switch (match) { 7510a549eb3c9627862a3e45d910d5c981191086a949Dmitri Plotnikov case CONTACTS_ID_PHOTO: { 7511bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro long contactId = Long.parseLong(uri.getPathSegments().get(1)); 7512ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return openPhotoAssetFile(db, uri, mode, 751324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro Data._ID + "=" + Contacts.PHOTO_ID + " AND " + 751424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro RawContacts.CONTACT_ID + "=?", 7515bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro new String[]{String.valueOf(contactId)}); 7516e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 7517b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 7518f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_ID_DISPLAY_PHOTO: { 7519f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 7520f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 7521f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by contact ID can only be read."); 7522f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7523f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long contactId = Long.parseLong(uri.getPathSegments().get(1)); 7524ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor c = db.query(Tables.CONTACTS, 7525f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{Contacts.PHOTO_FILE_ID}, 7526f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Contacts._ID + "=?", new String[]{String.valueOf(contactId)}, 7527f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null, null); 7528f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 752985077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro if (c.moveToFirst()) { 753085077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro long photoFileId = c.getLong(0); 753185077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro return openDisplayPhotoForRead(photoFileId); 753285077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } else { 753385077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro // No contact for this ID. 753485077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro throw new FileNotFoundException(uri.toString()); 753585077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } 753685077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } finally { 753785077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro c.close(); 753885077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } 753985077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } 754085077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro 754185077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro case PROFILE_DISPLAY_PHOTO: { 754285077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro if (!mode.equals("r")) { 754385077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro throw new IllegalArgumentException( 754485077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro "Display photos retrieved by contact ID can only be read."); 754585077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } 7546ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor c = db.query(Tables.CONTACTS, 754785077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro new String[]{Contacts.PHOTO_FILE_ID}, null, null, null, null, null); 754885077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro try { 754985077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro if (c.moveToFirst()) { 755085077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro long photoFileId = c.getLong(0); 755185077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro return openDisplayPhotoForRead(photoFileId); 755285077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } else { 755385077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro // No profile record. 755485077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro throw new FileNotFoundException(uri.toString()); 755585077339f2e0c6f21fd92fb8df335f3aae004fbaDave Santoro } 7556f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 7557f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 7558f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7559f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7560f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7561bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro case CONTACTS_LOOKUP_PHOTO: 7562bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro case CONTACTS_LOOKUP_ID_PHOTO: 7563f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_DISPLAY_PHOTO: 7564f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_ID_DISPLAY_PHOTO: { 7565f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 7566f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 7567bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro "Photos retrieved by contact lookup key can only be read."); 7568f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7569f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro List<String> pathSegments = uri.getPathSegments(); 7570f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro int segmentCount = pathSegments.size(); 7571f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (segmentCount < 4) { 75725d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new IllegalArgumentException(mDbHelper.get().exceptionMessage( 7573f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Missing a lookup key", uri)); 7574f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7575bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro 7576bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro boolean forDisplayPhoto = (match == CONTACTS_LOOKUP_ID_DISPLAY_PHOTO 7577bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro || match == CONTACTS_LOOKUP_DISPLAY_PHOTO); 7578f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String lookupKey = pathSegments.get(2); 7579bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro String[] projection = new String[]{Contacts.PHOTO_ID, Contacts.PHOTO_FILE_ID}; 7580f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (segmentCount == 5) { 7581f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long contactId = Long.parseLong(pathSegments.get(3)); 7582f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder lookupQb = new SQLiteQueryBuilder(); 7583f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForContacts(lookupQb, uri, projection); 7584ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor c = queryWithContactIdAndLookupKey(lookupQb, db, uri, 7585f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro projection, null, null, null, null, null, 758615826b1a7fd6d7a5be9223a61d49c0b532ccf01eDaniel Lehmann Contacts._ID, contactId, Contacts.LOOKUP_KEY, lookupKey, null); 7587f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (c != null) { 7588f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 7589f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 7590bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro if (forDisplayPhoto) { 7591bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro long photoFileId = 7592bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro c.getLong(c.getColumnIndex(Contacts.PHOTO_FILE_ID)); 7593bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro return openDisplayPhotoForRead(photoFileId); 7594bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro } else { 7595bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro long photoId = c.getLong(c.getColumnIndex(Contacts.PHOTO_ID)); 7596ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return openPhotoAssetFile(db, uri, mode, 7597bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro Data._ID + "=?", new String[]{String.valueOf(photoId)}); 7598bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro } 7599f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 7600f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 7601f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7602f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7603f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7604f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7605f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 7606f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForContacts(qb, uri, projection); 7607ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki long contactId = lookupContactIdByLookupKey(db, lookupKey); 7608ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor c = qb.query(db, projection, Contacts._ID + "=?", 7609f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{String.valueOf(contactId)}, null, null, null); 7610f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 7611f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 7612bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro if (forDisplayPhoto) { 7613bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro long photoFileId = c.getLong(c.getColumnIndex(Contacts.PHOTO_FILE_ID)); 7614bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro return openDisplayPhotoForRead(photoFileId); 7615bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro } else { 7616bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro long photoId = c.getLong(c.getColumnIndex(Contacts.PHOTO_ID)); 7617ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return openPhotoAssetFile(db, uri, mode, 7618bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro Data._ID + "=?", new String[]{String.valueOf(photoId)}); 7619bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro } 7620f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 7621f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 7622f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7623f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7624f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7625f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case RAW_CONTACTS_ID_DISPLAY_PHOTO: { 7626f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long rawContactId = Long.parseLong(uri.getPathSegments().get(1)); 7627f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro boolean writeable = !mode.equals("r"); 7628f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7629f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Find the primary photo data record for this raw contact. 7630f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 7631f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String[] projection = new String[]{Data._ID, Photo.PHOTO_FILE_ID}; 7632f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro setTablesAndProjectionMapForData(qb, uri, projection, false); 76337cf50494501938f175d288077145acf49da8f171Daniel Lehmann long photoMimetypeId = mDbHelper.get().getMimeTypeId(Photo.CONTENT_ITEM_TYPE); 7634ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki Cursor c = qb.query(db, projection, 76357cf50494501938f175d288077145acf49da8f171Daniel Lehmann Data.RAW_CONTACT_ID + "=? AND " + DataColumns.MIMETYPE_ID + "=?", 76367cf50494501938f175d288077145acf49da8f171Daniel Lehmann new String[]{String.valueOf(rawContactId), String.valueOf(photoMimetypeId)}, 7637f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro null, null, Data.IS_PRIMARY + " DESC"); 7638f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long dataId = 0; 7639f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = 0; 7640f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 7641f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (c.getCount() >= 1) { 7642f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.moveToFirst(); 7643f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro dataId = c.getLong(0); 7644f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro photoFileId = c.getLong(1); 7645f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7646f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } finally { 7647f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro c.close(); 7648f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7649f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7650f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // If writeable, open a writeable file descriptor that we can monitor. 7651f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // When the caller finishes writing content, we'll process the photo and 7652f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // update the data record. 7653f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (writeable) { 7654f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForWrite(rawContactId, dataId, uri, mode); 7655f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 7656f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 7657f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7658f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7659f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7660193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki case DISPLAY_PHOTO_ID: { 7661f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long photoFileId = ContentUris.parseId(uri); 7662f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mode.equals("r")) { 7663f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new IllegalArgumentException( 7664f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro "Display photos retrieved by key can only be read."); 7665f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7666f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return openDisplayPhotoForRead(photoFileId); 7667f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7668f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7669e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov case DATA_ID: { 767024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro long dataId = Long.parseLong(uri.getPathSegments().get(1)); 76717cf50494501938f175d288077145acf49da8f171Daniel Lehmann long photoMimetypeId = mDbHelper.get().getMimeTypeId(Photo.CONTENT_ITEM_TYPE); 7672ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return openPhotoAssetFile(db, uri, mode, 76737cf50494501938f175d288077145acf49da8f171Daniel Lehmann Data._ID + "=? AND " + DataColumns.MIMETYPE_ID + "=" + photoMimetypeId, 767424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro new String[]{String.valueOf(dataId)}); 7675d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 7676d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 7677fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen case PROFILE_AS_VCARD: { 7678fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // When opening a contact as file, we pass back contents as a 7679fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // vCard-encoded stream. We build into a local buffer first, 7680fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen // then pipe into MemoryFile once the exact size is known. 7681fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 7682fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(uri, localStream, null, null); 7683fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen return buildAssetFileDescriptor(localStream); 7684fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen } 768542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 7686fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen case CONTACTS_AS_VCARD: { 768742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // When opening a contact as file, we pass back contents as a 768842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // vCard-encoded stream. We build into a local buffer first, 768942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann // then pipe into MemoryFile once the exact size is known. 769042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 7691fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(uri, localStream, null, null); 7692f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return buildAssetFileDescriptor(localStream); 769342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 769442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann 769542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: { 769642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String lookupKeys = uri.getPathSegments().get(2); 769742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String[] loopupKeyList = lookupKeys.split(":"); 769842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final StringBuilder inBuilder = new StringBuilder(); 7699fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen Uri queryUri = Contacts.CONTENT_URI; 770042aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann int index = 0; 7701fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen 7702d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann // SQLite has limits on how many parameters can be used 7703d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann // so the IDs are concatenated to a query string here instead 770442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann for (String lookupKey : loopupKeyList) { 770542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann if (index == 0) { 7706d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann inBuilder.append("("); 770742aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } else { 7708d5a176cfe6d8701ae8b7882596711e5fc2746be1Daniel Lehmann inBuilder.append(","); 770942aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 77105d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro // TODO: Figure out what to do if the profile contact is in the list. 7711ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki long contactId = lookupContactIdByLookupKey(db, lookupKey); 771224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro inBuilder.append(contactId); 771342aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann index++; 771442aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann } 771542aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann inBuilder.append(')'); 771642aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann final String selection = Contacts._ID + " IN " + inBuilder.toString(); 7717d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 7718d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // When opening a contact as file, we pass back contents as a 7719d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // vCard-encoded stream. We build into a local buffer first, 7720d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey // then pipe into MemoryFile once the exact size is known. 7721d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); 7722fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen outputRawContactsAsVCard(queryUri, localStream, selection, null); 7723f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return buildAssetFileDescriptor(localStream); 7724d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 7725b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 7726b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov default: 77275d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new FileNotFoundException(mDbHelper.get().exceptionMessage( 77285d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro "File does not exist", uri)); 7729b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 7730b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 7731b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 7732afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro private AssetFileDescriptor openPhotoAssetFile(SQLiteDatabase db, Uri uri, String mode, 7733afc8e7ad6e5208db6c87b8500ecc1246ad966d62Dave Santoro String selection, String[] selectionArgs) 7734e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov throws FileNotFoundException { 7735e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov if (!"r".equals(mode)) { 77365d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro throw new FileNotFoundException(mDbHelper.get().exceptionMessage("Mode " + mode 7737e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov + " not supported.", uri)); 7738e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 7739e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov 7740e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov String sql = 7741ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann "SELECT " + Photo.PHOTO + " FROM " + Views.DATA + 7742e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov " WHERE " + selection; 774308ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood try { 7744f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor( 7745f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert DatabaseUtils.blobFileDescriptorForQuery(db, sql, selectionArgs)); 774608ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood } catch (SQLiteDoneException e) { 774708ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood // this will happen if the DB query returns no rows (i.e. contact does not exist) 774808ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood throw new FileNotFoundException(uri.toString()); 774908ee3fb4e82900b52d02627ed54907431f4f5adeMathew Inwood } 7750e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov } 7751e8d2c8276d6331843410c97751e46fc50b257379Dmitri Plotnikov 7752f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 7753f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Opens a display photo from the photo store for reading. 7754f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param photoFileId The display photo file ID 7755f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @return An asset file descriptor that allows the file to be read. 7756f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @throws FileNotFoundException If no photo file for the given ID exists. 7757f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 7758f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private AssetFileDescriptor openDisplayPhotoForRead(long photoFileId) 7759f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throws FileNotFoundException { 77605d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PhotoStore.Entry entry = mPhotoStore.get().get(photoFileId); 7761f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (entry != null) { 7762d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro try { 7763d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro return makeAssetFileDescriptor( 7764d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro ParcelFileDescriptor.open(new File(entry.path), 7765d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro ParcelFileDescriptor.MODE_READ_ONLY), 7766d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro entry.size); 7767d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } catch (FileNotFoundException fnfe) { 7768d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 7769d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro throw fnfe; 7770d9125effce84804631c8e618ae88b2cfc69cf529Dave Santoro } 7771f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 7772f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS); 7773f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new FileNotFoundException("No photo file found for ID " + photoFileId); 7774f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7775f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7776f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7777f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 7778f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Opens a file descriptor for a photo to be written. When the caller completes writing 7779f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * to the file (closing the output stream), the image will be parsed out and processed. 7780f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * If processing succeeds, the given raw contact ID's primary photo record will be 7781f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * populated with the inserted image (if no primary photo record exists, the data ID can 7782f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * be left as 0, and a new data record will be inserted). 7783f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param rawContactId Raw contact ID this photo entry should be associated with. 7784f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param dataId Data ID for a photo mimetype that will be updated with the inserted 7785f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * image. May be set to 0, in which case the inserted image will trigger creation 7786f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * of a new primary photo image data row for the raw contact. 7787f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param uri The URI being used to access this file. 7788f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param mode Read/write mode string. 7789f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @return An asset file descriptor the caller can use to write an image file for the 7790f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * raw contact. 7791f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 7792f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private AssetFileDescriptor openDisplayPhotoForWrite(long rawContactId, long dataId, Uri uri, 7793f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro String mode) { 7794f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 7795c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro ParcelFileDescriptor[] pipeFds = ParcelFileDescriptor.createPipe(); 7796c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro PipeMonitor pipeMonitor = new PipeMonitor(rawContactId, dataId, pipeFds[0]); 7797c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro pipeMonitor.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Object[]) null); 7798c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro return new AssetFileDescriptor(pipeFds[1], 0, AssetFileDescriptor.UNKNOWN_LENGTH); 7799f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } catch (IOException ioe) { 7800f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Log.e(TAG, "Could not create temp image file in mode " + mode); 7801f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return null; 7802f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7803f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7804f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7805f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 7806c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro * Async task that monitors the given file descriptor (the read end of a pipe) for 7807c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro * the writer finishing. If the data from the pipe contains a valid image, the image 7808c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro * is either inserted into the given raw contact or updated in the given data row. 7809f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 7810c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro private class PipeMonitor extends AsyncTask<Object, Object, Object> { 7811c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro private final ParcelFileDescriptor mDescriptor; 7812f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final long mRawContactId; 7813f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final long mDataId; 7814c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro private PipeMonitor(long rawContactId, long dataId, ParcelFileDescriptor descriptor) { 7815f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mRawContactId = rawContactId; 7816f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mDataId = dataId; 7817c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro mDescriptor = descriptor; 7818f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7819f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7820f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro @Override 7821c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro protected Object doInBackground(Object... params) { 7822c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro AutoCloseInputStream is = new AutoCloseInputStream(mDescriptor); 7823f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 7824c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro Bitmap b = BitmapFactory.decodeStream(is); 7825f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (b != null) { 7826fa4db3db4146a26f154ef2e89352ad70a5415b8eDaniel Lehmann waitForAccess(mWriteAccessLatch); 7827c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki PhotoProcessor processor = new PhotoProcessor(b, getMaxDisplayPhotoDim(), 7828c23a30e0510cf56d1dafddc79d1ab99ae9297a3fMakoto Onuki getMaxThumbnailDim()); 7829f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7830f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Store the compressed photo in the photo store. 78315d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro PhotoStore photoStore = ContactsContract.isProfileId(mRawContactId) 78325d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro ? mProfilePhotoStore 78335d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro : mContactsPhotoStore; 78345d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long photoFileId = photoStore.insert(processor); 7835f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7836c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro // Depending on whether we already had a data row to attach the photo 7837c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro // to, do an update or insert. 7838f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (mDataId != 0) { 7839f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Update the data record with the new photo. 7840f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues updateValues = new ContentValues(); 7841f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7842f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Signal that photo processing has already been handled. 7843f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(DataRowHandlerForPhoto.SKIP_PROCESSING_KEY, true); 7844f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7845f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (photoFileId != 0) { 7846f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(Photo.PHOTO_FILE_ID, photoFileId); 7847f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7848f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro updateValues.put(Photo.PHOTO, processor.getThumbnailPhotoBytes()); 7849c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro update(ContentUris.withAppendedId(Data.CONTENT_URI, mDataId), 7850c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro updateValues, null, null); 7851f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 7852f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Insert a new primary data record with the photo. 7853f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues insertValues = new ContentValues(); 7854f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7855f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Signal that photo processing has already been handled. 7856f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(DataRowHandlerForPhoto.SKIP_PROCESSING_KEY, true); 7857f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7858f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 7859f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Data.IS_PRIMARY, 1); 7860f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (photoFileId != 0) { 7861f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Photo.PHOTO_FILE_ID, photoFileId); 7862f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7863f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues.put(Photo.PHOTO, processor.getThumbnailPhotoBytes()); 7864f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insert(RawContacts.CONTENT_URI.buildUpon() 7865f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendPath(String.valueOf(mRawContactId)) 7866f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro .appendPath(RawContacts.Data.CONTENT_DIRECTORY).build(), 7867f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro insertValues); 7868f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7869c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro 7870f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7871c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro } catch (IOException e) { 7872c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro throw new RuntimeException(e); 7873f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7874c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro return null; 7875f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7876f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 7877f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 7878d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey private static final String CONTACT_MEMORY_FILE_NAME = "contactAssetFile"; 7879d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 7880d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey /** 7881f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert * Returns an {@link AssetFileDescriptor} backed by the 7882d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * contents of the given {@link ByteArrayOutputStream}. 7883d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey */ 7884f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor buildAssetFileDescriptor(ByteArrayOutputStream stream) { 7885d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey try { 7886d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey stream.flush(); 7887d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 7888d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final byte[] byteData = stream.toByteArray(); 7889d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 7890f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor( 7891f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert ParcelFileDescriptor.fromData(byteData, CONTACT_MEMORY_FILE_NAME), 7892f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert byteData.length); 7893d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } catch (IOException e) { 7894ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringert Log.w(TAG, "Problem writing stream into an ParcelFileDescriptor: " + e.toString()); 7895ac13ddd04d665442de846b59234bdc936a6699b4Bjorn Bringert return null; 7896d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 7897d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 7898d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 7899f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor makeAssetFileDescriptor(ParcelFileDescriptor fd) { 7900f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return makeAssetFileDescriptor(fd, AssetFileDescriptor.UNKNOWN_LENGTH); 7901f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert } 7902f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert 7903f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert private AssetFileDescriptor makeAssetFileDescriptor(ParcelFileDescriptor fd, long length) { 7904f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert return fd != null ? new AssetFileDescriptor(fd, 0, length) : null; 7905f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert } 7906f87d3f35a3759d5b95a403c2539859e1b3ee429fBjorn Bringert 7907d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey /** 7908d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * Output {@link RawContacts} matching the requested selection in the vCard 7909d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * format to the given {@link OutputStream}. This method returns silently if 7910d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey * any errors encountered. 7911d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey */ 7912fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen private void outputRawContactsAsVCard(Uri uri, OutputStream stream, 7913fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen String selection, String[] selectionArgs) { 7914d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey final Context context = this.getContext(); 7915dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen int vcardconfig = VCardConfig.VCARD_TYPE_DEFAULT; 7916fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen if(uri.getBooleanQueryParameter( 7917fdd04bc3a972cd72dfe7bf925e1624d656b34cf7Martijn Coenen Contacts.QUERY_PARAMETER_VCARD_NO_PHOTO, false)) { 7918dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen vcardconfig |= VCardConfig.FLAG_REFRAIN_IMAGE_EXPORT; 7919dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen } 79207a2a564e9a72969999821142c821eb1b912f0d95Daisuke Miyakawa final VCardComposer composer = 7921dfa6d58328345c7c91f2467d29189a57b96bfe2aMartijn Coenen new VCardComposer(context, vcardconfig, false); 7922108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Writer writer = null; 79233711af1a5799a7ae0c8e761e13a67a9fb5878cc8Martijn Coenen final Uri rawContactsUri; 79243711af1a5799a7ae0c8e761e13a67a9fb5878cc8Martijn Coenen if (mapsToProfileDb(uri)) { 792582792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // Pre-authorize the URI, since the caller would have already gone through the 792682792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // permission check to get here, but the pre-authorization at the top level wouldn't 792782792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro // carry over to the raw contact. 792882792ae937085bfa1f7878166e89ca4ea84fd652Dave Santoro rawContactsUri = preAuthorizeUri(RawContactsEntity.PROFILE_CONTENT_URI); 79293711af1a5799a7ae0c8e761e13a67a9fb5878cc8Martijn Coenen } else { 79303711af1a5799a7ae0c8e761e13a67a9fb5878cc8Martijn Coenen rawContactsUri = RawContactsEntity.CONTENT_URI; 79313711af1a5799a7ae0c8e761e13a67a9fb5878cc8Martijn Coenen } 7932108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa try { 7933108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer = new BufferedWriter(new OutputStreamWriter(stream)); 79343711af1a5799a7ae0c8e761e13a67a9fb5878cc8Martijn Coenen if (!composer.init(uri, selection, selectionArgs, null, rawContactsUri)) { 7935108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.w(TAG, "Failed to init VCardComposer"); 7936108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa return; 7937108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 7938d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey 7939108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa while (!composer.isAfterLast()) { 7940108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer.write(composer.createOneEntry()); 7941108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 7942108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } catch (IOException e) { 7943108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.e(TAG, "IOException: " + e); 7944108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } finally { 7945108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa composer.terminate(); 7946108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa if (writer != null) { 7947108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa try { 7948108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa writer.close(); 7949108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } catch (IOException e) { 7950108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa Log.w(TAG, "IOException during closing output stream: " + e); 7951108f1be6b0e855f1b335bc591755a9e5f488175aDaisuke Miyakawa } 7952d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 7953d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 7954d173ca0f279d89030cc7e3f1aadd18755a2e8766Jeff Sharkey } 7955b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 79564f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton @Override 79574f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton public String getType(Uri uri) { 7958a36c566037b4bb05f035d0c2cfd8b51386d7a8a6Jeff Hamilton final int match = sUriMatcher.match(uri); 79594f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton switch (match) { 7960b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS: 7961be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov return Contacts.CONTENT_TYPE; 79622d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill case CONTACTS_LOOKUP: 7963b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS_ID: 7964b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case CONTACTS_LOOKUP_ID: 796524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: 7966b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Contacts.CONTENT_ITEM_TYPE; 7967f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey case CONTACTS_AS_VCARD: 796842aff67de3f0f4b8664a74fe6ff63ae191aa51bfDaniel Lehmann case CONTACTS_AS_MULTI_VCARD: 796924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: 7970f9aeb84d61c01a473819e9173f8311ca5d678a8dJeff Sharkey return Contacts.CONTENT_VCARD_TYPE; 7971f06a42ca707b8c74d0ac9070db5f9767f4fe74ddDmitri Plotnikov case CONTACTS_ID_PHOTO: 7972bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro case CONTACTS_LOOKUP_PHOTO: 7973bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro case CONTACTS_LOOKUP_ID_PHOTO: 7974f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_ID_DISPLAY_PHOTO: 7975f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_DISPLAY_PHOTO: 7976f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case CONTACTS_LOOKUP_ID_DISPLAY_PHOTO: 7977f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro case RAW_CONTACTS_ID_DISPLAY_PHOTO: 7978193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki case DISPLAY_PHOTO_ID: 7979f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return "image/jpeg"; 7980b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case RAW_CONTACTS: 798124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: 7982be84be1519fe0b73f47c2b2fe9badb8a3e833b28Dmitri Plotnikov return RawContacts.CONTENT_TYPE; 7983b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case RAW_CONTACTS_ID: 798424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: 7985b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return RawContacts.CONTENT_ITEM_TYPE; 7986f481f22a9323fe338672f99b88b26c5f0725cd42David Brown case DATA: 798724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: 7988f481f22a9323fe338672f99b88b26c5f0725cd42David Brown return Data.CONTENT_TYPE; 7989508f57ee336c20583400b48b614bd3d57ca849ecJeff Sharkey case DATA_ID: 799076afa00cde0c8d407abf3597359280372fd85d41Makoto Onuki // We need db access for this. 799176afa00cde0c8d407abf3597359280372fd85d41Makoto Onuki waitForAccess(mReadAccessLatch); 799276afa00cde0c8d407abf3597359280372fd85d41Makoto Onuki 79935d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro long id = ContentUris.parseId(uri); 79945d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro if (ContactsContract.isProfileId(id)) { 79955d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mProfileHelper.getDataMimeType(id); 79965d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } else { 79975d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro return mContactsHelper.getDataMimeType(id); 79985d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 799948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES: 800048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Phone.CONTENT_TYPE; 800148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case PHONES_ID: 800248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Phone.CONTENT_ITEM_TYPE; 80039005e312949b4624aae6953dbdab2eaee1650835Dmitri Plotnikov case PHONE_LOOKUP: 80049005e312949b4624aae6953dbdab2eaee1650835Dmitri Plotnikov return PhoneLookup.CONTENT_TYPE; 800548828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS: 800648828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Email.CONTENT_TYPE; 800748828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case EMAILS_ID: 800848828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return Email.CONTENT_ITEM_TYPE; 800948828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS: 801048828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return StructuredPostal.CONTENT_TYPE; 801148828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov case POSTALS_ID: 801248828f54daafda2edb122258c4c6a7d2ca704128Dmitri Plotnikov return StructuredPostal.CONTENT_ITEM_TYPE; 8013b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_EXCEPTIONS: 8014b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return AggregationExceptions.CONTENT_TYPE; 8015b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_EXCEPTION_ID: 8016b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return AggregationExceptions.CONTENT_ITEM_TYPE; 8017b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case SETTINGS: 8018b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Settings.CONTENT_TYPE; 8019b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov case AGGREGATION_SUGGESTIONS: 8020b4cfef6f658ecade496351107f6ed2a4818f3e3aDmitri Plotnikov return Contacts.CONTENT_TYPE; 8021c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SUGGESTIONS: 8022c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return SearchManager.SUGGEST_MIME_TYPE; 8023c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov case SEARCH_SHORTCUT: 8024c70dc0e38ff82c6e6d6b7458637c54fbdf446aacDmitri Plotnikov return SearchManager.SHORTCUT_MIME_TYPE; 8025d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES: 8026d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov return Directory.CONTENT_TYPE; 8027d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov case DIRECTORIES_ID: 8028d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov return Directory.CONTENT_ITEM_TYPE; 8029af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki case STREAM_ITEMS: 8030af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki return StreamItems.CONTENT_TYPE; 8031af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki case STREAM_ITEMS_ID: 8032af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki return StreamItems.CONTENT_ITEM_TYPE; 8033af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki case STREAM_ITEMS_ID_PHOTOS: 8034af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki return StreamItems.StreamItemPhotos.CONTENT_TYPE; 8035af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki case STREAM_ITEMS_ID_PHOTOS_ID: 8036af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki return StreamItems.StreamItemPhotos.CONTENT_ITEM_TYPE; 8037af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki case STREAM_ITEMS_PHOTOS: 8038af43bfb95070c234ae7090f6041f6fc62366313aMakoto Onuki throw new UnsupportedOperationException("Not supported for write-only URI " + uri); 803961efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov default: 804076afa00cde0c8d407abf3597359280372fd85d41Makoto Onuki waitForAccess(mReadAccessLatch); 804161efab87c2c8166b3cd69ed1a908d1c0d7271d0bDmitri Plotnikov return mLegacyApiSupport.getType(uri); 80424f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 80434f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton } 80447e4676dfcaa8853b81c2133e0e318ed3436fe787Fred Quintana 804509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov public String[] getDefaultProjection(Uri uri) { 804609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov final int match = sUriMatcher.match(uri); 804709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov switch (match) { 804809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS: 804909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_LOOKUP: 805009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_ID: 805109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_LOOKUP_ID: 805209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_SUGGESTIONS: 805324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE: 805409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sContactsProjectionMap.getColumnNames(); 805509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 80568727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov case CONTACTS_ID_ENTITIES: 805724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_ENTITIES: 80588727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov return sEntityProjectionMap.getColumnNames(); 80598727a729d5c0e875538025f0a85b3ac64c3a7745Dmitri Plotnikov 806009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_AS_VCARD: 806109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case CONTACTS_AS_MULTI_VCARD: 806224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_AS_VCARD: 806309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sContactsVCardProjectionMap.getColumnNames(); 806409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 806509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case RAW_CONTACTS: 806609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case RAW_CONTACTS_ID: 806724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS: 806824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_RAW_CONTACTS_ID: 806909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sRawContactsProjectionMap.getColumnNames(); 807009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 807109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DATA_ID: 807209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONES: 807309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONES_ID: 807409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case EMAILS: 807509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case EMAILS_ID: 807609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case POSTALS: 807709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case POSTALS_ID: 807824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro case PROFILE_DATA: 807909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sDataProjectionMap.getColumnNames(); 808009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 808109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case PHONE_LOOKUP: 808209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sPhoneLookupProjectionMap.getColumnNames(); 808309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 808409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_EXCEPTIONS: 808509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case AGGREGATION_EXCEPTION_ID: 808609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sAggregationExceptionsProjectionMap.getColumnNames(); 808709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 808809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case SETTINGS: 808909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sSettingsProjectionMap.getColumnNames(); 809009ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 809109ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DIRECTORIES: 809209ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov case DIRECTORIES_ID: 809309ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return sDirectoryProjectionMap.getColumnNames(); 809409ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 809509ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov default: 809609ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov return null; 809709ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 809809ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov } 809909ae48b82b17e24016b14a1ab64706222ab1071fDmitri Plotnikov 8100f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov private class StructuredNameLookupBuilder extends NameLookupBuilder { 8101f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 8102f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov public StructuredNameLookupBuilder(NameSplitter splitter) { 8103f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov super(splitter); 8104f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 8105f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 8106f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov @Override 8107f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov protected void insertNameLookup(long rawContactId, long dataId, int lookupType, 8108f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov String name) { 81095d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro mDbHelper.get().insertNameLookup(rawContactId, dataId, lookupType, name); 8110f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 8111f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 8112f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov @Override 8113f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov protected String[] getCommonNicknameClusters(String normalizedName) { 8114d0569511c4b9eb961d5a73be16edb9767fa9c2ebDmitri Plotnikov return mCommonNicknameCache.getCommonNicknameClusters(normalizedName); 8115f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 8116f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov } 8117f23764675b35b5262a39c79aad8e9842460274b2Dmitri Plotnikov 81182d89933b87a15ae5ed5d6b6ec4220ac085695adaDmitri Plotnikov public void appendContactFilterAsNestedQuery(StringBuilder sb, String filterParam) { 8119d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov sb.append("(" + 8120d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov "SELECT DISTINCT " + RawContacts.CONTACT_ID + 8121d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " FROM " + Tables.RAW_CONTACTS + 8122d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " JOIN " + Tables.NAME_LOOKUP + 8123d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " ON(" + RawContactsColumns.CONCRETE_ID + "=" 8124d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov + NameLookupColumns.RAW_CONTACT_ID + ")" + 8125d60cf9ba1d039f1a22375f56c18356e0d4f8ca14Dmitri Plotnikov " WHERE normalized_name GLOB '"); 8126e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov sb.append(NameNormalizer.normalize(filterParam)); 8127916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov sb.append("*' AND " + NameLookupColumns.NAME_TYPE + 8128916f2d7104bfba857412a66b40ed60fea6546222Dmitri Plotnikov " IN(" + CONTACT_LOOKUP_NAME_TYPES + "))"); 8129e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov } 8130e46667e641cd1c60998e1ccab4b60531d5b12ef7Dmitri Plotnikov 8131fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood public boolean isPhoneNumber(String query) { 8132fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood if (TextUtils.isEmpty(query)) { 8133fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood return false; 8134fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood } 8135fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood // assume a phone number if it has at least 1 digit 8136fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood return countPhoneNumberDigits(query) > 0; 8137fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood } 8138fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood 8139fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood /** 8140fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood * Returns the number of digitis in a phone number ignoring special characters such as '-'. 8141fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood * If the string is not a valid phone number, 0 is returned. 8142fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood */ 8143fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood public static int countPhoneNumberDigits(String query) { 8144fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood int numDigits = 0; 8145fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood int len = query.length(); 81469a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov for (int i = 0; i < len; i++) { 8147fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood char c = query.charAt(i); 8148fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood if (Character.isDigit(c)) { 8149fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood numDigits ++; 8150fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood } else if (c == '*' || c == '#' || c == 'N' || c == '.' || c == ';' 8151fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood || c == '-' || c == '(' || c == ')' || c == ' ') { 8152fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood // carry on 8153fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood } else if (c == '+' && numDigits == 0) { 8154fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood // plus before any digits is ok 8155fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood } else { 8156fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood return 0; // not a phone number 81579a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 81589a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 8159fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood return numDigits; 81609a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 81619a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 81624a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov /** 81637a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * Takes components of a name from the query parameters and returns a cursor with those 81647a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * components as well as all missing components. There is no database activity involved 81657a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov * in this so the call can be made on the UI thread. 81667a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov */ 81677a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private Cursor completeName(Uri uri, String[] projection) { 81687a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov if (projection == null) { 81697a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov projection = sDataProjectionMap.getColumnNames(); 81707a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 81717a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 81727a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov ContentValues values = new ContentValues(); 8173f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov DataRowHandlerForStructuredName handler = (DataRowHandlerForStructuredName) 8174f6d4922f664127d0455b45b1f7444c4553581282Dmitri Plotnikov getDataRowHandler(StructuredName.CONTENT_ITEM_TYPE); 81757a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 81767a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov copyQueryParamsToContentValues(values, uri, 81777a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.DISPLAY_NAME, 81787a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PREFIX, 81797a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.GIVEN_NAME, 81807a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.MIDDLE_NAME, 81817a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.FAMILY_NAME, 81827a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.SUFFIX, 81837a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_NAME, 81847a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_FAMILY_NAME, 81857a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_MIDDLE_NAME, 81867a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov StructuredName.PHONETIC_GIVEN_NAME 81877a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov ); 81887a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 81897a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov handler.fixStructuredNameComponents(values, values); 81907a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 81917a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov MatrixCursor cursor = new MatrixCursor(projection); 81927a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov Object[] row = new Object[projection.length]; 81937a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov for (int i = 0; i < projection.length; i++) { 81947a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov row[i] = values.get(projection[i]); 81957a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 81967a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov cursor.addRow(row); 81977a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov return cursor; 81987a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 81997a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 82007a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov private void copyQueryParamsToContentValues(ContentValues values, Uri uri, String... columns) { 82017a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov for (String column : columns) { 82027a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov String param = uri.getQueryParameter(column); 82037a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov if (param != null) { 82047a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov values.put(column, param); 82057a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 82067a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 82077a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov } 82087a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 82097a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov 82107a3c645fa7db38449d34eb04d4e032fd079c3244Dmitri Plotnikov /** 82114a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov * Inserts an argument at the beginning of the selection arg list. 82124a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov */ 82134a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov private String[] insertSelectionArg(String[] selectionArgs, String arg) { 8214b67163a1088f09c59f324350662eb18772fac6b6Evan Millar if (selectionArgs == null) { 8215b67163a1088f09c59f324350662eb18772fac6b6Evan Millar return new String[] {arg}; 8216b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } else { 8217b67163a1088f09c59f324350662eb18772fac6b6Evan Millar int newLength = selectionArgs.length + 1; 8218b67163a1088f09c59f324350662eb18772fac6b6Evan Millar String[] newSelectionArgs = new String[newLength]; 82194a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov newSelectionArgs[0] = arg; 82204a023070dab9a069be4cac5f5ba5554b66238484Dmitri Plotnikov System.arraycopy(selectionArgs, 0, newSelectionArgs, 1, selectionArgs.length); 8221b67163a1088f09c59f324350662eb18772fac6b6Evan Millar return newSelectionArgs; 8222b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 8223b67163a1088f09c59f324350662eb18772fac6b6Evan Millar } 8224caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov 8225dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng private String[] appendSelectionArg(String[] selectionArgs, String arg) { 8226dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng if (selectionArgs == null) { 8227dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng return new String[]{arg}; 8228dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng } else { 8229dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng int newLength = selectionArgs.length + 1; 8230dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng String[] newSelectionArgs = new String[newLength]; 8231dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng newSelectionArgs[newLength] = arg; 8232dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng System.arraycopy(selectionArgs, 0, newSelectionArgs, 0, selectionArgs.length - 1); 8233dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng return newSelectionArgs; 8234dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng } 8235dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng } 8236dacd5de146b413de86d38b6f56a3fe0b2af4b155Chiao Cheng 8237caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov protected Account getDefaultAccount() { 8238caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov AccountManager accountManager = AccountManager.get(getContext()); 8239caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov try { 82405f1f4a062ac34d75d2dbf586702cbeb121cf09caDmitri Plotnikov Account[] accounts = accountManager.getAccountsByType(DEFAULT_ACCOUNT_TYPE); 8241caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov if (accounts != null && accounts.length > 0) { 8242caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov return accounts[0]; 8243caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 8244caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } catch (Throwable e) { 82456f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov Log.e(TAG, "Cannot determine the default account for contacts compatibility", e); 8246caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 82476f7446a25ecb55ee213eaa7702837cdf32e68777Dmitri Plotnikov return null; 8248caa1cf4ef062f163ac5e370cebc0e47b5ae7460eDmitri Plotnikov } 8249f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 825073f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov /** 825143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro * Returns true if the specified account type and data set is writable. 825273f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov */ 825349ed71913609193a00059df944f6259e9397b0bdMakoto Onuki public boolean isWritableAccountWithDataSet(String accountTypeAndDataSet) { 825443368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro if (accountTypeAndDataSet == null) { 8255bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov return true; 8256bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov } 8257bc487a312a84972f03776cdc5784cc132a57f8fdDmitri Plotnikov 825843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro Boolean writable = mAccountWritability.get(accountTypeAndDataSet); 825973f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov if (writable != null) { 826073f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov return writable; 826173f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov } 826273f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 8263627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov IContentService contentService = ContentResolver.getContentService(); 8264627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov try { 826543368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro // TODO(dsantoro): Need to update this logic to allow for sub-accounts. 8266627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov for (SyncAdapterType sync : contentService.getSyncAdapterTypes()) { 8267627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov if (ContactsContract.AUTHORITY.equals(sync.authority) && 826843368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro accountTypeAndDataSet.equals(sync.accountType)) { 826973f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov writable = sync.supportsUploading(); 827073f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov break; 8271627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 8272627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 8273627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } catch (RemoteException e) { 8274627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov Log.e(TAG, "Could not acquire sync adapter types"); 8275627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 827673f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 827773f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov if (writable == null) { 827873f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov writable = false; 827973f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov } 828073f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov 828143368a3f9e05a979e454e278d6a0e8475f08923dDave Santoro mAccountWritability.put(accountTypeAndDataSet, writable); 828273f1f396c155b247b903d8f4111db17d3e13dc4dDmitri Plotnikov return writable; 8283627152453c692915ac79191acd1d2d2a4dd6fb0dDmitri Plotnikov } 8284b4e61e064b59e8076df81b061add9fb358fd2ed9Dmitri Plotnikov 8285d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov 8286f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /* package */ static boolean readBooleanQueryParameter(Uri uri, String parameter, 8287f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov boolean defaultValue) { 8288f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 8289f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov // Manually parse the query, which is much faster than calling uri.getQueryParameter 8290f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String query = uri.getEncodedQuery(); 8291f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query == null) { 8292f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return defaultValue; 8293f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 8294f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 8295f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int index = query.indexOf(parameter); 8296f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (index == -1) { 8297f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return defaultValue; 8298f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 8299f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 8300f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index += parameter.length(); 8301f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 8302f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return !matchQueryParameter(query, index, "=0", false) 8303f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov && !matchQueryParameter(query, index, "=false", true); 8304f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 8305f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 8306f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov private static boolean matchQueryParameter(String query, int index, String value, 8307f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov boolean ignoreCase) { 8308f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int length = value.length(); 8309f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return query.regionMatches(ignoreCase, index, value, 0, length) 8310f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov && (query.length() == index + length || query.charAt(index + length) == '&'); 8311f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 8312f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 8313f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /** 8314f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov * A fast re-implementation of {@link Uri#getQueryParameter} 8315f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov */ 8316f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov /* package */ static String getQueryParameter(Uri uri, String parameter) { 8317f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String query = uri.getEncodedQuery(); 8318f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query == null) { 8319f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 8320f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 8321f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 8322f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int queryLength = query.length(); 8323f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int parameterLength = parameter.length(); 8324f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 8325f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov String value; 8326f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int index = 0; 8327f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov while (true) { 8328f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index = query.indexOf(parameter, index); 8329f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (index == -1) { 8330f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 83315fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa } 83325fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa 83335fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // Should match against the whole parameter instead of its suffix. 83345fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // e.g. The parameter "param" must not be found in "some_param=val". 83355fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa if (index > 0) { 83365fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa char prevChar = query.charAt(index - 1); 83375fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa if (prevChar != '?' && prevChar != '&') { 83385fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa // With "some_param=val1¶m=val2", we should find second "param" occurrence. 83395fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa index += parameterLength; 83405fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa continue; 83415fdc17bae46504edebe7285c3dbc7691ef3fbeb9Daisuke Miyakawa } 8342f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 8343f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 8344f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index += parameterLength; 8345f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 8346f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (queryLength == index) { 8347f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return null; 8348f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 8349f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 8350f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (query.charAt(index) == '=') { 8351f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov index++; 8352f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov break; 8353f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 8354f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 8355f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 8356f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov int ampIndex = query.indexOf('&', index); 8357f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov if (ampIndex == -1) { 8358f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov value = query.substring(index); 8359f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } else { 8360f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov value = query.substring(index, ampIndex); 8361f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 8362f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov 8363f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov return Uri.decode(value); 8364f7f747a00f4fa7a9e564507693419a5a8db0eb8fDmitri Plotnikov } 83655dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov 83660dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov protected boolean isAggregationUpgradeNeeded() { 83670dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov if (!mContactAggregator.isEnabled()) { 83680dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov return false; 83690dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 83700dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 83715d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro int version = Integer.parseInt(mContactsHelper.getProperty( 83729ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki DbProperties.AGGREGATION_ALGORITHM, "1")); 83730dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov return version < PROPERTY_AGGREGATION_ALGORITHM_VERSION; 83740dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 83750dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov 8376bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov protected void upgradeAggregationAlgorithmInBackground() { 83770dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov Log.i(TAG, "Upgrading aggregation algorithm"); 83780992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki 8379565b62f354d8b6aadc760092a7dbf483f8bbbe17Makoto Onuki final long start = SystemClock.elapsedRealtime(); 83800992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki setProviderStatus(ProviderStatus.STATUS_UPGRADING); 83810992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki 83820992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki // Re-aggregate all visible raw contacts. 83830dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov try { 83840992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki int count = 0; 83850992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki SQLiteDatabase db = null; 83860992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki boolean success = false; 8387ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki boolean transactionStarted = false; 83880dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov try { 8389ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki // Re-aggregation is only for the contacts DB. 83900992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki switchToContactMode(); 83910992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki db = mContactsHelper.getWritableDatabase(); 83920992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki 83930992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki // Start the actual process. 83940992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki db.beginTransaction(); 8395ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki transactionStarted = true; 83960992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki 83970992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki count = mContactAggregator.markAllVisibleForAggregation(db); 83980992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki mContactAggregator.aggregateInTransaction(mTransactionContext.get(), db); 83990992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki 84000992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki updateSearchIndexInTransaction(); 84010992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki 8402ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki updateAggregationAlgorithmVersion(); 84030992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki 84040992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki db.setTransactionSuccessful(); 84050992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki 84060992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki success = true; 84070dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } finally { 84080992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki mTransactionContext.get().clearAll(); 8409ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki if (transactionStarted) { 84100992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki db.endTransaction(); 84110992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki } 84120992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki final long end = SystemClock.elapsedRealtime(); 84130992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki Log.i(TAG, "Aggregation algorithm upgraded for " + count + " raw contacts" 84140992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki + (success ? (" in " + (end - start) + "ms") : " failed")); 84155d0a768b56ed4bd0dfef81b8389247ba74766659Dave Santoro } 8416ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki } catch (RuntimeException e) { 8417ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki Log.e(TAG, "Failed to upgrade aggregation algorithm; continuing anyway.", e); 8418ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki 8419ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki // Got some exception during re-aggregation. Re-aggregation isn't that important, so 8420ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki // just bump the aggregation algorithm version and let the provider start normally. 8421ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki try { 8422ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki final SQLiteDatabase db = mContactsHelper.getWritableDatabase(); 8423ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki db.beginTransaction(); 8424ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki try { 8425ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki updateAggregationAlgorithmVersion(); 8426ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki db.setTransactionSuccessful(); 8427ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki } finally { 8428ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki db.endTransaction(); 8429ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki } 8430ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki } catch (RuntimeException e2) { 8431ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki // Couldn't even update the algorithm version... There's really nothing we can do 8432ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki // here, so just go ahead and start the provider. Next time the provider starts 8433ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki // it'll try re-aggregation again, which may or may not succeed. 8434ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki Log.e(TAG, "Failed to bump aggregation algorithm version; continuing anyway.", e2); 8435ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki } 84360992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki } finally { // Need one more finally because endTransaction() may fail. 84370992b9d4969ed0eee6e879db94292b635229e2b7Makoto Onuki setProviderStatus(ProviderStatus.STATUS_NORMAL); 84380dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 84390dce6bf7a86a78d3073327419f17395c3a2d2688Dmitri Plotnikov } 84409a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov 8441ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki private void updateAggregationAlgorithmVersion() { 8442ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki mContactsHelper.setProperty(DbProperties.AGGREGATION_ALGORITHM, 8443ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki String.valueOf(PROPERTY_AGGREGATION_ALGORITHM_VERSION)); 8444ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki } 8445ff91ec356f1b17dea095a880f61b8bc4ff333b1eMakoto Onuki 8446193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki @VisibleForTesting 84479a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov boolean isPhone() { 8448193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki if (!mIsPhoneInitialized) { 8449193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki mIsPhone = new TelephonyManager(getContext()).isVoiceCapable(); 8450193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki mIsPhoneInitialized = true; 84519a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 8452193f2da3b4c3e019cc3a85a7101478332b1869ecMakoto Onuki return mIsPhone; 84539a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 845446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 8455fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood boolean isVoiceCapable() { 8456fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood // this copied from com.android.phone.PhoneApp.onCreate(): 8457fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood 8458fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood // "voice capable" flag. 8459fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood // This flag currently comes from a resource (which is 8460fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood // overrideable on a per-product basis): 8461fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood return getContext().getResources() 8462fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood .getBoolean(com.android.internal.R.bool.config_voice_capable); 8463fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood // ...but this might eventually become a PackageManager "system 8464fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood // feature" instead, in which case we'd do something like: 8465fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood // return 8466fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood // getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS); 8467fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood } 8468fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood 846946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private boolean handleDataUsageFeedback(Uri uri) { 8470dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki final long currentTimeMillis = Clock.getInstance().currentTimeMillis(); 847146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String usageType = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE); 847246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String[] ids = uri.getLastPathSegment().trim().split(","); 8473dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki final ArrayList<Long> dataIds = new ArrayList<Long>(ids.length); 847446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 847546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa for (String id : ids) { 847646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa dataIds.add(Long.valueOf(id)); 847746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 847846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final boolean successful; 847946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (TextUtils.isEmpty(usageType)) { 848046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa Log.w(TAG, "Method for data usage feedback isn't specified. Ignoring."); 848146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa successful = false; 848246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 848346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa successful = updateDataUsageStat(dataIds, usageType, currentTimeMillis) > 0; 848446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 848546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 848646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa // Handle old API. This doesn't affect the result of this entire method. 8487dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki final StringBuilder rawContactIdSelect = new StringBuilder(); 8488dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki rawContactIdSelect.append("SELECT " + Data.RAW_CONTACT_ID + " FROM " + Tables.DATA + 8489dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " WHERE " + Data._ID + " IN ("); 8490dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki for (int i = 0; i < ids.length; i++) { 8491dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki if (i > 0) rawContactIdSelect.append(","); 8492dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki rawContactIdSelect.append(ids[i]); 849346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 8494dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki rawContactIdSelect.append(")"); 849546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 8496ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 8497dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki 8498dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs1[0] = String.valueOf(currentTimeMillis); 8499dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki 8500dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki db.execSQL("UPDATE " + Tables.RAW_CONTACTS + 8501dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " SET " + RawContacts.LAST_TIME_CONTACTED + "=?" + 8502dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki "," + RawContacts.TIMES_CONTACTED + "=" + 8503dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki "ifnull(" + RawContacts.TIMES_CONTACTED + ",0) + 1" + 8504dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " WHERE " + RawContacts._ID + " IN (" + rawContactIdSelect.toString() + ")" 8505dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki , mSelectionArgs1); 8506dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki db.execSQL("UPDATE " + Tables.CONTACTS + 8507dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " SET " + Contacts.LAST_TIME_CONTACTED + "=?" + 8508dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki "," + Contacts.TIMES_CONTACTED + "=" + 8509dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki "ifnull(" + Contacts.TIMES_CONTACTED + ",0) + 1" + 8510dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " WHERE " + Contacts._ID + " IN (SELECT " + RawContacts.CONTACT_ID + 8511dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " FROM " + Tables.RAW_CONTACTS + 8512dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " WHERE " + RawContacts._ID + " IN (" + rawContactIdSelect.toString() + "))" 8513dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki , mSelectionArgs1); 851446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return successful; 851546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 851646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 8517dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki private interface DataUsageStatQuery { 8518dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki String TABLE = Tables.DATA_USAGE_STAT; 8519dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki 8520dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki String[] COLUMNS = new String[] { 8521dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki DataUsageStatColumns._ID, 8522dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki }; 8523dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki int ID = 0; 8524dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki 8525dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki String SELECTION = DataUsageStatColumns.DATA_ID + " =? AND " 8526dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki + DataUsageStatColumns.USAGE_TYPE_INT + " =?"; 8527dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki } 8528dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki 852946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 853046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Update {@link Tables#DATA_USAGE_STAT}. 853146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * 853246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * @return the number of rows affected. 853346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 8534f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa @VisibleForTesting 8535f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa /* package */ int updateDataUsageStat( 8536f9648a03e88e2d1a91c616a20d903e4c9a2468e5Daisuke Miyakawa List<Long> dataIds, String type, long currentTimeMillis) { 8537dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki 8538ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki final SQLiteDatabase db = mDbHelper.get().getWritableDatabase(); 8539dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki 8540dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki final String typeString = String.valueOf(getDataUsageFeedbackType(type, null)); 8541dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki final String currentTimeMillisString = String.valueOf(currentTimeMillis); 8542dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki 8543dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki for (long dataId : dataIds) { 8544dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki final String dataIdString = String.valueOf(dataId); 8545dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs2[0] = dataIdString; 8546dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs2[1] = typeString; 8547dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki final Cursor cursor = db.query(DataUsageStatQuery.TABLE, 8548dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki DataUsageStatQuery.COLUMNS, DataUsageStatQuery.SELECTION, 8549dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs2, null, null, null); 855046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa try { 8551dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki if (cursor.moveToFirst()) { 8552dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki final long id = cursor.getLong(DataUsageStatQuery.ID); 8553dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki 8554dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs2[0] = currentTimeMillisString; 8555dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs2[1] = String.valueOf(id); 8556dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki 8557dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki db.execSQL("UPDATE " + Tables.DATA_USAGE_STAT + 8558dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " SET " + DataUsageStatColumns.TIMES_USED + "=" + 8559dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki "ifnull(" + DataUsageStatColumns.TIMES_USED +",0)+1" + 8560dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki "," + DataUsageStatColumns.LAST_TIME_USED + "=?" + 8561dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki " WHERE " + DataUsageStatColumns._ID + "=?", 8562dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs2); 8563dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki } else { 8564dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs4[0] = dataIdString; 8565dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs4[1] = typeString; 8566dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs4[2] = "1"; // times used 8567dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs4[3] = currentTimeMillisString; 8568dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki db.execSQL("INSERT INTO " + Tables.DATA_USAGE_STAT + 8569dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki "(" + DataUsageStatColumns.DATA_ID + 8570dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki "," + DataUsageStatColumns.USAGE_TYPE_INT + 8571dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki "," + DataUsageStatColumns.TIMES_USED + 8572dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki "," + DataUsageStatColumns.LAST_TIME_USED + 8573dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki ") VALUES (?,?,?,?)", 8574dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki mSelectionArgs4); 857546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 857646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } finally { 8577dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki cursor.close(); 857846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 857946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 858046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 858146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return dataIds.size(); 858246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 858346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 858446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa /** 858546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * Returns a sort order String for promoting data rows (email addresses, phone numbers, etc.) 858646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * associated with a primary account. The primary account should be supplied from applications 858746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * with {@link ContactsContract#PRIMARY_ACCOUNT_NAME} and 858846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * {@link ContactsContract#PRIMARY_ACCOUNT_TYPE}. Null will be returned when the primary 858946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa * account isn't available. 859046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa */ 859146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa private String getAccountPromotionSortOrder(Uri uri) { 859246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String primaryAccountName = 859346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa uri.getQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME); 859446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa final String primaryAccountType = 859546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa uri.getQueryParameter(ContactsContract.PRIMARY_ACCOUNT_TYPE); 859646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa 859746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa // Data rows associated with primary account should be promoted. 859846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(primaryAccountName)) { 859946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa StringBuilder sb = new StringBuilder(); 860046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append("(CASE WHEN " + RawContacts.ACCOUNT_NAME + "="); 860146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DatabaseUtils.appendEscapedSQLString(sb, primaryAccountName); 860246abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa if (!TextUtils.isEmpty(primaryAccountType)) { 860346abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" AND " + RawContacts.ACCOUNT_TYPE + "="); 860446abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa DatabaseUtils.appendEscapedSQLString(sb, primaryAccountType); 860546abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 860646abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa sb.append(" THEN 0 ELSE 1 END)"); 860746abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return sb.toString(); 860846abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } else { 860946abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa return null; 861046abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 861146abbb56764add30cb6e6506f55d8dededc88113Daisuke Miyakawa } 8612b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson 8613b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson /** 8614b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson * Checks the URI for a deferred snippeting request 8615b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson * @return a boolean indicating if a deferred snippeting request is in the RI 8616b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson */ 8617b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson private boolean deferredSnippetingRequested(Uri uri) { 8618b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson String deferredSnippeting = 8619b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson getQueryParameter(uri, SearchSnippetColumns.DEFERRED_SNIPPETING_KEY); 8620b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson return !TextUtils.isEmpty(deferredSnippeting) && deferredSnippeting.equals("1"); 8621b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 8622b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson 8623b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson /** 8624b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson * Checks if query is a single word or not. 8625b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson * @return a boolean indicating if the query is one word or not 8626b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson */ 8627b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson private boolean isSingleWordQuery(String query) { 8628c231bb10ca1ae310568a0c7cb4f327e348ecde3bChiao Cheng // Split can remove empty trailing tokens but cannot remove starting empty tokens so we 8629c231bb10ca1ae310568a0c7cb4f327e348ecde3bChiao Cheng // have to loop. 8630c231bb10ca1ae310568a0c7cb4f327e348ecde3bChiao Cheng String[] tokens = query.split(QUERY_TOKENIZER_REGEX, 0); 8631c231bb10ca1ae310568a0c7cb4f327e348ecde3bChiao Cheng int count = 0; 8632c231bb10ca1ae310568a0c7cb4f327e348ecde3bChiao Cheng for (String token : tokens) { 8633c231bb10ca1ae310568a0c7cb4f327e348ecde3bChiao Cheng if (!"".equals(token)) { 8634c231bb10ca1ae310568a0c7cb4f327e348ecde3bChiao Cheng count++; 8635c231bb10ca1ae310568a0c7cb4f327e348ecde3bChiao Cheng } 8636c231bb10ca1ae310568a0c7cb4f327e348ecde3bChiao Cheng } 8637c231bb10ca1ae310568a0c7cb4f327e348ecde3bChiao Cheng return count == 1; 8638b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 8639b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson 8640b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson /** 8641b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson * Checks the projection for a SNIPPET column indicating that a snippet is needed 8642b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson * @return a boolean indicating if a snippet is needed or not. 8643b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson */ 8644b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson private boolean snippetNeeded(String [] projection) { 8645ac2a6e814edb3d5e5bcca28d7d3f3977a489c2edMakoto Onuki return ContactsDatabaseHelper.isInProjection(projection, SearchSnippetColumns.SNIPPET); 8646b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson } 86479ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki 86489ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki /** 8649084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki * Create a single row cursor for a simple, informational queries, such as 8650084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki * {@link ProviderStatus#CONTENT_URI}. 8651084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki */ 8652084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki @VisibleForTesting 8653084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki static Cursor buildSingleRowResult(String[] projection, String[] availableColumns, 8654084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki Object[] data) { 8655084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki Preconditions.checkArgument(availableColumns.length == data.length); 8656084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki if (projection == null) { 8657084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki projection = availableColumns; 8658084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki } 8659084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki final MatrixCursor c = new MatrixCursor(projection, 1); 8660084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki final RowBuilder row = c.newRow(); 8661084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki 8662084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki // It's O(n^2), but it's okay because we only have a few columns. 8663084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki for (int i = 0; i < c.getColumnCount(); i++) { 8664084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki final String column = c.getColumnName(i); 8665084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki 8666084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki boolean found = false; 8667084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki for (int j = 0; j < availableColumns.length; j++) { 8668084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki if (availableColumns[j].equals(column)) { 8669084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki row.add(data[j]); 8670084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki found = true; 8671084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki break; 8672084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki } 8673084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki } 8674084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki if (!found) { 8675084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki throw new IllegalArgumentException("Invalid column " + projection[i]); 8676084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki } 8677084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki } 8678084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki return c; 8679084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki } 8680084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki 8681084fe28445cf74e3fa93522f8f8e5da6e065b8c3Makoto Onuki /** 86829ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki * @return the currently active {@link ContactsDatabaseHelper} for the current thread. 86839ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki */ 8684833072a525ea45426082d3bac0cd6ae1a8c36f22Makoto Onuki @NeededForTesting 86859ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki public ContactsDatabaseHelper getThreadActiveDatabaseHelperForTest() { 86869ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki return mDbHelper.get(); 86879ba8463dd030e5e26a4f99dfe2a6ad52b2410d73Makoto Onuki } 868835997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 868935997f3fdee2984b6d5373326110eda26929001aMakoto Onuki @Override 869035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 869135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki pw.print("FastScrollingIndex stats:\n"); 869235997f3fdee2984b6d5373326110eda26929001aMakoto Onuki pw.printf("request=%d miss=%d (%d%%) avg time=%dms\n", 869335997f3fdee2984b6d5373326110eda26929001aMakoto Onuki mFastScrollingIndexCacheRequestCount, 869435997f3fdee2984b6d5373326110eda26929001aMakoto Onuki mFastScrollingIndexCacheMissCount, 869535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki safeDiv(mFastScrollingIndexCacheMissCount * 100, 869635997f3fdee2984b6d5373326110eda26929001aMakoto Onuki mFastScrollingIndexCacheRequestCount), 869735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki safeDiv(mTotalTimeFastScrollingIndexGenerate, mFastScrollingIndexCacheMissCount) 869835997f3fdee2984b6d5373326110eda26929001aMakoto Onuki ); 869935997f3fdee2984b6d5373326110eda26929001aMakoto Onuki } 870035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki 870135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki private static final long safeDiv(long dividend, long divisor) { 870235997f3fdee2984b6d5373326110eda26929001aMakoto Onuki return (divisor == 0) ? 0 : dividend / divisor; 870335997f3fdee2984b6d5373326110eda26929001aMakoto Onuki } 8704dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki 8705dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki private static final int getDataUsageFeedbackType(String type, Integer defaultType) { 8706dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki if (DataUsageFeedback.USAGE_TYPE_CALL.equals(type)) { 8707dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki return DataUsageStatColumns.USAGE_TYPE_INT_CALL; // 0 8708dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki } 8709dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki if (DataUsageFeedback.USAGE_TYPE_LONG_TEXT.equals(type)) { 8710dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki return DataUsageStatColumns.USAGE_TYPE_INT_LONG_TEXT; // 1 8711dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki } 8712dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki if (DataUsageFeedback.USAGE_TYPE_SHORT_TEXT.equals(type)) { 8713dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki return DataUsageStatColumns.USAGE_TYPE_INT_SHORT_TEXT; // 2 8714dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki } 8715dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki if (defaultType != null) { 8716dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki return defaultType; 8717dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki } 8718dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki throw new IllegalArgumentException("Invalid usage type " + type); 8719dfab50ecd585e55769dea451cb3a47ff69b8b86dMakoto Onuki } 8720ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 8721ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki /** Use only for debug logging */ 8722ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki @Override 8723ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki public String toString() { 8724ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki return "ContactsProvider2"; 8725ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki } 8726ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki 8727ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki @NeededForTesting 8728ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki public void switchToProfileModeForTest() { 8729ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki switchToProfileMode(); 8730ae32283e7fc5b749df96523d8bb343b9068b65baMakoto Onuki } 87314f864360c24bd26c111bf38a035e8e2d2609e84aJeff Hamilton} 8732